JDK-8059378 : EA: eliminate non-rematerializable allocations of non-escaping objects
  • Type: Enhancement
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 8u40,9,10
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • Submitted: 2014-09-29
  • Updated: 2022-01-25
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.
Other
tbdUnresolved
Related Reports
Relates :  
Description
After JDK-8058825, VM doesn't eliminate allocations of non-escaping objects, if they can't be rematerialized.
Escape analysis can be enhanced to do elimination if there's no need to rematerialize the object. 
Comments
There is code which checks type of ArrayCopy node to allow eliminate passed allocation: https://github.com/openjdk/jdk/blob/master/src/hotspot/share/opto/macro.cpp#L606 I thought we may have issue here. But based on `(CopyOfRange, tightly coupled allocation) ` type (in output) it could be `is_copyofrange_validated()` is false because allocation's klass is not exact. So my statement about ArrayCopy node is void. I also looked on OptoAssembly and class check failed (and code deoptimized) because we compare klass to `java/lang/Object`: movq RSI, precise [java/lang/Object: 0x00007fae6c2e2178 *: :Constant:exact * # ptr And it seems we can't avoid this check and deoptimization in this test - unless we add/use ARRAY argument profiling data. I think. So all my questions are answered. May be you can think of other test which does non-escaping allocation when klass is not known and see what happens.
25-01-2022

Thank you, Vladimir I / K. Things are much more clear now. However, I'm still confused. @V. Kozlov, what exactly do you mean by "we need to handle ArrayCopy node case"? Just sharing some things I noticed while debugging: - If I remove the exactness check added by Vladimir I. then both AllocateArray nodes are removed. - The two "NotScalar (Object is passed as argument)...)" messages are about the same AllocateArray node.
24-01-2022

So first, we need to handle ArrayCopy node case. Second, find why we deoptimize on class check.
21-01-2022

Deoptimization also happened in different place - class check from arraycopy intrinsic code, I think: UNCOMMON TRAP method=ArraysCopyOf.test(Ljava/lang/Class;)V bci=13 pc=0x00007f8aa1686ec8, relative_pc=0x0000000000000148, debug_id=0 compiler=c2 compile_id=1 (@0x00007f8aa1686ec8) thread=1275115 reason=class_check action=make_not_entrant unloaded_class_index=-1 debug_id=0 159 1 ArraysCopyOf::test (69 bytes) made not entrant DEOPT PACKING thread=0x00007f8aac02aa00 vframeArray=0x00007f8aac317e10 Compiled frame (sp=0x00007f8ab609c8d0 unextended sp=0x00007f8ab609c8d0, fp=0x0000000458819a20, real_fp=0x00007f8ab609c900, pc=0x00007f8aa1686ec8) nmethod 159 1 ArraysCopyOf::test (69 bytes) Virtual frames (innermost/newest first): VFrame 0 (0x00007f8a3c0b1978) - ArraysCopyOf.test(Ljava/lang/Class;)V - invokestatic @ bci=13 DEOPT UNPACKING thread=0x00007f8aac02aa00 vframeArray=0x00007f8aac317e10 mode=2 Virtual frames (outermost/oldest first): VFrame 0 (0x00007f8aac319318) - ArraysCopyOf.test(Ljava/lang/Class;)V - invokestatic @ bci=13 sp=0x00007f8ab609c880
21-01-2022

There is test ArraysCopyOf.java attached to JDK-8058825. It has call `Inner.test(example)` to which result of arraycopy passed. In JDK 9 the compiled code deoptimized at that call because `Inner` class was not loaded - it was uncommon trap. The JDK-8058825 fix added `!t->klass_is_exact()` check before we set `_is_scalar_replaceable = true` for allocation: https://github.com/openjdk/jdk/blob/master/src/hotspot/share/opto/escape.cpp#L3144 So allocation is not marked as scalarized by EA. The idea I proposed is to allow scalarize non-exact non-escaping allocation if there are no uncommon traps where we should correctly rematerialize object. Unfortunately with latest JDK the test behave totally different. You need to pre-load java.util.Arrays before test public static void main(String[] args) throws Throwable { + int[] a = new int[10]; + java.util.Arrays.fill(a, 1); // Load java.util.Arrays class test(String[].class); } Then allocations are not scalarized because we have new ArrayCopy nodes: $ ./build/fastdebug/images/jdk/bin/java -Xcomp -XX:CompileCommand=compileonly,ArraysCopyOf.test -XX:-TieredCompilation -XX:+PrintCompilation -XX:+PrintEscapeAnalysis -XX:+PrintEliminateAllocations -XX:+TraceDeoptimization -XX:CICompilerCount=1 -XX:CompileCommand=quiet ArraysCopyOf CompileCommand: compileonly ArraysCopyOf.test bool compileonly = true 154 1 b ArraysCopyOf::test (69 bytes) ======== Connection graph for ArraysCopyOf::test invocation #0: 2 iterations and 0.000004 sec to build connection graph with 242 nodes and worklist size 21 JavaObject NoEscape(NoEscape) [ [ 95 100 195cp ]] 83 AllocateArray === 60 54 55 8 1 ( 81 68 44 44 1 57 1 ) [[ 84 85 86 93 94 95 ]] rawptr:NotNull ( int:>=0, java/lang/Object:NotNull *, bool, int ) ArraysCopyOf::test @ bci:8 (line 12) !jvms: ArraysCopyOf::test @ bci:8 (line 12) LocalVar [ 83P [ 100 ]] 95 Proj === 83 [[ 96 100 ]] #5 !jvms: ArraysCopyOf::test @ bci:8 (line 12) LocalVar [ 95 83P [ 195cp ]] 100 CheckCastPP === 97 95 [[ 195 115 132 151 166 177 195 ]] #narrowoop: java/lang/Object *[int:0]:NotNull:exact * !jvms: ArraysCopyOf::test @ bci:8 (line 12) JavaObject NoEscape(NoEscape) [ 195cp [ 189 194 ]] 177 AllocateArray === 235 94 82 8 1 ( 81 147 44 44 1 1 1 100 44 120 ) [[ 178 179 180 187 188 189 ]] rawptr:NotNull ( int:>=0, java/lang/Object:NotNull *, bool, int ) ArraysCopyOf::test @ bci:13 (line 12) reexecute !jvms: ArraysCopyOf::test @ bci:13 (line 12) LocalVar [ 177P [ 194 ]] 189 Proj === 177 [[ 190 194 ]] #5 !jvms: ArraysCopyOf::test @ bci:13 (line 12) LocalVar [ 189 195cp 177P [ ]] 194 CheckCastPP === 191 189 [[ 195 225 ]] #narrowoop: java/lang/Object *[int:0]:NotNull * !jvms: ArraysCopyOf::test @ bci:13 (line 12) NotScalar (Object is passed as argument) 100 CheckCastPP === 97 95 [[ 195 115 132 151 166 177 195 ]] #narrowoop: java/lang/Object *[int:0]:NotNull:exact *,iid=83 !jvms: ArraysCopyOf::test @ bci:8 (line 12) >>>> 195 ArrayCopy === 191 188 176 8 1 ( 100 44 194 44 44 _ _ 68 147 1 1 1 100 44 120 ) [[ 198 200 201 202 217 ]] void ( java/lang/Object *, int, java/lang/Object *, int, int, int, int, BotPTR *+bot, BotPTR *+bot ) ArraysCopyOf::test @ bci:13 (line 12) reexecute (CopyOfRange, tightly coupled allocation) !jvms: ArraysCopyOf::test @ bci:13 (line 12) NotScalar (Object is passed as argument) 100 CheckCastPP === 97 95 [[ 195 115 132 151 166 177 195 ]] #narrowoop: java/lang/Object *[int:0]:NotNull:exact *,iid=83 !jvms: ArraysCopyOf::test @ bci:8 (line 12) >>>> 195 ArrayCopy === 191 188 176 8 1 ( 100 44 194 44 44 _ _ 68 147 1 1 1 100 44 120 ) [[ 198 200 201 202 217 ]] void ( java/lang/Object *, int, java/lang/Object *, int, int, int, int, BotPTR *+bot, BotPTR *+bot ) ArraysCopyOf::test @ bci:13 (line 12) reexecute (CopyOfRange, tightly coupled allocation) !jvms: ArraysCopyOf::test @ bci:13 (line 12)
21-01-2022

It was filed as a follow-up enhancement for JDK-8058825. The bug was related to Arrays.copyOf(). Vladimir K. noted that "we will not eliminate such allocations anymore - if it is not referenced in debug info (no deoptimiztion points) we could still eliminate it."
21-01-2022

@Vladimir Ivanov - Can you please give me an example where this problem can happen? I'll be glad to try and fix this issue while I study the workings of C2 Escape Analysis & Scalar Replacement.
21-01-2022