# HG changeset patch # User twisti # Date 1262626688 -3600 # Node ID 55dfb20908d0ba3532d7f6c5461eeb0b0fe38159 # Parent 973da517fcec4ab7dadb1da5e2658f74ae5e4c9b 6893081: method handle & invokedynamic code needs additional cleanup (post 6815692, 6858164) Summary: During the work for 6829187 we have fixed a number of basic bugs which are logically grouped with 6815692 and 6858164 but which must be reviewed and pushed separately. Reviewed-by: kvn, never diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/cpu/x86/vm/frame_x86.cpp --- a/hotspot/src/cpu/x86/vm/frame_x86.cpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/cpu/x86/vm/frame_x86.cpp Mon Jan 04 18:38:08 2010 +0100 @@ -330,6 +330,14 @@ // This is the sp before any possible extension (adapter/locals). intptr_t* unextended_sp = interpreter_frame_sender_sp(); + address sender_pc = this->sender_pc(); + CodeBlob* sender_cb = CodeCache::find_blob_unsafe(sender_pc); + assert(sender_cb, "sanity"); + nmethod* sender_nm = sender_cb->as_nmethod_or_null(); + if (sender_nm != NULL && sender_nm->is_method_handle_return(sender_pc)) { + unextended_sp = (intptr_t*) at(link_offset); + } + // The interpreter and compiler(s) always save EBP/RBP in a known // location on entry. We must record where that location is // so this if EBP/RBP was live on callout from c2 we can find @@ -352,7 +360,7 @@ #endif // AMD64 } #endif /* COMPILER2 */ - return frame(sp, unextended_sp, link(), sender_pc()); + return frame(sp, unextended_sp, link(), sender_pc); } @@ -375,6 +383,18 @@ intptr_t *saved_fp = (intptr_t*)*(sender_sp - frame::sender_sp_offset); + intptr_t* unextended_sp = sender_sp; + // If we are returning to a compiled method handle call site, + // the saved_fp will in fact be a saved value of the unextended SP. + // The simplest way to tell whether we are returning to such a call + // site is as follows: + CodeBlob* sender_cb = CodeCache::find_blob_unsafe(sender_pc); + assert(sender_cb, "sanity"); + nmethod* sender_nm = sender_cb->as_nmethod_or_null(); + if (sender_nm != NULL && sender_nm->is_method_handle_return(sender_pc)) { + unextended_sp = saved_fp; + } + if (map->update_map()) { // Tell GC to use argument oopmaps for some runtime stubs that need it. // For C1, the runtime stub might not have oop maps, so set this flag @@ -399,7 +419,7 @@ } assert(sender_sp != sp(), "must have changed"); - return frame(sender_sp, saved_fp, sender_pc); + return frame(sender_sp, unextended_sp, saved_fp, sender_pc); } frame frame::sender(RegisterMap* map) const { diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/cpu/x86/vm/methodHandles_x86.cpp --- a/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp Mon Jan 04 18:38:08 2010 +0100 @@ -65,9 +65,9 @@ // Verify that argslot lies within (rsp, rbp]. Label L_ok, L_bad; __ cmpptr(rax_argslot, rbp); - __ jcc(Assembler::above, L_bad); + __ jccb(Assembler::above, L_bad); __ cmpptr(rsp, rax_argslot); - __ jcc(Assembler::below, L_ok); + __ jccb(Assembler::below, L_ok); __ bind(L_bad); __ stop(error_message); __ bind(L_ok); @@ -136,9 +136,9 @@ if (arg_slots.is_register()) { Label L_ok, L_bad; __ cmpptr(arg_slots.as_register(), (int32_t) NULL_WORD); - __ jcc(Assembler::greater, L_bad); + __ jccb(Assembler::greater, L_bad); __ testl(arg_slots.as_register(), -stack_move_unit() - 1); - __ jcc(Assembler::zero, L_ok); + __ jccb(Assembler::zero, L_ok); __ bind(L_bad); __ stop("assert arg_slots <= 0 and clear low bits"); __ bind(L_ok); @@ -173,7 +173,7 @@ __ movptr(Address(rdx_temp, arg_slots, Address::times_ptr), rbx_temp); __ addptr(rdx_temp, wordSize); __ cmpptr(rdx_temp, rax_argslot); - __ jcc(Assembler::less, loop); + __ jccb(Assembler::less, loop); } // Now move the argslot down, to point to the opened-up space. @@ -211,9 +211,9 @@ Label L_ok, L_bad; __ lea(rbx_temp, Address(rax_argslot, arg_slots, Address::times_ptr)); __ cmpptr(rbx_temp, rbp); - __ jcc(Assembler::above, L_bad); + __ jccb(Assembler::above, L_bad); __ cmpptr(rsp, rax_argslot); - __ jcc(Assembler::below, L_ok); + __ jccb(Assembler::below, L_ok); __ bind(L_bad); __ stop("deleted argument(s) must fall within current frame"); __ bind(L_ok); @@ -221,9 +221,9 @@ if (arg_slots.is_register()) { Label L_ok, L_bad; __ cmpptr(arg_slots.as_register(), (int32_t) NULL_WORD); - __ jcc(Assembler::less, L_bad); + __ jccb(Assembler::less, L_bad); __ testl(arg_slots.as_register(), -stack_move_unit() - 1); - __ jcc(Assembler::zero, L_ok); + __ jccb(Assembler::zero, L_ok); __ bind(L_bad); __ stop("assert arg_slots >= 0 and clear low bits"); __ bind(L_ok); @@ -258,7 +258,7 @@ __ movptr(Address(rdx_temp, arg_slots, Address::times_ptr), rbx_temp); __ addptr(rdx_temp, -wordSize); __ cmpptr(rdx_temp, rsp); - __ jcc(Assembler::greaterEqual, loop); + __ jccb(Assembler::greaterEqual, loop); } // Now move the argslot up, to point to the just-copied block. @@ -384,11 +384,11 @@ // FIXME: fill in _raise_exception_method with a suitable sun.dyn method __ movptr(rbx_method, ExternalAddress((address) &_raise_exception_method)); __ testptr(rbx_method, rbx_method); - __ jcc(Assembler::zero, no_method); + __ jccb(Assembler::zero, no_method); int jobject_oop_offset = 0; __ movptr(rbx_method, Address(rbx_method, jobject_oop_offset)); // dereference the jobject __ testptr(rbx_method, rbx_method); - __ jcc(Assembler::zero, no_method); + __ jccb(Assembler::zero, no_method); __ verify_oop(rbx_method); __ push(rdi_pc); // and restore caller PC __ jmp(rbx_method_fie); @@ -535,16 +535,15 @@ if (arg_type == T_OBJECT) { __ movptr(Address(rax_argslot, 0), rbx_temp); } else { - __ load_sized_value(rbx_temp, prim_value_addr, + __ load_sized_value(rdx_temp, prim_value_addr, type2aelembytes(arg_type), is_signed_subword_type(arg_type)); - __ movptr(Address(rax_argslot, 0), rbx_temp); + __ movptr(Address(rax_argslot, 0), rdx_temp); #ifndef _LP64 if (arg_slots == 2) { - __ movl(rbx_temp, prim_value_addr.plus_disp(wordSize)); - __ movl(Address(rax_argslot, Interpreter::stackElementSize()), rbx_temp); + __ movl(rdx_temp, prim_value_addr.plus_disp(wordSize)); + __ movl(Address(rax_argslot, Interpreter::stackElementSize()), rdx_temp); } #endif //_LP64 - break; } if (direct_to_method) { @@ -586,7 +585,7 @@ Label done; __ movptr(rdx_temp, vmarg); __ testl(rdx_temp, rdx_temp); - __ jcc(Assembler::zero, done); // no cast if null + __ jccb(Assembler::zero, done); // no cast if null __ load_klass(rdx_temp, rdx_temp); // live at this point: @@ -677,24 +676,24 @@ // (now we are done with the old MH) // original 32-bit vmdata word must be of this form: - // | MBZ:16 | signBitCount:8 | srcDstTypes:8 | conversionOp:8 | - __ xchgl(rcx, rbx_vminfo); // free rcx for shifts + // | MBZ:6 | signBitCount:8 | srcDstTypes:8 | conversionOp:8 | + __ xchgptr(rcx, rbx_vminfo); // free rcx for shifts __ shll(rdx_temp /*, rcx*/); Label zero_extend, done; __ testl(rcx, CONV_VMINFO_SIGN_FLAG); - __ jcc(Assembler::zero, zero_extend); + __ jccb(Assembler::zero, zero_extend); // this path is taken for int->byte, int->short __ sarl(rdx_temp /*, rcx*/); - __ jmp(done); + __ jmpb(done); __ bind(zero_extend); // this is taken for int->char __ shrl(rdx_temp /*, rcx*/); __ bind(done); - __ movptr(vmarg, rdx_temp); - __ xchgl(rcx, rbx_vminfo); // restore rcx_recv + __ movl(vmarg, rdx_temp); + __ xchgptr(rcx, rbx_vminfo); // restore rcx_recv __ jump_to_method_handle_entry(rcx_recv, rdx_temp); } @@ -863,7 +862,7 @@ // Verify that argslot > destslot, by at least swap_bytes. Label L_ok; __ cmpptr(rax_argslot, rbx_destslot); - __ jcc(Assembler::aboveEqual, L_ok); + __ jccb(Assembler::aboveEqual, L_ok); __ stop("source must be above destination (upward rotation)"); __ bind(L_ok); } @@ -879,7 +878,7 @@ __ movptr(Address(rax_argslot, swap_bytes), rdx_temp); __ addptr(rax_argslot, -wordSize); __ cmpptr(rax_argslot, rbx_destslot); - __ jcc(Assembler::aboveEqual, loop); + __ jccb(Assembler::aboveEqual, loop); } else { __ addptr(rax_argslot, swap_bytes); #ifdef ASSERT @@ -887,7 +886,7 @@ // Verify that argslot < destslot, by at least swap_bytes. Label L_ok; __ cmpptr(rax_argslot, rbx_destslot); - __ jcc(Assembler::belowEqual, L_ok); + __ jccb(Assembler::belowEqual, L_ok); __ stop("source must be below destination (downward rotation)"); __ bind(L_ok); } @@ -903,7 +902,7 @@ __ movptr(Address(rax_argslot, -swap_bytes), rdx_temp); __ addptr(rax_argslot, wordSize); __ cmpptr(rax_argslot, rbx_destslot); - __ jcc(Assembler::belowEqual, loop); + __ jccb(Assembler::belowEqual, loop); } // pop the original first chunk into the destination slot, now free @@ -969,7 +968,7 @@ __ addptr(rax_argslot, wordSize); __ addptr(rdx_newarg, wordSize); __ cmpptr(rdx_newarg, rbx_oldarg); - __ jcc(Assembler::less, loop); + __ jccb(Assembler::less, loop); __ pop(rdi); // restore temp @@ -1121,7 +1120,7 @@ } __ addptr(rax_argslot, Interpreter::stackElementSize()); __ cmpptr(rax_argslot, rdx_argslot_limit); - __ jcc(Assembler::less, loop); + __ jccb(Assembler::less, loop); } else if (length_constant == 0) { __ bind(skip_array_check); // nothing to copy diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/cpu/x86/vm/runtime_x86_32.cpp --- a/hotspot/src/cpu/x86/vm/runtime_x86_32.cpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/cpu/x86/vm/runtime_x86_32.cpp Mon Jan 04 18:38:08 2010 +0100 @@ -43,11 +43,11 @@ // This code is entered with a jmp. // // Arguments: -// rax,: exception oop +// rax: exception oop // rdx: exception pc // // Results: -// rax,: exception oop +// rax: exception oop // rdx: exception pc in caller or ??? // destination: exception handler of caller // @@ -113,17 +113,17 @@ __ addptr(rsp, return_off * wordSize); // Epilog! __ pop(rdx); // Exception pc + // rax: exception handler for given - // rax,: exception handler for given + // Restore SP from BP if the exception PC is a MethodHandle call. + __ cmpl(Address(rcx, JavaThread::is_method_handle_exception_offset()), 0); + __ cmovptr(Assembler::notEqual, rsp, rbp); // We have a handler in rax, (could be deopt blob) // rdx - throwing pc, deopt blob will need it. __ push(rax); - // rcx contains handler address - - __ get_thread(rcx); // TLS // Get the exception __ movptr(rax, Address(rcx, JavaThread::exception_oop_offset())); // Get the exception pc in case we are deoptimized @@ -137,7 +137,7 @@ __ pop(rcx); - // rax,: exception oop + // rax: exception oop // rcx: exception handler // rdx: exception pc __ jmp (rcx); diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Mon Jan 04 18:38:08 2010 +0100 @@ -638,6 +638,10 @@ __ movptr(rax, Address(rsp, 0)); + // Must preserve original SP for loading incoming arguments because + // we need to align the outgoing SP for compiled code. + __ movptr(r11, rsp); + // Cut-out for having no stack args. Since up to 2 int/oop args are passed // in registers, we will occasionally have no stack args. int comp_words_on_stack = 0; @@ -661,6 +665,10 @@ // as far as the placement of the call instruction __ push(rax); + // Put saved SP in another register + const Register saved_sp = rax; + __ movptr(saved_sp, r11); + // Will jump to the compiled code just as if compiled code was doing it. // Pre-load the register-jump target early, to schedule it better. __ movptr(r11, Address(rbx, in_bytes(methodOopDesc::from_compiled_offset()))); @@ -680,11 +688,7 @@ assert(!regs[i].second()->is_valid() || regs[i].first()->next() == regs[i].second(), "scrambled load targets?"); // Load in argument order going down. - // int ld_off = (total_args_passed + comp_words_on_stack -i)*wordSize; - // base ld_off on r13 (sender_sp) as the stack alignment makes offsets from rsp - // unpredictable - int ld_off = ((total_args_passed - 1) - i)*Interpreter::stackElementSize(); - + int ld_off = (total_args_passed - i)*Interpreter::stackElementSize() + Interpreter::value_offset_in_bytes(); // Point to interpreter value (vs. tag) int next_off = ld_off - Interpreter::stackElementSize(); // @@ -699,10 +703,14 @@ if (r_1->is_stack()) { // Convert stack slot to an SP offset (+ wordSize to account for return address ) int st_off = regs[i].first()->reg2stack()*VMRegImpl::stack_slot_size + wordSize; + + // We can use r13 as a temp here because compiled code doesn't need r13 as an input + // and if we end up going thru a c2i because of a miss a reasonable value of r13 + // will be generated. if (!r_2->is_valid()) { // sign extend??? - __ movl(rax, Address(r13, ld_off)); - __ movptr(Address(rsp, st_off), rax); + __ movl(r13, Address(saved_sp, ld_off)); + __ movptr(Address(rsp, st_off), r13); } else { // // We are using two optoregs. This can be either T_OBJECT, T_ADDRESS, T_LONG, or T_DOUBLE @@ -715,9 +723,9 @@ // ld_off is MSW so get LSW const int offset = (sig_bt[i]==T_LONG||sig_bt[i]==T_DOUBLE)? next_off : ld_off; - __ movq(rax, Address(r13, offset)); + __ movq(r13, Address(saved_sp, offset)); // st_off is LSW (i.e. reg.first()) - __ movq(Address(rsp, st_off), rax); + __ movq(Address(rsp, st_off), r13); } } else if (r_1->is_Register()) { // Register argument Register r = r_1->as_Register(); @@ -732,16 +740,16 @@ next_off : ld_off; // this can be a misaligned move - __ movq(r, Address(r13, offset)); + __ movq(r, Address(saved_sp, offset)); } else { // sign extend and use a full word? - __ movl(r, Address(r13, ld_off)); + __ movl(r, Address(saved_sp, ld_off)); } } else { if (!r_2->is_valid()) { - __ movflt(r_1->as_XMMRegister(), Address(r13, ld_off)); + __ movflt(r_1->as_XMMRegister(), Address(saved_sp, ld_off)); } else { - __ movdbl(r_1->as_XMMRegister(), Address(r13, next_off)); + __ movdbl(r_1->as_XMMRegister(), Address(saved_sp, next_off)); } } } @@ -3319,6 +3327,10 @@ // rax: exception handler + // Restore SP from BP if the exception PC is a MethodHandle call. + __ cmpl(Address(r15_thread, JavaThread::is_method_handle_exception_offset()), 0); + __ cmovptr(Assembler::notEqual, rsp, rbp); + // We have a handler in rax (could be deopt blob). __ mov(r8, rax); diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp --- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Mon Jan 04 18:38:08 2010 +0100 @@ -1488,7 +1488,10 @@ if (interpreter_frame != NULL) { #ifdef ASSERT - assert(caller->unextended_sp() == interpreter_frame->interpreter_frame_sender_sp(), "Frame not properly walkable"); + if (!EnableMethodHandles) + // @@@ FIXME: Should we correct interpreter_frame_sender_sp in the calling sequences? + // Probably, since deoptimization doesn't work yet. + assert(caller->unextended_sp() == interpreter_frame->interpreter_frame_sender_sp(), "Frame not properly walkable"); assert(caller->sp() == interpreter_frame->sender_sp(), "Frame not properly walkable(2)"); #endif diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp --- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Mon Jan 04 18:38:08 2010 +0100 @@ -449,8 +449,12 @@ __ addptr(rax, stack_base); __ subptr(rax, stack_size); + // Use the maximum number of pages we might bang. + const int max_pages = StackShadowPages > (StackRedPages+StackYellowPages) ? StackShadowPages : + (StackRedPages+StackYellowPages); + // add in the red and yellow zone sizes - __ addptr(rax, (StackRedPages + StackYellowPages) * page_size); + __ addptr(rax, max_pages * page_size); // check against the current stack bottom __ cmpptr(rsp, rax); @@ -1502,8 +1506,10 @@ tempcount* Interpreter::stackElementWords() + popframe_extra_args; if (interpreter_frame != NULL) { #ifdef ASSERT - assert(caller->unextended_sp() == interpreter_frame->interpreter_frame_sender_sp(), - "Frame not properly walkable"); + if (!EnableMethodHandles) + // @@@ FIXME: Should we correct interpreter_frame_sender_sp in the calling sequences? + // Probably, since deoptimization doesn't work yet. + assert(caller->unextended_sp() == interpreter_frame->interpreter_frame_sender_sp(), "Frame not properly walkable"); assert(caller->sp() == interpreter_frame->sender_sp(), "Frame not properly walkable(2)"); #endif diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/share/vm/c1/c1_IR.hpp --- a/hotspot/src/share/vm/c1/c1_IR.hpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/share/vm/c1/c1_IR.hpp Mon Jan 04 18:38:08 2010 +0100 @@ -251,8 +251,9 @@ DebugToken* expvals = recorder->create_scope_values(expressions()); DebugToken* monvals = recorder->create_monitor_values(monitors()); // reexecute allowed only for the topmost frame - bool reexecute = topmost ? should_reexecute() : false; - recorder->describe_scope(pc_offset, scope()->method(), bci(), reexecute, locvals, expvals, monvals); + bool reexecute = topmost ? should_reexecute() : false; + bool is_method_handle_invoke = false; + recorder->describe_scope(pc_offset, scope()->method(), bci(), reexecute, is_method_handle_invoke, locvals, expvals, monvals); } }; diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/share/vm/ci/ciStreams.cpp --- a/hotspot/src/share/vm/ci/ciStreams.cpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/share/vm/ci/ciStreams.cpp Mon Jan 04 18:38:08 2010 +0100 @@ -339,9 +339,9 @@ // for checking linkability when retrieving the associated method. ciKlass* ciBytecodeStream::get_declared_method_holder() { bool ignore; - // report as Dynamic for invokedynamic, which is syntactically classless + // report as InvokeDynamic for invokedynamic, which is syntactically classless if (cur_bc() == Bytecodes::_invokedynamic) - return CURRENT_ENV->get_klass_by_name(_holder, ciSymbol::java_dyn_Dynamic(), false); + return CURRENT_ENV->get_klass_by_name(_holder, ciSymbol::java_dyn_InvokeDynamic(), false); return CURRENT_ENV->get_klass_by_index(_holder, get_method_holder_index(), ignore); } diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/share/vm/classfile/javaClasses.hpp --- a/hotspot/src/share/vm/classfile/javaClasses.hpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp Mon Jan 04 18:38:08 2010 +0100 @@ -1084,6 +1084,14 @@ static oop vmmethod(oop site); static void set_vmmethod(oop site, oop ref); + // Testers + static bool is_subclass(klassOop klass) { + return Klass::cast(klass)->is_subclass_of(SystemDictionary::CallSite_klass()); + } + static bool is_instance(oop obj) { + return obj != NULL && is_subclass(obj->klass()); + } + // Accessors for code generation: static int target_offset_in_bytes() { return _target_offset; } static int type_offset_in_bytes() { return _type_offset; } diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/share/vm/classfile/systemDictionary.cpp --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp Mon Jan 04 18:38:08 2010 +0100 @@ -1984,7 +1984,7 @@ scan = WKID(meth_group_end+1); } WKID indy_group_start = WK_KLASS_ENUM_NAME(Linkage_klass); - WKID indy_group_end = WK_KLASS_ENUM_NAME(Dynamic_klass); + WKID indy_group_end = WK_KLASS_ENUM_NAME(InvokeDynamic_klass); initialize_wk_klasses_until(indy_group_start, scan, CHECK); if (EnableInvokeDynamic) { initialize_wk_klasses_through(indy_group_end, scan, CHECK); @@ -2340,6 +2340,8 @@ SymbolPropertyEntry* spe = invoke_method_table()->find_entry(index, hash, signature); if (spe == NULL || spe->property_oop() == NULL) { // Must create lots of stuff here, but outside of the SystemDictionary lock. + if (THREAD->is_Compiler_thread()) + return NULL; // do not attempt from within compiler Handle mt = compute_method_handle_type(signature(), class_loader, protection_domain, CHECK_NULL); diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/share/vm/classfile/systemDictionary.hpp --- a/hotspot/src/share/vm/classfile/systemDictionary.hpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp Mon Jan 04 18:38:08 2010 +0100 @@ -144,7 +144,7 @@ template(WrongMethodTypeException_klass, java_dyn_WrongMethodTypeException, Opt) \ template(Linkage_klass, java_dyn_Linkage, Opt) \ template(CallSite_klass, java_dyn_CallSite, Opt) \ - template(Dynamic_klass, java_dyn_Dynamic, Opt) \ + template(InvokeDynamic_klass, java_dyn_InvokeDynamic, Opt) \ /* Note: MethodHandle must be first, and Dynamic last in group */ \ \ template(vector_klass, java_util_Vector, Pre) \ diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/share/vm/classfile/vmSymbols.hpp --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp Mon Jan 04 18:38:08 2010 +0100 @@ -218,7 +218,7 @@ template(base_name, "base") \ \ /* Support for JSR 292 & invokedynamic (JDK 1.7 and above) */ \ - template(java_dyn_Dynamic, "java/dyn/Dynamic") \ + template(java_dyn_InvokeDynamic, "java/dyn/InvokeDynamic") \ template(java_dyn_Linkage, "java/dyn/Linkage") \ template(java_dyn_CallSite, "java/dyn/CallSite") \ template(java_dyn_MethodHandle, "java/dyn/MethodHandle") \ diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/share/vm/code/codeBlob.hpp --- a/hotspot/src/share/vm/code/codeBlob.hpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/share/vm/code/codeBlob.hpp Mon Jan 04 18:38:08 2010 +0100 @@ -1,5 +1,5 @@ /* - * Copyright 1998-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -102,6 +102,9 @@ virtual bool is_compiled_by_c2() const { return false; } virtual bool is_compiled_by_c1() const { return false; } + // Casting + nmethod* as_nmethod_or_null() { return is_nmethod() ? (nmethod*) this : NULL; } + // Boundaries address header_begin() const { return (address) this; } address header_end() const { return ((address) this) + _header_size; }; diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/share/vm/code/debugInfoRec.cpp --- a/hotspot/src/share/vm/code/debugInfoRec.cpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/share/vm/code/debugInfoRec.cpp Mon Jan 04 18:38:08 2010 +0100 @@ -281,6 +281,7 @@ ciMethod* method, int bci, bool reexecute, + bool is_method_handle_invoke, DebugToken* locals, DebugToken* expressions, DebugToken* monitors) { @@ -292,8 +293,9 @@ int stream_offset = stream()->position(); last_pd->set_scope_decode_offset(stream_offset); - // Record reexecute bit into pcDesc + // Record flags into pcDesc. last_pd->set_should_reexecute(reexecute); + last_pd->set_is_method_handle_invoke(is_method_handle_invoke); // serialize sender stream offest stream()->write_int(sender_stream_offset); diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/share/vm/code/debugInfoRec.hpp --- a/hotspot/src/share/vm/code/debugInfoRec.hpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/share/vm/code/debugInfoRec.hpp Mon Jan 04 18:38:08 2010 +0100 @@ -88,6 +88,7 @@ ciMethod* method, int bci, bool reexecute, + bool is_method_handle_invoke = false, DebugToken* locals = NULL, DebugToken* expressions = NULL, DebugToken* monitors = NULL); diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/share/vm/code/nmethod.cpp --- a/hotspot/src/share/vm/code/nmethod.cpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/share/vm/code/nmethod.cpp Mon Jan 04 18:38:08 2010 +0100 @@ -1763,6 +1763,14 @@ "must end with a sentinel"); #endif //ASSERT + // Search for MethodHandle invokes and tag the nmethod. + for (int i = 0; i < count; i++) { + if (pcs[i].is_method_handle_invoke()) { + set_has_method_handle_invokes(true); + break; + } + } + int size = count * sizeof(PcDesc); assert(scopes_pcs_size() >= size, "oob"); memcpy(scopes_pcs_begin(), pcs, size); @@ -2030,6 +2038,18 @@ // ----------------------------------------------------------------------------- +// MethodHandle + +bool nmethod::is_method_handle_return(address return_pc) { + if (!has_method_handle_invokes()) return false; + PcDesc* pd = pc_desc_at(return_pc); + if (pd == NULL) + return false; + return pd->is_method_handle_invoke(); +} + + +// ----------------------------------------------------------------------------- // Verification class VerifyOopsClosure: public OopClosure { diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/share/vm/code/nmethod.hpp --- a/hotspot/src/share/vm/code/nmethod.hpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/share/vm/code/nmethod.hpp Mon Jan 04 18:38:08 2010 +0100 @@ -81,18 +81,19 @@ struct nmFlags { friend class VMStructs; - unsigned int version:8; // version number (0 = first version) - unsigned int level:4; // optimization level - unsigned int age:4; // age (in # of sweep steps) + unsigned int version:8; // version number (0 = first version) + unsigned int level:4; // optimization level + unsigned int age:4; // age (in # of sweep steps) - unsigned int state:2; // {alive, zombie, unloaded) + unsigned int state:2; // {alive, zombie, unloaded) - unsigned int isUncommonRecompiled:1; // recompiled because of uncommon trap? - unsigned int isToBeRecompiled:1; // to be recompiled as soon as it matures - unsigned int hasFlushedDependencies:1; // Used for maintenance of dependencies - unsigned int markedForReclamation:1; // Used by NMethodSweeper + unsigned int isUncommonRecompiled:1; // recompiled because of uncommon trap? + unsigned int isToBeRecompiled:1; // to be recompiled as soon as it matures + unsigned int hasFlushedDependencies:1; // Used for maintenance of dependencies + unsigned int markedForReclamation:1; // Used by NMethodSweeper - unsigned int has_unsafe_access:1; // May fault due to unsafe access. + unsigned int has_unsafe_access:1; // May fault due to unsafe access. + unsigned int has_method_handle_invokes:1; // Has this method MethodHandle invokes? void clear(); }; @@ -409,6 +410,9 @@ bool has_unsafe_access() const { return flags.has_unsafe_access; } void set_has_unsafe_access(bool z) { flags.has_unsafe_access = z; } + bool has_method_handle_invokes() const { return flags.has_method_handle_invokes; } + void set_has_method_handle_invokes(bool z) { flags.has_method_handle_invokes = z; } + int level() const { return flags.level; } void set_level(int newLevel) { check_safepoint(); flags.level = newLevel; } @@ -541,6 +545,9 @@ address get_original_pc(const frame* fr) { return *orig_pc_addr(fr); } void set_original_pc(const frame* fr, address pc) { *orig_pc_addr(fr) = pc; } + // MethodHandle + bool is_method_handle_return(address return_pc); + // jvmti support: void post_compiled_method_load_event(); diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/share/vm/code/pcDesc.hpp --- a/hotspot/src/share/vm/code/pcDesc.hpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/share/vm/code/pcDesc.hpp Mon Jan 04 18:38:08 2010 +0100 @@ -38,6 +38,7 @@ int word; struct { unsigned int reexecute: 1; + unsigned int is_method_handle_invoke: 1; } bits; bool operator ==(const PcDescFlags& other) { return word == other.word; } } _flags; @@ -72,6 +73,9 @@ _flags == pd->_flags; } + bool is_method_handle_invoke() const { return _flags.bits.is_method_handle_invoke; } + void set_is_method_handle_invoke(bool z) { _flags.bits.is_method_handle_invoke = z; } + // Returns the real pc address real_pc(const nmethod* code) const; diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/share/vm/compiler/methodLiveness.cpp --- a/hotspot/src/share/vm/compiler/methodLiveness.cpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/share/vm/compiler/methodLiveness.cpp Mon Jan 04 18:38:08 2010 +0100 @@ -782,6 +782,7 @@ case Bytecodes::_invokespecial: case Bytecodes::_invokestatic: case Bytecodes::_invokeinterface: + case Bytecodes::_invokedynamic: case Bytecodes::_newarray: case Bytecodes::_anewarray: case Bytecodes::_checkcast: diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/share/vm/interpreter/bytecode.cpp --- a/hotspot/src/share/vm/interpreter/bytecode.cpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/share/vm/interpreter/bytecode.cpp Mon Jan 04 18:38:08 2010 +0100 @@ -102,7 +102,9 @@ KlassHandle resolved_klass; constantPoolHandle constants(THREAD, _method->constants()); - if (adjusted_invoke_code() != Bytecodes::_invokeinterface) { + if (adjusted_invoke_code() == Bytecodes::_invokedynamic) { + LinkResolver::resolve_dynamic_method(m, resolved_klass, constants, index(), CHECK_(methodHandle())); + } else if (adjusted_invoke_code() != Bytecodes::_invokeinterface) { LinkResolver::resolve_method(m, resolved_klass, constants, index(), CHECK_(methodHandle())); } else { LinkResolver::resolve_interface_method(m, resolved_klass, constants, index(), CHECK_(methodHandle())); diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/share/vm/interpreter/bytecode.hpp --- a/hotspot/src/share/vm/interpreter/bytecode.hpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/share/vm/interpreter/bytecode.hpp Mon Jan 04 18:38:08 2010 +0100 @@ -210,7 +210,8 @@ bool is_valid() const { return is_invokeinterface() || is_invokevirtual() || is_invokestatic() || - is_invokespecial(); } + is_invokespecial() || + is_invokedynamic(); } // Creation inline friend Bytecode_invoke* Bytecode_invoke_at(methodHandle method, int bci); diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/share/vm/interpreter/bytecodes.cpp --- a/hotspot/src/share/vm/interpreter/bytecodes.cpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/share/vm/interpreter/bytecodes.cpp Mon Jan 04 18:38:08 2010 +0100 @@ -357,7 +357,7 @@ def(_invokespecial , "invokespecial" , "bjj" , NULL , T_ILLEGAL, -1, true); def(_invokestatic , "invokestatic" , "bjj" , NULL , T_ILLEGAL, 0, true); def(_invokeinterface , "invokeinterface" , "bjj__", NULL , T_ILLEGAL, -1, true); - def(_invokedynamic , "invokedynamic" , "bjjjj", NULL , T_ILLEGAL, -1, true ); + def(_invokedynamic , "invokedynamic" , "bjjjj", NULL , T_ILLEGAL, 0, true ); def(_new , "new" , "bii" , NULL , T_OBJECT , 1, true ); def(_newarray , "newarray" , "bc" , NULL , T_OBJECT , 0, true ); def(_anewarray , "anewarray" , "bii" , NULL , T_OBJECT , 0, true ); diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/share/vm/interpreter/interpreter.cpp --- a/hotspot/src/share/vm/interpreter/interpreter.cpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/share/vm/interpreter/interpreter.cpp Mon Jan 04 18:38:08 2010 +0100 @@ -323,7 +323,7 @@ // (NOT needed for the old calling convension) if (!is_top_frame) { int index = Bytes::get_native_u4(bcp+1); - method->constants()->cache()->entry_at(index)->set_parameter_size(callee_parameters); + method->constants()->cache()->secondary_entry_at(index)->set_parameter_size(callee_parameters); } break; } diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/share/vm/interpreter/linkResolver.cpp --- a/hotspot/src/share/vm/interpreter/linkResolver.cpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp Mon Jan 04 18:38:08 2010 +0100 @@ -75,6 +75,8 @@ _selected_method = selected_method; _vtable_index = vtable_index; if (CompilationPolicy::mustBeCompiled(selected_method)) { + // This path is unusual, mostly used by the '-Xcomp' stress test mode. + // Note: with several active threads, the mustBeCompiled may be true // while canBeCompiled is false; remove assert // assert(CompilationPolicy::canBeCompiled(selected_method), "cannot compile"); @@ -82,6 +84,16 @@ // don't force compilation, resolve was on behalf of compiler return; } + if (instanceKlass::cast(selected_method->method_holder())->is_not_initialized()) { + // 'is_not_initialized' means not only '!is_initialized', but also that + // initialization has not been started yet ('!being_initialized') + // Do not force compilation of methods in uninitialized classes. + // Note that doing this would throw an assert later, + // in CompileBroker::compile_method. + // We sometimes use the link resolver to do reflective lookups + // even before classes are initialized. + return; + } CompileBroker::compile_method(selected_method, InvocationEntryBci, methodHandle(), 0, "mustBeCompiled", CHECK); } @@ -223,6 +235,18 @@ resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, CHECK); } +void LinkResolver::resolve_dynamic_method(methodHandle& resolved_method, KlassHandle& resolved_klass, constantPoolHandle pool, int index, TRAPS) { + // The class is java.dyn.MethodHandle + resolved_klass = SystemDictionaryHandles::MethodHandle_klass(); + + symbolHandle method_name = vmSymbolHandles::invoke_name(); + + symbolHandle method_signature(THREAD, pool->signature_ref_at(index)); + KlassHandle current_klass (THREAD, pool->pool_holder()); + + resolve_method(resolved_method, resolved_klass, method_name, method_signature, current_klass, true, CHECK); +} + void LinkResolver::resolve_interface_method(methodHandle& resolved_method, KlassHandle& resolved_klass, constantPoolHandle pool, int index, TRAPS) { // resolve klass diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/share/vm/interpreter/linkResolver.hpp --- a/hotspot/src/share/vm/interpreter/linkResolver.hpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/share/vm/interpreter/linkResolver.hpp Mon Jan 04 18:38:08 2010 +0100 @@ -133,6 +133,7 @@ // static resolving for all calls except interface calls static void resolve_method (methodHandle& method_result, KlassHandle& klass_result, constantPoolHandle pool, int index, TRAPS); + static void resolve_dynamic_method (methodHandle& resolved_method, KlassHandle& resolved_klass, constantPoolHandle pool, int index, TRAPS); static void resolve_interface_method(methodHandle& method_result, KlassHandle& klass_result, constantPoolHandle pool, int index, TRAPS); // runtime/static resolving for fields diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/share/vm/opto/doCall.cpp --- a/hotspot/src/share/vm/opto/doCall.cpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/share/vm/opto/doCall.cpp Mon Jan 04 18:38:08 2010 +0100 @@ -308,7 +308,7 @@ return true; } if (dest_method->is_method_handle_invoke() - && holder_klass->name() == ciSymbol::java_dyn_Dynamic()) { + && holder_klass->name() == ciSymbol::java_dyn_InvokeDynamic()) { // FIXME: NYI uncommon_trap(Deoptimization::Reason_unhandled, Deoptimization::Action_none, diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/share/vm/opto/output.cpp --- a/hotspot/src/share/vm/opto/output.cpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/share/vm/opto/output.cpp Mon Jan 04 18:38:08 2010 +0100 @@ -911,9 +911,10 @@ ciMethod* scope_method = method ? method : _method; // Describe the scope here assert(jvms->bci() >= InvocationEntryBci && jvms->bci() <= 0x10000, "must be a valid or entry BCI"); - assert(!jvms->should_reexecute() || depth==max_depth, "reexecute allowed only for the youngest"); + assert(!jvms->should_reexecute() || depth == max_depth, "reexecute allowed only for the youngest"); // Now we can describe the scope. - debug_info()->describe_scope(safepoint_pc_offset,scope_method,jvms->bci(),jvms->should_reexecute(),locvals,expvals,monvals); + bool is_method_handle_invoke = false; + debug_info()->describe_scope(safepoint_pc_offset, scope_method, jvms->bci(), jvms->should_reexecute(), is_method_handle_invoke, locvals, expvals, monvals); } // End jvms loop // Mark the end of the scope set. diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/share/vm/opto/runtime.cpp --- a/hotspot/src/share/vm/opto/runtime.cpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/share/vm/opto/runtime.cpp Mon Jan 04 18:38:08 2010 +0100 @@ -1,5 +1,5 @@ /* - * Copyright 1998-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -858,6 +858,9 @@ thread->set_exception_pc(pc); thread->set_exception_handler_pc(handler_address); thread->set_exception_stack_size(0); + + // Check if the exception PC is a MethodHandle call. + thread->set_is_method_handle_exception(nm->is_method_handle_return(pc)); } // Restore correct return pc. Was saved above. diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/share/vm/runtime/arguments.cpp --- a/hotspot/src/share/vm/runtime/arguments.cpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/share/vm/runtime/arguments.cpp Mon Jan 04 18:38:08 2010 +0100 @@ -2699,6 +2699,15 @@ } ScavengeRootsInCode = 1; } +#ifdef COMPILER2 + if (EnableInvokeDynamic && DoEscapeAnalysis) { + // TODO: We need to find rules for invokedynamic and EA. For now, + // simply disable EA by default. + if (FLAG_IS_DEFAULT(DoEscapeAnalysis)) { + DoEscapeAnalysis = false; + } + } +#endif if (PrintGCDetails) { // Turn on -verbose:gc options as well @@ -2722,6 +2731,15 @@ // Set flags based on ergonomics. set_ergonomics_flags(); +#ifdef _LP64 + // XXX JSR 292 currently does not support compressed oops. + if (EnableMethodHandles && UseCompressedOops) { + if (FLAG_IS_DEFAULT(UseCompressedOops) || FLAG_IS_ERGO(UseCompressedOops)) { + UseCompressedOops = false; + } + } +#endif // _LP64 + // Check the GC selections again. if (!check_gc_consistency()) { return JNI_EINVAL; diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/share/vm/runtime/sharedRuntime.cpp --- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp Mon Jan 04 18:38:08 2010 +0100 @@ -802,7 +802,7 @@ #ifdef ASSERT // Check that the receiver klass is of the right subtype and that it is initialized for virtual calls - if (bc != Bytecodes::_invokestatic) { + if (bc != Bytecodes::_invokestatic && bc != Bytecodes::_invokedynamic) { assert(receiver.not_null(), "should have thrown exception"); KlassHandle receiver_klass (THREAD, receiver->klass()); klassOop rk = constants->klass_ref_at(bytecode_index, CHECK_(nullHandle)); @@ -1027,7 +1027,16 @@ frame stub_frame = thread->last_frame(); assert(stub_frame.is_runtime_frame(), "sanity check"); frame caller_frame = stub_frame.sender(®_map); - if (caller_frame.is_interpreted_frame() || caller_frame.is_entry_frame() ) { + + // MethodHandle invokes don't have a CompiledIC and should always + // simply redispatch to the callee_target. + address sender_pc = caller_frame.pc(); + CodeBlob* sender_cb = caller_frame.cb(); + nmethod* sender_nm = sender_cb->as_nmethod_or_null(); + + if (caller_frame.is_interpreted_frame() || + caller_frame.is_entry_frame() || + (sender_nm != NULL && sender_nm->is_method_handle_return(sender_pc))) { methodOop callee = thread->callee_target(); guarantee(callee != NULL && callee->is_method(), "bad handshake"); thread->set_vm_result(callee); diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/share/vm/runtime/thread.cpp --- a/hotspot/src/share/vm/runtime/thread.cpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/share/vm/runtime/thread.cpp Mon Jan 04 18:38:08 2010 +0100 @@ -3055,6 +3055,12 @@ warning("java.lang.ArithmeticException has not been initialized"); warning("java.lang.StackOverflowError has not been initialized"); } + + if (EnableInvokeDynamic) { + // JSR 292: An intialized java.dyn.InvokeDynamic is required in + // the compiler. + initialize_class(vmSymbolHandles::java_dyn_InvokeDynamic(), CHECK_0); + } } // See : bugid 4211085. diff -r 973da517fcec -r 55dfb20908d0 hotspot/src/share/vm/runtime/thread.hpp --- a/hotspot/src/share/vm/runtime/thread.hpp Mon Jan 04 07:04:46 2010 -0800 +++ b/hotspot/src/share/vm/runtime/thread.hpp Mon Jan 04 18:38:08 2010 +0100 @@ -760,6 +760,7 @@ volatile address _exception_pc; // PC where exception happened volatile address _exception_handler_pc; // PC for handler of exception volatile int _exception_stack_size; // Size of frame where exception happened + volatile int _is_method_handle_exception; // True if the current exception PC is at a MethodHandle call. // support for compilation bool _is_compiling; // is true if a compilation is active inthis thread (one compilation per thread possible) @@ -1095,11 +1096,13 @@ int exception_stack_size() const { return _exception_stack_size; } address exception_pc() const { return _exception_pc; } address exception_handler_pc() const { return _exception_handler_pc; } + int is_method_handle_exception() const { return _is_method_handle_exception; } void set_exception_oop(oop o) { _exception_oop = o; } void set_exception_pc(address a) { _exception_pc = a; } void set_exception_handler_pc(address a) { _exception_handler_pc = a; } void set_exception_stack_size(int size) { _exception_stack_size = size; } + void set_is_method_handle_exception(int value) { _is_method_handle_exception = value; } // Stack overflow support inline size_t stack_available(address cur_sp); @@ -1173,6 +1176,7 @@ static ByteSize exception_pc_offset() { return byte_offset_of(JavaThread, _exception_pc ); } static ByteSize exception_handler_pc_offset() { return byte_offset_of(JavaThread, _exception_handler_pc); } static ByteSize exception_stack_size_offset() { return byte_offset_of(JavaThread, _exception_stack_size); } + static ByteSize is_method_handle_exception_offset() { return byte_offset_of(JavaThread, _is_method_handle_exception); } static ByteSize stack_guard_state_offset() { return byte_offset_of(JavaThread, _stack_guard_state ); } static ByteSize suspend_flags_offset() { return byte_offset_of(JavaThread, _suspend_flags ); }