Skip to content

Commit 6e3a3dd

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 0e84588 commit 6e3a3dd

File tree

1 file changed

+18
-10
lines changed

1 file changed

+18
-10
lines changed

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

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1641,19 +1641,22 @@ public IRubyObject write(ThreadContext context, IRubyObject[] args) {
16411641
private static final MethodHandle CAT_WITH_CODE_RANGE;
16421642
private static final MethodHandle MODIFY_AND_CLEAR_CODE_RANGE;
16431643
private static final MethodHandle SUBSTR_ENC;
1644+
private static final MethodHandle CHECK_ENCODING;
16441645

16451646
static {
1646-
MethodHandle cat, modify, substr;
1647+
MethodHandle cat, modify, substr, checkEncoding;
16471648
MethodHandles.Lookup lookup = MethodHandles.lookup();
16481649
try {
16491650
cat = lookup.findVirtual(RubyString.class, "catWithCodeRange", MethodType.methodType(RubyString.class, RubyString.class));
16501651
modify = lookup.findVirtual(RubyString.class, "modifyAndClearCodeRange", MethodType.methodType(void.class));
16511652
substr = lookup.findVirtual(RubyString.class, "substrEnc", MethodType.methodType(IRubyObject.class, Ruby.class, int.class, int.class));
1653+
checkEncoding = lookup.findStatic(RubyEncoding.class, "checkEncoding", MethodType.methodType(void.class, ThreadContext.class, Encoding.class, CodeRangeable.class));
16521654
} catch (NoSuchMethodException | IllegalAccessException ex) {
16531655
try {
16541656
cat = lookup.findVirtual(RubyString.class, "cat19", MethodType.methodType(RubyString.class, RubyString.class));
16551657
modify = lookup.findVirtual(RubyString.class, "modify19", MethodType.methodType(void.class));
16561658
substr = lookup.findVirtual(RubyString.class, "substr19", MethodType.methodType(IRubyObject.class, Ruby.class, int.class, int.class));
1659+
checkEncoding = lookup.findStatic(StringIO.class, "checkEncoding", MethodType.methodType(void.class, ThreadContext.class, Encoding.class, CodeRangeable.class));
16571660
} catch (NoSuchMethodException | IllegalAccessException ex2) {
16581661
throw new ExceptionInInitializerError(ex2);
16591662
}
@@ -1662,6 +1665,7 @@ public IRubyObject write(ThreadContext context, IRubyObject[] args) {
16621665
CAT_WITH_CODE_RANGE = cat;
16631666
MODIFY_AND_CLEAR_CODE_RANGE = modify;
16641667
SUBSTR_ENC = substr;
1668+
CHECK_ENCODING = checkEncoding;
16651669
}
16661670

16671671
private static void catString(RubyString myString, RubyString str) {
@@ -1706,7 +1710,7 @@ private long stringIOWrite(ThreadContext context, Ruby runtime, IRubyObject arg)
17061710
if (enc != encStr && enc != ASCIIEncoding.INSTANCE && enc != USASCIIEncoding.INSTANCE) {
17071711
RubyString converted = EncodingUtils.strConvEnc(context, str, encStr, enc);
17081712
if (converted == str && encStr != ASCIIEncoding.INSTANCE && encStr != USASCIIEncoding.INSTANCE) { /* conversion failed */
1709-
rb_enc_check_hack(context, enc, str);
1713+
rb_enc_check(context, enc, str);
17101714
}
17111715
str = converted;
17121716
}
@@ -1740,16 +1744,20 @@ private long stringIOWrite(ThreadContext context, Ruby runtime, IRubyObject arg)
17401744
return len;
17411745
}
17421746

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

1750-
See discussion in https://github.com/ruby/stringio/pull/116.
1755+
/**
1756+
* Fallback version of rb_enc_check logic for JRuby prior to 9.4.13.0 that did not have a version accepting enc.
1757+
*
1758+
* See discussion in https://github.com/ruby/stringio/pull/116.
17511759
*/
1752-
private static void rb_enc_check_hack(ThreadContext context, Encoding enc, CodeRangeable str) {
1760+
private static void checkEncoding(ThreadContext context, Encoding enc, CodeRangeable str) {
17531761
CodeRangeable fakeCodeRangeable = new EncodingOnlyCodeRangeable(enc);
17541762
Encoding enc1 = StringSupport.areCompatible(fakeCodeRangeable, str);
17551763
if (enc1 == null) throw context.runtime.newEncodingCompatibilityError("incompatible character encodings: " +

0 commit comments

Comments
 (0)