@@ -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