--- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Mon Jul 23 13:04:59 2012 -0700
+++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Tue Jul 24 10:51:00 2012 -0700
@@ -31,7 +31,7 @@
#include "ci/ciCallSite.hpp"
#include "ci/ciField.hpp"
#include "ci/ciKlass.hpp"
-#include "ci/ciMethodHandle.hpp"
+#include "ci/ciMemberName.hpp"
#include "compiler/compileBroker.hpp"
#include "interpreter/bytecode.hpp"
#include "runtime/sharedRuntime.hpp"
@@ -914,11 +914,11 @@
void GraphBuilder::store_local(ValueType* type, int index) {
Value x = pop(type);
- store_local(state(), x, type, index);
+ store_local(state(), x, index);
}
-void GraphBuilder::store_local(ValueStack* state, Value x, ValueType* type, int index) {
+void GraphBuilder::store_local(ValueStack* state, Value x, int index) {
if (parsing_jsr()) {
// We need to do additional tracking of the location of the return
// address for jsrs since we don't handle arbitrary jsr/ret
@@ -1535,7 +1535,7 @@
case T_ARRAY:
case T_OBJECT:
if (field_val.as_object()->should_be_constant()) {
- constant = new Constant(as_ValueType(field_val));
+ constant = new Constant(as_ValueType(field_val));
}
break;
@@ -1562,12 +1562,51 @@
append(new StoreField(append(obj), offset, field, val, true, state_before, needs_patching));
}
break;
- case Bytecodes::_getfield :
- {
+ case Bytecodes::_getfield: {
+ // Check for compile-time constants, i.e., trusted final non-static fields.
+ Instruction* constant = NULL;
+ obj = apop();
+ ObjectType* obj_type = obj->type()->as_ObjectType();
+ if (obj_type->is_constant() && !PatchALot) {
+ ciObject* const_oop = obj_type->constant_value();
+ if (field->is_constant()) {
+ ciConstant field_val = field->constant_value_of(const_oop);
+ BasicType field_type = field_val.basic_type();
+ switch (field_type) {
+ case T_ARRAY:
+ case T_OBJECT:
+ if (field_val.as_object()->should_be_constant()) {
+ constant = new Constant(as_ValueType(field_val));
+ }
+ break;
+ default:
+ constant = new Constant(as_ValueType(field_val));
+ }
+ } else {
+ // For constant CallSites treat the target field as a compile time constant.
+ if (const_oop->is_call_site()) {
+ ciCallSite* call_site = const_oop->as_call_site();
+ if (field->is_call_site_target()) {
+ ciMethodHandle* target = call_site->get_target();
+ if (target != NULL) { // just in case
+ ciConstant field_val(T_OBJECT, target);
+ constant = new Constant(as_ValueType(field_val));
+ // Add a dependence for invalidation of the optimization.
+ if (!call_site->is_constant_call_site()) {
+ dependency_recorder()->assert_call_site_target_value(call_site, target);
+ }
+ }
+ }
+ }
+ }
+ }
+ if (constant != NULL) {
+ push(type, append(constant));
+ } else {
if (state_before == NULL) {
state_before = copy_state_for_exception();
}
- LoadField* load = new LoadField(apop(), offset, field, false, state_before, needs_patching);
+ LoadField* load = new LoadField(obj, offset, field, false, state_before, needs_patching);
Value replacement = !needs_patching ? _memory->load(load) : load;
if (replacement != load) {
assert(replacement->is_linked() || !replacement->can_be_linked(), "should already by linked");
@@ -1575,22 +1614,23 @@
} else {
push(type, append(load));
}
- break;
- }
-
- case Bytecodes::_putfield :
- { Value val = pop(type);
- if (state_before == NULL) {
- state_before = copy_state_for_exception();
- }
- StoreField* store = new StoreField(apop(), offset, field, val, false, state_before, needs_patching);
- if (!needs_patching) store = _memory->store(store);
- if (store != NULL) {
- append(store);
- }
}
break;
- default :
+ }
+ case Bytecodes::_putfield: {
+ Value val = pop(type);
+ obj = apop();
+ if (state_before == NULL) {
+ state_before = copy_state_for_exception();
+ }
+ StoreField* store = new StoreField(obj, offset, field, val, false, state_before, needs_patching);
+ if (!needs_patching) store = _memory->store(store);
+ if (store != NULL) {
+ append(store);
+ }
+ break;
+ }
+ default:
ShouldNotReachHere();
break;
}
@@ -1604,38 +1644,73 @@
void GraphBuilder::invoke(Bytecodes::Code code) {
+ const bool has_receiver =
+ code == Bytecodes::_invokespecial ||
+ code == Bytecodes::_invokevirtual ||
+ code == Bytecodes::_invokeinterface;
+ const bool is_invokedynamic = (code == Bytecodes::_invokedynamic);
+
bool will_link;
- ciMethod* target = stream()->get_method(will_link);
+ ciMethod* target = stream()->get_method(will_link);
+ ciKlass* holder = stream()->get_declared_method_holder();
+ const Bytecodes::Code bc_raw = stream()->cur_bc_raw();
+
+ // FIXME bail out for now
+ if ((bc_raw == Bytecodes::_invokehandle || is_invokedynamic) && !will_link) {
+ BAILOUT("unlinked call site (FIXME needs patching or recompile support)");
+ }
+
// we have to make sure the argument size (incl. the receiver)
// is correct for compilation (the call would fail later during
// linkage anyway) - was bug (gri 7/28/99)
- if (target->is_loaded() && target->is_static() != (code == Bytecodes::_invokestatic)) BAILOUT("will cause link error");
+ {
+ // Use raw to get rewritten bytecode.
+ const bool is_invokestatic = bc_raw == Bytecodes::_invokestatic;
+ const bool allow_static =
+ is_invokestatic ||
+ bc_raw == Bytecodes::_invokehandle ||
+ bc_raw == Bytecodes::_invokedynamic;
+ if (target->is_loaded()) {
+ if (( target->is_static() && !allow_static) ||
+ (!target->is_static() && is_invokestatic)) {
+ BAILOUT("will cause link error");
+ }
+ }
+ }
ciInstanceKlass* klass = target->holder();
// check if CHA possible: if so, change the code to invoke_special
ciInstanceKlass* calling_klass = method()->holder();
- ciKlass* holder = stream()->get_declared_method_holder();
ciInstanceKlass* callee_holder = ciEnv::get_instance_klass_for_declared_method_holder(holder);
ciInstanceKlass* actual_recv = callee_holder;
- // some methods are obviously bindable without any type checks so
- // convert them directly to an invokespecial.
- if (target->is_loaded() && !target->is_abstract() &&
- target->can_be_statically_bound() && code == Bytecodes::_invokevirtual) {
- code = Bytecodes::_invokespecial;
+ // Some methods are obviously bindable without any type checks so
+ // convert them directly to an invokespecial or invokestatic.
+ if (target->is_loaded() && !target->is_abstract() && target->can_be_statically_bound()) {
+ switch (bc_raw) {
+ case Bytecodes::_invokevirtual: code = Bytecodes::_invokespecial; break;
+ case Bytecodes::_invokehandle: code = Bytecodes::_invokestatic; break;
+ }
}
- bool is_invokedynamic = code == Bytecodes::_invokedynamic;
+ // Push appendix argument (MethodType, CallSite, etc.), if one.
+ if (stream()->has_appendix()) {
+ ciObject* appendix = stream()->get_appendix();
+ Value arg = append(new Constant(new ObjectConstant(appendix)));
+ apush(arg);
+ }
// NEEDS_CLEANUP
- // I've added the target-is_loaded() test below but I don't really understand
+ // I've added the target->is_loaded() test below but I don't really understand
// how klass->is_loaded() can be true and yet target->is_loaded() is false.
// this happened while running the JCK invokevirtual tests under doit. TKR
ciMethod* cha_monomorphic_target = NULL;
ciMethod* exact_target = NULL;
Value better_receiver = NULL;
if (UseCHA && DeoptC1 && klass->is_loaded() && target->is_loaded() &&
- !target->is_method_handle_invoke()) {
+ !(// %%% FIXME: Are both of these relevant?
+ target->is_method_handle_intrinsic() ||
+ target->is_compiled_lambda_form())) {
Value receiver = NULL;
ciInstanceKlass* receiver_klass = NULL;
bool type_is_exact = false;
@@ -1761,23 +1836,15 @@
code == Bytecodes::_invokedynamic) {
ciMethod* inline_target = (cha_monomorphic_target != NULL) ? cha_monomorphic_target : target;
bool success = false;
- if (target->is_method_handle_invoke()) {
+ if (target->is_method_handle_intrinsic()) {
// method handle invokes
- success = !is_invokedynamic ? for_method_handle_inline(target) : for_invokedynamic_inline(target);
- }
- if (!success) {
+ success = for_method_handle_inline(target);
+ } else {
// static binding => check if callee is ok
- success = try_inline(inline_target, (cha_monomorphic_target != NULL) || (exact_target != NULL), better_receiver);
+ success = try_inline(inline_target, (cha_monomorphic_target != NULL) || (exact_target != NULL), code, better_receiver);
}
CHECK_BAILOUT();
-#ifndef PRODUCT
- // printing
- if (PrintInlining && !success) {
- // if it was successfully inlined, then it was already printed.
- print_inline_result(inline_target, success);
- }
-#endif
clear_inline_bailout();
if (success) {
// Register dependence if JVMTI has either breakpoint
@@ -1788,8 +1855,13 @@
}
return;
}
+ } else {
+ print_inlining(target, "no static binding", /*success*/ false);
}
+ } else {
+ print_inlining(target, "not inlineable", /*success*/ false);
}
+
// If we attempted an inline which did not succeed because of a
// bailout during construction of the callee graph, the entire
// compilation has to be aborted. This is fairly rare and currently
@@ -1803,10 +1875,6 @@
// inlining not successful => standard invoke
bool is_loaded = target->is_loaded();
- bool has_receiver =
- code == Bytecodes::_invokespecial ||
- code == Bytecodes::_invokevirtual ||
- code == Bytecodes::_invokeinterface;
ValueType* result_type = as_ValueType(target->return_type());
// We require the debug info to be the "state before" because
@@ -1855,7 +1923,7 @@
} else if (exact_target != NULL) {
target_klass = exact_target->holder();
}
- profile_call(recv, target_klass);
+ profile_call(target, recv, target_klass);
}
}
@@ -3097,30 +3165,61 @@
}
-bool GraphBuilder::try_inline(ciMethod* callee, bool holder_known, Value receiver) {
- // Clear out any existing inline bailout condition
+bool GraphBuilder::try_inline(ciMethod* callee, bool holder_known, Bytecodes::Code bc, Value receiver) {
+ const char* msg = NULL;
+
+ // clear out any existing inline bailout condition
clear_inline_bailout();
- if (callee->should_exclude()) {
- // callee is excluded
- INLINE_BAILOUT("excluded by CompilerOracle")
- } else if (callee->should_not_inline()) {
- // callee is excluded
- INLINE_BAILOUT("disallowed by CompilerOracle")
- } else if (!callee->can_be_compiled()) {
- // callee is not compilable (prob. has breakpoints)
- INLINE_BAILOUT("not compilable (disabled)")
- } else if (callee->intrinsic_id() != vmIntrinsics::_none && try_inline_intrinsics(callee)) {
- // intrinsics can be native or not
+ // exclude methods we don't want to inline
+ msg = should_not_inline(callee);
+ if (msg != NULL) {
+ print_inlining(callee, msg, /*success*/ false);
+ return false;
+ }
+
+ // handle intrinsics
+ if (callee->intrinsic_id() != vmIntrinsics::_none) {
+ if (try_inline_intrinsics(callee)) {
+ print_inlining(callee, "intrinsic");
+ return true;
+ }
+ // try normal inlining
+ }
+
+ // certain methods cannot be parsed at all
+ msg = check_can_parse(callee);
+ if (msg != NULL) {
+ print_inlining(callee, msg, /*success*/ false);
+ return false;
+ }
+
+ // If bytecode not set use the current one.
+ if (bc == Bytecodes::_illegal) {
+ bc = code();
+ }
+ if (try_inline_full(callee, holder_known, bc, receiver))
return true;
- } else if (callee->is_native()) {
- // non-intrinsic natives cannot be inlined
- INLINE_BAILOUT("non-intrinsic native")
- } else if (callee->is_abstract()) {
- INLINE_BAILOUT("abstract")
- } else {
- return try_inline_full(callee, holder_known, NULL, receiver);
- }
+ print_inlining(callee, _inline_bailout_msg, /*success*/ false);
+ return false;
+}
+
+
+const char* GraphBuilder::check_can_parse(ciMethod* callee) const {
+ // Certain methods cannot be parsed at all:
+ if ( callee->is_native()) return "native method";
+ if ( callee->is_abstract()) return "abstract method";
+ if (!callee->can_be_compiled()) return "not compilable (disabled)";
+ return NULL;
+}
+
+
+// negative filter: should callee NOT be inlined? returns NULL, ok to inline, or rejection msg
+const char* GraphBuilder::should_not_inline(ciMethod* callee) const {
+ if ( callee->should_exclude()) return "excluded by CompilerOracle";
+ if ( callee->should_not_inline()) return "disallowed by CompilerOracle";
+ if ( callee->dont_inline()) return "don't inline by annotation";
+ return NULL;
}
@@ -3304,7 +3403,7 @@
recv = args->at(0);
null_check(recv);
}
- profile_call(recv, NULL);
+ profile_call(callee, recv, NULL);
}
}
}
@@ -3315,13 +3414,6 @@
Value value = append_split(result);
if (result_type != voidType) push(result_type, value);
-#ifndef PRODUCT
- // printing
- if (PrintInlining) {
- print_inline_result(callee, true);
- }
-#endif
-
// done
return true;
}
@@ -3477,7 +3569,7 @@
}
-bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, BlockBegin* cont_block, Value receiver) {
+bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, Bytecodes::Code bc, Value receiver) {
assert(!callee->is_native(), "callee must not be native");
if (CompilationPolicy::policy()->should_not_inline(compilation()->env(), callee)) {
INLINE_BAILOUT("inlining prohibited by policy");
@@ -3508,10 +3600,10 @@
if (callee->force_inline() || callee->should_inline()) {
// ignore heuristic controls on inlining
if (callee->force_inline())
- CompileTask::print_inlining(callee, scope()->level(), bci(), "force inline by annotation");
+ print_inlining(callee, "force inline by annotation");
} else {
- if (inline_level() > MaxInlineLevel ) INLINE_BAILOUT("too-deep inlining");
- if (recursive_inline_level(callee) > MaxRecursiveInlineLevel) INLINE_BAILOUT("too-deep recursive inlining");
+ if (inline_level() > MaxInlineLevel ) INLINE_BAILOUT("inlining too deep");
+ if (recursive_inline_level(callee) > MaxRecursiveInlineLevel) INLINE_BAILOUT("recursive inlining too deep");
if (callee->code_size_for_inlining() > max_inline_size() ) INLINE_BAILOUT("callee is too large");
// don't inline throwable methods unless the inlining tree is rooted in a throwable class
@@ -3530,28 +3622,25 @@
if (compilation()->env()->num_inlined_bytecodes() > DesiredMethodLimit) {
INLINE_BAILOUT("total inlining greater than DesiredMethodLimit");
}
+ // printing
+ print_inlining(callee, "");
}
-#ifndef PRODUCT
- // printing
- if (PrintInlining) {
- print_inline_result(callee, true);
- }
-#endif
-
// NOTE: Bailouts from this point on, which occur at the
// GraphBuilder level, do not cause bailout just of the inlining but
// in fact of the entire compilation.
BlockBegin* orig_block = block();
+ const bool is_invokedynamic = bc == Bytecodes::_invokedynamic;
+ const bool has_receiver = (bc != Bytecodes::_invokestatic && !is_invokedynamic);
+
const int args_base = state()->stack_size() - callee->arg_size();
assert(args_base >= 0, "stack underflow during inlining");
// Insert null check if necessary
Value recv = NULL;
- if (code() != Bytecodes::_invokestatic &&
- code() != Bytecodes::_invokedynamic) {
+ if (has_receiver) {
// note: null check must happen even if first instruction of callee does
// an implicit null check since the callee is in a different scope
// and we must make sure exception handling does the right thing
@@ -3567,7 +3656,7 @@
compilation()->set_would_profile(true);
if (profile_calls()) {
- profile_call(recv, holder_known ? callee->holder() : NULL);
+ profile_call(callee, recv, holder_known ? callee->holder() : NULL);
}
}
@@ -3576,7 +3665,7 @@
// fall-through of control flow, all return instructions of the
// callee will need to be replaced by Goto's pointing to this
// continuation point.
- BlockBegin* cont = cont_block != NULL ? cont_block : block_at(next_bci());
+ BlockBegin* cont = block_at(next_bci());
bool continuation_existed = true;
if (cont == NULL) {
cont = new BlockBegin(next_bci());
@@ -3609,17 +3698,10 @@
// note: this will also ensure that all arguments are computed before being passed
ValueStack* callee_state = state();
ValueStack* caller_state = state()->caller_state();
- { int i = args_base;
- while (i < caller_state->stack_size()) {
- const int par_no = i - args_base;
- Value arg = caller_state->stack_at_inc(i);
- // NOTE: take base() of arg->type() to avoid problems storing
- // constants
- if (receiver != NULL && par_no == 0) {
- arg = receiver;
- }
- store_local(callee_state, arg, arg->type()->base(), par_no);
- }
+ for (int i = args_base; i < caller_state->stack_size(); ) {
+ const int arg_no = i - args_base;
+ Value arg = caller_state->stack_at_inc(i);
+ store_local(callee_state, arg, arg_no);
}
// Remove args from stack.
@@ -3695,29 +3777,27 @@
// block merging. This allows load elimination and CSE to take place
// across multiple callee scopes if they are relatively simple, and
// is currently essential to making inlining profitable.
- if (cont_block == NULL) {
- if (num_returns() == 1
- && block() == orig_block
- && block() == inline_cleanup_block()) {
- _last = inline_cleanup_return_prev();
- _state = inline_cleanup_state();
- } else if (continuation_preds == cont->number_of_preds()) {
- // Inlining caused that the instructions after the invoke in the
- // caller are not reachable any more. So skip filling this block
- // with instructions!
- assert(cont == continuation(), "");
+ if (num_returns() == 1
+ && block() == orig_block
+ && block() == inline_cleanup_block()) {
+ _last = inline_cleanup_return_prev();
+ _state = inline_cleanup_state();
+ } else if (continuation_preds == cont->number_of_preds()) {
+ // Inlining caused that the instructions after the invoke in the
+ // caller are not reachable any more. So skip filling this block
+ // with instructions!
+ assert(cont == continuation(), "");
+ assert(_last && _last->as_BlockEnd(), "");
+ _skip_block = true;
+ } else {
+ // Resume parsing in continuation block unless it was already parsed.
+ // Note that if we don't change _last here, iteration in
+ // iterate_bytecodes_for_block will stop when we return.
+ if (!continuation()->is_set(BlockBegin::was_visited_flag)) {
+ // add continuation to work list instead of parsing it immediately
assert(_last && _last->as_BlockEnd(), "");
+ scope_data()->parent()->add_to_work_list(continuation());
_skip_block = true;
- } else {
- // Resume parsing in continuation block unless it was already parsed.
- // Note that if we don't change _last here, iteration in
- // iterate_bytecodes_for_block will stop when we return.
- if (!continuation()->is_set(BlockBegin::was_visited_flag)) {
- // add continuation to work list instead of parsing it immediately
- assert(_last && _last->as_BlockEnd(), "");
- scope_data()->parent()->add_to_work_list(continuation());
- _skip_block = true;
- }
}
}
@@ -3735,114 +3815,88 @@
bool GraphBuilder::for_method_handle_inline(ciMethod* callee) {
- assert(!callee->is_static(), "change next line");
- int index = state()->stack_size() - (callee->arg_size_no_receiver() + 1);
- Value receiver = state()->stack_at(index);
-
- if (receiver->type()->is_constant()) {
- ciMethodHandle* method_handle = receiver->type()->as_ObjectType()->constant_value()->as_method_handle();
-
- // Set the callee to have access to the class and signature in
- // the MethodHandleCompiler.
- method_handle->set_callee(callee);
- method_handle->set_caller(method());
-
- // Get an adapter for the MethodHandle.
- ciMethod* method_handle_adapter = method_handle->get_method_handle_adapter();
- if (method_handle_adapter != NULL) {
- return try_inline(method_handle_adapter, /*holder_known=*/ true);
- }
- } else if (receiver->as_CheckCast()) {
- // Match MethodHandle.selectAlternative idiom
- Phi* phi = receiver->as_CheckCast()->obj()->as_Phi();
-
- if (phi != NULL && phi->operand_count() == 2) {
- // Get the two MethodHandle inputs from the Phi.
- Value op1 = phi->operand_at(0);
- Value op2 = phi->operand_at(1);
- ObjectType* op1type = op1->type()->as_ObjectType();
- ObjectType* op2type = op2->type()->as_ObjectType();
-
- if (op1type->is_constant() && op2type->is_constant()) {
- ciMethodHandle* mh1 = op1type->constant_value()->as_method_handle();
- ciMethodHandle* mh2 = op2type->constant_value()->as_method_handle();
-
- // Set the callee to have access to the class and signature in
- // the MethodHandleCompiler.
- mh1->set_callee(callee);
- mh1->set_caller(method());
- mh2->set_callee(callee);
- mh2->set_caller(method());
-
- // Get adapters for the MethodHandles.
- ciMethod* mh1_adapter = mh1->get_method_handle_adapter();
- ciMethod* mh2_adapter = mh2->get_method_handle_adapter();
-
- if (mh1_adapter != NULL && mh2_adapter != NULL) {
- set_inline_cleanup_info();
-
- // Build the If guard
- BlockBegin* one = new BlockBegin(next_bci());
- BlockBegin* two = new BlockBegin(next_bci());
- BlockBegin* end = new BlockBegin(next_bci());
- Instruction* iff = append(new If(phi, If::eql, false, op1, one, two, NULL, false));
- block()->set_end(iff->as_BlockEnd());
-
- // Connect up the states
- one->merge(block()->end()->state());
- two->merge(block()->end()->state());
-
- // Save the state for the second inlinee
- ValueStack* state_before = copy_state_before();
-
- // Parse first adapter
- _last = _block = one;
- if (!try_inline_full(mh1_adapter, /*holder_known=*/ true, end, NULL)) {
- restore_inline_cleanup_info();
- block()->clear_end(); // remove appended iff
- return false;
- }
-
- // Parse second adapter
- _last = _block = two;
- _state = state_before;
- if (!try_inline_full(mh2_adapter, /*holder_known=*/ true, end, NULL)) {
- restore_inline_cleanup_info();
- block()->clear_end(); // remove appended iff
- return false;
- }
-
- connect_to_end(end);
+ ValueStack* state_before = state()->copy_for_parsing();
+ vmIntrinsics::ID iid = callee->intrinsic_id();
+ switch (iid) {
+ case vmIntrinsics::_invokeBasic:
+ {
+ // get MethodHandle receiver
+ const int args_base = state()->stack_size() - callee->arg_size();
+ ValueType* type = state()->stack_at(args_base)->type();
+ if (type->is_constant()) {
+ ciMethod* target = type->as_ObjectType()->constant_value()->as_method_handle()->get_vmtarget();
+ guarantee(!target->is_method_handle_intrinsic(), "should not happen"); // XXX remove
+ Bytecodes::Code bc = target->is_static() ? Bytecodes::_invokestatic : Bytecodes::_invokevirtual;
+ if (try_inline(target, /*holder_known*/ true, bc)) {
return true;
}
+ } else {
+ print_inlining(callee, "receiver not constant", /*success*/ false);
}
}
+ break;
+
+ case vmIntrinsics::_linkToVirtual:
+ case vmIntrinsics::_linkToStatic:
+ case vmIntrinsics::_linkToSpecial:
+ case vmIntrinsics::_linkToInterface:
+ {
+ // pop MemberName argument
+ const int args_base = state()->stack_size() - callee->arg_size();
+ ValueType* type = apop()->type();
+ if (type->is_constant()) {
+ ciMethod* target = type->as_ObjectType()->constant_value()->as_member_name()->get_vmtarget();
+ // If the target is another method handle invoke try recursivly to get
+ // a better target.
+ if (target->is_method_handle_intrinsic()) {
+ if (for_method_handle_inline(target)) {
+ return true;
+ }
+ } else {
+ ciSignature* signature = target->signature();
+ const int receiver_skip = target->is_static() ? 0 : 1;
+ // Cast receiver to its type.
+ if (!target->is_static()) {
+ ciKlass* tk = signature->accessing_klass();
+ Value obj = state()->stack_at(args_base);
+ if (obj->exact_type() == NULL &&
+ obj->declared_type() != tk && tk != compilation()->env()->Object_klass()) {
+ TypeCast* c = new TypeCast(tk, obj, state_before);
+ append(c);
+ state()->stack_at_put(args_base, c);
+ }
+ }
+ // Cast reference arguments to its type.
+ for (int i = 0, j = 0; i < signature->count(); i++) {
+ ciType* t = signature->type_at(i);
+ if (t->is_klass()) {
+ ciKlass* tk = t->as_klass();
+ Value obj = state()->stack_at(args_base + receiver_skip + j);
+ if (obj->exact_type() == NULL &&
+ obj->declared_type() != tk && tk != compilation()->env()->Object_klass()) {
+ TypeCast* c = new TypeCast(t, obj, state_before);
+ append(c);
+ state()->stack_at_put(args_base + receiver_skip + j, c);
+ }
+ }
+ j += t->size(); // long and double take two slots
+ }
+ Bytecodes::Code bc = target->is_static() ? Bytecodes::_invokestatic : Bytecodes::_invokevirtual;
+ if (try_inline(target, /*holder_known*/ true, bc)) {
+ return true;
+ }
+ }
+ } else {
+ print_inlining(callee, "MemberName not constant", /*success*/ false);
+ }
+ }
+ break;
+
+ default:
+ fatal(err_msg("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid)));
+ break;
}
- return false;
-}
-
-
-bool GraphBuilder::for_invokedynamic_inline(ciMethod* callee) {
- // Get the MethodHandle from the CallSite.
- ciCallSite* call_site = stream()->get_call_site();
- ciMethodHandle* method_handle = call_site->get_target();
-
- // Set the callee to have access to the class and signature in the
- // MethodHandleCompiler.
- method_handle->set_callee(callee);
- method_handle->set_caller(method());
-
- // Get an adapter for the MethodHandle.
- ciMethod* method_handle_adapter = method_handle->get_invokedynamic_adapter();
- if (method_handle_adapter != NULL) {
- if (try_inline(method_handle_adapter, /*holder_known=*/ true)) {
- // Add a dependence for invalidation of the optimization.
- if (!call_site->is_constant_call_site()) {
- dependency_recorder()->assert_call_site_target_value(call_site, method_handle);
- }
- return true;
- }
- }
+ set_state(state_before);
return false;
}
@@ -4034,22 +4088,24 @@
}
-#ifndef PRODUCT
-void GraphBuilder::print_inline_result(ciMethod* callee, bool res) {
- CompileTask::print_inlining(callee, scope()->level(), bci(), _inline_bailout_msg);
- if (res && CIPrintMethodCodes) {
+void GraphBuilder::print_inlining(ciMethod* callee, const char* msg, bool success) {
+ if (!PrintInlining) return;
+ assert(msg != NULL, "must be");
+ CompileTask::print_inlining(callee, scope()->level(), bci(), msg);
+ if (success && CIPrintMethodCodes) {
callee->print_codes();
}
}
+#ifndef PRODUCT
void GraphBuilder::print_stats() {
vmap()->print();
}
#endif // PRODUCT
-void GraphBuilder::profile_call(Value recv, ciKlass* known_holder) {
- append(new ProfileCall(method(), bci(), recv, known_holder));
+void GraphBuilder::profile_call(ciMethod* callee, Value recv, ciKlass* known_holder) {
+ append(new ProfileCall(method(), bci(), callee, recv, known_holder));
}
void GraphBuilder::profile_invocation(ciMethod* callee, ValueStack* state) {