Skip to content

Commit 10e94d6

Browse files
committed
Use newer rb_enc_check from JRuby if available
This method is added to JRuby in 9.4.13.0 and avoids the overhead of creating a fake CodeRangeable. See jruby/jruby#8643
1 parent 1b70e20 commit 10e94d6

File tree

1 file changed

+18
-10
lines changed

1 file changed

+18
-10
lines changed

ext/java/org/jruby/ext/stringio/StringIO.java

+18-10
Original file line numberDiff line numberDiff line change
@@ -1633,19 +1633,22 @@ public IRubyObject write(ThreadContext context, IRubyObject[] args) {
16331633
private static final MethodHandle CAT_WITH_CODE_RANGE;
16341634
private static final MethodHandle MODIFY_AND_CLEAR_CODE_RANGE;
16351635
private static final MethodHandle SUBSTR_ENC;
1636+
private static final MethodHandle CHECK_ENCODING;
16361637

16371638
static {
1638-
MethodHandle cat, modify, substr;
1639+
MethodHandle cat, modify, substr, checkEncoding;
16391640
MethodHandles.Lookup lookup = MethodHandles.lookup();
16401641
try {
16411642
cat = lookup.findVirtual(RubyString.class, "catWithCodeRange", MethodType.methodType(RubyString.class, RubyString.class));
16421643
modify = lookup.findVirtual(RubyString.class, "modifyAndClearCodeRange", MethodType.methodType(void.class));
16431644
substr = lookup.findVirtual(RubyString.class, "substrEnc", MethodType.methodType(IRubyObject.class, Ruby.class, int.class, int.class));
1645+
checkEncoding = lookup.findStatic(RubyEncoding.class, "checkEncoding", MethodType.methodType(void.class, ThreadContext.class, Encoding.class, CodeRangeable.class));
16441646
} catch (NoSuchMethodException | IllegalAccessException ex) {
16451647
try {
16461648
cat = lookup.findVirtual(RubyString.class, "cat19", MethodType.methodType(RubyString.class, RubyString.class));
16471649
modify = lookup.findVirtual(RubyString.class, "modify19", MethodType.methodType(void.class));
16481650
substr = lookup.findVirtual(RubyString.class, "substr19", MethodType.methodType(IRubyObject.class, Ruby.class, int.class, int.class));
1651+
checkEncoding = lookup.findStatic(StringIO.class, "checkEncoding", MethodType.methodType(void.class, ThreadContext.class, Encoding.class, CodeRangeable.class));
16491652
} catch (NoSuchMethodException | IllegalAccessException ex2) {
16501653
throw new ExceptionInInitializerError(ex2);
16511654
}
@@ -1654,6 +1657,7 @@ public IRubyObject write(ThreadContext context, IRubyObject[] args) {
16541657
CAT_WITH_CODE_RANGE = cat;
16551658
MODIFY_AND_CLEAR_CODE_RANGE = modify;
16561659
SUBSTR_ENC = substr;
1660+
CHECK_ENCODING = checkEncoding;
16571661
}
16581662

16591663
private static void catString(RubyString myString, RubyString str) {
@@ -1698,7 +1702,7 @@ private long stringIOWrite(ThreadContext context, Ruby runtime, IRubyObject arg)
16981702
if (enc != encStr && enc != ASCIIEncoding.INSTANCE && enc != USASCIIEncoding.INSTANCE) {
16991703
RubyString converted = EncodingUtils.strConvEnc(context, str, encStr, enc);
17001704
if (converted == str && encStr != ASCIIEncoding.INSTANCE && encStr != USASCIIEncoding.INSTANCE) { /* conversion failed */
1701-
rb_enc_check_hack(context, enc, str);
1705+
rb_enc_check(context, enc, str);
17021706
}
17031707
str = converted;
17041708
}
@@ -1732,16 +1736,20 @@ private long stringIOWrite(ThreadContext context, Ruby runtime, IRubyObject arg)
17321736
return len;
17331737
}
17341738

1735-
/*
1736-
This hack inlines the JRuby version of rb_enc_check (RubString.checkEncoding) because it only supports str1 being
1737-
a true string. This breaks an expectation in StringIO test "test_write_encoding_conversion".
1738-
1739-
If the StringIO string is blank, logic downstream from "rb_enc_check" in "encoding_compatible_latter" will simply
1740-
choose the second encoding rather than fail as the test expects.
1739+
private static void rb_enc_check(ThreadContext context, Encoding enc, CodeRangeable str) {
1740+
try {
1741+
CHECK_ENCODING.invokeExact(context, enc, str);
1742+
} catch (Throwable t) {
1743+
Helpers.throwException(t);
1744+
}
1745+
}
17411746

1742-
See discussion in https://github.com/ruby/stringio/pull/116.
1747+
/**
1748+
* Fallback version of rb_enc_check logic for JRuby prior to 9.4.13.0 that did not have a version accepting enc.
1749+
*
1750+
* See discussion in https://github.com/ruby/stringio/pull/116.
17431751
*/
1744-
private static void rb_enc_check_hack(ThreadContext context, Encoding enc, CodeRangeable str) {
1752+
private static void checkEncoding(ThreadContext context, Encoding enc, CodeRangeable str) {
17451753
CodeRangeable fakeCodeRangeable = new EncodingOnlyCodeRangeable(enc);
17461754
Encoding enc1 = StringSupport.areCompatible(fakeCodeRangeable, str);
17471755
if (enc1 == null) throw context.runtime.newEncodingCompatibilityError("incompatible character encodings: " +

0 commit comments

Comments
 (0)