Skip to content

Commit 75b3f33

Browse files
committed
Enable the creation of dummy encodings from C extensions.
PullRequest: truffleruby/747
2 parents 2ee81e7 + d44041b commit 75b3f33

File tree

7 files changed

+77
-17
lines changed

7 files changed

+77
-17
lines changed

lib/truffle/truffle/cext.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,11 @@ def rb_enc_to_index(enc)
733733
Truffle.invoke_primitive :encoding_get_encoding_index, enc
734734
end
735735

736+
def rb_define_dummy_encoding(name)
737+
_, idx = Truffle::EncodingOperations.dummy_encoding(name)
738+
idx
739+
end
740+
736741
def rb_str_new_frozen(value)
737742
if value.frozen?
738743
value
@@ -899,7 +904,7 @@ def rb_str_encode(str, to, ecflags, ecopts)
899904
end
900905

901906
def rb_str_conv_enc_opts(str, from, to, ecflags, ecopts)
902-
if (to.ascii_compatible? && str.ascii_only?) || to == Encoding::ASCII_8BIT
907+
if (to.ascii_compatible? && str.ascii_only?) || to == Encoding::ASCII_8BIT || to.dummy?
903908
if str.encoding != to
904909
str = str.dup
905910
str.force_encoding(to)

src/main/c/cext/ruby.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3091,7 +3091,7 @@ int rb_enc_replicate(const char *name, rb_encoding *encoding) {
30913091
}
30923092

30933093
int rb_define_dummy_encoding(const char *name) {
3094-
rb_tr_error("rb_define_dummy_encoding not implemented");
3094+
return polyglot_as_i32(RUBY_CEXT_INVOKE_NO_WRAP("rb_define_dummy_encoding", rb_str_new_cstr(name)));
30953095
}
30963096

30973097
#undef rb_enc_str_new_cstr

src/main/java/org/truffleruby/core/CoreLibrary.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1424,6 +1424,7 @@ public DynamicObject getWarningModule() {
14241424
"/core/truffle/boot.rb",
14251425
"/core/truffle/debug.rb",
14261426
"/core/truffle/warnings.rb",
1427+
"/core/truffle/encoding_operations.rb",
14271428
"/core/truffle/exception_operations.rb",
14281429
"/core/truffle/hash_operations.rb",
14291430
"/core/truffle/numeric_operations.rb",

src/main/java/org/truffleruby/core/encoding/EncodingLayout.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@ DynamicObjectFactory createEncodingShape(DynamicObject logicalClass,
2323

2424
DynamicObject createEncoding(DynamicObjectFactory factory,
2525
Encoding encoding,
26-
DynamicObject name,
27-
boolean dummy);
26+
DynamicObject name);
2827

2928
boolean isEncoding(DynamicObject object);
3029
boolean isEncoding(Object object);
@@ -33,6 +32,4 @@ DynamicObject createEncoding(DynamicObjectFactory factory,
3332

3433
DynamicObject getName(DynamicObject object);
3534

36-
boolean getDummy(DynamicObject object);
37-
3835
}

src/main/java/org/truffleruby/core/encoding/EncodingManager.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,15 +170,15 @@ private void initializeLocaleEncoding(TruffleNFIPlatform nfi, NativeConfiguratio
170170
}
171171

172172
@TruffleBoundary
173-
private static DynamicObject newRubyEncoding(RubyContext context, Encoding encoding, byte[] name, int p, int end, boolean dummy) {
173+
private static DynamicObject newRubyEncoding(RubyContext context, Encoding encoding, byte[] name, int p, int end) {
174174
assert p == 0 : "Ropes can't be created with non-zero offset: " + p;
175175
assert end == name.length : "Ropes must have the same exact length as the name array (len = " + end + "; name.length = " + name.length + ")";
176176

177177
final Rope rope = RopeOperations.create(name, USASCIIEncoding.INSTANCE, CodeRange.CR_7BIT);
178178
final Rope cachedRope = context.getRopeCache().getRope(rope.getBytes(), rope.getEncoding(), rope.getCodeRange());
179179
final DynamicObject string = StringOperations.createFrozenString(context, cachedRope);
180180

181-
return Layouts.ENCODING.createEncoding(context.getCoreLibrary().getEncodingFactory(), encoding, string, dummy);
181+
return Layouts.ENCODING.createEncoding(context.getCoreLibrary().getEncodingFactory(), encoding, string);
182182
}
183183

184184
public static Encoding getEncoding(String name) {
@@ -240,7 +240,7 @@ public DynamicObject getRubyEncoding(Encoding encoding) {
240240
public synchronized DynamicObject defineEncoding(EncodingDB.Entry encodingEntry, byte[] name, int p, int end) {
241241
final Encoding encoding = encodingEntry.getEncoding();
242242
final int encodingIndex = encoding.getIndex();
243-
final DynamicObject rubyEncoding = newRubyEncoding(context, encoding, name, p, end, encodingEntry.isDummy());
243+
final DynamicObject rubyEncoding = newRubyEncoding(context, encoding, name, p, end);
244244

245245
assert encodingIndex >= ENCODING_LIST_BY_ENCODING_INDEX.size() || ENCODING_LIST_BY_ENCODING_INDEX.get(encodingIndex) == null;
246246

@@ -260,6 +260,18 @@ public DynamicObject defineAlias(Encoding encoding, String name) {
260260
return rubyEncoding;
261261
}
262262

263+
@TruffleBoundary
264+
public synchronized DynamicObject createDummyEncoding(String name) {
265+
if (getRubyEncoding(name) != null) {
266+
return null;
267+
}
268+
269+
byte[] nameBytes = name.getBytes();
270+
EncodingDB.dummy(nameBytes);
271+
final Entry entry = EncodingDB.getEncodings().get(nameBytes);
272+
return defineEncoding(entry, nameBytes, 0, nameBytes.length);
273+
}
274+
263275
@TruffleBoundary
264276
public synchronized DynamicObject replicateEncoding(Encoding encoding, String name) {
265277
if (getRubyEncoding(name) != null) {

src/main/java/org/truffleruby/core/encoding/EncodingNodes.java

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ protected int getCacheLimit() {
421421
protected static boolean isDummy(DynamicObject encoding) {
422422
assert RubyGuards.isRubyEncoding(encoding);
423423

424-
return Layouts.ENCODING.getDummy(encoding);
424+
return Layouts.ENCODING.getEncoding(encoding).isDummy();
425425
}
426426
}
427427

@@ -652,21 +652,29 @@ public DynamicObject encodingGetObjectEncodingNil(DynamicObject object) {
652652

653653
}
654654

655+
public static abstract class EncodingCreationNode extends PrimitiveArrayArgumentsNode {
656+
657+
public DynamicObject setIndexOrRaiseError(String name, DynamicObject newEncoding) {
658+
if (newEncoding == null) {
659+
throw new RaiseException(getContext(), coreExceptions().argumentErrorEncodingAlreadyRegistered(name, this));
660+
}
661+
662+
final int index = Layouts.ENCODING.getEncoding(newEncoding).getIndex();
663+
return createArray(new Object[]{ newEncoding, index }, 2);
664+
}
665+
666+
}
667+
655668
@Primitive(name = "encoding_replicate")
656-
public static abstract class EncodingReplicateNode extends PrimitiveArrayArgumentsNode {
669+
public static abstract class EncodingReplicateNode extends EncodingCreationNode {
657670

658671
@Specialization(guards = "isRubyString(nameObject)")
659672
public DynamicObject encodingReplicate(DynamicObject self, DynamicObject nameObject) {
660673
final String name = StringOperations.getString(nameObject);
661674
final Encoding encoding = EncodingOperations.getEncoding(self);
662675

663676
final DynamicObject newEncoding = replicate(name, encoding);
664-
if (newEncoding == null) {
665-
throw new RaiseException(getContext(), coreExceptions().argumentErrorEncodingAlreadyRegistered(name, this));
666-
}
667-
668-
final int index = Layouts.ENCODING.getEncoding(newEncoding).getIndex();
669-
return createArray(new Object[]{ newEncoding, index }, 2);
677+
return setIndexOrRaiseError(name, newEncoding);
670678
}
671679

672680
@TruffleBoundary
@@ -676,6 +684,24 @@ private DynamicObject replicate(String name, Encoding encoding) {
676684

677685
}
678686

687+
@Primitive(name = "encoding_create_dummy", needsSelf = false)
688+
public static abstract class DummyEncodingeNode extends EncodingCreationNode {
689+
690+
@Specialization(guards = "isRubyString(nameObject)")
691+
public DynamicObject createDummyEncoding(DynamicObject nameObject) {
692+
final String name = StringOperations.getString(nameObject);
693+
694+
final DynamicObject newEncoding = createDummy(name);
695+
return setIndexOrRaiseError(name, newEncoding);
696+
}
697+
698+
@TruffleBoundary
699+
private DynamicObject createDummy(String name) {
700+
return getContext().getEncodingManager().createDummyEncoding(name);
701+
}
702+
703+
}
704+
679705
@Primitive(name = "encoding_get_encoding_by_index", needsSelf = false, lowerFixnum = 1)
680706
public static abstract class GetEncodingObjectByIndexNode extends PrimitiveArrayArgumentsNode {
681707

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# frozen_string_literal: true
2+
3+
# Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved. This
4+
# code is released under a tri EPL/GPL/LGPL license. You can use it,
5+
# redistribute it and/or modify it under the terms of the:
6+
#
7+
# Eclipse Public License version 1.0, or
8+
# GNU General Public License version 2, or
9+
# GNU Lesser General Public License version 2.1.
10+
11+
module Truffle
12+
module EncodingOperations
13+
def self.dummy_encoding(name)
14+
new_encoding, index = Truffle.invoke_primitive :encoding_create_dummy, name
15+
::Encoding::EncodingMap[name.upcase.to_sym] = [nil, index]
16+
[new_encoding, index]
17+
end
18+
end
19+
end

0 commit comments

Comments
 (0)