Mercurial > hg > truffle
diff src/share/vm/opto/doCall.cpp @ 6266:1d7922586cf6
7023639: JSR 292 method handle invocation needs a fast path for compiled code
6984705: JSR 292 method handle creation should not go through JNI
Summary: remove assembly code for JDK 7 chained method handles
Reviewed-by: jrose, twisti, kvn, mhaupt
Contributed-by: John Rose <john.r.rose@oracle.com>, Christian Thalinger <christian.thalinger@oracle.com>, Michael Haupt <michael.haupt@oracle.com>
author | twisti |
---|---|
date | Tue, 24 Jul 2012 10:51:00 -0700 |
parents | cdd249497b34 |
children | 977007096840 |
line wrap: on
line diff
--- a/src/share/vm/opto/doCall.cpp Mon Jul 23 13:04:59 2012 -0700 +++ b/src/share/vm/opto/doCall.cpp Tue Jul 24 10:51:00 2012 -0700 @@ -59,13 +59,13 @@ } #endif -CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index, bool call_is_virtual, +CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool call_is_virtual, JVMState* jvms, bool allow_inline, float prof_factor, bool allow_intrinsics) { ciMethod* caller = jvms->method(); int bci = jvms->bci(); Bytecodes::Code bytecode = caller->java_code_at_bci(bci); - guarantee(call_method != NULL, "failed method resolution"); + guarantee(callee != NULL, "failed method resolution"); // Dtrace currently doesn't work unless all calls are vanilla if (env()->dtrace_method_probes()) { @@ -91,7 +91,7 @@ int rid = (receiver_count >= 0)? log->identify(profile.receiver(0)): -1; int r2id = (rid != -1 && profile.has_receiver(1))? log->identify(profile.receiver(1)):-1; log->begin_elem("call method='%d' count='%d' prof_factor='%g'", - log->identify(call_method), site_count, prof_factor); + log->identify(callee), site_count, prof_factor); if (call_is_virtual) log->print(" virtual='1'"); if (allow_inline) log->print(" inline='1'"); if (receiver_count >= 0) { @@ -109,7 +109,7 @@ // We do this before the strict f.p. check below because the // intrinsics handle strict f.p. correctly. if (allow_inline && allow_intrinsics) { - CallGenerator* cg = find_intrinsic(call_method, call_is_virtual); + CallGenerator* cg = find_intrinsic(callee, call_is_virtual); if (cg != NULL) return cg; } @@ -117,19 +117,12 @@ // NOTE: This must happen before normal inlining logic below since // MethodHandle.invoke* are native methods which obviously don't // have bytecodes and so normal inlining fails. - if (call_method->is_method_handle_invoke()) { - if (bytecode != Bytecodes::_invokedynamic) { - GraphKit kit(jvms); - Node* method_handle = kit.argument(0); - return CallGenerator::for_method_handle_call(method_handle, jvms, caller, call_method, profile); - } - else { - return CallGenerator::for_invokedynamic_call(jvms, caller, call_method, profile); - } + if (callee->is_method_handle_intrinsic()) { + return CallGenerator::for_method_handle_call(jvms, caller, callee); } // Do not inline strict fp into non-strict code, or the reverse - if (caller->is_strict() ^ call_method->is_strict()) { + if (caller->is_strict() ^ callee->is_strict()) { allow_inline = false; } @@ -155,26 +148,26 @@ } WarmCallInfo scratch_ci; if (!UseOldInlining) - scratch_ci.init(jvms, call_method, profile, prof_factor); - WarmCallInfo* ci = ilt->ok_to_inline(call_method, jvms, profile, &scratch_ci); + scratch_ci.init(jvms, callee, profile, prof_factor); + WarmCallInfo* ci = ilt->ok_to_inline(callee, jvms, profile, &scratch_ci); assert(ci != &scratch_ci, "do not let this pointer escape"); bool allow_inline = (ci != NULL && !ci->is_cold()); bool require_inline = (allow_inline && ci->is_hot()); if (allow_inline) { - CallGenerator* cg = CallGenerator::for_inline(call_method, expected_uses); - if (require_inline && cg != NULL && should_delay_inlining(call_method, jvms)) { + CallGenerator* cg = CallGenerator::for_inline(callee, expected_uses); + if (require_inline && cg != NULL && should_delay_inlining(callee, jvms)) { // Delay the inlining of this method to give us the // opportunity to perform some high level optimizations // first. - return CallGenerator::for_late_inline(call_method, cg); + return CallGenerator::for_late_inline(callee, cg); } if (cg == NULL) { // Fall through. } else if (require_inline || !InlineWarmCalls) { return cg; } else { - CallGenerator* cold_cg = call_generator(call_method, vtable_index, call_is_virtual, jvms, false, prof_factor); + CallGenerator* cold_cg = call_generator(callee, vtable_index, call_is_virtual, jvms, false, prof_factor); return CallGenerator::for_warm_call(ci, cold_cg, cg); } } @@ -189,7 +182,7 @@ (profile.morphism() == 2 && UseBimorphicInlining)) { // receiver_method = profile.method(); // Profiles do not suggest methods now. Look it up in the major receiver. - receiver_method = call_method->resolve_invoke(jvms->method()->holder(), + receiver_method = callee->resolve_invoke(jvms->method()->holder(), profile.receiver(0)); } if (receiver_method != NULL) { @@ -201,7 +194,7 @@ CallGenerator* next_hit_cg = NULL; ciMethod* next_receiver_method = NULL; if (profile.morphism() == 2 && UseBimorphicInlining) { - next_receiver_method = call_method->resolve_invoke(jvms->method()->holder(), + next_receiver_method = callee->resolve_invoke(jvms->method()->holder(), profile.receiver(1)); if (next_receiver_method != NULL) { next_hit_cg = this->call_generator(next_receiver_method, @@ -224,12 +217,12 @@ ) { // Generate uncommon trap for class check failure path // in case of monomorphic or bimorphic virtual call site. - miss_cg = CallGenerator::for_uncommon_trap(call_method, reason, + miss_cg = CallGenerator::for_uncommon_trap(callee, reason, Deoptimization::Action_maybe_recompile); } else { // Generate virtual call for class check failure path // in case of polymorphic virtual call site. - miss_cg = CallGenerator::for_virtual_call(call_method, vtable_index); + miss_cg = CallGenerator::for_virtual_call(callee, vtable_index); } if (miss_cg != NULL) { if (next_hit_cg != NULL) { @@ -252,11 +245,11 @@ // There was no special inlining tactic, or it bailed out. // Use a more generic tactic, like a simple call. if (call_is_virtual) { - return CallGenerator::for_virtual_call(call_method, vtable_index); + return CallGenerator::for_virtual_call(callee, vtable_index); } else { // Class Hierarchy Analysis or Type Profile reveals a unique target, // or it is a static or special call. - return CallGenerator::for_direct_call(call_method, should_delay_inlining(call_method, jvms)); + return CallGenerator::for_direct_call(callee, should_delay_inlining(callee, jvms)); } } @@ -355,33 +348,40 @@ // Find target being called bool will_link; - ciMethod* dest_method = iter().get_method(will_link); - ciInstanceKlass* holder_klass = dest_method->holder(); + ciMethod* bc_callee = iter().get_method(will_link); // actual callee from bytecode + ciInstanceKlass* holder_klass = bc_callee->holder(); ciKlass* holder = iter().get_declared_method_holder(); ciInstanceKlass* klass = ciEnv::get_instance_klass_for_declared_method_holder(holder); - int nargs = dest_method->arg_size(); - if (is_invokedynamic) nargs -= 1; - // uncommon-trap when callee is unloaded, uninitialized or will not link // bailout when too many arguments for register representation - if (!will_link || can_not_compile_call_site(dest_method, klass)) { + if (!will_link || can_not_compile_call_site(bc_callee, klass)) { #ifndef PRODUCT if (PrintOpto && (Verbose || WizardMode)) { method()->print_name(); tty->print_cr(" can not compile call at bci %d to:", bci()); - dest_method->print_name(); tty->cr(); + bc_callee->print_name(); tty->cr(); } #endif return; } assert(holder_klass->is_loaded(), ""); - assert((dest_method->is_static() || is_invokedynamic) == !has_receiver , "must match bc"); + //assert((bc_callee->is_static() || is_invokedynamic) == !has_receiver , "must match bc"); // XXX invokehandle (cur_bc_raw) // Note: this takes into account invokeinterface of methods declared in java/lang/Object, // which should be invokevirtuals but according to the VM spec may be invokeinterfaces assert(holder_klass->is_interface() || holder_klass->super() == NULL || (bc() != Bytecodes::_invokeinterface), "must match bc"); // Note: In the absence of miranda methods, an abstract class K can perform // an invokevirtual directly on an interface method I.m if K implements I. + const int nargs = bc_callee->arg_size(); + + // Push appendix argument (MethodType, CallSite, etc.), if one. + if (iter().has_appendix()) { + ciObject* appendix_arg = iter().get_appendix(); + const TypeOopPtr* appendix_arg_type = TypeOopPtr::make_from_constant(appendix_arg); + Node* appendix_arg_node = _gvn.makecon(appendix_arg_type); + push(appendix_arg_node); + } + // --------------------- // Does Class Hierarchy Analysis reveal only a single target of a v-call? // Then we may inline or make a static call, but become dependent on there being only 1 target. @@ -392,21 +392,21 @@ // Choose call strategy. bool call_is_virtual = is_virtual_or_interface; int vtable_index = methodOopDesc::invalid_vtable_index; - ciMethod* call_method = dest_method; + ciMethod* callee = bc_callee; // Try to get the most accurate receiver type if (is_virtual_or_interface) { Node* receiver_node = stack(sp() - nargs); const TypeOopPtr* receiver_type = _gvn.type(receiver_node)->isa_oopptr(); - ciMethod* optimized_virtual_method = optimize_inlining(method(), bci(), klass, dest_method, receiver_type); + ciMethod* optimized_virtual_method = optimize_inlining(method(), bci(), klass, bc_callee, receiver_type); // Have the call been sufficiently improved such that it is no longer a virtual? if (optimized_virtual_method != NULL) { - call_method = optimized_virtual_method; + callee = optimized_virtual_method; call_is_virtual = false; - } else if (!UseInlineCaches && is_virtual && call_method->is_loaded()) { + } else if (!UseInlineCaches && is_virtual && callee->is_loaded()) { // We can make a vtable call at this site - vtable_index = call_method->resolve_vtable_index(method()->holder(), klass); + vtable_index = callee->resolve_vtable_index(method()->holder(), klass); } } @@ -416,22 +416,24 @@ bool try_inline = (C->do_inlining() || InlineAccessors); // --------------------- - inc_sp(- nargs); // Temporarily pop args for JVM state of call + dec_sp(nargs); // Temporarily pop args for JVM state of call JVMState* jvms = sync_jvms(); // --------------------- // Decide call tactic. // This call checks with CHA, the interpreter profile, intrinsics table, etc. // It decides whether inlining is desirable or not. - CallGenerator* cg = C->call_generator(call_method, vtable_index, call_is_virtual, jvms, try_inline, prof_factor()); + CallGenerator* cg = C->call_generator(callee, vtable_index, call_is_virtual, jvms, try_inline, prof_factor()); + + bc_callee = callee = NULL; // don't use bc_callee and callee after this point // --------------------- // Round double arguments before call - round_double_arguments(dest_method); + round_double_arguments(cg->method()); #ifndef PRODUCT // bump global counters for calls - count_compiled_calls(false/*at_method_entry*/, cg->is_inline()); + count_compiled_calls(/*at_method_entry*/ false, cg->is_inline()); // Record first part of parsing work for this call parse_histogram()->record_change(); @@ -447,8 +449,8 @@ // because exceptions don't return to the call site.) profile_call(receiver); - JVMState* new_jvms; - if ((new_jvms = cg->generate(jvms)) == NULL) { + JVMState* new_jvms = cg->generate(jvms); + if (new_jvms == NULL) { // When inlining attempt fails (e.g., too many arguments), // it may contaminate the current compile state, making it // impossible to pull back and try again. Once we call @@ -460,7 +462,7 @@ // the call site, perhaps because it did not match a pattern the // intrinsic was expecting to optimize. Should always be possible to // get a normal java call that may inline in that case - cg = C->call_generator(call_method, vtable_index, call_is_virtual, jvms, try_inline, prof_factor(), /* allow_intrinsics= */ false); + cg = C->call_generator(cg->method(), vtable_index, call_is_virtual, jvms, try_inline, prof_factor(), /* allow_intrinsics= */ false); if ((new_jvms = cg->generate(jvms)) == NULL) { guarantee(failing(), "call failed to generate: calls should work"); return; @@ -469,8 +471,8 @@ if (cg->is_inline()) { // Accumulate has_loops estimate - C->set_has_loops(C->has_loops() || call_method->has_loops()); - C->env()->notice_inlined_method(call_method); + C->set_has_loops(C->has_loops() || cg->method()->has_loops()); + C->env()->notice_inlined_method(cg->method()); } // Reset parser state from [new_]jvms, which now carries results of the call. @@ -492,20 +494,74 @@ } // Round double result after a call from strict to non-strict code - round_double_result(dest_method); + round_double_result(cg->method()); + + ciType* rtype = cg->method()->return_type(); + if (iter().cur_bc_raw() == Bytecodes::_invokehandle || is_invokedynamic) { + // Be careful here with return types. + ciType* ctype = iter().get_declared_method_signature()->return_type(); + if (ctype != rtype) { + BasicType rt = rtype->basic_type(); + BasicType ct = ctype->basic_type(); + Node* retnode = peek(); + if (ct == T_VOID) { + // It's OK for a method to return a value that is discarded. + // The discarding does not require any special action from the caller. + // The Java code knows this, at VerifyType.isNullConversion. + pop_node(rt); // whatever it was, pop it + retnode = top(); + } else if (rt == T_INT || is_subword_type(rt)) { + // FIXME: This logic should be factored out. + if (ct == T_BOOLEAN) { + retnode = _gvn.transform( new (C, 3) AndINode(retnode, intcon(0x1)) ); + } else if (ct == T_CHAR) { + retnode = _gvn.transform( new (C, 3) AndINode(retnode, intcon(0xFFFF)) ); + } else if (ct == T_BYTE) { + retnode = _gvn.transform( new (C, 3) LShiftINode(retnode, intcon(24)) ); + retnode = _gvn.transform( new (C, 3) RShiftINode(retnode, intcon(24)) ); + } else if (ct == T_SHORT) { + retnode = _gvn.transform( new (C, 3) LShiftINode(retnode, intcon(16)) ); + retnode = _gvn.transform( new (C, 3) RShiftINode(retnode, intcon(16)) ); + } else { + assert(ct == T_INT, err_msg("rt=%d, ct=%d", rt, ct)); + } + } else if (rt == T_OBJECT) { + assert(ct == T_OBJECT, err_msg("rt=T_OBJECT, ct=%d", ct)); + if (ctype->is_loaded()) { + Node* if_fail = top(); + retnode = gen_checkcast(retnode, makecon(TypeKlassPtr::make(ctype->as_klass())), &if_fail); + if (if_fail != top()) { + PreserveJVMState pjvms(this); + set_control(if_fail); + builtin_throw(Deoptimization::Reason_class_check); + } + pop(); + push(retnode); + } + } else { + assert(ct == rt, err_msg("unexpected mismatch rt=%d, ct=%d", rt, ct)); + // push a zero; it's better than getting an oop/int mismatch + retnode = pop_node(rt); + retnode = zerocon(ct); + push_node(ct, retnode); + } + // Now that the value is well-behaved, continue with the call-site type. + rtype = ctype; + } + } // If the return type of the method is not loaded, assert that the // value we got is a null. Otherwise, we need to recompile. - if (!dest_method->return_type()->is_loaded()) { + if (!rtype->is_loaded()) { #ifndef PRODUCT if (PrintOpto && (Verbose || WizardMode)) { method()->print_name(); tty->print_cr(" asserting nullness of result at bci: %d", bci()); - dest_method->print_name(); tty->cr(); + cg->method()->print_name(); tty->cr(); } #endif if (C->log() != NULL) { C->log()->elem("assert_null reason='return' klass='%d'", - C->log()->identify(dest_method->return_type())); + C->log()->identify(rtype)); } // If there is going to be a trap, put it at the next bytecode: set_bci(iter().next_bci());