Skip to content

Commit

Permalink
[Truffle] Initial import of Rubinius's encoding system.
Browse files Browse the repository at this point in the history
  • Loading branch information
nirvdrum committed Mar 25, 2015
1 parent f75b331 commit 7879048
Show file tree
Hide file tree
Showing 8 changed files with 904 additions and 7 deletions.
Expand Up @@ -11,6 +11,7 @@

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;

import org.jcodings.Encoding;
Expand All @@ -20,11 +21,19 @@
import org.jruby.Ruby;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.truffle.nodes.dispatch.CallDispatchHeadNode;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNodeFactory;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.UndefinedPlaceholder;
import org.jruby.truffle.runtime.core.*;
import org.jruby.truffle.runtime.hash.HashOperations;
import org.jruby.truffle.runtime.hash.KeyValue;
import org.jruby.util.ByteList;
import org.jruby.util.io.EncodingUtils;

import java.util.ArrayList;
import java.util.List;

@CoreClass(name = "Encoding::Converter")
public abstract class EncodingConverterNodes {

Expand Down Expand Up @@ -76,7 +85,7 @@ public RubyArray convpath(RubyEncodingConverter converter) {

}

@CoreMethod(names = "initialize", required = 2)
@CoreMethod(names = "initialize", required = 2, optional = 1)
public abstract static class InitializeNode extends CoreMethodNode {

public InitializeNode(RubyContext context, SourceSection sourceSection) {
Expand All @@ -89,7 +98,32 @@ public InitializeNode(InitializeNode prev) {

@TruffleBoundary
@Specialization
public RubyNilClass initialize(RubyEncodingConverter self, RubyString source, RubyString destination) {
public RubyNilClass initialize(RubyEncodingConverter self, RubyString source, RubyString destination, UndefinedPlaceholder options) {
notDesignedForCompilation();

// Adapted from RubyConverter - see attribution there

Ruby runtime = getContext().getRuntime();
Encoding[] encs = {null, null};
byte[][] encNames = {null, null};
int[] ecflags = {0};
IRubyObject[] ecopts = {runtime.getNil()};

EncodingUtils.econvArgs(runtime.getCurrentContext(), new IRubyObject[]{getContext().toJRuby(source), getContext().toJRuby(destination)}, encNames, encs, ecflags, ecopts);
EConv econv = EncodingUtils.econvOpenOpts(runtime.getCurrentContext(), encNames[0], encNames[1], ecflags[0], ecopts[0]);

if (econv == null) {
throw new UnsupportedOperationException();
}

self.setEConv(econv);

return nil();
}

@TruffleBoundary
@Specialization
public RubyNilClass initialize(RubyEncodingConverter self, RubyString source, RubyString destination, RubyHash options) {
notDesignedForCompilation();

// Adapted from RubyConverter - see attribution there
Expand Down Expand Up @@ -182,4 +216,43 @@ public void call(byte[] source, byte[] destination, int depth) {

}

@RubiniusOnly
@CoreMethod(names = "transcoding_map", onSingleton = true)
public abstract static class TranscodingMapNode extends CoreMethodNode {

@Child private CallDispatchHeadNode newLookupTableNode;
@Child private CallDispatchHeadNode lookupTableWriteNode;

public TranscodingMapNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
newLookupTableNode = DispatchHeadNodeFactory.createMethodCall(context);
lookupTableWriteNode = DispatchHeadNodeFactory.createMethodCall(context);
}

public TranscodingMapNode(TranscodingMapNode prev) {
super(prev);
newLookupTableNode = prev.newLookupTableNode;
lookupTableWriteNode = prev.lookupTableWriteNode;
}

@Specialization
public RubyHash transcodingMap(VirtualFrame frame) {
List<KeyValue> entries = new ArrayList<>();

for (RubyEncoding e : RubyEncoding.cloneEncodingList()) {
final RubySymbol key = getContext().newSymbol(e.getName());
final Object value = newLookupTableNode.call(frame, getContext().getCoreLibrary().getLookupTableClass(), "new", null);

final Object tupleValues = new Object[2];


lookupTableWriteNode.call(frame, value, "[]=", null, key, nil());

entries.add(new KeyValue(key, value));
}

return HashOperations.verySlowFromEntries(getContext().getCoreLibrary().getHashClass(), entries, true);
}
}

}
Expand Up @@ -30,9 +30,13 @@
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.coerce.ToStrNode;
import org.jruby.truffle.nodes.coerce.ToStrNodeFactory;
import org.jruby.truffle.nodes.dispatch.CallDispatchHeadNode;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNode;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNodeFactory;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.RubyArray;
import org.jruby.truffle.runtime.core.RubyBasicObject;
import org.jruby.truffle.runtime.core.RubyEncoding;
import org.jruby.truffle.runtime.core.RubyHash;
import org.jruby.truffle.runtime.core.RubyNilClass;
Expand Down Expand Up @@ -501,6 +505,80 @@ public boolean isDummy(RubyEncoding encoding) {
}
}

@RubiniusOnly
@CoreMethod(names = "encoding_map", onSingleton = true)
public abstract static class EncodingMapNode extends CoreMethodNode {

@Child private CallDispatchHeadNode newLookupTableNode;
@Child private CallDispatchHeadNode lookupTableWriteNode;
@Child private CallDispatchHeadNode newTupleNode;

public EncodingMapNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
newLookupTableNode = DispatchHeadNodeFactory.createMethodCall(context);
lookupTableWriteNode = DispatchHeadNodeFactory.createMethodCall(context);
newTupleNode = DispatchHeadNodeFactory.createMethodCall(context);
}

public EncodingMapNode(EncodingMapNode prev) {
super(prev);
newLookupTableNode = prev.newLookupTableNode;
lookupTableWriteNode = prev.lookupTableWriteNode;
newTupleNode = prev.newTupleNode;
}

@Specialization
public Object encodingMap(VirtualFrame frame) {
Object ret = newLookupTableNode.call(frame, getContext().getCoreLibrary().getLookupTableClass(), "new", null);

final RubyEncoding[] encodings = RubyEncoding.cloneEncodingList();
for (int i = 0; i < encodings.length; i++) {
final RubySymbol key = getContext().newSymbol(encodings[i].getName());
final Object value = newTupleNode.call(frame, getContext().getCoreLibrary().getTupleClass(), "create", null, nil(), i);

lookupTableWriteNode.call(frame, ret, "[]=", null, key, value);
}

final Hash.HashEntryIterator i = getContext().getRuntime().getEncodingService().getAliases().entryIterator();
while (i.hasNext()) {
final CaseInsensitiveBytesHash.CaseInsensitiveBytesHashEntry<EncodingDB.Entry> e =
((CaseInsensitiveBytesHash.CaseInsensitiveBytesHashEntry<EncodingDB.Entry>)i.next());

final RubySymbol key = getContext().newSymbol(new ByteList(e.bytes, e.p, e.end - e.p));
final RubyString alias = getContext().makeString(new ByteList(e.bytes, e.p, e.end - e.p));
final int index = e.value.getIndex();


final Object value = newTupleNode.call(frame, getContext().getCoreLibrary().getTupleClass(), "create", null, alias, index);
lookupTableWriteNode.call(frame, ret, "[]=", null, key, value);
}

final Object externalTuple = newTupleNode.call(
frame,
getContext().getCoreLibrary().getTupleClass(),
"create",
null,
getContext().makeString("external"),
getContext().getRuntime().getDefaultExternalEncoding().getIndex()
);

lookupTableWriteNode.call(frame, ret, "[]=", null, getContext().newSymbol("EXTERNAL"), externalTuple);

final Object localeTuple = newTupleNode.call(
frame,
getContext().getCoreLibrary().getTupleClass(),
"create",
null,
getContext().makeString("locale"),
getContext().getRuntime().getEncodingService().getLocaleEncoding().getIndex()
);

lookupTableWriteNode.call(frame, ret, "[]=", null, getContext().newSymbol("LOCALE"), localeTuple);

return ret;
}
}

@CoreMethod(names = { "name", "to_s" })
public abstract static class ToSNode extends CoreMethodNode {

Expand Down
Expand Up @@ -20,6 +20,97 @@
*/
public abstract class EncodingPrimitiveNodes {

@RubiniusPrimitive(name = "encoding_converter_allocate")
public static abstract class EncodingConverterAllocateNode extends RubiniusPrimitiveNode {

public EncodingConverterAllocateNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public EncodingConverterAllocateNode(EncodingConverterAllocateNode prev) {
super(prev);
}

@Specialization
public Object encodingConverterAllocate(RubyEncoding fromEncoding, RubyEncoding toEncoding, RubyHash options) {
return new RubyEncodingConverter(getContext().getCoreLibrary().getEncodingConverterClass(), null);
}

}

@RubiniusPrimitive(name = "encoding_converter_primitive_convert")
public static abstract class EncodingConverterPrimitiveConvertNode extends RubiniusPrimitiveNode {

public EncodingConverterPrimitiveConvertNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public EncodingConverterPrimitiveConvertNode(EncodingConverterPrimitiveConvertNode prev) {
super(prev);
}

@Specialization
public Object encodingConverterPrimitiveConvert(RubyBasicObject encodingConverter, RubyString source,
RubyString target, int offset, int size, RubyHash options) {
throw new UnsupportedOperationException("not implemented");
}

}

@RubiniusPrimitive(name = "encoding_converter_putback")
public static abstract class EncodingConverterPutbackNode extends RubiniusPrimitiveNode {

public EncodingConverterPutbackNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public EncodingConverterPutbackNode(EncodingConverterPutbackNode prev) {
super(prev);
}

@Specialization
public Object encodingConverterPutback(RubyBasicObject encodingConverter, int maxBytes) {
throw new UnsupportedOperationException("not implemented");
}

}

@RubiniusPrimitive(name = "encoding_converter_last_error")
public static abstract class EncodingConverterLastErrorNode extends RubiniusPrimitiveNode {

public EncodingConverterLastErrorNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public EncodingConverterLastErrorNode(EncodingConverterLastErrorNode prev) {
super(prev);
}

@Specialization
public Object encodingConverterLastError(RubyBasicObject encodingConverter) {
throw new UnsupportedOperationException("not implemented");
}

}

@RubiniusPrimitive(name = "encoding_converter_primitive_errinfo")
public static abstract class EncodingConverterErrinfoNode extends RubiniusPrimitiveNode {

public EncodingConverterErrinfoNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public EncodingConverterErrinfoNode(EncodingConverterErrinfoNode prev) {
super(prev);
}

@Specialization
public Object encodingConverterLastError(RubyBasicObject encodingConverter) {
throw new UnsupportedOperationException("not implemented");
}

}

@RubiniusPrimitive(name = "encoding_get_object_encoding", needsSelf = false)
public static abstract class EncodingGetObjectEncodingNode extends RubiniusPrimitiveNode {

Expand Down
Expand Up @@ -76,6 +76,7 @@ public class CoreLibrary {
private final RubyClass keyErrorClass;
private final RubyClass loadErrorClass;
private final RubyClass localJumpErrorClass;
private final RubyClass lookupTableClass;
private final RubyClass matchDataClass;
private final RubyClass moduleClass;
private final RubyClass nameErrorClass;
Expand Down Expand Up @@ -106,6 +107,7 @@ public class CoreLibrary {
private final RubyClass threadClass;
private final RubyClass timeClass;
private final RubyClass trueClass;
private final RubyClass tupleClass;
private final RubyClass typeErrorClass;
private final RubyClass zeroDivisionErrorClass;
private final RubyModule configModule;
Expand Down Expand Up @@ -179,9 +181,6 @@ public CoreLibrary(RubyContext context) {
// Exception
exceptionClass = defineClass("Exception", new RubyException.ExceptionAllocator());

// EncodingError
encodingErrorClass = defineClass(exceptionClass, "EncodingError");

// FiberError
fiberErrorClass = defineClass(exceptionClass, "FiberError");

Expand All @@ -194,6 +193,7 @@ public CoreLibrary(RubyContext context) {
// StandardError
standardErrorClass = defineClass(exceptionClass, "StandardError");
argumentErrorClass = defineClass(standardErrorClass, "ArgumentError");
encodingErrorClass = defineClass(standardErrorClass, "EncodingError");
ioErrorClass = defineClass(standardErrorClass, "IOError");
localJumpErrorClass = defineClass(standardErrorClass, "LocalJumpError");
regexpErrorClass = defineClass(standardErrorClass, "RegexpError");
Expand Down Expand Up @@ -299,7 +299,7 @@ public CoreLibrary(RubyContext context) {

// The rest

encodingCompatibilityErrorClass = defineClass(encodingClass, standardErrorClass, "CompatibilityError");
encodingCompatibilityErrorClass = defineClass(encodingClass, encodingErrorClass, "CompatibilityError");

encodingConverterClass = defineClass(encodingClass, objectClass, "Converter", new RubyEncodingConverter.EncodingConverterAllocator());

Expand All @@ -309,7 +309,9 @@ public CoreLibrary(RubyContext context) {

rubiniusModule = defineModule("Rubinius");
byteArrayClass = defineClass(rubiniusModule, objectClass, "ByteArray");
lookupTableClass = defineClass(rubiniusModule, hashClass, "LookupTable");
stringDataClass = defineClass(rubiniusModule, objectClass, "StringData");
tupleClass = defineClass(rubiniusModule, arrayClass, "Tuple");

// Include the core modules

Expand Down Expand Up @@ -1149,10 +1151,18 @@ public RubyClass getByteArrayClass() {
return byteArrayClass;
}

public RubyClass getLookupTableClass() {
return lookupTableClass;
}

public RubyClass getStringDataClass() {
return stringDataClass;
}

public RubyClass getTupleClass() {
return tupleClass;
}

public RubyBasicObject getRubiniusUndefined() {
return rubiniusUndefined;
}
Expand Down
3 changes: 2 additions & 1 deletion truffle/src/main/ruby/core.rb
Expand Up @@ -15,7 +15,6 @@
require_relative 'core/rubinius/api/shims/lookuptable'
require_relative 'core/rubinius/api/shims/array'
require_relative 'core/rubinius/api/shims/rubinius'
require_relative 'core/rubinius/api/shims/lookuptable'
require_relative 'core/rubinius/api/shims/thread'
require_relative 'core/rubinius/api/shims/tuple'
require_relative 'core/rubinius/api/shims/undefined'
Expand Down Expand Up @@ -54,6 +53,8 @@
require_relative 'core/rubinius/common/integer'
require_relative 'core/rubinius/common/bignum'
require_relative 'core/rubinius/common/fixnum'
require_relative 'core/rubinius/api/shims/encoding'
require_relative 'core/rubinius/common/encoding'
require_relative 'core/rubinius/common/false'
require_relative 'core/rubinius/common/float'
require_relative 'core/rubinius/common/immediate'
Expand Down

0 comments on commit 7879048

Please sign in to comment.