JDK-8148752 : MethodHandle inlining with long/double arguments is broken in C2
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 8,9
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2016-02-01
  • Updated: 2017-07-26
  • Resolved: 2016-02-10
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8 JDK 9
8u102Fixed 9 b107Fixed
Related Reports
Duplicate :  
Duplicate :  
Description
After the integration of Indify String Concatenation (JDK-8148483), compiler/jvmci/compilerToVM/GetNextStackFrameTest.java fails with the following stack trace:

java.lang.StringIndexOutOfBoundsException: offset 87, count -1323521248, length 340
	at java.lang.String.checkBoundsOffCount(String.java:3107)
	at java.lang.StringLatin1.inflate(StringLatin1.java:528)
	at java.lang.String.getBytes(String.java:3002)
	at java.lang.AbstractStringBuilder.putStringAt(AbstractStringBuilder.java:1644)
	at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:488)
	at java.lang.StringBuilder.append(StringBuilder.java:141)
	at java.lang.StringBuilder.append(StringBuilder.java:135)
	at java.lang.String$Concat/55860507.concat(Unknown Source)
	at jdk.vm.ci.hotspot.HotSpotStackFrameReference.toString(HotSpotStackFrameReference.java:90)
	at jdk.test.lib.Asserts.format(Asserts.java:443)

It also fails with -XX:-OptimizeStringConcat:

java.lang.ArrayStoreException
	at java.lang.System.arraycopy(Native Method)
	at java.lang.String.getBytes(String.java:3000)
	at java.lang.AbstractStringBuilder.putStringAt(AbstractStringBuilder.java:1644)
	at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:488)
	at java.lang.StringBuilder.append(StringBuilder.java:141)
	at java.lang.StringBuilder.append(StringBuilder.java:135)
	at java.lang.String$Concat/931594624.concat(Unknown Source)
	at jdk.vm.ci.hotspot.HotSpotStackFrameReference.toString(HotSpotStackFrameReference.java:90)
	at jdk.test.lib.Asserts.format(Asserts.java:443)

It does not fail with -Djava.lang.invoke.stringConcat=MH_SB_SIZED.
Comments
verified by nightly testing
26-07-2017

Changed title from "Compiled StringBuilder code throws StringIndexOutOfBoundsException" to "MethodHandle inlining with long/double arguments is broken in C2" because this bug is likely to show up in other variants.
12-04-2016

We should handle this like C1 does in GraphBuilder::try_method_handle_inline(): http://cr.openjdk.java.net/~thartmann/8148752/webrev.00/
09-02-2016

HotSpotStackFrameReference::toString() looks like this: 1 fast_lgetfield 2 <jdk/vm/ci/hotspot/HotSpotStackFrameReference.stackPointer/J> 4 aload_0 5 fast_igetfield 3 <jdk/vm/ci/hotspot/HotSpotStackFrameReference.frameNumber/I> 8 aload_0 9 fast_igetfield 8 <jdk/vm/ci/hotspot/HotSpotStackFrameReference.bci/I> 12 fast_aload_0 13 invokevirtual 11 <jdk/vm/ci/hotspot/HotSpotStackFrameReference.getMethod()Ljdk/vm/ci/meta/ResolvedJavaMethod;> 0 bci: 13 VirtualCallData count(0) nonprofiled_count(0) entries(1) 'jdk/vm/ci/hotspot/HotSpotStackFrameReference'(1 1.00) method_entries(0) 16 aload_0 17 fast_agetfield 4 <jdk/vm/ci/hotspot/HotSpotStackFrameReference.locals/[Ljava/lang/Object;> 20 invokestatic 12 <java/util/Arrays.toString([Ljava/lang/Object;)Ljava/lang/String;> 56 bci: 20 CounterData count(1) 23 aload_0 24 fast_agetfield 5 <jdk/vm/ci/hotspot/HotSpotStackFrameReference.localIsVirtual/[Z> 27 invokestatic 13 <java/util/Arrays.toString([Z)Ljava/lang/String;> 72 bci: 27 CounterData count(1) 30 invokedynamic bsm=81 14 <makeConcatWithConstants(JIILjdk/vm/ci/meta/ResolvedJavaMethod;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;> 88 bci: 30 CounterData count(2) 35 areturn The invokedynamic @ bci:30 is resolved and inlined like this: 345117010::invokeStatic_JIIL3_L @ bci:21 1163020763::reinvoke @ bci:24 62297476::linkToTargetMethod @ bci:14 HotSpotStackFrameReference::toString @ bci:30 In CallGenerator::for_method_handle_inline() we inline invokeStatic_JIIL3_L and cast the reference arguments to its type. The graph looks similar to this: 62 CreateEx === 59 52 [[ 61 ]] #java/lang/Throwable:NotNull * Oop:java/lang/Throwable:NotNull * !jvms: HotSpotStackFrameReference::toString @ bci:20 49 DecodeN === _ 48 [[ 61 50 ]] #narrowoop: java/lang/Object *[int:>=0] * !jvms: HotSpotStackFrameReference::toString @ bci:17 45 DecodeN === _ 44 [[ 38 33 50 61 ]] #jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod * Interface:jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod * !jvms: HotSpotStackFrameReference::getMethod @ bci:1 HotSpotStackFrameReference::toString @ bci:13 31 LoadI === _ 7 30 [[ 21 33 50 61 ]] @jdk/vm/ci/hotspot/HotSpotStackFrameReference+24 *, name=bci, idx=6; #int !jvms: HotSpotStackFrameReference::toString @ bci:9 28 LoadI === _ 7 27 [[ 21 33 50 61 ]] @jdk/vm/ci/hotspot/HotSpotStackFrameReference+12 *, name=frameNumber, idx=5; #int !jvms: HotSpotStackFrameReference::toString @ bci:5 25 LoadL === _ 7 24 [[ 21 33 50 61 ]] @jdk/vm/ci/hotspot/HotSpotStackFrameReference+16 *, name=stackPointer, idx=4; #long !jvms: HotSpotStackFrameReference::toString @ bci:1 10 Parm === 3 [[ 4 18 21 24 24 27 27 30 30 21 33 39 43 43 47 47 50 61 ]] Parm0: jdk/vm/ci/hotspot/HotSpotStackFrameReference:NotNull * Oop:jdk/vm/ci/hotspot/HotSpotStackFrameReference:NotNull * !jvms: HotSpotStackFrameReference::toString @ bci:-1 9 Parm === 3 [[ 4 12 18 21 33 39 61 ]] ReturnAdr !jvms: HotSpotStackFrameReference::toString @ bci:-1 8 Parm === 3 [[ 4 12 18 21 33 39 50 61 ]] FramePtr !jvms: HotSpotStackFrameReference::toString @ bci:-1 60 MergeMem === _ 1 53 1 [[ 61 ]] { - } Memory: @BotPTR *+bot, idx=Bot; !jvms: HotSpotStackFrameReference::toString @ bci:20 52 Proj === 50 [[ 33 57 61 62 ]] #1 !jvms: HotSpotStackFrameReference::toString @ bci:20 59 CatchProj === 57 [[ 61 62 ]] #1@bci -1 !jvms: HotSpotStackFrameReference::toString @ bci:20 61 SafePoint === 59 52 60 8 9 10 25 1 28 31 45 49 1 1 62 [[]] SafePoint !orig=33,21,18 The JIIL3 arguments are (25 1), 28, 31, ... The problem is that in CallGenerator::for_method_handle_inline() we handle the long tuple (25 1) as two arguments and therefore cast the 3rd argument (45 DecodeN) from Object to String (because the 4th argument is of type String): 43 AddP === _ 10 10 42 [[ 44 ]] Oop:jdk/vm/ci/hotspot/HotSpotStackFrameReference:NotNull+32 * [narrow] !jvms: HotSpotStackFrameReference::getMethod @ bci:1 HotSpotStackFrameReference::toString @ bci:13 7 Parm === 3 [[ 4 11 19 20 25 28 31 32 40 44 36 37 48 50 63 82 ]] Memory Memory: @BotPTR *+bot, idx=Bot; !jvms: HotSpotStackFrameReference::toString @ bci:-1 71 Proj === 69 [[ 33 76 80 81 83 85 96 98 107 109 119 121 129 125 123 ]] #1 !jvms: HotSpotStackFrameReference::toString @ bci:27 70 Proj === 69 [[ 76 ]] #0 !jvms: HotSpotStackFrameReference::toString @ bci:27 44 LoadN === _ 7 43 [[ 45 ]] @jdk/vm/ci/hotspot/HotSpotStackFrameReference+32 * [narrow], name=method, idx=7; #narrowoop: jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod * !jvms: HotSpotStackFrameReference::getMethod @ bci:1 HotSpotStackFrameReference::toString @ bci:13 76 Catch === 70 71 [[ 77 78 ]] !jvms: HotSpotStackFrameReference::toString @ bci:27 45 DecodeN === _ 44 [[ 38 33 50 61 69 80 96 98 107 109 119 121 123 135 ]] #jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod * Interface:jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod * !jvms: HotSpotStackFrameReference::getMethod @ bci:1 HotSpotStackFrameReference::toString @ bci:13 77 CatchProj === 76 [[ 33 96 98 107 109 119 121 129 124 135 ]] #0@bci -1 !jvms: HotSpotStackFrameReference::toString @ bci:27 135 CheckCastPP === 77 45 [[]] #java/lang/String:exact * Oop:java/lang/String:exact * !jvms: 345117010::invokeStatic_JIIL3_L @ bci:21 1163020763::reinvoke @ bci:24 62297476::linkToTargetMethod @ bci:14 HotSpotStackFrameReference::toString @ bci:30 As a result, C2 assumes the 3rd argument is always of type String and inlines String.toString(). However, at runtime the type is 'ResolvedJavaMethod', causing the crash.
09-02-2016

Here is the relevant stack: V [libjvm.so+0x9fc696] Exceptions::_throw_msg(Thread*, char const*, int, Symbol*, char const*)+0x146 V [libjvm.so+0xca5553] JVM_ArrayCopy+0x2f3 J 1035 java.lang.System.arraycopy(Ljava/lang/Object;ILjava/lang/Object;II)V (0 bytes) @ 0x00007f1fe5388711 [0x00007f1fe53885a0+0x0000000000000171] j java.lang.String.getBytes([BIB)V+22 J 59 C2 java.lang.AbstractStringBuilder.append(Ljava/lang/String;)Ljava/lang/AbstractStringBuilder; (129 bytes) @ 0x00007f1fe51c1804 [0x00007f1fe51c16c0+0x0000000000000144] J 3299 C2 jdk.vm.ci.hotspot.HotSpotStackFrameReference.toString()Ljava/lang/String; (36 bytes) @ 0x00007f1fe580eea0 [0x00007f1fe580eae0+0x00000000000003c0] J 3298 C2 compiler.jvmci.compilerToVM.GetNextStackFrameTest.walkThrough()V (120 bytes) @ 0x00007f1fe581e760 [0x00007f1fe581e4c0+0x00000000000002a0] The problem is in the C2 compiled method HotSpotStackFrameReference.toString(): 0x00007f767cc7121b: mov 0x20(%rsi),%r11d ... 0x00007f767cc712aa: shl $0x3,%r11 ;*getfield method {reexecute=0 rethrow=0 return_oop=0} ... 0x00007f767cc71445: mov %r11,0x30(%rsp) ... 0x00007f767cc715f4: mov 0x30(%rsp),%rdx 0x00007f767cc715f9: test %rdx,%rdx 0x00007f767cc715fc: je 0x00007f767cc71710 0x00007f767cc71602: mov %rbp,%rsi 0x00007f767cc71605: nop 0x00007f767cc71606: nop 0x00007f767cc71607: callq 0x00007f767c47d280 ; call java.lang.StringBuilder::append(String) We call StringBuilder.append(String) with the String argument in $rdx but the actual argument is not a String but a HotSpotResolvedJavaMethodImpl: (rr) print/x $rdx $3 = 0x6cab6f928 (rr) call pp(0x6cab6f928) "Executing pp" jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl - klass: 'jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl' - ---- fields (total size 6 words): - protected 'name' 'Ljava/lang/String;' @12 "frame4" (d956df2b e3f357a8) - private final 'metaspaceMethod' 'J' @16 139774945089448 (e3f357a8 7f1f) - private final 'holder' 'Ljdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl;' @24 a 'jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl' (d956d188 d956dc93) - private final 'constantPool' 'Ljdk/vm/ci/hotspot/HotSpotConstantPool;' @28 a 'jdk/vm/ci/hotspot/HotSpotConstantPool' (d956dc93 d956df32) - private final 'signature' 'Ljdk/vm/ci/hotspot/HotSpotSignature;' @32 a 'jdk/vm/ci/hotspot/HotSpotSignature' (d956df32 0) - private 'methodData' 'Ljdk/vm/ci/hotspot/HotSpotMethodData;' @36 NULL (0 0) - private 'code' '[B' @40 NULL (0 0) - private 'toJavaCache' 'Ljava/lang/reflect/Executable;' @44 NULL (0 5) The bytecode is correct and calls StringBuilder.append(Object) to append the method object: 34: ldc #31 // String , method= 36: invokevirtual #19 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 39: aload 4 41: invokevirtual #34 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; It seems that C2 assumes that the argument object is always a String and therefore inlines String.toString(): @ 41 java.lang.StringBuilder::append (9 bytes) inline (hot) @ 2 java.lang.String::valueOf (14 bytes) inline (hot) @ 10 java.lang.String::toString (2 bytes) inline (hot) We fail later in arraycopy after accessing String.value from an object which is not a String.
05-02-2016

Removing @ForceInline from the generated method in BC_* strategies seems to avoid the issue. A clue? diff -r f90110e9109d src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java --- a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java Wed Feb 03 00:49:41 2016 +0300 +++ b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java Wed Feb 03 01:14:47 2016 +0300 @@ -757,7 +757,7 @@ null, null); - mv.visitAnnotation("Ljdk/internal/vm/annotation/ForceInline;", true); +// mv.visitAnnotation("Ljdk/internal/vm/annotation/ForceInline;", true); mv.visitCode(); Class<?>[] arr = args.parameterArray();
02-02-2016