Skip to content

Commit 7879048

Browse files
committed
[Truffle] Initial import of Rubinius's encoding system.
1 parent f75b331 commit 7879048

File tree

8 files changed

+904
-7
lines changed

8 files changed

+904
-7
lines changed

truffle/src/main/java/org/jruby/truffle/nodes/core/EncodingConverterNodes.java

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
1313
import com.oracle.truffle.api.dsl.Specialization;
14+
import com.oracle.truffle.api.frame.VirtualFrame;
1415
import com.oracle.truffle.api.source.SourceSection;
1516

1617
import org.jcodings.Encoding;
@@ -20,11 +21,19 @@
2021
import org.jruby.Ruby;
2122
import org.jruby.runtime.ThreadContext;
2223
import org.jruby.runtime.builtin.IRubyObject;
24+
import org.jruby.truffle.nodes.dispatch.CallDispatchHeadNode;
25+
import org.jruby.truffle.nodes.dispatch.DispatchHeadNodeFactory;
2326
import org.jruby.truffle.runtime.RubyContext;
27+
import org.jruby.truffle.runtime.UndefinedPlaceholder;
2428
import org.jruby.truffle.runtime.core.*;
29+
import org.jruby.truffle.runtime.hash.HashOperations;
30+
import org.jruby.truffle.runtime.hash.KeyValue;
2531
import org.jruby.util.ByteList;
2632
import org.jruby.util.io.EncodingUtils;
2733

34+
import java.util.ArrayList;
35+
import java.util.List;
36+
2837
@CoreClass(name = "Encoding::Converter")
2938
public abstract class EncodingConverterNodes {
3039

@@ -76,7 +85,7 @@ public RubyArray convpath(RubyEncodingConverter converter) {
7685

7786
}
7887

79-
@CoreMethod(names = "initialize", required = 2)
88+
@CoreMethod(names = "initialize", required = 2, optional = 1)
8089
public abstract static class InitializeNode extends CoreMethodNode {
8190

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

9099
@TruffleBoundary
91100
@Specialization
92-
public RubyNilClass initialize(RubyEncodingConverter self, RubyString source, RubyString destination) {
101+
public RubyNilClass initialize(RubyEncodingConverter self, RubyString source, RubyString destination, UndefinedPlaceholder options) {
102+
notDesignedForCompilation();
103+
104+
// Adapted from RubyConverter - see attribution there
105+
106+
Ruby runtime = getContext().getRuntime();
107+
Encoding[] encs = {null, null};
108+
byte[][] encNames = {null, null};
109+
int[] ecflags = {0};
110+
IRubyObject[] ecopts = {runtime.getNil()};
111+
112+
EncodingUtils.econvArgs(runtime.getCurrentContext(), new IRubyObject[]{getContext().toJRuby(source), getContext().toJRuby(destination)}, encNames, encs, ecflags, ecopts);
113+
EConv econv = EncodingUtils.econvOpenOpts(runtime.getCurrentContext(), encNames[0], encNames[1], ecflags[0], ecopts[0]);
114+
115+
if (econv == null) {
116+
throw new UnsupportedOperationException();
117+
}
118+
119+
self.setEConv(econv);
120+
121+
return nil();
122+
}
123+
124+
@TruffleBoundary
125+
@Specialization
126+
public RubyNilClass initialize(RubyEncodingConverter self, RubyString source, RubyString destination, RubyHash options) {
93127
notDesignedForCompilation();
94128

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

183217
}
184218

219+
@RubiniusOnly
220+
@CoreMethod(names = "transcoding_map", onSingleton = true)
221+
public abstract static class TranscodingMapNode extends CoreMethodNode {
222+
223+
@Child private CallDispatchHeadNode newLookupTableNode;
224+
@Child private CallDispatchHeadNode lookupTableWriteNode;
225+
226+
public TranscodingMapNode(RubyContext context, SourceSection sourceSection) {
227+
super(context, sourceSection);
228+
newLookupTableNode = DispatchHeadNodeFactory.createMethodCall(context);
229+
lookupTableWriteNode = DispatchHeadNodeFactory.createMethodCall(context);
230+
}
231+
232+
public TranscodingMapNode(TranscodingMapNode prev) {
233+
super(prev);
234+
newLookupTableNode = prev.newLookupTableNode;
235+
lookupTableWriteNode = prev.lookupTableWriteNode;
236+
}
237+
238+
@Specialization
239+
public RubyHash transcodingMap(VirtualFrame frame) {
240+
List<KeyValue> entries = new ArrayList<>();
241+
242+
for (RubyEncoding e : RubyEncoding.cloneEncodingList()) {
243+
final RubySymbol key = getContext().newSymbol(e.getName());
244+
final Object value = newLookupTableNode.call(frame, getContext().getCoreLibrary().getLookupTableClass(), "new", null);
245+
246+
final Object tupleValues = new Object[2];
247+
248+
249+
lookupTableWriteNode.call(frame, value, "[]=", null, key, nil());
250+
251+
entries.add(new KeyValue(key, value));
252+
}
253+
254+
return HashOperations.verySlowFromEntries(getContext().getCoreLibrary().getHashClass(), entries, true);
255+
}
256+
}
257+
185258
}

truffle/src/main/java/org/jruby/truffle/nodes/core/EncodingNodes.java

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,13 @@
3030
import org.jruby.truffle.nodes.RubyNode;
3131
import org.jruby.truffle.nodes.coerce.ToStrNode;
3232
import org.jruby.truffle.nodes.coerce.ToStrNodeFactory;
33+
import org.jruby.truffle.nodes.dispatch.CallDispatchHeadNode;
34+
import org.jruby.truffle.nodes.dispatch.DispatchHeadNode;
35+
import org.jruby.truffle.nodes.dispatch.DispatchHeadNodeFactory;
3336
import org.jruby.truffle.runtime.RubyContext;
3437
import org.jruby.truffle.runtime.control.RaiseException;
3538
import org.jruby.truffle.runtime.core.RubyArray;
39+
import org.jruby.truffle.runtime.core.RubyBasicObject;
3640
import org.jruby.truffle.runtime.core.RubyEncoding;
3741
import org.jruby.truffle.runtime.core.RubyHash;
3842
import org.jruby.truffle.runtime.core.RubyNilClass;
@@ -501,6 +505,80 @@ public boolean isDummy(RubyEncoding encoding) {
501505
}
502506
}
503507

508+
@RubiniusOnly
509+
@CoreMethod(names = "encoding_map", onSingleton = true)
510+
public abstract static class EncodingMapNode extends CoreMethodNode {
511+
512+
@Child private CallDispatchHeadNode newLookupTableNode;
513+
@Child private CallDispatchHeadNode lookupTableWriteNode;
514+
@Child private CallDispatchHeadNode newTupleNode;
515+
516+
public EncodingMapNode(RubyContext context, SourceSection sourceSection) {
517+
super(context, sourceSection);
518+
newLookupTableNode = DispatchHeadNodeFactory.createMethodCall(context);
519+
lookupTableWriteNode = DispatchHeadNodeFactory.createMethodCall(context);
520+
newTupleNode = DispatchHeadNodeFactory.createMethodCall(context);
521+
}
522+
523+
public EncodingMapNode(EncodingMapNode prev) {
524+
super(prev);
525+
newLookupTableNode = prev.newLookupTableNode;
526+
lookupTableWriteNode = prev.lookupTableWriteNode;
527+
newTupleNode = prev.newTupleNode;
528+
}
529+
530+
@Specialization
531+
public Object encodingMap(VirtualFrame frame) {
532+
Object ret = newLookupTableNode.call(frame, getContext().getCoreLibrary().getLookupTableClass(), "new", null);
533+
534+
final RubyEncoding[] encodings = RubyEncoding.cloneEncodingList();
535+
for (int i = 0; i < encodings.length; i++) {
536+
final RubySymbol key = getContext().newSymbol(encodings[i].getName());
537+
final Object value = newTupleNode.call(frame, getContext().getCoreLibrary().getTupleClass(), "create", null, nil(), i);
538+
539+
lookupTableWriteNode.call(frame, ret, "[]=", null, key, value);
540+
}
541+
542+
final Hash.HashEntryIterator i = getContext().getRuntime().getEncodingService().getAliases().entryIterator();
543+
while (i.hasNext()) {
544+
final CaseInsensitiveBytesHash.CaseInsensitiveBytesHashEntry<EncodingDB.Entry> e =
545+
((CaseInsensitiveBytesHash.CaseInsensitiveBytesHashEntry<EncodingDB.Entry>)i.next());
546+
547+
final RubySymbol key = getContext().newSymbol(new ByteList(e.bytes, e.p, e.end - e.p));
548+
final RubyString alias = getContext().makeString(new ByteList(e.bytes, e.p, e.end - e.p));
549+
final int index = e.value.getIndex();
550+
551+
552+
final Object value = newTupleNode.call(frame, getContext().getCoreLibrary().getTupleClass(), "create", null, alias, index);
553+
lookupTableWriteNode.call(frame, ret, "[]=", null, key, value);
554+
}
555+
556+
final Object externalTuple = newTupleNode.call(
557+
frame,
558+
getContext().getCoreLibrary().getTupleClass(),
559+
"create",
560+
null,
561+
getContext().makeString("external"),
562+
getContext().getRuntime().getDefaultExternalEncoding().getIndex()
563+
);
564+
565+
lookupTableWriteNode.call(frame, ret, "[]=", null, getContext().newSymbol("EXTERNAL"), externalTuple);
566+
567+
final Object localeTuple = newTupleNode.call(
568+
frame,
569+
getContext().getCoreLibrary().getTupleClass(),
570+
"create",
571+
null,
572+
getContext().makeString("locale"),
573+
getContext().getRuntime().getEncodingService().getLocaleEncoding().getIndex()
574+
);
575+
576+
lookupTableWriteNode.call(frame, ret, "[]=", null, getContext().newSymbol("LOCALE"), localeTuple);
577+
578+
return ret;
579+
}
580+
}
581+
504582
@CoreMethod(names = { "name", "to_s" })
505583
public abstract static class ToSNode extends CoreMethodNode {
506584

truffle/src/main/java/org/jruby/truffle/nodes/rubinius/EncodingPrimitiveNodes.java

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,97 @@
2020
*/
2121
public abstract class EncodingPrimitiveNodes {
2222

23+
@RubiniusPrimitive(name = "encoding_converter_allocate")
24+
public static abstract class EncodingConverterAllocateNode extends RubiniusPrimitiveNode {
25+
26+
public EncodingConverterAllocateNode(RubyContext context, SourceSection sourceSection) {
27+
super(context, sourceSection);
28+
}
29+
30+
public EncodingConverterAllocateNode(EncodingConverterAllocateNode prev) {
31+
super(prev);
32+
}
33+
34+
@Specialization
35+
public Object encodingConverterAllocate(RubyEncoding fromEncoding, RubyEncoding toEncoding, RubyHash options) {
36+
return new RubyEncodingConverter(getContext().getCoreLibrary().getEncodingConverterClass(), null);
37+
}
38+
39+
}
40+
41+
@RubiniusPrimitive(name = "encoding_converter_primitive_convert")
42+
public static abstract class EncodingConverterPrimitiveConvertNode extends RubiniusPrimitiveNode {
43+
44+
public EncodingConverterPrimitiveConvertNode(RubyContext context, SourceSection sourceSection) {
45+
super(context, sourceSection);
46+
}
47+
48+
public EncodingConverterPrimitiveConvertNode(EncodingConverterPrimitiveConvertNode prev) {
49+
super(prev);
50+
}
51+
52+
@Specialization
53+
public Object encodingConverterPrimitiveConvert(RubyBasicObject encodingConverter, RubyString source,
54+
RubyString target, int offset, int size, RubyHash options) {
55+
throw new UnsupportedOperationException("not implemented");
56+
}
57+
58+
}
59+
60+
@RubiniusPrimitive(name = "encoding_converter_putback")
61+
public static abstract class EncodingConverterPutbackNode extends RubiniusPrimitiveNode {
62+
63+
public EncodingConverterPutbackNode(RubyContext context, SourceSection sourceSection) {
64+
super(context, sourceSection);
65+
}
66+
67+
public EncodingConverterPutbackNode(EncodingConverterPutbackNode prev) {
68+
super(prev);
69+
}
70+
71+
@Specialization
72+
public Object encodingConverterPutback(RubyBasicObject encodingConverter, int maxBytes) {
73+
throw new UnsupportedOperationException("not implemented");
74+
}
75+
76+
}
77+
78+
@RubiniusPrimitive(name = "encoding_converter_last_error")
79+
public static abstract class EncodingConverterLastErrorNode extends RubiniusPrimitiveNode {
80+
81+
public EncodingConverterLastErrorNode(RubyContext context, SourceSection sourceSection) {
82+
super(context, sourceSection);
83+
}
84+
85+
public EncodingConverterLastErrorNode(EncodingConverterLastErrorNode prev) {
86+
super(prev);
87+
}
88+
89+
@Specialization
90+
public Object encodingConverterLastError(RubyBasicObject encodingConverter) {
91+
throw new UnsupportedOperationException("not implemented");
92+
}
93+
94+
}
95+
96+
@RubiniusPrimitive(name = "encoding_converter_primitive_errinfo")
97+
public static abstract class EncodingConverterErrinfoNode extends RubiniusPrimitiveNode {
98+
99+
public EncodingConverterErrinfoNode(RubyContext context, SourceSection sourceSection) {
100+
super(context, sourceSection);
101+
}
102+
103+
public EncodingConverterErrinfoNode(EncodingConverterErrinfoNode prev) {
104+
super(prev);
105+
}
106+
107+
@Specialization
108+
public Object encodingConverterLastError(RubyBasicObject encodingConverter) {
109+
throw new UnsupportedOperationException("not implemented");
110+
}
111+
112+
}
113+
23114
@RubiniusPrimitive(name = "encoding_get_object_encoding", needsSelf = false)
24115
public static abstract class EncodingGetObjectEncodingNode extends RubiniusPrimitiveNode {
25116

truffle/src/main/java/org/jruby/truffle/runtime/core/CoreLibrary.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ public class CoreLibrary {
7676
private final RubyClass keyErrorClass;
7777
private final RubyClass loadErrorClass;
7878
private final RubyClass localJumpErrorClass;
79+
private final RubyClass lookupTableClass;
7980
private final RubyClass matchDataClass;
8081
private final RubyClass moduleClass;
8182
private final RubyClass nameErrorClass;
@@ -106,6 +107,7 @@ public class CoreLibrary {
106107
private final RubyClass threadClass;
107108
private final RubyClass timeClass;
108109
private final RubyClass trueClass;
110+
private final RubyClass tupleClass;
109111
private final RubyClass typeErrorClass;
110112
private final RubyClass zeroDivisionErrorClass;
111113
private final RubyModule configModule;
@@ -179,9 +181,6 @@ public CoreLibrary(RubyContext context) {
179181
// Exception
180182
exceptionClass = defineClass("Exception", new RubyException.ExceptionAllocator());
181183

182-
// EncodingError
183-
encodingErrorClass = defineClass(exceptionClass, "EncodingError");
184-
185184
// FiberError
186185
fiberErrorClass = defineClass(exceptionClass, "FiberError");
187186

@@ -194,6 +193,7 @@ public CoreLibrary(RubyContext context) {
194193
// StandardError
195194
standardErrorClass = defineClass(exceptionClass, "StandardError");
196195
argumentErrorClass = defineClass(standardErrorClass, "ArgumentError");
196+
encodingErrorClass = defineClass(standardErrorClass, "EncodingError");
197197
ioErrorClass = defineClass(standardErrorClass, "IOError");
198198
localJumpErrorClass = defineClass(standardErrorClass, "LocalJumpError");
199199
regexpErrorClass = defineClass(standardErrorClass, "RegexpError");
@@ -299,7 +299,7 @@ public CoreLibrary(RubyContext context) {
299299

300300
// The rest
301301

302-
encodingCompatibilityErrorClass = defineClass(encodingClass, standardErrorClass, "CompatibilityError");
302+
encodingCompatibilityErrorClass = defineClass(encodingClass, encodingErrorClass, "CompatibilityError");
303303

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

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

310310
rubiniusModule = defineModule("Rubinius");
311311
byteArrayClass = defineClass(rubiniusModule, objectClass, "ByteArray");
312+
lookupTableClass = defineClass(rubiniusModule, hashClass, "LookupTable");
312313
stringDataClass = defineClass(rubiniusModule, objectClass, "StringData");
314+
tupleClass = defineClass(rubiniusModule, arrayClass, "Tuple");
313315

314316
// Include the core modules
315317

@@ -1149,10 +1151,18 @@ public RubyClass getByteArrayClass() {
11491151
return byteArrayClass;
11501152
}
11511153

1154+
public RubyClass getLookupTableClass() {
1155+
return lookupTableClass;
1156+
}
1157+
11521158
public RubyClass getStringDataClass() {
11531159
return stringDataClass;
11541160
}
11551161

1162+
public RubyClass getTupleClass() {
1163+
return tupleClass;
1164+
}
1165+
11561166
public RubyBasicObject getRubiniusUndefined() {
11571167
return rubiniusUndefined;
11581168
}

truffle/src/main/ruby/core.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
require_relative 'core/rubinius/api/shims/lookuptable'
1616
require_relative 'core/rubinius/api/shims/array'
1717
require_relative 'core/rubinius/api/shims/rubinius'
18-
require_relative 'core/rubinius/api/shims/lookuptable'
1918
require_relative 'core/rubinius/api/shims/thread'
2019
require_relative 'core/rubinius/api/shims/tuple'
2120
require_relative 'core/rubinius/api/shims/undefined'
@@ -54,6 +53,8 @@
5453
require_relative 'core/rubinius/common/integer'
5554
require_relative 'core/rubinius/common/bignum'
5655
require_relative 'core/rubinius/common/fixnum'
56+
require_relative 'core/rubinius/api/shims/encoding'
57+
require_relative 'core/rubinius/common/encoding'
5758
require_relative 'core/rubinius/common/false'
5859
require_relative 'core/rubinius/common/float'
5960
require_relative 'core/rubinius/common/immediate'

0 commit comments

Comments
 (0)