diff options
author | roland <none@none> | 2013-10-12 12:12:59 +0200 |
---|---|---|
committer | roland <none@none> | 2013-10-12 12:12:59 +0200 |
commit | c1531fdc640bc7ee40de4967ab4f7e466a6f17ad (patch) | |
tree | 11f553c8e4e3b4fd73fdc5debc03e460a639272c /src/share/vm/c1 | |
parent | 900779844ce827b54475e06ca6167dc0a66dcabc (diff) |
8026054: New type profiling points: type of return values at calls
Summary: x86 interpreter and c1 type profiling for return values at calls
Reviewed-by: kvn, twisti
Diffstat (limited to 'src/share/vm/c1')
-rw-r--r-- | src/share/vm/c1/c1_Canonicalizer.cpp | 1 | ||||
-rw-r--r-- | src/share/vm/c1/c1_Canonicalizer.hpp | 1 | ||||
-rw-r--r-- | src/share/vm/c1/c1_GraphBuilder.cpp | 35 | ||||
-rw-r--r-- | src/share/vm/c1/c1_GraphBuilder.hpp | 1 | ||||
-rw-r--r-- | src/share/vm/c1/c1_Instruction.hpp | 34 | ||||
-rw-r--r-- | src/share/vm/c1/c1_InstructionPrinter.cpp | 6 | ||||
-rw-r--r-- | src/share/vm/c1/c1_InstructionPrinter.hpp | 1 | ||||
-rw-r--r-- | src/share/vm/c1/c1_LIRGenerator.cpp | 19 | ||||
-rw-r--r-- | src/share/vm/c1/c1_LIRGenerator.hpp | 1 | ||||
-rw-r--r-- | src/share/vm/c1/c1_Optimizer.cpp | 7 | ||||
-rw-r--r-- | src/share/vm/c1/c1_RangeCheckElimination.hpp | 1 | ||||
-rw-r--r-- | src/share/vm/c1/c1_ValueMap.hpp | 1 |
12 files changed, 106 insertions, 2 deletions
diff --git a/src/share/vm/c1/c1_Canonicalizer.cpp b/src/share/vm/c1/c1_Canonicalizer.cpp index b80b199c9..f98edc6f5 100644 --- a/src/share/vm/c1/c1_Canonicalizer.cpp +++ b/src/share/vm/c1/c1_Canonicalizer.cpp @@ -935,6 +935,7 @@ void Canonicalizer::do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) {} void Canonicalizer::do_UnsafePrefetchRead (UnsafePrefetchRead* x) {} void Canonicalizer::do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) {} void Canonicalizer::do_ProfileCall(ProfileCall* x) {} +void Canonicalizer::do_ProfileReturnType(ProfileReturnType* x) {} void Canonicalizer::do_ProfileInvoke(ProfileInvoke* x) {} void Canonicalizer::do_RuntimeCall(RuntimeCall* x) {} void Canonicalizer::do_RangeCheckPredicate(RangeCheckPredicate* x) {} diff --git a/src/share/vm/c1/c1_Canonicalizer.hpp b/src/share/vm/c1/c1_Canonicalizer.hpp index 9e34ac79a..43ce4a41c 100644 --- a/src/share/vm/c1/c1_Canonicalizer.hpp +++ b/src/share/vm/c1/c1_Canonicalizer.hpp @@ -104,6 +104,7 @@ class Canonicalizer: InstructionVisitor { virtual void do_UnsafePrefetchRead (UnsafePrefetchRead* x); virtual void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x); virtual void do_ProfileCall (ProfileCall* x); + virtual void do_ProfileReturnType (ProfileReturnType* x); virtual void do_ProfileInvoke (ProfileInvoke* x); virtual void do_RuntimeCall (RuntimeCall* x); virtual void do_MemBar (MemBar* x); diff --git a/src/share/vm/c1/c1_GraphBuilder.cpp b/src/share/vm/c1/c1_GraphBuilder.cpp index f93a6e890..23d800528 100644 --- a/src/share/vm/c1/c1_GraphBuilder.cpp +++ b/src/share/vm/c1/c1_GraphBuilder.cpp @@ -1466,9 +1466,22 @@ void GraphBuilder::method_return(Value x) { // State at end of inlined method is the state of the caller // without the method parameters on stack, including the // return value, if any, of the inlined method on operand stack. + int invoke_bci = state()->caller_state()->bci(); set_state(state()->caller_state()->copy_for_parsing()); if (x != NULL) { state()->push(x->type(), x); + if (profile_calls() && MethodData::profile_return() && x->type()->is_object_kind()) { + ciMethod* caller = state()->scope()->method(); + ciMethodData* md = caller->method_data_or_null(); + ciProfileData* data = md->bci_to_data(invoke_bci); + if (data->is_CallTypeData() || data->is_VirtualCallTypeData()) { + bool has_return = data->is_CallTypeData() ? ((ciCallTypeData*)data)->has_return() : ((ciVirtualCallTypeData*)data)->has_return(); + // May not be true in case of an inlined call through a method handle intrinsic. + if (has_return) { + profile_return_type(x, method(), caller, invoke_bci); + } + } + } } Goto* goto_callee = new Goto(continuation(), false); @@ -2008,6 +2021,9 @@ void GraphBuilder::invoke(Bytecodes::Code code) { push(result_type, result); } } + if (profile_calls() && MethodData::profile_return() && result_type->is_object_kind()) { + profile_return_type(result, target); + } } @@ -3556,6 +3572,10 @@ bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) { Value value = append_split(result); if (result_type != voidType) push(result_type, value); + if (callee != method() && profile_calls() && MethodData::profile_return() && result_type->is_object_kind()) { + profile_return_type(result, callee); + } + // done return true; } @@ -4312,6 +4332,21 @@ void GraphBuilder::profile_call(ciMethod* callee, Value recv, ciKlass* known_hol append(new ProfileCall(method(), bci(), callee, recv, known_holder, obj_args, inlined)); } +void GraphBuilder::profile_return_type(Value ret, ciMethod* callee, ciMethod* m, int invoke_bci) { + assert((m == NULL) == (invoke_bci < 0), "invalid method and invalid bci together"); + if (m == NULL) { + m = method(); + } + if (invoke_bci < 0) { + invoke_bci = bci(); + } + ciMethodData* md = m->method_data_or_null(); + ciProfileData* data = md->bci_to_data(invoke_bci); + if (data->is_CallTypeData() || data->is_VirtualCallTypeData()) { + append(new ProfileReturnType(m , invoke_bci, callee, ret)); + } +} + void GraphBuilder::profile_invocation(ciMethod* callee, ValueStack* state) { append(new ProfileInvoke(callee, state)); } diff --git a/src/share/vm/c1/c1_GraphBuilder.hpp b/src/share/vm/c1/c1_GraphBuilder.hpp index 217da78bb..7945674fc 100644 --- a/src/share/vm/c1/c1_GraphBuilder.hpp +++ b/src/share/vm/c1/c1_GraphBuilder.hpp @@ -375,6 +375,7 @@ class GraphBuilder VALUE_OBJ_CLASS_SPEC { void print_inlining(ciMethod* callee, const char* msg = NULL, bool success = true); void profile_call(ciMethod* callee, Value recv, ciKlass* predicted_holder, Values* obj_args, bool inlined); + void profile_return_type(Value ret, ciMethod* callee, ciMethod* m = NULL, int bci = -1); void profile_invocation(ciMethod* inlinee, ValueStack* state); // Shortcuts to profiling control. diff --git a/src/share/vm/c1/c1_Instruction.hpp b/src/share/vm/c1/c1_Instruction.hpp index 466d814c6..19490bbc9 100644 --- a/src/share/vm/c1/c1_Instruction.hpp +++ b/src/share/vm/c1/c1_Instruction.hpp @@ -107,6 +107,7 @@ class UnsafePrefetch; class UnsafePrefetchRead; class UnsafePrefetchWrite; class ProfileCall; +class ProfileReturnType; class ProfileInvoke; class RuntimeCall; class MemBar; @@ -211,6 +212,7 @@ class InstructionVisitor: public StackObj { virtual void do_UnsafePrefetchRead (UnsafePrefetchRead* x) = 0; virtual void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) = 0; virtual void do_ProfileCall (ProfileCall* x) = 0; + virtual void do_ProfileReturnType (ProfileReturnType* x) = 0; virtual void do_ProfileInvoke (ProfileInvoke* x) = 0; virtual void do_RuntimeCall (RuntimeCall* x) = 0; virtual void do_MemBar (MemBar* x) = 0; @@ -2518,6 +2520,38 @@ LEAF(ProfileCall, Instruction) } }; +LEAF(ProfileReturnType, Instruction) + private: + ciMethod* _method; + ciMethod* _callee; + int _bci_of_invoke; + Value _ret; + + public: + ProfileReturnType(ciMethod* method, int bci, ciMethod* callee, Value ret) + : Instruction(voidType) + , _method(method) + , _callee(callee) + , _bci_of_invoke(bci) + , _ret(ret) + { + set_needs_null_check(true); + // The ProfileType has side-effects and must occur precisely where located + pin(); + } + + ciMethod* method() const { return _method; } + ciMethod* callee() const { return _callee; } + int bci_of_invoke() const { return _bci_of_invoke; } + Value ret() const { return _ret; } + + virtual void input_values_do(ValueVisitor* f) { + if (_ret != NULL) { + f->visit(&_ret); + } + } +}; + // Call some C runtime function that doesn't safepoint, // optionally passing the current thread as the first argument. LEAF(RuntimeCall, Instruction) diff --git a/src/share/vm/c1/c1_InstructionPrinter.cpp b/src/share/vm/c1/c1_InstructionPrinter.cpp index c15538116..7f87e1183 100644 --- a/src/share/vm/c1/c1_InstructionPrinter.cpp +++ b/src/share/vm/c1/c1_InstructionPrinter.cpp @@ -904,6 +904,12 @@ void InstructionPrinter::do_ProfileCall(ProfileCall* x) { output()->put(')'); } +void InstructionPrinter::do_ProfileReturnType(ProfileReturnType* x) { + output()->print("profile ret type "); + print_value(x->ret()); + output()->print(" %s.%s", x->method()->holder()->name()->as_utf8(), x->method()->name()->as_utf8()); + output()->put(')'); +} void InstructionPrinter::do_ProfileInvoke(ProfileInvoke* x) { output()->print("profile_invoke "); output()->print(" %s.%s", x->inlinee()->holder()->name()->as_utf8(), x->inlinee()->name()->as_utf8()); diff --git a/src/share/vm/c1/c1_InstructionPrinter.hpp b/src/share/vm/c1/c1_InstructionPrinter.hpp index 8c80b6c75..2ad20d3e6 100644 --- a/src/share/vm/c1/c1_InstructionPrinter.hpp +++ b/src/share/vm/c1/c1_InstructionPrinter.hpp @@ -132,6 +132,7 @@ class InstructionPrinter: public InstructionVisitor { virtual void do_UnsafePrefetchRead (UnsafePrefetchRead* x); virtual void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x); virtual void do_ProfileCall (ProfileCall* x); + virtual void do_ProfileReturnType (ProfileReturnType* x); virtual void do_ProfileInvoke (ProfileInvoke* x); virtual void do_RuntimeCall (RuntimeCall* x); virtual void do_MemBar (MemBar* x); diff --git a/src/share/vm/c1/c1_LIRGenerator.cpp b/src/share/vm/c1/c1_LIRGenerator.cpp index 3eedf1f31..40bccf8ef 100644 --- a/src/share/vm/c1/c1_LIRGenerator.cpp +++ b/src/share/vm/c1/c1_LIRGenerator.cpp @@ -3089,7 +3089,7 @@ void LIRGenerator::profile_arguments(ProfileCall* x) { Bytecodes::Code bc = x->method()->java_code_at_bci(bci); int start = 0; - int stop = args->number_of_arguments(); + int stop = data->is_CallTypeData() ? ((ciCallTypeData*)data)->number_of_arguments() : ((ciVirtualCallTypeData*)data)->number_of_arguments(); if (x->nb_profiled_args() < stop) { // if called through method handle invoke, some arguments may have been popped stop = x->nb_profiled_args(); @@ -3099,7 +3099,7 @@ void LIRGenerator::profile_arguments(ProfileCall* x) { bool has_receiver = x->inlined() && !x->callee()->is_static() && !Bytecodes::has_receiver(bc); ciSignatureStream sig_stream(sig, has_receiver ? x->callee()->holder() : NULL); for (int i = 0; i < stop; i++) { - int off = in_bytes(TypeStackSlotEntries::type_offset(i)) - in_bytes(TypeStackSlotEntries::args_data_offset()); + int off = in_bytes(TypeEntriesAtCall::argument_type_offset(i)) - in_bytes(TypeEntriesAtCall::args_data_offset()); ciKlass* exact = profile_arg_type(md, base_offset, off, args->type(i), x->profiled_arg_at(i+start), mdp, !x->arg_needs_null_check(i+start), sig_stream.next_klass()); @@ -3131,6 +3131,21 @@ void LIRGenerator::do_ProfileCall(ProfileCall* x) { __ profile_call(x->method(), x->bci_of_invoke(), x->callee(), mdo, recv, tmp, x->known_holder()); } +void LIRGenerator::do_ProfileReturnType(ProfileReturnType* x) { + int bci = x->bci_of_invoke(); + ciMethodData* md = x->method()->method_data_or_null(); + ciProfileData* data = md->bci_to_data(bci); + assert(data->is_CallTypeData() || data->is_VirtualCallTypeData(), "wrong profile data type"); + ciReturnTypeEntry* ret = data->is_CallTypeData() ? ((ciCallTypeData*)data)->ret() : ((ciVirtualCallTypeData*)data)->ret(); + LIR_Opr mdp = LIR_OprFact::illegalOpr; + ciKlass* exact = profile_arg_type(md, 0, md->byte_offset_of_slot(data, ret->type_offset()), + ret->type(), x->ret(), mdp, + !x->needs_null_check(), x->callee()->signature()->return_type()->as_klass()); + if (exact != NULL) { + md->set_return_type(bci, exact); + } +} + void LIRGenerator::do_ProfileInvoke(ProfileInvoke* x) { // We can safely ignore accessors here, since c2 will inline them anyway, // accessors are also always mature. diff --git a/src/share/vm/c1/c1_LIRGenerator.hpp b/src/share/vm/c1/c1_LIRGenerator.hpp index fce938a03..05399e590 100644 --- a/src/share/vm/c1/c1_LIRGenerator.hpp +++ b/src/share/vm/c1/c1_LIRGenerator.hpp @@ -536,6 +536,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { virtual void do_UnsafePrefetchRead (UnsafePrefetchRead* x); virtual void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x); virtual void do_ProfileCall (ProfileCall* x); + virtual void do_ProfileReturnType (ProfileReturnType* x); virtual void do_ProfileInvoke (ProfileInvoke* x); virtual void do_RuntimeCall (RuntimeCall* x); virtual void do_MemBar (MemBar* x); diff --git a/src/share/vm/c1/c1_Optimizer.cpp b/src/share/vm/c1/c1_Optimizer.cpp index 0be6099aa..90667b46f 100644 --- a/src/share/vm/c1/c1_Optimizer.cpp +++ b/src/share/vm/c1/c1_Optimizer.cpp @@ -531,6 +531,7 @@ public: void do_UnsafePrefetchRead (UnsafePrefetchRead* x); void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x); void do_ProfileCall (ProfileCall* x); + void do_ProfileReturnType (ProfileReturnType* x); void do_ProfileInvoke (ProfileInvoke* x); void do_RuntimeCall (RuntimeCall* x); void do_MemBar (MemBar* x); @@ -658,6 +659,7 @@ class NullCheckEliminator: public ValueVisitor { void handle_ExceptionObject (ExceptionObject* x); void handle_Phi (Phi* x); void handle_ProfileCall (ProfileCall* x); + void handle_ProfileReturnType (ProfileReturnType* x); }; @@ -718,6 +720,7 @@ void NullCheckVisitor::do_UnsafePrefetchRead (UnsafePrefetchRead* x) {} void NullCheckVisitor::do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) {} void NullCheckVisitor::do_ProfileCall (ProfileCall* x) { nce()->clear_last_explicit_null_check(); nce()->handle_ProfileCall(x); } +void NullCheckVisitor::do_ProfileReturnType (ProfileReturnType* x) { nce()->handle_ProfileReturnType(x); } void NullCheckVisitor::do_ProfileInvoke (ProfileInvoke* x) {} void NullCheckVisitor::do_RuntimeCall (RuntimeCall* x) {} void NullCheckVisitor::do_MemBar (MemBar* x) {} @@ -1142,6 +1145,10 @@ void NullCheckEliminator::handle_ProfileCall(ProfileCall* x) { } } +void NullCheckEliminator::handle_ProfileReturnType(ProfileReturnType* x) { + x->set_needs_null_check(!set_contains(x->ret())); +} + void Optimizer::eliminate_null_checks() { ResourceMark rm; diff --git a/src/share/vm/c1/c1_RangeCheckElimination.hpp b/src/share/vm/c1/c1_RangeCheckElimination.hpp index 1d7897bda..b022a8137 100644 --- a/src/share/vm/c1/c1_RangeCheckElimination.hpp +++ b/src/share/vm/c1/c1_RangeCheckElimination.hpp @@ -162,6 +162,7 @@ public: void do_UnsafePrefetchRead (UnsafePrefetchRead* x) { /* nothing to do */ }; void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) { /* nothing to do */ }; void do_ProfileCall (ProfileCall* x) { /* nothing to do */ }; + void do_ProfileReturnType (ProfileReturnType* x) { /* nothing to do */ }; void do_ProfileInvoke (ProfileInvoke* x) { /* nothing to do */ }; void do_RuntimeCall (RuntimeCall* x) { /* nothing to do */ }; void do_MemBar (MemBar* x) { /* nothing to do */ }; diff --git a/src/share/vm/c1/c1_ValueMap.hpp b/src/share/vm/c1/c1_ValueMap.hpp index 820d1909e..1404aa0b8 100644 --- a/src/share/vm/c1/c1_ValueMap.hpp +++ b/src/share/vm/c1/c1_ValueMap.hpp @@ -203,6 +203,7 @@ class ValueNumberingVisitor: public InstructionVisitor { void do_UnsafePrefetchRead (UnsafePrefetchRead* x) { /* nothing to do */ } void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) { /* nothing to do */ } void do_ProfileCall (ProfileCall* x) { /* nothing to do */ } + void do_ProfileReturnType (ProfileReturnType* x) { /* nothing to do */ } void do_ProfileInvoke (ProfileInvoke* x) { /* nothing to do */ }; void do_RuntimeCall (RuntimeCall* x) { /* nothing to do */ }; void do_MemBar (MemBar* x) { /* nothing to do */ }; |