changeset 59717:e8d34f3f6833

8244719: CTW: C2 compilation fails with "assert(!VerifyHashTableKeys || _hash_lock == 0) failed: remove node from hash table before modifying it" Summary: Fix Parse::Block::init_graph() to also count predecessors for exception blocks because they can have a direct bytecode jump to them resulting in this assertion failure. Reviewed-by: kvn, thartmann
author chagedorn
date Wed, 10 Jun 2020 17:56:23 +0200
parents f32cc62c5821
children 506abc554cae
files src/hotspot/share/opto/parse1.cpp test/hotspot/jtreg/compiler/parsing/TestExceptionBlockWithPredecessors.jasm test/hotspot/jtreg/compiler/parsing/TestExceptionBlockWithPredecessorsMain.java
diffstat 3 files changed, 225 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/opto/parse1.cpp	Wed Jun 10 15:50:26 2020 +0000
+++ b/src/hotspot/share/opto/parse1.cpp	Wed Jun 10 17:56:23 2020 +0200
@@ -1293,9 +1293,11 @@
     _successors[i] = block2;
 
     // Accumulate pred info for the other block, too.
-    if (i < ns) {
-      block2->_pred_count++;
-    } else {
+    // Note: We also need to set _pred_count for exception blocks since they could
+    // also have normal predecessors (reached without athrow by an explicit jump).
+    // This also means that next_path_num can be called along exception paths.
+    block2->_pred_count++;
+    if (i >= ns) {
       block2->_is_handler = true;
     }
 
@@ -1310,10 +1312,6 @@
     }
     #endif
   }
-
-  // Note: We never call next_path_num along exception paths, so they
-  // never get processed as "ready".  Also, the input phis of exception
-  // handlers get specially processed, so that
 }
 
 //---------------------------successor_for_bci---------------------------------
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/compiler/parsing/TestExceptionBlockWithPredecessors.jasm	Wed Jun 10 17:56:23 2020 +0200
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+super public class compiler/parsing/TestExceptionBlockWithPredecessors
+	version 59:0
+{
+
+Field loopCounter:I;
+Field switchOn:I;
+Field iFld:I;
+
+public Method "<init>":"()V"
+	stack 1 locals 1
+{
+		aload_0;
+		invokespecial	Method java/lang/Object."<init>":"()V";
+		return;
+}
+
+Method test:"()V"
+	stack 4 locals 2
+{
+		try t0, t1;
+		aload_0;
+		invokevirtual	Method dontInlineThrow:"()V";
+		aload_0;
+		getfield	Field switchOn:"I";
+		tableswitch{ //1 to 3
+		1: L32;
+		2: L53;
+		3: L57;
+		default: L67 };
+	L32:	stack_frame_type same;
+		aload_0;
+		getfield	Field loopCounter:"I";
+		bipush	10;
+		if_icmpge	L67;
+		aload_0;
+		invokevirtual	Method dontInlineThrow:"()V";
+	L53:	stack_frame_type same;
+		aload_0;
+		invokevirtual	Method dontInlineThrow:"()V";
+	L57:	stack_frame_type same;
+		aload_0;
+		dup;
+		getfield	Field loopCounter:"I";
+		iconst_1;
+		iadd;
+		putfield	Field loopCounter:"I";
+		goto	L32;
+		endtry t0, t1;
+	L67:	stack_frame_type same;
+		goto	L74;
+		catch t0 java/lang/RuntimeException;
+		stack_frame_type stack1;
+		stack_map class java/lang/RuntimeException;
+		astore_1;
+		aload_1;
+		aload_0;
+		getfield	Field loopCounter:"I";
+		bipush	10;
+		if_icmpge	L70;
+        aload_0;
+        dup;
+		getfield	Field loopCounter:"I";
+		iconst_1;
+		iadd;
+		putfield	Field loopCounter:"I";
+		goto L70;
+		catch t1 java/lang/Throwable;
+	L70:    stack_frame_type stack1;
+		stack_map class java/lang/Throwable;
+		astore_1;
+	L74:	stack_frame_type same;
+		return;
+}
+
+Method testWorksWithoutPreds:"()V"
+	stack 4 locals 2
+{
+		try t0, t1;
+		aload_0;
+		invokevirtual	Method dontInlineThrow:"()V";
+		aload_0;
+		getfield	Field switchOn:"I";
+		tableswitch{ //1 to 3
+		1: L32; // No profile information about it. Never taken. Skip on it in first iteration in do_all_blocks()
+		2: L53;
+		3: L57;
+		default: L67 };
+	L32:	stack_frame_type same; // Only parsed in second iteration of do_all_blocks(), when both exception handler blocks are already parsed
+		aload_0;
+		getfield	Field loopCounter:"I";
+		bipush	10;
+		if_icmpge	L67;
+		aload_0;
+		invokevirtual	Method dontInlineThrow:"()V";
+        aload_0;
+	    getfield	Field iFld:"I";
+		bipush	10;
+		if_icmpeq	L53;
+		aload_0;
+		invokevirtual	Method dontInlineThrow:"()V";
+	L52:	stack_frame_type same;
+        aload_0;
+		invokevirtual	Method dontInlineThrow:"()V";
+	L53:	stack_frame_type same;
+		aload_0;
+		invokevirtual	Method dontInlineThrow:"()V";
+	L57:	stack_frame_type same;
+		aload_0;
+		dup;
+		getfield	Field loopCounter:"I";
+		iconst_1;
+		iadd;
+		putfield	Field loopCounter:"I";
+		goto	L32; // Only merge block starting at that bytecode which has a smaller rpo than this block -> process in next iteration in do_all_blocks()
+		endtry t0, t1;
+	L67:	stack_frame_type same;
+		goto	L74;
+		catch t0 java/lang/RuntimeException;
+		stack_frame_type stack1;
+		stack_map class java/lang/RuntimeException;
+		astore_1;
+		aload_0;
+		getfield	Field loopCounter:"I";
+		bipush	10;
+		if_icmpge	L74;
+        aload_0;
+        dup;
+		getfield	Field loopCounter:"I";
+		iconst_1;
+		iadd;
+		putfield	Field loopCounter:"I";
+		goto L74;
+		catch t1 java/lang/Throwable;
+	L70:    stack_frame_type stack1;
+		stack_map class java/lang/Throwable;
+		astore_1;
+	L74:	stack_frame_type same;
+		return;
+}
+
+
+public Method dontInlineThrow:"()V"
+	throws java/lang/RuntimeException
+	stack 0 locals 1
+{
+		return;
+}
+
+} // end Class TestExceptionBlockWithPredecessors
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/compiler/parsing/TestExceptionBlockWithPredecessorsMain.java	Wed Jun 10 17:56:23 2020 +0200
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8244719
+ * @summary Tests custom bytecode with an explicit entry (fall through or jump) to an exception block which was unexpected for C2 parsing.
+ *
+ * @compile TestExceptionBlockWithPredecessors.jasm
+ * @run main/othervm -Xbatch -XX:CompileCommand=dontinline,compiler.parsing.TestExceptionBlockWithPredecessors::*
+ *                   compiler.parsing.TestExceptionBlockWithPredecessorsMain
+ */
+
+package compiler.parsing;
+
+public class TestExceptionBlockWithPredecessorsMain {
+    public static void main(String[] args) {
+        TestExceptionBlockWithPredecessors t = new TestExceptionBlockWithPredecessors();
+        for (int i = 0; i < 10000; i++) {
+            t.loopCounter = (i % 2 == 0) ? 0 : 10;
+            t.switchOn = (i % 2 == 0) ? 2 : 3;
+            t.test(); // Triggers assertion failure
+            t.testWorksWithoutPreds(); // Works since no predecessors for exception handler
+        }
+    }
+}