# HG changeset patch # User twisti # Date 1305234288 25200 # Node ID fabcf26ee72fb34e42c1b27b598de2564fb5fa0f # Parent 2f17eb233d13add599bd0de4085acf537dbf03cb 6998541: JSR 292 implement missing return-type conversion for OP_RETYPE_RAW Reviewed-by: jrose, kvn, never diff -r 2f17eb233d13 -r fabcf26ee72f src/cpu/sparc/vm/methodHandles_sparc.cpp --- a/src/cpu/sparc/vm/methodHandles_sparc.cpp Thu May 12 10:33:17 2011 -0700 +++ b/src/cpu/sparc/vm/methodHandles_sparc.cpp Thu May 12 14:04:48 2011 -0700 @@ -142,18 +142,8 @@ Register O2_form = O2_scratch; Register O3_adapter = O3_scratch; __ load_heap_oop(Address(O0_mtype, __ delayed_value(java_lang_invoke_MethodType::form_offset_in_bytes, O1_scratch)), O2_form); - // load_heap_oop(Address(O2_form, __ delayed_value(java_lang_invoke_MethodTypeForm::genericInvoker_offset_in_bytes, O1_scratch)), O3_adapter); - // deal with old JDK versions: - __ add( Address(O2_form, __ delayed_value(java_lang_invoke_MethodTypeForm::genericInvoker_offset_in_bytes, O1_scratch)), O3_adapter); - __ cmp(O3_adapter, O2_form); - Label sorry_no_invoke_generic; - __ brx(Assembler::lessUnsigned, false, Assembler::pn, sorry_no_invoke_generic); - __ delayed()->nop(); - - __ load_heap_oop(Address(O3_adapter, 0), O3_adapter); - __ tst(O3_adapter); - __ brx(Assembler::zero, false, Assembler::pn, sorry_no_invoke_generic); - __ delayed()->nop(); + __ load_heap_oop(Address(O2_form, __ delayed_value(java_lang_invoke_MethodTypeForm::genericInvoker_offset_in_bytes, O1_scratch)), O3_adapter); + __ verify_oop(O3_adapter); __ st_ptr(O3_adapter, Address(O4_argbase, 1 * Interpreter::stackElementSize)); // As a trusted first argument, pass the type being called, so the adapter knows // the actual types of the arguments and return values. @@ -164,12 +154,6 @@ trace_method_handle(_masm, "invokeGeneric"); __ jump_to_method_handle_entry(G3_method_handle, O1_scratch); - __ bind(sorry_no_invoke_generic); // no invokeGeneric implementation available! - __ mov(O0_mtype, G5_method_type); // required by throw_WrongMethodType - // mov(G3_method_handle, G3_method_handle); // already in this register - __ jump_to(AddressLiteral(Interpreter::throw_WrongMethodType_entry()), O1_scratch); - __ delayed()->nop(); - return entry_point; } diff -r 2f17eb233d13 -r fabcf26ee72f src/cpu/x86/vm/methodHandles_x86.cpp --- a/src/cpu/x86/vm/methodHandles_x86.cpp Thu May 12 10:33:17 2011 -0700 +++ b/src/cpu/x86/vm/methodHandles_x86.cpp Thu May 12 14:04:48 2011 -0700 @@ -163,7 +163,7 @@ BLOCK_COMMENT("ricochet_blob.bounce"); if (VerifyMethodHandles) RicochetFrame::verify_clean(_masm); - trace_method_handle(_masm, "ricochet_blob.bounce"); + trace_method_handle(_masm, "return/ricochet_blob.bounce"); __ jmp(frame_address(continuation_offset_in_bytes())); __ hlt(); @@ -615,18 +615,10 @@ rcx_argslot, rbx_temp, rdx_temp); // load up an adapter from the calling type (Java weaves this) - __ load_heap_oop(rdx_temp, Address(rax_mtype, __ delayed_value(java_lang_invoke_MethodType::form_offset_in_bytes, rdi_temp))); Register rdx_adapter = rdx_temp; - // __ load_heap_oop(rdx_adapter, Address(rdx_temp, java_lang_invoke_MethodTypeForm::genericInvoker_offset_in_bytes())); - // deal with old JDK versions: - __ lea(rdi_temp, Address(rdx_temp, __ delayed_value(java_lang_invoke_MethodTypeForm::genericInvoker_offset_in_bytes, rdi_temp))); - __ cmpptr(rdi_temp, rdx_temp); - Label sorry_no_invoke_generic; - __ jcc(Assembler::below, sorry_no_invoke_generic); - - __ load_heap_oop(rdx_adapter, Address(rdi_temp, 0)); - __ testptr(rdx_adapter, rdx_adapter); - __ jcc(Assembler::zero, sorry_no_invoke_generic); + __ load_heap_oop(rdx_temp, Address(rax_mtype, __ delayed_value(java_lang_invoke_MethodType::form_offset_in_bytes, rdi_temp))); + __ load_heap_oop(rdx_adapter, Address(rdx_temp, __ delayed_value(java_lang_invoke_MethodTypeForm::genericInvoker_offset_in_bytes, rdi_temp))); + __ verify_oop(rdx_adapter); __ movptr(Address(rcx_argslot, 1 * Interpreter::stackElementSize), rdx_adapter); // As a trusted first argument, pass the type being called, so the adapter knows // the actual types of the arguments and return values. @@ -637,12 +629,6 @@ trace_method_handle(_masm, "invokeGeneric"); __ jump_to_method_handle_entry(rcx, rdi_temp); - __ bind(sorry_no_invoke_generic); // no invokeGeneric implementation available! - __ movptr(rcx_recv, Address(rcx_argslot, -1 * Interpreter::stackElementSize)); // recover original MH - __ push(rax_mtype); // required mtype - __ push(rcx_recv); // bad mh (1st stacked argument) - __ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry())); - return entry_point; } @@ -688,7 +674,7 @@ __ movptr(Address(rdx_temp, arg_slots, Interpreter::stackElementScale()), rbx_temp); __ addptr(rdx_temp, wordSize); __ cmpptr(rdx_temp, rax_argslot); - __ jcc(Assembler::less, loop); + __ jcc(Assembler::below, loop); } // Now move the argslot down, to point to the opened-up space. @@ -731,7 +717,7 @@ __ movptr(Address(rdx_temp, arg_slots, Interpreter::stackElementScale()), rbx_temp); __ addptr(rdx_temp, -wordSize); __ cmpptr(rdx_temp, rsp); - __ jcc(Assembler::greaterEqual, loop); + __ jcc(Assembler::aboveEqual, loop); } // Now move the argslot up, to point to the just-copied block. @@ -980,12 +966,21 @@ intptr_t* saved_sp, intptr_t* saved_bp) { // called as a leaf from native code: do not block the JVM! + bool has_mh = (strstr(adaptername, "return/") == NULL); // return adapters don't have rcx_mh intptr_t* last_sp = (intptr_t*) saved_bp[frame::interpreter_frame_last_sp_offset]; - intptr_t* base_sp = (intptr_t*) saved_bp[frame::interpreter_frame_monitor_block_top_offset]; - tty->print_cr("MH %s mh="INTPTR_FORMAT" sp=("INTPTR_FORMAT"+"INTX_FORMAT") stack_size="INTX_FORMAT" bp="INTPTR_FORMAT, - adaptername, (intptr_t)mh, (intptr_t)entry_sp, (intptr_t)(saved_sp - entry_sp), (intptr_t)(base_sp - last_sp), (intptr_t)saved_bp); - if (last_sp != saved_sp && last_sp != NULL) - tty->print_cr("*** last_sp="INTPTR_FORMAT, (intptr_t)last_sp); + intptr_t* base_sp = last_sp; + typedef MethodHandles::RicochetFrame RicochetFrame; + RicochetFrame* rfp = (RicochetFrame*)((address)saved_bp - RicochetFrame::sender_link_offset_in_bytes()); + if (!UseRicochetFrames || Universe::heap()->is_in((address) rfp->saved_args_base())) { + // Probably an interpreter frame. + base_sp = (intptr_t*) saved_bp[frame::interpreter_frame_monitor_block_top_offset]; + } + intptr_t mh_reg = (intptr_t)mh; + const char* mh_reg_name = "rcx_mh"; + if (!has_mh) mh_reg_name = "rcx"; + tty->print_cr("MH %s %s="PTR_FORMAT" sp=("PTR_FORMAT"+"INTX_FORMAT") stack_size="INTX_FORMAT" bp="PTR_FORMAT, + adaptername, mh_reg_name, mh_reg, + (intptr_t)entry_sp, (intptr_t)(saved_sp - entry_sp), (intptr_t)(base_sp - last_sp), (intptr_t)saved_bp); if (Verbose) { tty->print(" reg dump: "); int saved_regs_count = (entry_sp-1) - saved_regs; @@ -996,18 +991,21 @@ tty->cr(); tty->print(" + dump: "); } - tty->print(" %d: "INTPTR_FORMAT, i, saved_regs[i]); + tty->print(" %d: "PTR_FORMAT, i, saved_regs[i]); } tty->cr(); + if (last_sp != saved_sp && last_sp != NULL) + tty->print_cr("*** last_sp="PTR_FORMAT, (intptr_t)last_sp); int stack_dump_count = 16; if (stack_dump_count < (int)(saved_bp + 2 - saved_sp)) stack_dump_count = (int)(saved_bp + 2 - saved_sp); if (stack_dump_count > 64) stack_dump_count = 48; for (i = 0; i < stack_dump_count; i += 4) { - tty->print_cr(" dump at SP[%d] "INTPTR_FORMAT": "INTPTR_FORMAT" "INTPTR_FORMAT" "INTPTR_FORMAT" "INTPTR_FORMAT, + tty->print_cr(" dump at SP[%d] "PTR_FORMAT": "PTR_FORMAT" "PTR_FORMAT" "PTR_FORMAT" "PTR_FORMAT, i, (intptr_t) &entry_sp[i+0], entry_sp[i+0], entry_sp[i+1], entry_sp[i+2], entry_sp[i+3]); } - print_method_handle(mh); + if (has_mh) + print_method_handle(mh); } } @@ -1073,7 +1071,6 @@ //OP_COLLECT_ARGS is below... |(1<get_methodOop()); // We catch all exceptions here that could happen in the method // handle compiler and stop the VM. - MethodHandleCompiler mhc(h, callee, call_profile()->count(), is_invokedynamic, THREAD); + MethodHandleCompiler mhc(h, callee, _profile->count(), is_invokedynamic, THREAD); if (!HAS_PENDING_EXCEPTION) { methodHandle m = mhc.compile(THREAD); if (!HAS_PENDING_EXCEPTION) { @@ -58,6 +59,22 @@ return NULL; } +// ------------------------------------------------------------------ +// ciMethodHandle::get_adapter +// +// Return an adapter for this MethodHandle. +ciMethod* ciMethodHandle::get_adapter(bool is_invokedynamic) const { + ciMethod* result = get_adapter_impl(is_invokedynamic); + if (result) { + // Fake up the MDO maturity. + ciMethodData* mdo = result->method_data(); + if (mdo != NULL && _caller->method_data() != NULL && _caller->method_data()->is_mature()) { + mdo->set_mature(); + } + } + return result; +} + // ------------------------------------------------------------------ // ciMethodHandle::print_impl diff -r 2f17eb233d13 -r fabcf26ee72f src/share/vm/ci/ciMethodHandle.hpp --- a/src/share/vm/ci/ciMethodHandle.hpp Thu May 12 10:33:17 2011 -0700 +++ b/src/share/vm/ci/ciMethodHandle.hpp Thu May 12 14:04:48 2011 -0700 @@ -35,35 +35,36 @@ class ciMethodHandle : public ciInstance { private: ciMethod* _callee; + ciMethod* _caller; ciCallProfile* _profile; // Return an adapter for this MethodHandle. - ciMethod* get_adapter(bool is_invokedynamic) const; + ciMethod* get_adapter_impl(bool is_invokedynamic) const; + ciMethod* get_adapter( bool is_invokedynamic) const; protected: void print_impl(outputStream* st); public: - ciMethodHandle(instanceHandle h_i) : ciInstance(h_i) {}; + ciMethodHandle(instanceHandle h_i) : + ciInstance(h_i), + _callee(NULL), + _caller(NULL), + _profile(NULL) + {} // What kind of ciObject is this? bool is_method_handle() const { return true; } - ciMethod* callee() const { return _callee; } - void set_callee(ciMethod* m) { _callee = m; } - - ciCallProfile* call_profile() const { return _profile; } - void set_call_profile(ciCallProfile* profile) { _profile = profile; } + void set_callee(ciMethod* m) { _callee = m; } + void set_caller(ciMethod* m) { _caller = m; } + void set_call_profile(ciCallProfile* profile) { _profile = profile; } // Return an adapter for a MethodHandle call. - ciMethod* get_method_handle_adapter() const { - return get_adapter(false); - } + ciMethod* get_method_handle_adapter() const { return get_adapter(false); } // Return an adapter for an invokedynamic call. - ciMethod* get_invokedynamic_adapter() const { - return get_adapter(true); - } + ciMethod* get_invokedynamic_adapter() const { return get_adapter(true); } }; #endif // SHARE_VM_CI_CIMETHODHANDLE_HPP diff -r 2f17eb233d13 -r fabcf26ee72f src/share/vm/opto/doCall.cpp --- a/src/share/vm/opto/doCall.cpp Thu May 12 10:33:17 2011 -0700 +++ b/src/share/vm/opto/doCall.cpp Thu May 12 14:04:48 2011 -0700 @@ -62,7 +62,10 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index, bool call_is_virtual, JVMState* jvms, bool allow_inline, float prof_factor) { - CallGenerator* cg; + CallGenerator* cg; + ciMethod* caller = jvms->method(); + int bci = jvms->bci(); + Bytecodes::Code bytecode = caller->java_code_at_bci(bci); guarantee(call_method != NULL, "failed method resolution"); // Dtrace currently doesn't work unless all calls are vanilla @@ -73,8 +76,7 @@ // Note: When we get profiling during stage-1 compiles, we want to pull // from more specific profile data which pertains to this inlining. // Right now, ignore the information in jvms->caller(), and do method[bci]. - ciCallProfile profile = jvms->method()->call_profile_at_bci(jvms->bci()); - Bytecodes::Code bytecode = jvms->method()->java_code_at_bci(jvms->bci()); + ciCallProfile profile = caller->call_profile_at_bci(bci); // See how many times this site has been invoked. int site_count = profile.count(); @@ -126,9 +128,10 @@ ciObject* const_oop = oop_ptr->const_oop(); ciMethodHandle* method_handle = const_oop->as_method_handle(); - // Set the actually called method to have access to the class - // and signature in the MethodHandleCompiler. + // Set the callee to have access to the class and signature in + // the MethodHandleCompiler. method_handle->set_callee(call_method); + method_handle->set_caller(caller); method_handle->set_call_profile(&profile); // Get an adapter for the MethodHandle. @@ -150,9 +153,10 @@ ciCallSite* call_site = str.get_call_site(); ciMethodHandle* method_handle = call_site->get_target(); - // Set the actually called method to have access to the class - // and signature in the MethodHandleCompiler. + // Set the callee to have access to the class and signature in + // the MethodHandleCompiler. method_handle->set_callee(call_method); + method_handle->set_caller(caller); method_handle->set_call_profile(&profile); // Get an adapter for the MethodHandle. diff -r 2f17eb233d13 -r fabcf26ee72f src/share/vm/prims/methodHandleWalk.cpp --- a/src/share/vm/prims/methodHandleWalk.cpp Thu May 12 10:33:17 2011 -0700 +++ b/src/share/vm/prims/methodHandleWalk.cpp Thu May 12 14:04:48 2011 -0700 @@ -31,6 +31,11 @@ * JSR 292 reference implementation: method handle structure analysis */ +#ifdef PRODUCT +#define print_method_handle(mh) {} +#else //PRODUCT +extern "C" void print_method_handle(oop mh); +#endif //PRODUCT // ----------------------------------------------------------------------------- // MethodHandleChain @@ -206,8 +211,10 @@ lose("bad argument index", CHECK_(empty)); } + bool retain_original_args = false; // used by fold/collect logic + // perform the adapter action - switch (chain().adapter_conversion_op()) { + switch (conv_op) { case java_lang_invoke_AdapterMethodHandle::OP_RETYPE_ONLY: // No changes to arguments; pass the bits through. break; @@ -216,51 +223,36 @@ // To keep the verifier happy, emit bitwise ("raw") conversions as needed. // See MethodHandles::same_basic_type_for_arguments for allowed conversions. Handle incoming_mtype(THREAD, chain().method_type_oop()); - oop outgoing_mh_oop = chain().vmtarget_oop(); - if (!java_lang_invoke_MethodHandle::is_instance(outgoing_mh_oop)) - lose("outgoing target not a MethodHandle", CHECK_(empty)); - Handle outgoing_mtype(THREAD, java_lang_invoke_MethodHandle::type(outgoing_mh_oop)); - outgoing_mh_oop = NULL; // GC safety + Handle outgoing_mtype; + { + oop outgoing_mh_oop = chain().vmtarget_oop(); + if (!java_lang_invoke_MethodHandle::is_instance(outgoing_mh_oop)) + lose("outgoing target not a MethodHandle", CHECK_(empty)); + outgoing_mtype = Handle(THREAD, java_lang_invoke_MethodHandle::type(outgoing_mh_oop)); + } int nptypes = java_lang_invoke_MethodType::ptype_count(outgoing_mtype()); if (nptypes != java_lang_invoke_MethodType::ptype_count(incoming_mtype())) lose("incoming and outgoing parameter count do not agree", CHECK_(empty)); + // Argument types. for (int i = 0, slot = _outgoing.length() - 1; slot >= 0; slot--) { SlotState* arg_state = slot_state(slot); if (arg_state->_type == T_VOID) continue; - ArgToken arg = _outgoing.at(slot)._arg; - klassOop in_klass = NULL; - klassOop out_klass = NULL; - BasicType inpbt = java_lang_Class::as_BasicType(java_lang_invoke_MethodType::ptype(incoming_mtype(), i), &in_klass); - BasicType outpbt = java_lang_Class::as_BasicType(java_lang_invoke_MethodType::ptype(outgoing_mtype(), i), &out_klass); - assert(inpbt == arg.basic_type(), "sanity"); - - if (inpbt != outpbt) { - vmIntrinsics::ID iid = vmIntrinsics::for_raw_conversion(inpbt, outpbt); - if (iid == vmIntrinsics::_none) { - lose("no raw conversion method", CHECK_(empty)); - } - ArgToken arglist[2]; - arglist[0] = arg; // outgoing 'this' - arglist[1] = ArgToken(); // sentinel - arg = make_invoke(NULL, iid, Bytecodes::_invokestatic, false, 1, &arglist[0], CHECK_(empty)); - change_argument(inpbt, slot, outpbt, arg); - } - + klassOop src_klass = NULL; + klassOop dst_klass = NULL; + BasicType src = java_lang_Class::as_BasicType(java_lang_invoke_MethodType::ptype(incoming_mtype(), i), &src_klass); + BasicType dst = java_lang_Class::as_BasicType(java_lang_invoke_MethodType::ptype(outgoing_mtype(), i), &dst_klass); + retype_raw_argument_type(src, dst, slot, CHECK_(empty)); i++; // We need to skip void slots at the top of the loop. } - BasicType inrbt = java_lang_Class::as_BasicType(java_lang_invoke_MethodType::rtype(incoming_mtype())); - BasicType outrbt = java_lang_Class::as_BasicType(java_lang_invoke_MethodType::rtype(outgoing_mtype())); - if (inrbt != outrbt) { - if (inrbt == T_INT && outrbt == T_VOID) { - // See comments in MethodHandles::same_basic_type_for_arguments. - } else { - assert(false, "IMPLEMENT ME"); - lose("no raw conversion method", CHECK_(empty)); - } + // Return type. + { + BasicType src = java_lang_Class::as_BasicType(java_lang_invoke_MethodType::rtype(incoming_mtype())); + BasicType dst = java_lang_Class::as_BasicType(java_lang_invoke_MethodType::rtype(outgoing_mtype())); + retype_raw_return_type(src, dst, CHECK_(empty)); } break; } @@ -273,7 +265,7 @@ assert(dest == arg_state->_type, ""); ArgToken arg = arg_state->_arg; ArgToken new_arg = make_conversion(T_OBJECT, dest_klass, Bytecodes::_checkcast, arg, CHECK_(empty)); - assert(arg.index() == new_arg.index(), "should be the same index"); + assert(arg.token_type() >= tt_symbolic || arg.index() == new_arg.index(), "should be the same index"); debug_only(dest_klass = (klassOop)badOop); break; } @@ -332,7 +324,7 @@ ArgToken arglist[2]; arglist[0] = arg; // outgoing value arglist[1] = ArgToken(); // sentinel - arg = make_invoke(NULL, boxer, Bytecodes::_invokevirtual, false, 1, &arglist[0], CHECK_(empty)); + arg = make_invoke(NULL, boxer, Bytecodes::_invokestatic, false, 1, &arglist[0], CHECK_(empty)); change_argument(src, arg_slot, T_OBJECT, arg); break; } @@ -404,13 +396,54 @@ break; } - case java_lang_invoke_AdapterMethodHandle::OP_COLLECT_ARGS: { //NYI, may GC - lose("unimplemented", CHECK_(empty)); - break; - } - - case java_lang_invoke_AdapterMethodHandle::OP_FOLD_ARGS: { //NYI, may GC - lose("unimplemented", CHECK_(empty)); + case java_lang_invoke_AdapterMethodHandle::OP_FOLD_ARGS: + retain_original_args = true; // and fall through: + case java_lang_invoke_AdapterMethodHandle::OP_COLLECT_ARGS: { + // call argument MH recursively + //{static int x; if (!x++) print_method_handle(chain().method_handle_oop()); --x;} + Handle recursive_mh(THREAD, chain().adapter_arg_oop()); + if (!java_lang_invoke_MethodHandle::is_instance(recursive_mh())) { + lose("recursive target not a MethodHandle", CHECK_(empty)); + } + Handle recursive_mtype(THREAD, java_lang_invoke_MethodHandle::type(recursive_mh())); + int argc = java_lang_invoke_MethodType::ptype_count(recursive_mtype()); + int coll_slots = java_lang_invoke_MethodHandle::vmslots(recursive_mh()); + BasicType rtype = java_lang_Class::as_BasicType(java_lang_invoke_MethodType::rtype(recursive_mtype())); + ArgToken* arglist = NEW_RESOURCE_ARRAY(ArgToken, 1 + argc + 1); // 1+: mh, +1: sentinel + arglist[0] = make_oop_constant(recursive_mh(), CHECK_(empty)); + if (arg_slot < 0 || coll_slots < 0 || arg_slot + coll_slots > _outgoing.length()) { + lose("bad fold/collect arg slot", CHECK_(empty)); + } + for (int i = 0, slot = arg_slot + coll_slots - 1; slot >= arg_slot; slot--) { + SlotState* arg_state = slot_state(slot); + BasicType arg_type = arg_state->_type; + if (arg_type == T_VOID) continue; + ArgToken arg = _outgoing.at(slot)._arg; + if (i >= argc) { lose("bad fold/collect arg", CHECK_(empty)); } + arglist[1+i] = arg; + if (!retain_original_args) + change_argument(arg_type, slot, T_VOID, ArgToken(tt_void)); + } + arglist[1+argc] = ArgToken(); // sentinel + oop invoker = java_lang_invoke_MethodTypeForm::vmlayout( + java_lang_invoke_MethodType::form(recursive_mtype()) ); + if (invoker == NULL || !invoker->is_method()) { + lose("bad vmlayout slot", CHECK_(empty)); + } + // FIXME: consider inlining the invokee at the bytecode level + ArgToken ret = make_invoke(methodOop(invoker), vmIntrinsics::_none, + Bytecodes::_invokevirtual, false, 1+argc, &arglist[0], CHECK_(empty)); + DEBUG_ONLY(invoker = NULL); + if (rtype == T_OBJECT) { + klassOop rklass = java_lang_Class::as_klassOop( java_lang_invoke_MethodType::rtype(recursive_mtype()) ); + if (rklass != SystemDictionary::Object_klass() && + !Klass::cast(rklass)->is_interface()) { + // preserve type safety + ret = make_conversion(T_OBJECT, rklass, Bytecodes::_checkcast, ret, CHECK_(empty)); + } + } + int ret_slot = arg_slot + (retain_original_args ? coll_slots : 0); + change_argument(T_VOID, ret_slot, rtype, ret); break; } @@ -504,7 +537,7 @@ lose("bad bound value", CHECK_(empty)); } } - debug_only(arg_oop = badOop); + DEBUG_ONLY(arg_oop = badOop); change_argument(T_VOID, arg_slot, arg_type, arg); } @@ -547,11 +580,10 @@ } for (int i = 0; i < nptypes; i++) { klassOop arg_type_klass = NULL; - BasicType arg_type = java_lang_Class::as_BasicType( - java_lang_invoke_MethodType::ptype(mtype(), i), &arg_type_klass); + BasicType arg_type = java_lang_Class::as_BasicType(java_lang_invoke_MethodType::ptype(mtype(), i), &arg_type_klass); int index = new_local_index(arg_type); ArgToken arg = make_parameter(arg_type, arg_type_klass, index, CHECK); - debug_only(arg_type_klass = (klassOop) NULL); + DEBUG_ONLY(arg_type_klass = (klassOop) NULL); _outgoing.at_put(argp, make_state(arg_type, arg)); if (type2size[arg_type] == 2) { // add the extra slot, so we can model the JVM stack @@ -561,8 +593,7 @@ } // call make_parameter at the end of the list for the return type klassOop ret_type_klass = NULL; - BasicType ret_type = java_lang_Class::as_BasicType( - java_lang_invoke_MethodType::rtype(mtype()), &ret_type_klass); + BasicType ret_type = java_lang_Class::as_BasicType(java_lang_invoke_MethodType::rtype(mtype()), &ret_type_klass); ArgToken ret = make_parameter(ret_type, ret_type_klass, -1, CHECK); // ignore ret; client can catch it if needed } @@ -614,6 +645,48 @@ // ----------------------------------------------------------------------------- +// MethodHandleWalker::retype_raw_conversion +// +// Do the raw retype conversions for OP_RETYPE_RAW. +void MethodHandleWalker::retype_raw_conversion(BasicType src, BasicType dst, bool for_return, int slot, TRAPS) { + if (src != dst) { + if (MethodHandles::same_basic_type_for_returns(src, dst, /*raw*/ true)) { + if (MethodHandles::is_float_fixed_reinterpretation_cast(src, dst)) { + if (for_return) Untested("MHW return raw conversion"); // still untested + vmIntrinsics::ID iid = vmIntrinsics::for_raw_conversion(src, dst); + if (iid == vmIntrinsics::_none) { + lose("no raw conversion method", CHECK); + } + ArgToken arglist[2]; + if (!for_return) { + // argument type conversion + ArgToken arg = _outgoing.at(slot)._arg; + assert(arg.token_type() >= tt_symbolic || src == arg.basic_type(), "sanity"); + arglist[0] = arg; // outgoing 'this' + arglist[1] = ArgToken(); // sentinel + arg = make_invoke(NULL, iid, Bytecodes::_invokestatic, false, 1, &arglist[0], CHECK); + change_argument(src, slot, dst, arg); + } else { + // return type conversion + klassOop arg_klass = NULL; + arglist[0] = make_parameter(src, arg_klass, -1, CHECK); // return value + arglist[1] = ArgToken(); // sentinel + (void) make_invoke(NULL, iid, Bytecodes::_invokestatic, false, 1, &arglist[0], CHECK); + } + } else { + // Nothing to do. + } + } else if (src == T_OBJECT && is_java_primitive(dst)) { + // ref-to-prim: discard ref, push zero + lose("requested ref-to-prim conversion not expected", CHECK); + } else { + lose("requested raw conversion not allowed", CHECK); + } + } +} + + +// ----------------------------------------------------------------------------- // MethodHandleCompiler MethodHandleCompiler::MethodHandleCompiler(Handle root, methodHandle callee, int invoke_count, bool is_invokedynamic, TRAPS) @@ -719,6 +792,7 @@ case Bytecodes::_astore_1: case Bytecodes::_astore_2: case Bytecodes::_astore_3: + case Bytecodes::_iand: case Bytecodes::_i2l: case Bytecodes::_i2f: case Bytecodes::_i2d: @@ -945,7 +1019,11 @@ break; default: - ShouldNotReachHere(); + if (op == Bytecodes::_illegal) + lose("no such primitive conversion", THREAD); + else + lose("bad primitive conversion op", THREAD); + return make_prim_constant(type, &zero_jvalue, THREAD); } return make_parameter(type, tk, index, THREAD); @@ -956,7 +1034,9 @@ // MethodHandleCompiler // -static jvalue zero_jvalue; +// Values used by the compiler. +jvalue MethodHandleCompiler::zero_jvalue = { 0 }; +jvalue MethodHandleCompiler::one_jvalue = { 1 }; // Emit bytecodes for the given invoke instruction. MethodHandleWalker::ArgToken @@ -964,18 +1044,18 @@ Bytecodes::Code op, bool tailcall, int argc, MethodHandleWalker::ArgToken* argv, TRAPS) { + ArgToken zero; if (m == NULL) { // Get the intrinsic methodOop. m = vmIntrinsics::method_for(iid); if (m == NULL) { - ArgToken zero; lose(vmIntrinsics::name_at(iid), CHECK_(zero)); } } - klassOop klass = m->method_holder(); - Symbol* name = m->name(); - Symbol* signature = m->signature(); + klassOop klass = m->method_holder(); + Symbol* name = m->name(); + Symbol* signature = m->signature(); if (tailcall) { // Actually, in order to make these methods more recognizable, @@ -1041,7 +1121,6 @@ if (rbt != _rtype) { if (rbt == T_VOID) { // push a zero of the right sort - ArgToken zero; if (_rtype == T_OBJECT) { zero = make_oop_constant(NULL, CHECK_(zero)); } else { @@ -1051,9 +1130,27 @@ } else if (_rtype == T_VOID) { // We'll emit a _return with something on the stack. // It's OK to ignore what's on the stack. + } else if (rbt == T_INT && is_subword_type(_rtype)) { + // Convert value to match return type. + switch (_rtype) { + case T_BOOLEAN: { + // boolean is treated as a one-bit unsigned integer. + // Cf. API documentation: java/lang/invoke/MethodHandles.html#explicitCastArguments + ArgToken one = make_prim_constant(T_INT, &one_jvalue, CHECK_(zero)); + emit_load_constant(one); + emit_bc(Bytecodes::_iand); + break; + } + case T_BYTE: emit_bc(Bytecodes::_i2b); break; + case T_CHAR: emit_bc(Bytecodes::_i2c); break; + case T_SHORT: emit_bc(Bytecodes::_i2s); break; + default: ShouldNotReachHere(); + } + } else if (is_subword_type(rbt) && (is_subword_type(_rtype) || (_rtype == T_INT))) { + // The subword type was returned as an int and will be passed + // on as an int. } else { - tty->print_cr("*** rbt=%d != rtype=%d", rbt, _rtype); - assert(false, "IMPLEMENT ME"); + lose("unknown conversion", CHECK_(zero)); } } switch (_rtype) { @@ -1216,17 +1313,17 @@ typeArrayHandle exception_handlers(THREAD, Universe::the_empty_int_array()); m->set_exception_table(exception_handlers()); - // Set the invocation counter's count to the invoke count of the - // original call site. - InvocationCounter* ic = m->invocation_counter(); - ic->set(InvocationCounter::wait_for_compile, _invoke_count); - // Rewrite the method and set up the constant pool cache. objArrayOop m_array = oopFactory::new_system_objArray(1, CHECK_(empty)); objArrayHandle methods(THREAD, m_array); methods->obj_at_put(0, m()); Rewriter::rewrite(_target_klass(), cpool, methods, CHECK_(empty)); // Use fake class. + // Set the invocation counter's count to the invoke count of the + // original call site. + InvocationCounter* ic = m->invocation_counter(); + ic->set(InvocationCounter::wait_for_compile, _invoke_count); + // Create a new MDO { methodDataOop mdo = oopFactory::new_methodData(m, CHECK_(empty)); @@ -1235,10 +1332,12 @@ // Iterate over all profile data and set the count of the counter // data entries to the original call site counter. - for (ProfileData* pd = mdo->first_data(); mdo->is_valid(pd); pd = mdo->next_data(pd)) { - if (pd->is_CounterData()) { - CounterData* cd = pd->as_CounterData(); - cd->set_count(_invoke_count); + for (ProfileData* profile_data = mdo->first_data(); + mdo->is_valid(profile_data); + profile_data = mdo->next_data(profile_data)) { + if (profile_data->is_CounterData()) { + CounterData* counter_data = profile_data->as_CounterData(); + counter_data->set_count(_invoke_count); } } } @@ -1257,7 +1356,6 @@ #ifndef PRODUCT -#if 0 // MH printer for debugging. class MethodHandlePrinter : public MethodHandleWalker { @@ -1265,6 +1363,7 @@ outputStream* _out; bool _verbose; int _temp_num; + int _param_state; stringStream _strbuf; const char* strbuf() { const char* s = _strbuf.as_string(); @@ -1272,14 +1371,21 @@ return s; } ArgToken token(const char* str) { - return (ArgToken) str; + jvalue string_con; + string_con.j = (intptr_t) str; + return ArgToken(tt_symbolic, T_LONG, string_con); + } + const char* string(ArgToken token) { + return (const char*) (intptr_t) token.get_jlong(); } void start_params() { + _param_state <<= 1; _out->print("("); } void end_params() { if (_verbose) _out->print("\n"); _out->print(") => {"); + _param_state >>= 1; } void put_type_name(BasicType type, klassOop tk, outputStream* s) { const char* kname = NULL; @@ -1299,9 +1405,10 @@ public: MethodHandlePrinter(Handle root, bool verbose, outputStream* out, TRAPS) - : MethodHandleWalker(root, THREAD), + : MethodHandleWalker(root, false, THREAD), _out(out), _verbose(verbose), + _param_state(0), _temp_num(0) { start_params(); @@ -1309,9 +1416,10 @@ virtual ArgToken make_parameter(BasicType type, klassOop tk, int argnum, TRAPS) { if (argnum < 0) { end_params(); - return NULL; + return token("return"); } - if (argnum == 0) { + if ((_param_state & 1) == 0) { + _param_state |= 1; _out->print(_verbose ? "\n " : ""); } else { _out->print(_verbose ? ",\n " : ", "); @@ -1341,8 +1449,15 @@ java_lang_boxing_object::print(type, con, &_strbuf); return maybe_make_temp("constant", type, "k"); } - virtual ArgToken make_conversion(BasicType type, klassOop tk, Bytecodes::Code op, ArgToken src, TRAPS) { - _strbuf.print("%s(%s", Bytecodes::name(op), (const char*)src); + void print_bytecode_name(Bytecodes::Code op) { + if (Bytecodes::is_defined(op)) + _strbuf.print("%s", Bytecodes::name(op)); + else + _strbuf.print("bytecode_%d", (int) op); + } + virtual ArgToken make_conversion(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& src, TRAPS) { + print_bytecode_name(op); + _strbuf.print("(%s", string(src)); if (tk != NULL) { _strbuf.print(", "); put_type_name(type, tk, &_strbuf); @@ -1350,8 +1465,8 @@ _strbuf.print(")"); return maybe_make_temp("convert", type, "v"); } - virtual ArgToken make_fetch(BasicType type, klassOop tk, Bytecodes::Code op, ArgToken base, ArgToken offset, TRAPS) { - _strbuf.print("%s(%s, %s", Bytecodes::name(op), (const char*)base, (const char*)offset); + virtual ArgToken make_fetch(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& base, const ArgToken& offset, TRAPS) { + _strbuf.print("%s(%s, %s", Bytecodes::name(op), string(base), string(offset)); if (tk != NULL) { _strbuf.print(", "); put_type_name(type, tk, &_strbuf); @@ -1362,7 +1477,8 @@ virtual ArgToken make_invoke(methodOop m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS) { - Symbol* name, sig; + Symbol* name; + Symbol* sig; if (m != NULL) { name = m->name(); sig = m->signature(); @@ -1372,7 +1488,7 @@ } _strbuf.print("%s %s%s(", Bytecodes::name(op), name->as_C_string(), sig->as_C_string()); for (int i = 0; i < argc; i++) { - _strbuf.print("%s%s", (i > 0 ? ", " : ""), (const char*)argv[i]); + _strbuf.print("%s%s", (i > 0 ? ", " : ""), string(argv[i])); } _strbuf.print(")"); if (!tailcall) { @@ -1410,24 +1526,20 @@ if (HAS_PENDING_EXCEPTION) { oop ex = PENDING_EXCEPTION; CLEAR_PENDING_EXCEPTION; - out->print("\n*** "); - if (ex != Universe::virtual_machine_error_instance()) - ex->print_on(out); - else - out->print("lose: %s", printer.lose_message()); - out->print("\n}\n"); + out->print(" *** "); + if (printer.lose_message() != NULL) out->print("%s ", printer.lose_message()); + out->print("}"); } out->print("\n"); } }; -#endif // 0 extern "C" void print_method_handle(oop mh) { if (!mh->is_oop()) { - tty->print_cr("*** not a method handle: "INTPTR_FORMAT, (intptr_t)mh); + tty->print_cr("*** not a method handle: "PTR_FORMAT, (intptr_t)mh); } else if (java_lang_invoke_MethodHandle::is_instance(mh)) { - //MethodHandlePrinter::print(mh); + MethodHandlePrinter::print(mh); } else { tty->print("*** not a method handle: "); mh->print(); diff -r 2f17eb233d13 -r fabcf26ee72f src/share/vm/prims/methodHandleWalk.hpp --- a/src/share/vm/prims/methodHandleWalk.hpp Thu May 12 10:33:17 2011 -0700 +++ b/src/share/vm/prims/methodHandleWalk.hpp Thu May 12 14:04:48 2011 -0700 @@ -113,6 +113,7 @@ tt_parameter, tt_temporary, tt_constant, + tt_symbolic, tt_illegal }; @@ -164,6 +165,10 @@ bool _for_invokedynamic; int _local_index; + // This array is kept in an unusual order, indexed by low-level "slot number". + // TOS is always _outgoing.at(0), so simple pushes and pops shift the whole _outgoing array. + // If there is a receiver in the current argument list, it is at _outgoing.at(_outgoing.length()-1). + // If a value at _outgoing.at(n) is T_LONG or T_DOUBLE, the value at _outgoing.at(n+1) is T_VOID. GrowableArray _outgoing; // current outgoing parameter slots int _outgoing_argc; // # non-empty outgoing slots @@ -173,6 +178,11 @@ // Insert or delete a second empty slot as needed. void change_argument(BasicType old_type, int slot, BasicType new_type, const ArgToken& new_arg); + // Raw retype conversions for OP_RAW_RETYPE. + void retype_raw_conversion(BasicType src, BasicType dst, bool for_return, int slot, TRAPS); + void retype_raw_argument_type(BasicType src, BasicType dst, int slot, TRAPS) { retype_raw_conversion(src, dst, false, slot, CHECK); } + void retype_raw_return_type( BasicType src, BasicType dst, TRAPS) { retype_raw_conversion(src, dst, true, -1, CHECK); } + SlotState* slot_state(int slot) { if (slot < 0 || slot >= _outgoing.length()) return NULL; @@ -221,12 +231,12 @@ int max_locals() const { return _local_index; } // plug-in abstract interpretation steps: - virtual ArgToken make_parameter( BasicType type, klassOop tk, int argnum, TRAPS ) = 0; - virtual ArgToken make_prim_constant( BasicType type, jvalue* con, TRAPS ) = 0; - virtual ArgToken make_oop_constant( oop con, TRAPS ) = 0; - virtual ArgToken make_conversion( BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& src, TRAPS ) = 0; - virtual ArgToken make_fetch( BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& base, const ArgToken& offset, TRAPS ) = 0; - virtual ArgToken make_invoke( methodOop m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS ) = 0; + virtual ArgToken make_parameter(BasicType type, klassOop tk, int argnum, TRAPS) = 0; + virtual ArgToken make_prim_constant(BasicType type, jvalue* con, TRAPS) = 0; + virtual ArgToken make_oop_constant(oop con, TRAPS) = 0; + virtual ArgToken make_conversion(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& src, TRAPS) = 0; + virtual ArgToken make_fetch(BasicType type, klassOop tk, Bytecodes::Code op, const ArgToken& base, const ArgToken& offset, TRAPS) = 0; + virtual ArgToken make_invoke(methodOop m, vmIntrinsics::ID iid, Bytecodes::Code op, bool tailcall, int argc, ArgToken* argv, TRAPS) = 0; // For make_invoke, the methodOop can be NULL if the intrinsic ID // is something other than vmIntrinsics::_none. @@ -253,6 +263,10 @@ KlassHandle _target_klass; Thread* _thread; + // Values used by the compiler. + static jvalue zero_jvalue; + static jvalue one_jvalue; + // Fake constant pool entry. class ConstantValue { private: @@ -417,7 +431,7 @@ methodHandle get_method_oop(TRAPS) const; public: - MethodHandleCompiler(Handle root, methodHandle call_method, int invoke_count, bool for_invokedynamic, TRAPS); + MethodHandleCompiler(Handle root, methodHandle callee, int invoke_count, bool for_invokedynamic, TRAPS); // Compile the given MH chain into bytecode. methodHandle compile(TRAPS); diff -r 2f17eb233d13 -r fabcf26ee72f src/share/vm/prims/methodHandles.cpp --- a/src/share/vm/prims/methodHandles.cpp Thu May 12 10:33:17 2011 -0700 +++ b/src/share/vm/prims/methodHandles.cpp Thu May 12 14:04:48 2011 -0700 @@ -1099,6 +1099,14 @@ return Klass::cast(SystemDictionary::Object_klass())->java_mirror(); } +bool MethodHandles::is_float_fixed_reinterpretation_cast(BasicType src, BasicType dst) { + if (src == T_FLOAT) return dst == T_INT; + if (src == T_INT) return dst == T_FLOAT; + if (src == T_DOUBLE) return dst == T_LONG; + if (src == T_LONG) return dst == T_DOUBLE; + return false; +} + bool MethodHandles::same_basic_type_for_arguments(BasicType src, BasicType dst, bool raw, @@ -1125,10 +1133,8 @@ return true; // remaining case: byte fits in short } // allow float/fixed reinterpretation casts - if (src == T_FLOAT) return dst == T_INT; - if (src == T_INT) return dst == T_FLOAT; - if (src == T_DOUBLE) return dst == T_LONG; - if (src == T_LONG) return dst == T_DOUBLE; + if (is_float_fixed_reinterpretation_cast(src, dst)) + return true; return false; } @@ -1399,7 +1405,7 @@ int argnum, bool raw) { const char* err = NULL; - bool for_return = (argnum < 0); + const bool for_return = (argnum < 0); // just in case: if (src_type == T_ARRAY) src_type = T_OBJECT; @@ -1408,17 +1414,17 @@ // Produce some nice messages if VerifyMethodHandles is turned on: if (!same_basic_type_for_arguments(src_type, dst_type, raw, for_return)) { if (src_type == T_OBJECT) { - if (raw && dst_type == T_INT && is_always_null_type(src_klass)) - return NULL; // OK to convert a null pointer to a garbage int - err = ((argnum >= 0) + if (raw && is_java_primitive(dst_type)) + return NULL; // ref-to-prim discards ref and returns zero + err = (!for_return ? "type mismatch: passing a %s for method argument #%d, which expects primitive %s" : "type mismatch: returning a %s, but caller expects primitive %s"); } else if (dst_type == T_OBJECT) { - err = ((argnum >= 0) + err = (!for_return ? "type mismatch: passing a primitive %s for method argument #%d, which expects %s" : "type mismatch: returning a primitive %s, but caller expects %s"); } else { - err = ((argnum >= 0) + err = (!for_return ? "type mismatch: passing a %s for method argument #%d, which expects %s" : "type mismatch: returning a %s, but caller expects %s"); } @@ -1427,11 +1433,11 @@ if (!class_cast_needed(dst_klass, src_klass)) { if (raw) return NULL; // reverse cast is OK; the MH target is trusted to enforce it - err = ((argnum >= 0) + err = (!for_return ? "cast required: passing a %s for method argument #%d, which expects %s" : "cast required: returning a %s, but caller expects %s"); } else { - err = ((argnum >= 0) + err = (!for_return ? "reference mismatch: passing a %s for method argument #%d, which expects %s" : "reference mismatch: returning a %s, but caller expects %s"); } @@ -1452,7 +1458,7 @@ size_t msglen = strlen(err) + strlen(src_name) + strlen(dst_name) + (argnum < 10 ? 1 : 11); char* msg = NEW_RESOURCE_ARRAY(char, msglen + 1); - if (argnum >= 0) { + if (!for_return) { assert(strstr(err, "%d") != NULL, ""); jio_snprintf(msg, msglen, err, src_name, argnum, dst_name); } else { @@ -2180,9 +2186,10 @@ } void MethodHandles::init_AdapterMethodHandle(Handle mh, Handle target, int argnum, TRAPS) { - int argslot = java_lang_invoke_AdapterMethodHandle::vmargslot(mh()); - jint conversion = java_lang_invoke_AdapterMethodHandle::conversion(mh()); - jint conv_op = adapter_conversion_op(conversion); + Handle argument = java_lang_invoke_AdapterMethodHandle::argument(mh()); + int argslot = java_lang_invoke_AdapterMethodHandle::vmargslot(mh()); + jint conversion = java_lang_invoke_AdapterMethodHandle::conversion(mh()); + jint conv_op = adapter_conversion_op(conversion); // adjust the adapter code to the internal EntryKind enumeration: EntryKind ek_orig = adapter_entry_kind(conv_op); @@ -2241,7 +2248,7 @@ } else if (src == T_DOUBLE && dest == T_FLOAT) { ek_opt = _adapter_opt_d2f; } else { - assert(false, ""); + goto throw_not_impl; // runs user code, hence could block } break; case 1 *4+ 2: @@ -2250,11 +2257,11 @@ } else if (src == T_FLOAT && dest == T_DOUBLE) { ek_opt = _adapter_opt_f2d; } else { - assert(false, ""); + goto throw_not_impl; // runs user code, hence could block } break; default: - assert(false, ""); + goto throw_not_impl; // runs user code, hence could block break; } } @@ -2271,7 +2278,7 @@ ek_opt = _adapter_opt_unboxl; break; default: - assert(false, ""); + goto throw_not_impl; break; } } @@ -2284,6 +2291,9 @@ vminfo = argslot; ek_opt = _adapter_opt_collect_ref; ensure_vmlayout_field(target, CHECK); + // for MethodHandleWalk: + if (java_lang_invoke_AdapterMethodHandle::is_instance(argument())) + ensure_vmlayout_field(argument, CHECK); if (!OptimizeMethodHandles) break; switch (type2size[src]) { case 1: @@ -2311,7 +2321,7 @@ ek_opt = _adapter_opt_collect_2_ref; break; default: - assert(false, ""); + goto throw_not_impl; break; } } @@ -2335,7 +2345,7 @@ rotate > 0 ? _adapter_opt_rot_2_up : _adapter_opt_rot_2_down); break; default: - assert(false, ""); + goto throw_not_impl; break; } } @@ -2402,12 +2412,11 @@ case _adapter_collect_args: { assert(UseRicochetFrames, "else don't come here"); - int elem_slots = argument_slot_count( - java_lang_invoke_MethodHandle::type( - java_lang_invoke_AdapterMethodHandle::argument(mh()) ) ); + int elem_slots = argument_slot_count(java_lang_invoke_MethodHandle::type(argument())); // vminfo will be the location to insert the return value vminfo = argslot; ensure_vmlayout_field(target, CHECK); + ensure_vmlayout_field(argument, CHECK); // general case: switch (dest) { @@ -2472,12 +2481,11 @@ case _adapter_fold_args: { assert(UseRicochetFrames, "else don't come here"); - int elem_slots = argument_slot_count( - java_lang_invoke_MethodHandle::type( - java_lang_invoke_AdapterMethodHandle::argument(mh()) ) ); + int elem_slots = argument_slot_count(java_lang_invoke_MethodHandle::type(argument())); // vminfo will be the location to insert the return value vminfo = argslot + elem_slots; ensure_vmlayout_field(target, CHECK); + ensure_vmlayout_field(argument, CHECK); switch (dest) { default : if (!is_subword_type(dest)) goto throw_not_impl; @@ -2527,15 +2535,31 @@ break; } - if (err != NULL && (vminfo & CONV_VMINFO_MASK) != vminfo) { + if (err == NULL && (vminfo & CONV_VMINFO_MASK) != vminfo) { // should not happen, since vminfo is used to encode arg/slot indexes < 255 err = "vminfo overflow"; } - if (err != NULL && !have_entry(ek_opt)) { + if (err == NULL && !have_entry(ek_opt)) { err = "adapter stub for this kind of method handle is missing"; } + if (err == NULL && ek_opt == ek_orig) { + switch (ek_opt) { + case _adapter_prim_to_prim: + case _adapter_ref_to_prim: + case _adapter_prim_to_ref: + case _adapter_swap_args: + case _adapter_rot_args: + case _adapter_collect_args: + case _adapter_fold_args: + case _adapter_spread_args: + // should be handled completely by optimized cases; see above + err = "init_AdapterMethodHandle should not issue this"; + break; + } + } + if (err != NULL) { throw_InternalError_for_bad_conversion(conversion, err, THREAD); return; diff -r 2f17eb233d13 -r fabcf26ee72f src/share/vm/prims/methodHandles.hpp --- a/src/share/vm/prims/methodHandles.hpp Thu May 12 10:33:17 2011 -0700 +++ b/src/share/vm/prims/methodHandles.hpp Thu May 12 14:04:48 2011 -0700 @@ -698,6 +698,8 @@ KlassHandle receiver_klass, TRAPS); +public: + static bool is_float_fixed_reinterpretation_cast(BasicType src, BasicType dst); static bool same_basic_type_for_arguments(BasicType src, BasicType dst, bool raw = false, bool for_return = false);