aboutsummaryrefslogtreecommitdiff
path: root/src/share/vm/c1
diff options
context:
space:
mode:
Diffstat (limited to 'src/share/vm/c1')
-rw-r--r--src/share/vm/c1/c1_Compilation.cpp11
-rw-r--r--src/share/vm/c1/c1_Compilation.hpp2
-rw-r--r--src/share/vm/c1/c1_GraphBuilder.cpp67
-rw-r--r--src/share/vm/c1/c1_GraphBuilder.hpp5
-rw-r--r--src/share/vm/c1/c1_Instruction.cpp83
-rw-r--r--src/share/vm/c1/c1_Instruction.hpp101
-rw-r--r--src/share/vm/c1/c1_InstructionPrinter.cpp8
-rw-r--r--src/share/vm/c1/c1_LIR.cpp26
-rw-r--r--src/share/vm/c1/c1_LIR.hpp51
-rw-r--r--src/share/vm/c1/c1_LIRAssembler.hpp1
-rw-r--r--src/share/vm/c1/c1_LIRGenerator.cpp112
-rw-r--r--src/share/vm/c1/c1_LIRGenerator.hpp2
-rw-r--r--src/share/vm/c1/c1_Optimizer.cpp9
-rw-r--r--src/share/vm/c1/c1_RangeCheckElimination.hpp2
14 files changed, 373 insertions, 107 deletions
diff --git a/src/share/vm/c1/c1_Compilation.cpp b/src/share/vm/c1/c1_Compilation.cpp
index 1cdcab542..574fda194 100644
--- a/src/share/vm/c1/c1_Compilation.cpp
+++ b/src/share/vm/c1/c1_Compilation.cpp
@@ -601,6 +601,17 @@ void Compilation::bailout(const char* msg) {
}
}
+ciKlass* Compilation::cha_exact_type(ciType* type) {
+ if (type != NULL && type->is_loaded() && type->is_instance_klass()) {
+ ciInstanceKlass* ik = type->as_instance_klass();
+ assert(ik->exact_klass() == NULL, "no cha for final klass");
+ if (DeoptC1 && UseCHA && !(ik->has_subklass() || ik->is_interface())) {
+ dependency_recorder()->assert_leaf_type(ik);
+ return ik;
+ }
+ }
+ return NULL;
+}
void Compilation::print_timers() {
// tty->print_cr(" Native methods : %6.3f s, Average : %2.3f", CompileBroker::_t_native_compilation.seconds(), CompileBroker::_t_native_compilation.seconds() / CompileBroker::_total_native_compile_count);
diff --git a/src/share/vm/c1/c1_Compilation.hpp b/src/share/vm/c1/c1_Compilation.hpp
index f98ae97f3..7386dc414 100644
--- a/src/share/vm/c1/c1_Compilation.hpp
+++ b/src/share/vm/c1/c1_Compilation.hpp
@@ -246,6 +246,8 @@ class Compilation: public StackObj {
(RangeCheckElimination || UseLoopInvariantCodeMotion) &&
method()->method_data()->trap_count(Deoptimization::Reason_none) == 0;
}
+
+ ciKlass* cha_exact_type(ciType* type);
};
diff --git a/src/share/vm/c1/c1_GraphBuilder.cpp b/src/share/vm/c1/c1_GraphBuilder.cpp
index 03d0d75fa..f93a6e890 100644
--- a/src/share/vm/c1/c1_GraphBuilder.cpp
+++ b/src/share/vm/c1/c1_GraphBuilder.cpp
@@ -1658,6 +1658,42 @@ Dependencies* GraphBuilder::dependency_recorder() const {
return compilation()->dependency_recorder();
}
+// How many arguments do we want to profile?
+Values* GraphBuilder::args_list_for_profiling(int& start, bool may_have_receiver) {
+ int n = 0;
+ assert(start == 0, "should be initialized");
+ if (MethodData::profile_arguments()) {
+ ciProfileData* data = method()->method_data()->bci_to_data(bci());
+ if (data->is_CallTypeData() || data->is_VirtualCallTypeData()) {
+ n = data->is_CallTypeData() ? data->as_CallTypeData()->number_of_arguments() : data->as_VirtualCallTypeData()->number_of_arguments();
+ bool has_receiver = may_have_receiver && Bytecodes::has_receiver(method()->java_code_at_bci(bci()));
+ start = has_receiver ? 1 : 0;
+ }
+ }
+ if (n > 0) {
+ return new Values(n);
+ }
+ return NULL;
+}
+
+// Collect arguments that we want to profile in a list
+Values* GraphBuilder::collect_args_for_profiling(Values* args, bool may_have_receiver) {
+ int start = 0;
+ Values* obj_args = args_list_for_profiling(start, may_have_receiver);
+ if (obj_args == NULL) {
+ return NULL;
+ }
+ int s = obj_args->size();
+ for (int i = start, j = 0; j < s; i++) {
+ if (args->at(i)->type()->is_object_kind()) {
+ obj_args->push(args->at(i));
+ j++;
+ }
+ }
+ assert(s == obj_args->length(), "missed on arg?");
+ return obj_args;
+}
+
void GraphBuilder::invoke(Bytecodes::Code code) {
bool will_link;
@@ -1957,7 +1993,7 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
} else if (exact_target != NULL) {
target_klass = exact_target->holder();
}
- profile_call(target, recv, target_klass);
+ profile_call(target, recv, target_klass, collect_args_for_profiling(args, false), false);
}
}
@@ -3509,7 +3545,7 @@ bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) {
recv = args->at(0);
null_check(recv);
}
- profile_call(callee, recv, NULL);
+ profile_call(callee, recv, NULL, collect_args_for_profiling(args, true), true);
}
}
}
@@ -3763,7 +3799,28 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, Bytecode
compilation()->set_would_profile(true);
if (profile_calls()) {
- profile_call(callee, recv, holder_known ? callee->holder() : NULL);
+ int start = 0;
+ Values* obj_args = args_list_for_profiling(start, has_receiver);
+ if (obj_args != NULL) {
+ int s = obj_args->size();
+ // if called through method handle invoke, some arguments may have been popped
+ for (int i = args_base+start, j = 0; j < obj_args->size() && i < state()->stack_size(); ) {
+ Value v = state()->stack_at_inc(i);
+ if (v->type()->is_object_kind()) {
+ obj_args->push(v);
+ j++;
+ }
+ }
+#ifdef ASSERT
+ {
+ bool ignored_will_link;
+ ciSignature* declared_signature = NULL;
+ ciMethod* real_target = method()->get_method_at_bci(bci(), ignored_will_link, &declared_signature);
+ assert(s == obj_args->length() || real_target->is_method_handle_intrinsic(), "missed on arg?");
+ }
+#endif
+ }
+ profile_call(callee, recv, holder_known ? callee->holder() : NULL, obj_args, true);
}
}
@@ -4251,8 +4308,8 @@ void GraphBuilder::print_stats() {
}
#endif // PRODUCT
-void GraphBuilder::profile_call(ciMethod* callee, Value recv, ciKlass* known_holder) {
- append(new ProfileCall(method(), bci(), callee, recv, known_holder));
+void GraphBuilder::profile_call(ciMethod* callee, Value recv, ciKlass* known_holder, Values* obj_args, bool inlined) {
+ append(new ProfileCall(method(), bci(), callee, recv, known_holder, obj_args, inlined));
}
void GraphBuilder::profile_invocation(ciMethod* callee, ValueStack* state) {
diff --git a/src/share/vm/c1/c1_GraphBuilder.hpp b/src/share/vm/c1/c1_GraphBuilder.hpp
index ae5afd4e0..217da78bb 100644
--- a/src/share/vm/c1/c1_GraphBuilder.hpp
+++ b/src/share/vm/c1/c1_GraphBuilder.hpp
@@ -374,7 +374,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);
+ void profile_call(ciMethod* callee, Value recv, ciKlass* predicted_holder, Values* obj_args, bool inlined);
void profile_invocation(ciMethod* inlinee, ValueStack* state);
// Shortcuts to profiling control.
@@ -386,6 +386,9 @@ class GraphBuilder VALUE_OBJ_CLASS_SPEC {
bool profile_inlined_calls() { return _compilation->profile_inlined_calls(); }
bool profile_checkcasts() { return _compilation->profile_checkcasts(); }
+ Values* args_list_for_profiling(int& start, bool may_have_receiver);
+ Values* collect_args_for_profiling(Values* args, bool may_have_receiver);
+
public:
NOT_PRODUCT(void print_stats();)
diff --git a/src/share/vm/c1/c1_Instruction.cpp b/src/share/vm/c1/c1_Instruction.cpp
index a026b4cbe..e5829611e 100644
--- a/src/share/vm/c1/c1_Instruction.cpp
+++ b/src/share/vm/c1/c1_Instruction.cpp
@@ -104,6 +104,14 @@ void Instruction::state_values_do(ValueVisitor* f) {
}
}
+ciType* Instruction::exact_type() const {
+ ciType* t = declared_type();
+ if (t != NULL && t->is_klass()) {
+ return t->as_klass()->exact_klass();
+ }
+ return NULL;
+}
+
#ifndef PRODUCT
void Instruction::check_state(ValueStack* state) {
@@ -135,9 +143,7 @@ void Instruction::print(InstructionPrinter& ip) {
// perform constant and interval tests on index value
bool AccessIndexed::compute_needs_range_check() {
-
if (length()) {
-
Constant* clength = length()->as_Constant();
Constant* cindex = index()->as_Constant();
if (clength && cindex) {
@@ -157,34 +163,8 @@ bool AccessIndexed::compute_needs_range_check() {
}
-ciType* Local::exact_type() const {
- ciType* type = declared_type();
-
- // for primitive arrays, the declared type is the exact type
- if (type->is_type_array_klass()) {
- return type;
- } else if (type->is_instance_klass()) {
- ciInstanceKlass* ik = (ciInstanceKlass*)type;
- if (ik->is_loaded() && ik->is_final() && !ik->is_interface()) {
- return type;
- }
- } else if (type->is_obj_array_klass()) {
- ciObjArrayKlass* oak = (ciObjArrayKlass*)type;
- ciType* base = oak->base_element_type();
- if (base->is_instance_klass()) {
- ciInstanceKlass* ik = base->as_instance_klass();
- if (ik->is_loaded() && ik->is_final()) {
- return type;
- }
- } else if (base->is_primitive_type()) {
- return type;
- }
- }
- return NULL;
-}
-
ciType* Constant::exact_type() const {
- if (type()->is_object()) {
+ if (type()->is_object() && type()->as_ObjectType()->is_loaded()) {
return type()->as_ObjectType()->exact_type();
}
return NULL;
@@ -192,19 +172,18 @@ ciType* Constant::exact_type() const {
ciType* LoadIndexed::exact_type() const {
ciType* array_type = array()->exact_type();
- if (array_type == NULL) {
- return NULL;
- }
- assert(array_type->is_array_klass(), "what else?");
- ciArrayKlass* ak = (ciArrayKlass*)array_type;
+ if (array_type != NULL) {
+ assert(array_type->is_array_klass(), "what else?");
+ ciArrayKlass* ak = (ciArrayKlass*)array_type;
- if (ak->element_type()->is_instance_klass()) {
- ciInstanceKlass* ik = (ciInstanceKlass*)ak->element_type();
- if (ik->is_loaded() && ik->is_final()) {
- return ik;
+ if (ak->element_type()->is_instance_klass()) {
+ ciInstanceKlass* ik = (ciInstanceKlass*)ak->element_type();
+ if (ik->is_loaded() && ik->is_final()) {
+ return ik;
+ }
}
}
- return NULL;
+ return Instruction::exact_type();
}
@@ -224,22 +203,6 @@ ciType* LoadField::declared_type() const {
}
-ciType* LoadField::exact_type() const {
- ciType* type = declared_type();
- // for primitive arrays, the declared type is the exact type
- if (type->is_type_array_klass()) {
- return type;
- }
- if (type->is_instance_klass()) {
- ciInstanceKlass* ik = (ciInstanceKlass*)type;
- if (ik->is_loaded() && ik->is_final()) {
- return type;
- }
- }
- return NULL;
-}
-
-
ciType* NewTypeArray::exact_type() const {
return ciTypeArrayKlass::make(elt_type());
}
@@ -264,16 +227,6 @@ ciType* CheckCast::declared_type() const {
return klass();
}
-ciType* CheckCast::exact_type() const {
- if (klass()->is_instance_klass()) {
- ciInstanceKlass* ik = (ciInstanceKlass*)klass();
- if (ik->is_loaded() && ik->is_final()) {
- return ik;
- }
- }
- return NULL;
-}
-
// Implementation of ArithmeticOp
bool ArithmeticOp::is_commutative() const {
diff --git a/src/share/vm/c1/c1_Instruction.hpp b/src/share/vm/c1/c1_Instruction.hpp
index 9563b720a..466d814c6 100644
--- a/src/share/vm/c1/c1_Instruction.hpp
+++ b/src/share/vm/c1/c1_Instruction.hpp
@@ -322,6 +322,36 @@ class Instruction: public CompilationResourceObj {
_type = type;
}
+ // Helper class to keep track of which arguments need a null check
+ class ArgsNonNullState {
+ private:
+ int _nonnull_state; // mask identifying which args are nonnull
+ public:
+ ArgsNonNullState()
+ : _nonnull_state(AllBits) {}
+
+ // Does argument number i needs a null check?
+ bool arg_needs_null_check(int i) const {
+ // No data is kept for arguments starting at position 33 so
+ // conservatively assume that they need a null check.
+ if (i >= 0 && i < (int)sizeof(_nonnull_state) * BitsPerByte) {
+ return is_set_nth_bit(_nonnull_state, i);
+ }
+ return true;
+ }
+
+ // Set whether argument number i needs a null check or not
+ void set_arg_needs_null_check(int i, bool check) {
+ if (i >= 0 && i < (int)sizeof(_nonnull_state) * BitsPerByte) {
+ if (check) {
+ _nonnull_state |= nth_bit(i);
+ } else {
+ _nonnull_state &= ~(nth_bit(i));
+ }
+ }
+ }
+ };
+
public:
void* operator new(size_t size) throw() {
Compilation* c = Compilation::current();
@@ -566,7 +596,7 @@ class Instruction: public CompilationResourceObj {
virtual void other_values_do(ValueVisitor* f) { /* usually no other - override on demand */ }
void values_do(ValueVisitor* f) { input_values_do(f); state_values_do(f); other_values_do(f); }
- virtual ciType* exact_type() const { return NULL; }
+ virtual ciType* exact_type() const;
virtual ciType* declared_type() const { return NULL; }
// hashing
@@ -689,7 +719,6 @@ LEAF(Local, Instruction)
int java_index() const { return _java_index; }
virtual ciType* declared_type() const { return _declared_type; }
- virtual ciType* exact_type() const;
// generic
virtual void input_values_do(ValueVisitor* f) { /* no values */ }
@@ -806,7 +835,6 @@ LEAF(LoadField, AccessField)
{}
ciType* declared_type() const;
- ciType* exact_type() const;
// generic
HASHING2(LoadField, !needs_patching() && !field()->is_volatile(), obj()->subst(), offset()) // cannot be eliminated if needs patching or if volatile
@@ -1299,6 +1327,7 @@ BASE(NewArray, StateSplit)
virtual bool needs_exception_state() const { return false; }
+ ciType* exact_type() const { return NULL; }
ciType* declared_type() const;
// generic
@@ -1422,7 +1451,6 @@ LEAF(CheckCast, TypeCheck)
}
ciType* declared_type() const;
- ciType* exact_type() const;
};
@@ -1490,7 +1518,7 @@ LEAF(Intrinsic, StateSplit)
vmIntrinsics::ID _id;
Values* _args;
Value _recv;
- int _nonnull_state; // mask identifying which args are nonnull
+ ArgsNonNullState _nonnull_state;
public:
// preserves_state can be set to true for Intrinsics
@@ -1511,7 +1539,6 @@ LEAF(Intrinsic, StateSplit)
, _id(id)
, _args(args)
, _recv(NULL)
- , _nonnull_state(AllBits)
{
assert(args != NULL, "args must exist");
ASSERT_VALUES
@@ -1537,21 +1564,12 @@ LEAF(Intrinsic, StateSplit)
Value receiver() const { assert(has_receiver(), "must have receiver"); return _recv; }
bool preserves_state() const { return check_flag(PreservesStateFlag); }
- bool arg_needs_null_check(int i) {
- if (i >= 0 && i < (int)sizeof(_nonnull_state) * BitsPerByte) {
- return is_set_nth_bit(_nonnull_state, i);
- }
- return true;
+ bool arg_needs_null_check(int i) const {
+ return _nonnull_state.arg_needs_null_check(i);
}
void set_arg_needs_null_check(int i, bool check) {
- if (i >= 0 && i < (int)sizeof(_nonnull_state) * BitsPerByte) {
- if (check) {
- _nonnull_state |= nth_bit(i);
- } else {
- _nonnull_state &= ~(nth_bit(i));
- }
- }
+ _nonnull_state.set_arg_needs_null_check(i, check);
}
// generic
@@ -2450,34 +2468,55 @@ LEAF(UnsafePrefetchWrite, UnsafePrefetch)
LEAF(ProfileCall, Instruction)
private:
- ciMethod* _method;
- int _bci_of_invoke;
- ciMethod* _callee; // the method that is called at the given bci
- Value _recv;
- ciKlass* _known_holder;
+ ciMethod* _method;
+ int _bci_of_invoke;
+ ciMethod* _callee; // the method that is called at the given bci
+ Value _recv;
+ ciKlass* _known_holder;
+ Values* _obj_args; // arguments for type profiling
+ ArgsNonNullState _nonnull_state; // Do we know whether some arguments are never null?
+ bool _inlined; // Are we profiling a call that is inlined
public:
- ProfileCall(ciMethod* method, int bci, ciMethod* callee, Value recv, ciKlass* known_holder)
+ ProfileCall(ciMethod* method, int bci, ciMethod* callee, Value recv, ciKlass* known_holder, Values* obj_args, bool inlined)
: Instruction(voidType)
, _method(method)
, _bci_of_invoke(bci)
, _callee(callee)
, _recv(recv)
, _known_holder(known_holder)
+ , _obj_args(obj_args)
+ , _inlined(inlined)
{
// The ProfileCall has side-effects and must occur precisely where located
pin();
}
- ciMethod* method() { return _method; }
- int bci_of_invoke() { return _bci_of_invoke; }
- ciMethod* callee() { return _callee; }
- Value recv() { return _recv; }
- ciKlass* known_holder() { return _known_holder; }
+ ciMethod* method() const { return _method; }
+ int bci_of_invoke() const { return _bci_of_invoke; }
+ ciMethod* callee() const { return _callee; }
+ Value recv() const { return _recv; }
+ ciKlass* known_holder() const { return _known_holder; }
+ int nb_profiled_args() const { return _obj_args == NULL ? 0 : _obj_args->length(); }
+ Value profiled_arg_at(int i) const { return _obj_args->at(i); }
+ bool arg_needs_null_check(int i) const {
+ return _nonnull_state.arg_needs_null_check(i);
+ }
+ bool inlined() const { return _inlined; }
- virtual void input_values_do(ValueVisitor* f) { if (_recv != NULL) f->visit(&_recv); }
-};
+ void set_arg_needs_null_check(int i, bool check) {
+ _nonnull_state.set_arg_needs_null_check(i, check);
+ }
+ virtual void input_values_do(ValueVisitor* f) {
+ if (_recv != NULL) {
+ f->visit(&_recv);
+ }
+ for (int i = 0; i < nb_profiled_args(); i++) {
+ f->visit(_obj_args->adr_at(i));
+ }
+ }
+};
// Call some C runtime function that doesn't safepoint,
// optionally passing the current thread as the first argument.
diff --git a/src/share/vm/c1/c1_InstructionPrinter.cpp b/src/share/vm/c1/c1_InstructionPrinter.cpp
index cfca00ab2..c15538116 100644
--- a/src/share/vm/c1/c1_InstructionPrinter.cpp
+++ b/src/share/vm/c1/c1_InstructionPrinter.cpp
@@ -892,6 +892,14 @@ void InstructionPrinter::do_ProfileCall(ProfileCall* x) {
if (x->known_holder() != NULL) {
output()->print(", ");
print_klass(x->known_holder());
+ output()->print(" ");
+ }
+ for (int i = 0; i < x->nb_profiled_args(); i++) {
+ if (i > 0) output()->print(", ");
+ print_value(x->profiled_arg_at(i));
+ if (x->arg_needs_null_check(i)) {
+ output()->print(" [NC]");
+ }
}
output()->put(')');
}
diff --git a/src/share/vm/c1/c1_LIR.cpp b/src/share/vm/c1/c1_LIR.cpp
index cb0ceab90..f40d91333 100644
--- a/src/share/vm/c1/c1_LIR.cpp
+++ b/src/share/vm/c1/c1_LIR.cpp
@@ -1001,6 +1001,17 @@ void LIR_OpVisitState::visit(LIR_Op* op) {
assert(opProfileCall->_tmp1->is_valid(), "used"); do_temp(opProfileCall->_tmp1);
break;
}
+
+// LIR_OpProfileType:
+ case lir_profile_type: {
+ assert(op->as_OpProfileType() != NULL, "must be");
+ LIR_OpProfileType* opProfileType = (LIR_OpProfileType*)op;
+
+ do_input(opProfileType->_mdp); do_temp(opProfileType->_mdp);
+ do_input(opProfileType->_obj);
+ do_temp(opProfileType->_tmp);
+ break;
+ }
default:
ShouldNotReachHere();
}
@@ -1151,6 +1162,10 @@ void LIR_OpProfileCall::emit_code(LIR_Assembler* masm) {
masm->emit_profile_call(this);
}
+void LIR_OpProfileType::emit_code(LIR_Assembler* masm) {
+ masm->emit_profile_type(this);
+}
+
// LIR_List
LIR_List::LIR_List(Compilation* compilation, BlockBegin* block)
: _operations(8)
@@ -1803,6 +1818,8 @@ const char * LIR_Op::name() const {
case lir_cas_int: s = "cas_int"; break;
// LIR_OpProfileCall
case lir_profile_call: s = "profile_call"; break;
+ // LIR_OpProfileType
+ case lir_profile_type: s = "profile_type"; break;
// LIR_OpAssert
#ifdef ASSERT
case lir_assert: s = "assert"; break;
@@ -2086,6 +2103,15 @@ void LIR_OpProfileCall::print_instr(outputStream* out) const {
tmp1()->print(out); out->print(" ");
}
+// LIR_OpProfileType
+void LIR_OpProfileType::print_instr(outputStream* out) const {
+ out->print("exact = "); exact_klass()->print_name_on(out);
+ out->print("current = "); ciTypeEntries::print_ciklass(out, current_klass());
+ mdp()->print(out); out->print(" ");
+ obj()->print(out); out->print(" ");
+ tmp()->print(out); out->print(" ");
+}
+
#endif // PRODUCT
// Implementation of LIR_InsertionBuffer
diff --git a/src/share/vm/c1/c1_LIR.hpp b/src/share/vm/c1/c1_LIR.hpp
index d0dca72f3..a339af509 100644
--- a/src/share/vm/c1/c1_LIR.hpp
+++ b/src/share/vm/c1/c1_LIR.hpp
@@ -882,6 +882,7 @@ class LIR_OpLock;
class LIR_OpTypeCheck;
class LIR_OpCompareAndSwap;
class LIR_OpProfileCall;
+class LIR_OpProfileType;
#ifdef ASSERT
class LIR_OpAssert;
#endif
@@ -1005,6 +1006,7 @@ enum LIR_Code {
, end_opCompareAndSwap
, begin_opMDOProfile
, lir_profile_call
+ , lir_profile_type
, end_opMDOProfile
, begin_opAssert
, lir_assert
@@ -1145,6 +1147,7 @@ class LIR_Op: public CompilationResourceObj {
virtual LIR_OpTypeCheck* as_OpTypeCheck() { return NULL; }
virtual LIR_OpCompareAndSwap* as_OpCompareAndSwap() { return NULL; }
virtual LIR_OpProfileCall* as_OpProfileCall() { return NULL; }
+ virtual LIR_OpProfileType* as_OpProfileType() { return NULL; }
#ifdef ASSERT
virtual LIR_OpAssert* as_OpAssert() { return NULL; }
#endif
@@ -1925,8 +1928,8 @@ class LIR_OpProfileCall : public LIR_Op {
public:
// Destroys recv
- LIR_OpProfileCall(LIR_Code code, ciMethod* profiled_method, int profiled_bci, ciMethod* profiled_callee, LIR_Opr mdo, LIR_Opr recv, LIR_Opr t1, ciKlass* known_holder)
- : LIR_Op(code, LIR_OprFact::illegalOpr, NULL) // no result, no info
+ LIR_OpProfileCall(ciMethod* profiled_method, int profiled_bci, ciMethod* profiled_callee, LIR_Opr mdo, LIR_Opr recv, LIR_Opr t1, ciKlass* known_holder)
+ : LIR_Op(lir_profile_call, LIR_OprFact::illegalOpr, NULL) // no result, no info
, _profiled_method(profiled_method)
, _profiled_bci(profiled_bci)
, _profiled_callee(profiled_callee)
@@ -1948,6 +1951,45 @@ class LIR_OpProfileCall : public LIR_Op {
virtual void print_instr(outputStream* out) const PRODUCT_RETURN;
};
+// LIR_OpProfileType
+class LIR_OpProfileType : public LIR_Op {
+ friend class LIR_OpVisitState;
+
+ private:
+ LIR_Opr _mdp;
+ LIR_Opr _obj;
+ LIR_Opr _tmp;
+ ciKlass* _exact_klass; // non NULL if we know the klass statically (no need to load it from _obj)
+ intptr_t _current_klass; // what the profiling currently reports
+ bool _not_null; // true if we know statically that _obj cannot be null
+ bool _no_conflict; // true if we're profling parameters, _exact_klass is not NULL and we know
+ // _exact_klass it the only possible type for this parameter in any context.
+
+ public:
+ // Destroys recv
+ LIR_OpProfileType(LIR_Opr mdp, LIR_Opr obj, ciKlass* exact_klass, intptr_t current_klass, LIR_Opr tmp, bool not_null, bool no_conflict)
+ : LIR_Op(lir_profile_type, LIR_OprFact::illegalOpr, NULL) // no result, no info
+ , _mdp(mdp)
+ , _obj(obj)
+ , _exact_klass(exact_klass)
+ , _current_klass(current_klass)
+ , _tmp(tmp)
+ , _not_null(not_null)
+ , _no_conflict(no_conflict) { }
+
+ LIR_Opr mdp() const { return _mdp; }
+ LIR_Opr obj() const { return _obj; }
+ LIR_Opr tmp() const { return _tmp; }
+ ciKlass* exact_klass() const { return _exact_klass; }
+ intptr_t current_klass() const { return _current_klass; }
+ bool not_null() const { return _not_null; }
+ bool no_conflict() const { return _no_conflict; }
+
+ virtual void emit_code(LIR_Assembler* masm);
+ virtual LIR_OpProfileType* as_OpProfileType() { return this; }
+ virtual void print_instr(outputStream* out) const PRODUCT_RETURN;
+};
+
class LIR_InsertionBuffer;
//--------------------------------LIR_List---------------------------------------------------
@@ -2247,7 +2289,10 @@ class LIR_List: public CompilationResourceObj {
ciMethod* profiled_method, int profiled_bci);
// MethodData* profiling
void profile_call(ciMethod* method, int bci, ciMethod* callee, LIR_Opr mdo, LIR_Opr recv, LIR_Opr t1, ciKlass* cha_klass) {
- append(new LIR_OpProfileCall(lir_profile_call, method, bci, callee, mdo, recv, t1, cha_klass));
+ append(new LIR_OpProfileCall(method, bci, callee, mdo, recv, t1, cha_klass));
+ }
+ void profile_type(LIR_Address* mdp, LIR_Opr obj, ciKlass* exact_klass, intptr_t current_klass, LIR_Opr tmp, bool not_null, bool no_conflict) {
+ append(new LIR_OpProfileType(LIR_OprFact::address(mdp), obj, exact_klass, current_klass, tmp, not_null, no_conflict));
}
void xadd(LIR_Opr src, LIR_Opr add, LIR_Opr res, LIR_Opr tmp) { append(new LIR_Op2(lir_xadd, src, add, res, tmp)); }
diff --git a/src/share/vm/c1/c1_LIRAssembler.hpp b/src/share/vm/c1/c1_LIRAssembler.hpp
index 57df2725e..68f249a2a 100644
--- a/src/share/vm/c1/c1_LIRAssembler.hpp
+++ b/src/share/vm/c1/c1_LIRAssembler.hpp
@@ -208,6 +208,7 @@ class LIR_Assembler: public CompilationResourceObj {
void emit_call(LIR_OpJavaCall* op);
void emit_rtcall(LIR_OpRTCall* op);
void emit_profile_call(LIR_OpProfileCall* op);
+ void emit_profile_type(LIR_OpProfileType* op);
void emit_delay(LIR_OpDelay* op);
void arith_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest, CodeEmitInfo* info, bool pop_fpu_stack);
diff --git a/src/share/vm/c1/c1_LIRGenerator.cpp b/src/share/vm/c1/c1_LIRGenerator.cpp
index f71470e5e..3eedf1f31 100644
--- a/src/share/vm/c1/c1_LIRGenerator.cpp
+++ b/src/share/vm/c1/c1_LIRGenerator.cpp
@@ -2571,6 +2571,78 @@ void LIRGenerator::do_Goto(Goto* x) {
}
+ciKlass* LIRGenerator::profile_arg_type(ciMethodData* md, int md_base_offset, int md_offset, intptr_t profiled_k, Value arg, LIR_Opr& mdp, bool not_null, ciKlass* signature_k) {
+ ciKlass* result = NULL;
+ bool do_null = !not_null && !TypeEntries::was_null_seen(profiled_k);
+ bool do_update = !TypeEntries::is_type_unknown(profiled_k);
+ // known not to be null or null bit already set and already set to
+ // unknown: nothing we can do to improve profiling
+ if (!do_null && !do_update) {
+ return result;
+ }
+
+ ciKlass* exact_klass = NULL;
+ Compilation* comp = Compilation::current();
+ if (do_update) {
+ // try to find exact type, using CHA if possible, so that loading
+ // the klass from the object can be avoided
+ ciType* type = arg->exact_type();
+ if (type == NULL) {
+ type = arg->declared_type();
+ type = comp->cha_exact_type(type);
+ }
+ assert(type == NULL || type->is_klass(), "type should be class");
+ exact_klass = (type != NULL && type->is_loaded()) ? (ciKlass*)type : NULL;
+
+ do_update = exact_klass == NULL || ciTypeEntries::valid_ciklass(profiled_k) != exact_klass;
+ }
+
+ if (!do_null && !do_update) {
+ return result;
+ }
+
+ ciKlass* exact_signature_k = NULL;
+ if (do_update) {
+ // Is the type from the signature exact (the only one possible)?
+ exact_signature_k = signature_k->exact_klass();
+ if (exact_signature_k == NULL) {
+ exact_signature_k = comp->cha_exact_type(signature_k);
+ } else {
+ result = exact_signature_k;
+ do_update = false;
+ // Known statically. No need to emit any code: prevent
+ // LIR_Assembler::emit_profile_type() from emitting useless code
+ profiled_k = ciTypeEntries::with_status(result, profiled_k);
+ }
+ if (exact_signature_k != NULL && exact_klass != exact_signature_k) {
+ assert(exact_klass == NULL, "arg and signature disagree?");
+ // sometimes the type of the signature is better than the best type
+ // the compiler has
+ exact_klass = exact_signature_k;
+ do_update = exact_klass == NULL || ciTypeEntries::valid_ciklass(profiled_k) != exact_klass;
+ }
+ }
+
+ if (!do_null && !do_update) {
+ return result;
+ }
+
+ if (mdp == LIR_OprFact::illegalOpr) {
+ mdp = new_register(T_METADATA);
+ __ metadata2reg(md->constant_encoding(), mdp);
+ if (md_base_offset != 0) {
+ LIR_Address* base_type_address = new LIR_Address(mdp, md_base_offset, T_ADDRESS);
+ mdp = new_pointer_register();
+ __ leal(LIR_OprFact::address(base_type_address), mdp);
+ }
+ }
+ LIRItem value(arg, this);
+ value.load_item();
+ __ profile_type(new LIR_Address(mdp, md_offset, T_METADATA),
+ value.result(), exact_klass, profiled_k, new_pointer_register(), not_null, exact_signature_k != NULL);
+ return result;
+}
+
void LIRGenerator::do_Base(Base* x) {
__ std_entry(LIR_OprFact::illegalOpr);
// Emit moves from physical registers / stack slots to virtual registers
@@ -3004,12 +3076,52 @@ void LIRGenerator::do_Intrinsic(Intrinsic* x) {
}
}
+void LIRGenerator::profile_arguments(ProfileCall* x) {
+ if (MethodData::profile_arguments()) {
+ int bci = x->bci_of_invoke();
+ ciMethodData* md = x->method()->method_data_or_null();
+ ciProfileData* data = md->bci_to_data(bci);
+ if (data->is_CallTypeData() || data->is_VirtualCallTypeData()) {
+ ByteSize extra = data->is_CallTypeData() ? CallTypeData::args_data_offset() : VirtualCallTypeData::args_data_offset();
+ int base_offset = md->byte_offset_of_slot(data, extra);
+ LIR_Opr mdp = LIR_OprFact::illegalOpr;
+ ciTypeStackSlotEntries* args = data->is_CallTypeData() ? ((ciCallTypeData*)data)->args() : ((ciVirtualCallTypeData*)data)->args();
+
+ Bytecodes::Code bc = x->method()->java_code_at_bci(bci);
+ int start = 0;
+ int stop = args->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();
+ }
+ ciSignature* sig = x->callee()->signature();
+ // method handle call to virtual method
+ 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());
+ 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());
+ if (exact != NULL) {
+ md->set_argument_type(bci, i, exact);
+ }
+ }
+ }
+ }
+}
+
void LIRGenerator::do_ProfileCall(ProfileCall* x) {
// Need recv in a temporary register so it interferes with the other temporaries
LIR_Opr recv = LIR_OprFact::illegalOpr;
LIR_Opr mdo = new_register(T_OBJECT);
// tmp is used to hold the counters on SPARC
LIR_Opr tmp = new_pointer_register();
+
+ if (x->nb_profiled_args() > 0) {
+ profile_arguments(x);
+ }
+
if (x->recv() != NULL) {
LIRItem value(x->recv(), this);
value.load_item();
diff --git a/src/share/vm/c1/c1_LIRGenerator.hpp b/src/share/vm/c1/c1_LIRGenerator.hpp
index 0a0292073..fce938a03 100644
--- a/src/share/vm/c1/c1_LIRGenerator.hpp
+++ b/src/share/vm/c1/c1_LIRGenerator.hpp
@@ -434,6 +434,8 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
void do_ThreadIDIntrinsic(Intrinsic* x);
void do_ClassIDIntrinsic(Intrinsic* x);
#endif
+ ciKlass* profile_arg_type(ciMethodData* md, int md_first_offset, int md_offset, intptr_t profiled_k, Value arg, LIR_Opr& mdp, bool not_null, ciKlass* signature_k);
+ void profile_arguments(ProfileCall* x);
public:
Compilation* compilation() const { return _compilation; }
diff --git a/src/share/vm/c1/c1_Optimizer.cpp b/src/share/vm/c1/c1_Optimizer.cpp
index 90dc27972..0be6099aa 100644
--- a/src/share/vm/c1/c1_Optimizer.cpp
+++ b/src/share/vm/c1/c1_Optimizer.cpp
@@ -657,6 +657,7 @@ class NullCheckEliminator: public ValueVisitor {
void handle_Intrinsic (Intrinsic* x);
void handle_ExceptionObject (ExceptionObject* x);
void handle_Phi (Phi* x);
+ void handle_ProfileCall (ProfileCall* x);
};
@@ -715,7 +716,8 @@ void NullCheckVisitor::do_UnsafePutObject(UnsafePutObject* x) {}
void NullCheckVisitor::do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) {}
void NullCheckVisitor::do_UnsafePrefetchRead (UnsafePrefetchRead* x) {}
void NullCheckVisitor::do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) {}
-void NullCheckVisitor::do_ProfileCall (ProfileCall* x) { nce()->clear_last_explicit_null_check(); }
+void NullCheckVisitor::do_ProfileCall (ProfileCall* x) { nce()->clear_last_explicit_null_check();
+ nce()->handle_ProfileCall(x); }
void NullCheckVisitor::do_ProfileInvoke (ProfileInvoke* x) {}
void NullCheckVisitor::do_RuntimeCall (RuntimeCall* x) {}
void NullCheckVisitor::do_MemBar (MemBar* x) {}
@@ -1134,6 +1136,11 @@ void NullCheckEliminator::handle_Phi(Phi* x) {
}
}
+void NullCheckEliminator::handle_ProfileCall(ProfileCall* x) {
+ for (int i = 0; i < x->nb_profiled_args(); i++) {
+ x->set_arg_needs_null_check(i, !set_contains(x->profiled_arg_at(i)));
+ }
+}
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 ae1a25568..1d7897bda 100644
--- a/src/share/vm/c1/c1_RangeCheckElimination.hpp
+++ b/src/share/vm/c1/c1_RangeCheckElimination.hpp
@@ -162,7 +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_ProfileInvoke (ProfileInvoke* 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 */ };
void do_RangeCheckPredicate(RangeCheckPredicate* x) { /* nothing to do */ };