264 lines
9.5 KiB
Diff
264 lines
9.5 KiB
Diff
From 1f8f5bac958a2655d9188744e6402b96a5f6d666 Mon Sep 17 00:00:00 2001
|
|
Date: Fri, 22 Jan 2021 16:37:39 +0800
|
|
Subject: 8237894: C1 compilation fails with
|
|
assert(x->type()->tag() == f->type()->tag())
|
|
|
|
Summary: <c1>: C1 compilation fails with assert(x->type()->tag() == f->type()->tag()) failed: should have same type
|
|
LLT: hotspot/test/compiler/c1/TestValueNumberingNullObject.java
|
|
Bug url: https://bugs.openjdk.java.net/browse/JDK-8237894
|
|
---
|
|
hotspot/src/share/vm/c1/c1_GraphBuilder.cpp | 29 ++--
|
|
hotspot/src/share/vm/c1/c1_Instruction.hpp | 14 +-
|
|
.../c1/TestValueNumberingNullObject.java | 131 ++++++++++++++++++
|
|
3 files changed, 157 insertions(+), 17 deletions(-)
|
|
create mode 100644 hotspot/test/compiler/c1/TestValueNumberingNullObject.java
|
|
|
|
diff --git a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp
|
|
index 99f1c510c..174e59436 100644
|
|
--- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp
|
|
+++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
|
|
+ * Copyright (c) 1999, 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
|
|
@@ -3891,6 +3891,23 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, Bytecode
|
|
INLINE_BAILOUT("mdo allocation failed");
|
|
}
|
|
|
|
+ const bool is_invokedynamic = (bc == Bytecodes::_invokedynamic);
|
|
+ const bool has_receiver = (bc != Bytecodes::_invokestatic && !is_invokedynamic);
|
|
+
|
|
+ const int args_base = state()->stack_size() - callee->arg_size();
|
|
+ assert(args_base >= 0, "stack underflow during inlining");
|
|
+
|
|
+ Value recv = NULL;
|
|
+ if (has_receiver) {
|
|
+ assert(!callee->is_static(), "callee must not be static");
|
|
+ assert(callee->arg_size() > 0, "must have at least a receiver");
|
|
+
|
|
+ recv = state()->stack_at(args_base);
|
|
+ if (recv->is_null_obj()) {
|
|
+ INLINE_BAILOUT("receiver is always null");
|
|
+ }
|
|
+ }
|
|
+
|
|
// now perform tests that are based on flag settings
|
|
if (callee->force_inline() || callee->should_inline()) {
|
|
if (inline_level() > MaxForceInlineLevel ) INLINE_BAILOUT("MaxForceInlineLevel");
|
|
@@ -3932,21 +3949,11 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, Bytecode
|
|
|
|
BlockBegin* orig_block = block();
|
|
|
|
- const bool is_invokedynamic = bc == Bytecodes::_invokedynamic;
|
|
- const bool has_receiver = (bc != Bytecodes::_invokestatic && !is_invokedynamic);
|
|
-
|
|
- const int args_base = state()->stack_size() - callee->arg_size();
|
|
- assert(args_base >= 0, "stack underflow during inlining");
|
|
-
|
|
// Insert null check if necessary
|
|
- Value recv = NULL;
|
|
if (has_receiver) {
|
|
// note: null check must happen even if first instruction of callee does
|
|
// an implicit null check since the callee is in a different scope
|
|
// and we must make sure exception handling does the right thing
|
|
- assert(!callee->is_static(), "callee must not be static");
|
|
- assert(callee->arg_size() > 0, "must have at least a receiver");
|
|
- recv = state()->stack_at(args_base);
|
|
null_check(recv);
|
|
}
|
|
|
|
diff --git a/hotspot/src/share/vm/c1/c1_Instruction.hpp b/hotspot/src/share/vm/c1/c1_Instruction.hpp
|
|
index ee4adbc48..6e61358e6 100644
|
|
--- a/hotspot/src/share/vm/c1/c1_Instruction.hpp
|
|
+++ b/hotspot/src/share/vm/c1/c1_Instruction.hpp
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
|
|
+ * Copyright (c) 1999, 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
|
|
@@ -277,7 +277,7 @@ class InstructionVisitor: public StackObj {
|
|
|
|
|
|
#define HASHING3(class_name, enabled, f1, f2, f3) \
|
|
- virtual intx hash() const { \
|
|
+ virtual intx hash() const { \
|
|
return (enabled) ? HASH4(name(), f1, f2, f3) : 0; \
|
|
} \
|
|
virtual bool is_equal(Value v) const { \
|
|
@@ -462,6 +462,8 @@ class Instruction: public CompilationResourceObj {
|
|
bool is_linked() const { return check_flag(IsLinkedInBlockFlag); }
|
|
bool can_be_linked() { return as_Local() == NULL && as_Phi() == NULL; }
|
|
|
|
+ bool is_null_obj() { return as_Constant() != NULL && type()->as_ObjectType()->constant_value()->is_null_object(); }
|
|
+
|
|
bool has_uses() const { return use_count() > 0; }
|
|
ValueStack* state_before() const { return _state_before; }
|
|
ValueStack* exception_state() const { return _exception_state; }
|
|
@@ -839,8 +841,8 @@ LEAF(LoadField, AccessField)
|
|
|
|
ciType* declared_type() const;
|
|
|
|
- // generic
|
|
- HASHING2(LoadField, !needs_patching() && !field()->is_volatile(), obj()->subst(), offset()) // cannot be eliminated if needs patching or if volatile
|
|
+ // generic; cannot be eliminated if needs patching or if volatile.
|
|
+ HASHING3(LoadField, !needs_patching() && !field()->is_volatile(), obj()->subst(), offset(), declared_type())
|
|
};
|
|
|
|
|
|
@@ -966,8 +968,8 @@ LEAF(LoadIndexed, AccessIndexed)
|
|
ciType* exact_type() const;
|
|
ciType* declared_type() const;
|
|
|
|
- // generic
|
|
- HASHING2(LoadIndexed, true, array()->subst(), index()->subst())
|
|
+ // generic;
|
|
+ HASHING3(LoadIndexed, true, type()->tag(), array()->subst(), index()->subst())
|
|
};
|
|
|
|
|
|
diff --git a/hotspot/test/compiler/c1/TestValueNumberingNullObject.java b/hotspot/test/compiler/c1/TestValueNumberingNullObject.java
|
|
new file mode 100644
|
|
index 000000000..66d5581f5
|
|
--- /dev/null
|
|
+++ b/hotspot/test/compiler/c1/TestValueNumberingNullObject.java
|
|
@@ -0,0 +1,131 @@
|
|
+/*
|
|
+ * 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 8237894
|
|
+ * @summary CTW: C1 compilation fails with assert(x->type()->tag() == f->type()->tag()) failed: should have same type
|
|
+ *
|
|
+ * @run main/othervm
|
|
+ * -Xcomp -Xbatch -XX:CompileCommand=compileonly,compiler.c1.T*::*
|
|
+ * -XX:CompileCommand=exclude,compiler.c1.TestValueNumberingNullObject::main
|
|
+ * -XX:CompileCommand=inline,*.*
|
|
+ * -XX:TieredStopAtLevel=3
|
|
+ * compiler.c1.TestValueNumberingNullObject
|
|
+ */
|
|
+
|
|
+package compiler.c1;
|
|
+
|
|
+class T1 {
|
|
+
|
|
+ public T2 f1;
|
|
+
|
|
+ public int za() {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ public int zb() {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ public int zc() {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ public int zd() {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ public int ze() {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ public int zf() {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ public int zg() {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ public int zh() {
|
|
+ return 0;
|
|
+ }
|
|
+}
|
|
+
|
|
+class T2 {
|
|
+
|
|
+ public T1 f1;
|
|
+
|
|
+ public int zh() {
|
|
+ return 0;
|
|
+ }
|
|
+}
|
|
+
|
|
+public class TestValueNumberingNullObject {
|
|
+
|
|
+ public static void main(String args[]) {
|
|
+ new T1(); // Load
|
|
+ new T2(); // Load
|
|
+ try {
|
|
+ // case 1
|
|
+ // Null based field access.
|
|
+ // Value Numbering null based field access causes instructions to be eliminated across type/subtypes.
|
|
+ // declared type of these instructions are field type, so it being receiver causes problems to Type System.
|
|
+ // to mitigate this issue, we hash declared type in addition to existing hashing.
|
|
+ testFieldAccess();
|
|
+ } catch (Exception e) {
|
|
+ }
|
|
+ try {
|
|
+ // case 2
|
|
+ // Null based indexed access.
|
|
+ // Value Numbering null based indexed access causes instructions to be eliminated across type/subtypes.
|
|
+ // element basic type in encoded in the access instruction, this causes problems to Type system.
|
|
+ // declared type of these instructions are null, so it being receiver doesn't cause any problem to Type System.
|
|
+ // to mitigate this issue, we hash basic type in addition to existing hashing
|
|
+ basicTypeAccess();
|
|
+ } catch (Exception e) {
|
|
+ }
|
|
+ }
|
|
+
|
|
+ static long testFieldAccess() {
|
|
+ T1 t1 = null;
|
|
+ T2 t2 = null;
|
|
+ T1[] t3 = null;
|
|
+ T2[] t4 = null;
|
|
+
|
|
+ long value = t1.f1.zh() + t2.f1.zh();
|
|
+ // null array object based field access.
|
|
+ value += t3[2].f1.zh() + t4[2].f1.zh();
|
|
+ return value;
|
|
+ }
|
|
+
|
|
+ static long basicTypeAccess() {
|
|
+ long[] f1 = null;
|
|
+ int[] f2 = null;
|
|
+ T2[] t2 = null;
|
|
+ T1[] t1 = null;
|
|
+ return f1[5] + f2[5] + t2[5].zh() + t1[5].zh();
|
|
+ }
|
|
+}
|
|
+
|
|
--
|
|
2.19.0
|
|
|