Fri, 27 Sep 2013 11:52:24 +0400
8014447: Object.hashCode intrinsic breaks inline caches
Summary: Try to inline as normal method first, then fall back to intrinsic.
Reviewed-by: kvn, twisti
1.1 --- a/src/share/vm/opto/callGenerator.hpp Sat Sep 28 12:42:22 2013 -0700 1.2 +++ b/src/share/vm/opto/callGenerator.hpp Fri Sep 27 11:52:24 2013 +0400 1.3 @@ -65,6 +65,8 @@ 1.4 virtual bool is_predicted() const { return false; } 1.5 // is_trap: Does not return to the caller. (E.g., uncommon trap.) 1.6 virtual bool is_trap() const { return false; } 1.7 + // does_virtual_dispatch: Should try inlining as normal method first. 1.8 + virtual bool does_virtual_dispatch() const { return false; } 1.9 1.10 // is_late_inline: supports conversion of call into an inline 1.11 virtual bool is_late_inline() const { return false; }
2.1 --- a/src/share/vm/opto/doCall.cpp Sat Sep 28 12:42:22 2013 -0700 2.2 +++ b/src/share/vm/opto/doCall.cpp Fri Sep 27 11:52:24 2013 +0400 2.3 @@ -110,6 +110,7 @@ 2.4 // then we return it as the inlined version of the call. 2.5 // We do this before the strict f.p. check below because the 2.6 // intrinsics handle strict f.p. correctly. 2.7 + CallGenerator* cg_intrinsic = NULL; 2.8 if (allow_inline && allow_intrinsics) { 2.9 CallGenerator* cg = find_intrinsic(callee, call_does_dispatch); 2.10 if (cg != NULL) { 2.11 @@ -121,7 +122,16 @@ 2.12 cg = CallGenerator::for_predicted_intrinsic(cg, inline_cg); 2.13 } 2.14 } 2.15 - return cg; 2.16 + 2.17 + // If intrinsic does the virtual dispatch, we try to use the type profile 2.18 + // first, and hopefully inline it as the regular virtual call below. 2.19 + // We will retry the intrinsic if nothing had claimed it afterwards. 2.20 + if (cg->does_virtual_dispatch()) { 2.21 + cg_intrinsic = cg; 2.22 + cg = NULL; 2.23 + } else { 2.24 + return cg; 2.25 + } 2.26 } 2.27 } 2.28 2.29 @@ -266,6 +276,13 @@ 2.30 } 2.31 } 2.32 2.33 + // Nothing claimed the intrinsic, we go with straight-forward inlining 2.34 + // for already discovered intrinsic. 2.35 + if (allow_inline && allow_intrinsics && cg_intrinsic != NULL) { 2.36 + assert(cg_intrinsic->does_virtual_dispatch(), "sanity"); 2.37 + return cg_intrinsic; 2.38 + } 2.39 + 2.40 // There was no special inlining tactic, or it bailed out. 2.41 // Use a more generic tactic, like a simple call. 2.42 if (call_does_dispatch) {
3.1 --- a/src/share/vm/opto/library_call.cpp Sat Sep 28 12:42:22 2013 -0700 3.2 +++ b/src/share/vm/opto/library_call.cpp Fri Sep 27 11:52:24 2013 +0400 3.3 @@ -47,19 +47,22 @@ 3.4 private: 3.5 bool _is_virtual; 3.6 bool _is_predicted; 3.7 + bool _does_virtual_dispatch; 3.8 vmIntrinsics::ID _intrinsic_id; 3.9 3.10 public: 3.11 - LibraryIntrinsic(ciMethod* m, bool is_virtual, bool is_predicted, vmIntrinsics::ID id) 3.12 + LibraryIntrinsic(ciMethod* m, bool is_virtual, bool is_predicted, bool does_virtual_dispatch, vmIntrinsics::ID id) 3.13 : InlineCallGenerator(m), 3.14 _is_virtual(is_virtual), 3.15 _is_predicted(is_predicted), 3.16 + _does_virtual_dispatch(does_virtual_dispatch), 3.17 _intrinsic_id(id) 3.18 { 3.19 } 3.20 virtual bool is_intrinsic() const { return true; } 3.21 virtual bool is_virtual() const { return _is_virtual; } 3.22 virtual bool is_predicted() const { return _is_predicted; } 3.23 + virtual bool does_virtual_dispatch() const { return _does_virtual_dispatch; } 3.24 virtual JVMState* generate(JVMState* jvms); 3.25 virtual Node* generate_predicate(JVMState* jvms); 3.26 vmIntrinsics::ID intrinsic_id() const { return _intrinsic_id; } 3.27 @@ -355,6 +358,7 @@ 3.28 } 3.29 3.30 bool is_predicted = false; 3.31 + bool does_virtual_dispatch = false; 3.32 3.33 switch (id) { 3.34 case vmIntrinsics::_compareTo: 3.35 @@ -381,8 +385,10 @@ 3.36 break; 3.37 case vmIntrinsics::_hashCode: 3.38 if (!InlineObjectHash) return NULL; 3.39 + does_virtual_dispatch = true; 3.40 break; 3.41 case vmIntrinsics::_clone: 3.42 + does_virtual_dispatch = true; 3.43 case vmIntrinsics::_copyOf: 3.44 case vmIntrinsics::_copyOfRange: 3.45 if (!InlineObjectCopy) return NULL; 3.46 @@ -541,7 +547,7 @@ 3.47 if (!InlineUnsafeOps) return NULL; 3.48 } 3.49 3.50 - return new LibraryIntrinsic(m, is_virtual, is_predicted, (vmIntrinsics::ID) id); 3.51 + return new LibraryIntrinsic(m, is_virtual, is_predicted, does_virtual_dispatch, (vmIntrinsics::ID) id); 3.52 } 3.53 3.54 //----------------------register_library_intrinsics-----------------------