aboutsummaryrefslogtreecommitdiff
path: root/src/share/vm/c1
diff options
context:
space:
mode:
authorroland <none@none>2013-10-12 12:12:59 +0200
committerroland <none@none>2013-10-12 12:12:59 +0200
commitc1531fdc640bc7ee40de4967ab4f7e466a6f17ad (patch)
tree11f553c8e4e3b4fd73fdc5debc03e460a639272c /src/share/vm/c1
parent900779844ce827b54475e06ca6167dc0a66dcabc (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.cpp1
-rw-r--r--src/share/vm/c1/c1_Canonicalizer.hpp1
-rw-r--r--src/share/vm/c1/c1_GraphBuilder.cpp35
-rw-r--r--src/share/vm/c1/c1_GraphBuilder.hpp1
-rw-r--r--src/share/vm/c1/c1_Instruction.hpp34
-rw-r--r--src/share/vm/c1/c1_InstructionPrinter.cpp6
-rw-r--r--src/share/vm/c1/c1_InstructionPrinter.hpp1
-rw-r--r--src/share/vm/c1/c1_LIRGenerator.cpp19
-rw-r--r--src/share/vm/c1/c1_LIRGenerator.hpp1
-rw-r--r--src/share/vm/c1/c1_Optimizer.cpp7
-rw-r--r--src/share/vm/c1/c1_RangeCheckElimination.hpp1
-rw-r--r--src/share/vm/c1/c1_ValueMap.hpp1
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 */ };