8217760: C2: Missing symbolic info on a call from intrinsics when invoked through MethodHandle
Reviewed-by: thartmann, roland
--- a/src/hotspot/share/opto/callGenerator.cpp Fri Jan 25 18:13:25 2019 +0000
+++ b/src/hotspot/share/opto/callGenerator.cpp Fri Jan 25 13:37:08 2019 -0800
@@ -46,9 +46,17 @@
return TypeFunc::make(method());
}
-bool CallGenerator::is_inlined_method_handle_intrinsic(JVMState* jvms, ciMethod* callee) {
- ciMethod* symbolic_info = jvms->method()->get_method_at_bci(jvms->bci());
- return symbolic_info->is_method_handle_intrinsic() && !callee->is_method_handle_intrinsic();
+bool CallGenerator::is_inlined_method_handle_intrinsic(JVMState* jvms, ciMethod* m) {
+ return is_inlined_method_handle_intrinsic(jvms->method(), jvms->bci(), m);
+}
+
+bool CallGenerator::is_inlined_method_handle_intrinsic(ciMethod* caller, int bci, ciMethod* m) {
+ ciMethod* symbolic_info = caller->get_method_at_bci(bci);
+ return is_inlined_method_handle_intrinsic(symbolic_info, m);
+}
+
+bool CallGenerator::is_inlined_method_handle_intrinsic(ciMethod* symbolic_info, ciMethod* m) {
+ return symbolic_info->is_method_handle_intrinsic() && !m->is_method_handle_intrinsic();
}
//-----------------------------ParseGenerator---------------------------------
--- a/src/hotspot/share/opto/callGenerator.hpp Fri Jan 25 18:13:25 2019 +0000
+++ b/src/hotspot/share/opto/callGenerator.hpp Fri Jan 25 13:37:08 2019 -0800
@@ -176,6 +176,8 @@
}
static bool is_inlined_method_handle_intrinsic(JVMState* jvms, ciMethod* m);
+ static bool is_inlined_method_handle_intrinsic(ciMethod* caller, int bci, ciMethod* m);
+ static bool is_inlined_method_handle_intrinsic(ciMethod* symbolic_info, ciMethod* m);
};
--- a/src/hotspot/share/opto/callnode.cpp Fri Jan 25 18:13:25 2019 +0000
+++ b/src/hotspot/share/opto/callnode.cpp Fri Jan 25 13:37:08 2019 -0800
@@ -967,6 +967,21 @@
return CallNode::cmp(call) && _method == call._method &&
_override_symbolic_info == call._override_symbolic_info;
}
+#ifdef ASSERT
+bool CallJavaNode::validate_symbolic_info() const {
+ if (method() == NULL) {
+ return true; // call into runtime or uncommon trap
+ }
+ ciMethod* symbolic_info = jvms()->method()->get_method_at_bci(_bci);
+ ciMethod* callee = method();
+ if (symbolic_info->is_method_handle_intrinsic() && !callee->is_method_handle_intrinsic()) {
+ assert(override_symbolic_info(), "should be set");
+ }
+ assert(ciMethod::is_consistent_info(symbolic_info, callee), "inconsistent info");
+ return true;
+}
+#endif
+
#ifndef PRODUCT
void CallJavaNode::dump_spec(outputStream *st) const {
if( _method ) _method->print_short_name(st);
--- a/src/hotspot/share/opto/callnode.hpp Fri Jan 25 18:13:25 2019 +0000
+++ b/src/hotspot/share/opto/callnode.hpp Fri Jan 25 13:37:08 2019 -0800
@@ -683,6 +683,8 @@
void set_override_symbolic_info(bool f) { _override_symbolic_info = f; }
bool override_symbolic_info() const { return _override_symbolic_info; }
+ DEBUG_ONLY( bool validate_symbolic_info() const; )
+
#ifndef PRODUCT
virtual void dump_spec(outputStream *st) const;
virtual void dump_compact_spec(outputStream *st) const;
--- a/src/hotspot/share/opto/library_call.cpp Fri Jan 25 18:13:25 2019 +0000
+++ b/src/hotspot/share/opto/library_call.cpp Fri Jan 25 13:37:08 2019 -0800
@@ -3850,6 +3850,13 @@
method, bci());
slow_call->set_optimized_virtual(true);
}
+ if (CallGenerator::is_inlined_method_handle_intrinsic(this->method(), bci(), callee())) {
+ // To be able to issue a direct call (optimized virtual or virtual)
+ // and skip a call to MH.linkTo*/invokeBasic adapter, additional information
+ // about the method being invoked should be attached to the call site to
+ // make resolution logic work (see SharedRuntime::resolve_{virtual,opt_virtual}_call_C).
+ slow_call->set_override_symbolic_info(true);
+ }
set_arguments_for_java_call(slow_call);
set_edges_for_java_call(slow_call);
return slow_call;
--- a/src/hotspot/share/opto/matcher.cpp Fri Jan 25 18:13:25 2019 +0000
+++ b/src/hotspot/share/opto/matcher.cpp Fri Jan 25 13:37:08 2019 -0800
@@ -1170,6 +1170,7 @@
if( mcall->is_MachCallJava() ) {
MachCallJavaNode *mcall_java = mcall->as_MachCallJava();
const CallJavaNode *call_java = call->as_CallJava();
+ assert(call_java->validate_symbolic_info(), "inconsistent info");
method = call_java->method();
mcall_java->_method = method;
mcall_java->_bci = call_java->_bci;
--- a/test/hotspot/jtreg/compiler/jsr292/NonInlinedCall/InvokeTest.java Fri Jan 25 18:13:25 2019 +0000
+++ b/test/hotspot/jtreg/compiler/jsr292/NonInlinedCall/InvokeTest.java Fri Jan 25 13:37:08 2019 -0800
@@ -60,6 +60,8 @@
static final MethodHandle privateMH; // invokespecial I.f4 T
static final MethodHandle basicMH;
+ static final MethodHandle intrinsicMH; // invokevirtual Object.hashCode
+
static final WhiteBox WB = WhiteBox.getWhiteBox();
static volatile boolean doDeopt = false;
@@ -75,6 +77,7 @@
specialMH = LOOKUP.findSpecial(T.class, "f4", mtype, T.class);
privateMH = LOOKUP.findSpecial(I.class, "f4", mtype, I.class);
basicMH = NonInlinedReinvoker.make(staticMH);
+ intrinsicMH = LOOKUP.findVirtual(Object.class, "hashCode", MethodType.methodType(int.class));
} catch (Exception e) {
throw new Error(e);
}
@@ -117,6 +120,10 @@
static class Q2 extends T implements J2 {}
static class Q3 extends T implements J3 {}
+ static class H {
+ public int hashCode() { return 0; }
+ }
+
@DontInline
static void linkToVirtual(T recv, Class<?> expected) {
try {
@@ -138,6 +145,16 @@
}
@DontInline
+ static void linkToVirtualIntrinsic(Object recv, int expected) {
+ try {
+ int v = (int)intrinsicMH.invokeExact(recv);
+ assertEquals(v, expected);
+ } catch (Throwable e) {
+ throw new Error(e);
+ }
+ }
+
+ @DontInline
static void linkToInterface(I recv, Class<?> expected) {
try {
Class<?> cls = (Class<?>)intfMH.invokeExact(recv);
@@ -177,7 +194,6 @@
}
}
-
@DontInline
static void invokeBasic() {
try {
@@ -215,6 +231,8 @@
run(() -> linkToVirtual(new T(), T.class));
run(() -> linkToVirtualDefault(new T(), I.class));
+ run(() -> linkToVirtualIntrinsic(new H(), 0));
+
// Megamorphic case (optimized virtual call)
run(() -> {
linkToVirtual(new T() {}, T.class);