Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8296412

Special case infinite loops with unmerged backedges in IdealLoopTree::check_safepts

XMLWordPrintable

    • b03

        Working hypothesis:
        Maybe backedge of irreducible loop is missing a SafePoint.

        During fuzzing work of JDK-8280126, I found an S.jasm that triggers the following assert:

        # Internal Error (/home/emanuel/Documents/fork2-jdk/open/src/hotspot/share/opto/loopnode.cpp:3610), pid=159269, tid=159282
        # assert(is_member(nlpt)) failed: nested loop
        #
        # JRE version: Java(TM) SE Runtime Environment (20.0) (slowdebug build 20-internal-2022-10-06-1045569.emanuel...)
        # Java VM: Java HotSpot(TM) 64-Bit Server VM (slowdebug 20-internal-2022-10-06-1045569.emanuel..., compiled mode, compressed oops, compressed class ptrs, g1 gc, linux-amd64)
        # Problematic frame:
        # V [libjvm.so+0xf5cb86] IdealLoopTree::check_safepts(VectorSet&, Node_List&)+0x200

        Current CompileTask:
        C2: 742 26 b S::test (27 bytes)

        Stack: [0x00007f4a65dfe000,0x00007f4a65eff000], sp=0x00007f4a65ef9090, free space=1004k
        Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
        V [libjvm.so+0xf5cb86] IdealLoopTree::check_safepts(VectorSet&, Node_List&)+0x200 (loopnode.cpp:3610)
        V [libjvm.so+0xf5c9f7] IdealLoopTree::check_safepts(VectorSet&, Node_List&)+0x71 (loopnode.cpp:3584)
        V [libjvm.so+0xf5c9cf] IdealLoopTree::check_safepts(VectorSet&, Node_List&)+0x49 (loopnode.cpp:3583)
        V [libjvm.so+0xf5ff1f] PhaseIdealLoop::build_and_optimize()+0x8bf (loopnode.cpp:4358)
        V [libjvm.so+0x8a6343] PhaseIdealLoop::PhaseIdealLoop(PhaseIterGVN&, LoopOptsMode)+0x105 (loopnode.hpp:1087)
        V [libjvm.so+0x8a653e] PhaseIdealLoop::optimize(PhaseIterGVN&, LoopOptsMode)+0x46 (loopnode.hpp:1166)
        V [libjvm.so+0x899177] Compile::Optimize()+0xa69 (compile.cpp:2365)
        V [libjvm.so+0x892104] Compile::Compile(ciEnv*, ciMethod*, int, Options, DirectiveSet*)+0x1404 (compile.cpp:830)
        V [libjvm.so+0x780a9b] C2Compiler::compile_method(ciEnv*, ciMethod*, int, bool, DirectiveSet*)+0x179 (c2compiler.cpp:113)
        V [libjvm.so+0x8b0df8] CompileBroker::invoke_compiler_on_method(CompileTask*)+0x916 (compileBroker.cpp:2240)
        V [libjvm.so+0x8afa61] CompileBroker::compiler_thread_loop()+0x3ed (compileBroker.cpp:1916)
        V [libjvm.so+0x8d01aa] CompilerThread::thread_entry(JavaThread*, JavaThread*)+0x72 (compilerThread.cpp:58)
        V [libjvm.so+0xc5e0cc] JavaThread::thread_main_inner()+0x144 (javaThread.cpp:699)
        V [libjvm.so+0xc5df84] JavaThread::run()+0x182 (javaThread.cpp:684)
        V [libjvm.so+0x13306e7] Thread::call_run()+0x195 (thread.cpp:224)
        V [libjvm.so+0x10ddf15] thread_native_entry(Thread*)+0x19b (os_linux.cpp:710)

        Reproduce it:
        java -jar ~/Documents/asmtools-7.0-build/release/lib/asmtools.jar jasm S.jasm
        java -Xcomp -XX:CompileCommand=compileonly,S::test -XX:-TieredCompilation -XX:PerMethodTrapLimit=0 -XX:-RenumberLiveNodes S

        Note that the flags
         -XX:PerMethodTrapLimit=0 -XX:-RenumberLiveNodes
        are not required, but simplify the graph by removing traps (no predicates inserted), and the node idx are stable as they are not renumbered during remove useless.

        While it is well possible that this is only reproducilbe with irreducible loops, it does not seem to have to do with dead irreducible loops, so it is a separate bug from JDK-8280126.

        Analysis:
        (please look at attached png's for node idx)
        In IdealLoopTree::check_safepts.
        this:
          Loop: N37/N57
            Loop: N37/N56 sfpts={ 44 }
        We start walking from n = tail() up the n = idom(n):
        57 IfFalse
        55 If
        We realize that 55 If belongs to:
        Loop: N37/N56
        Hence, we jump to head of that loop, so set n:
        37 Region
        (note: this is the loop head of "this" loop, we should abort the idom walk)
        We take n = idom(n), and get:
        25 IfTrue
        (this node is outside the loop, but the assumption of the code is that we are still inside the loop)
        This node's loop (nlpt) is:
        Loop: N0/N0 has_sfpt
          Loop: N103/N102 sfpts={ 82 70 }
          Loop: N37/N57
            Loop: N37/N56 sfpts={ 44 }
        (this is the root loop)
        Now we hit the assert, we check that "nlpt" is a member of "this".

        Why does this usually work?
        Usually, when we have a nested loop, where the loop is shared, we seem to always have a SafePoint on the backedge of the outer loop. So when we exit the inner loop, we expect to go through a SafePoint before we take the backedge to the loop head.
        This seems not to be given, and may well have to do with the fact that we have an irreducible loop here (37 and 38 Region).

        What could be solutions?
        I have not really understood the issue. But some first thoughts include:
        1) Checking when we jump to the loop-head of the inner loop, if this is also the loop head of the outer loop. But this would be accepting that backedges of outer-loops do not have safepoints.
        2) Insert the safepoint during parsing.

          1. hs_err_pid159269.log
            75 kB
            Emanuel Peter
          2. replay_pid159269.log
            147 kB
            Emanuel Peter
          3. S.jasm
            0.7 kB
            Emanuel Peter
          4. S.jasm.0.png
            77 kB
            Emanuel Peter
          5. S.jasm.1.png
            57 kB
            Emanuel Peter
          6. S.jasm.2.png
            58 kB
            Emanuel Peter

              epeter Emanuel Peter
              epeter Emanuel Peter
              Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

                Created:
                Updated:
                Resolved: