# HG changeset patch # User vlivanov # Date 1548378613 28800 # Thu Jan 24 17:10:13 2019 -0800 # Node ID adf7d5a73dc7c1f771d00c172fbb66518616573a # Parent 80b55cf3a8048585c5baf9fd78297c7e7cba9905 8217760: C2: Missing symbolic info on a call from intrinsics when invoked through MethodHandle Reviewed-by: ? diff --git a/src/hotspot/share/opto/callGenerator.cpp b/src/hotspot/share/opto/callGenerator.cpp --- a/src/hotspot/share/opto/callGenerator.cpp +++ b/src/hotspot/share/opto/callGenerator.cpp @@ -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--------------------------------- diff --git a/src/hotspot/share/opto/callGenerator.hpp b/src/hotspot/share/opto/callGenerator.hpp --- a/src/hotspot/share/opto/callGenerator.hpp +++ b/src/hotspot/share/opto/callGenerator.hpp @@ -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); }; diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp --- a/src/hotspot/share/opto/callnode.cpp +++ b/src/hotspot/share/opto/callnode.cpp @@ -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); diff --git a/src/hotspot/share/opto/callnode.hpp b/src/hotspot/share/opto/callnode.hpp --- a/src/hotspot/share/opto/callnode.hpp +++ b/src/hotspot/share/opto/callnode.hpp @@ -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; diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -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; diff --git a/src/hotspot/share/opto/matcher.cpp b/src/hotspot/share/opto/matcher.cpp --- a/src/hotspot/share/opto/matcher.cpp +++ b/src/hotspot/share/opto/matcher.cpp @@ -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; diff --git a/test/hotspot/jtreg/compiler/jsr292/NonInlinedCall/InvokeTest.java b/test/hotspot/jtreg/compiler/jsr292/NonInlinedCall/InvokeTest.java --- a/test/hotspot/jtreg/compiler/jsr292/NonInlinedCall/InvokeTest.java +++ b/test/hotspot/jtreg/compiler/jsr292/NonInlinedCall/InvokeTest.java @@ -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);