# HG changeset patch # User twisti # Date 1347911878 25200 # Node ID a326d528f3e11ee315c4ff17348d2480f0b72924 # Parent 7fd047780d473ba2decf0a1b4c2f829ab1ce6d05 7196262: JSR 292: java/lang/invoke/PrivateInvokeTest.java fails on solaris-sparc Reviewed-by: kvn, jrose, bdelsart diff -r 7fd047780d47 -r a326d528f3e1 hotspot/src/cpu/sparc/vm/assembler_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp Fri Sep 14 22:00:41 2012 -0700 +++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp Mon Sep 17 12:57:58 2012 -0700 @@ -725,24 +725,6 @@ } -// Convert to C varargs format -void MacroAssembler::set_varargs( Argument inArg, Register d ) { - // spill register-resident args to their memory slots - // (SPARC calling convention requires callers to have already preallocated these) - // Note that the inArg might in fact be an outgoing argument, - // if a leaf routine or stub does some tricky argument shuffling. - // This routine must work even though one of the saved arguments - // is in the d register (e.g., set_varargs(Argument(0, false), O0)). - for (Argument savePtr = inArg; - savePtr.is_register(); - savePtr = savePtr.successor()) { - st_ptr(savePtr.as_register(), savePtr.address_in_frame()); - } - // return the address of the first memory slot - Address a = inArg.address_in_frame(); - add(a.base(), a.disp(), d); -} - // Conditional breakpoint (for assertion checks in assembly code) void MacroAssembler::breakpoint_trap(Condition c, CC cc) { trap(c, cc, G0, ST_RESERVED_FOR_USER_0); @@ -2943,6 +2925,20 @@ assert(itable_index.is_constant() || itable_index.as_register() == method_result, "caller must use same register for non-constant itable index as for method"); + Label L_no_such_interface_restore; + bool did_save = false; + if (scan_temp == noreg || sethi_temp == noreg) { + Register recv_2 = recv_klass->is_global() ? recv_klass : L0; + Register intf_2 = intf_klass->is_global() ? intf_klass : L1; + assert(method_result->is_global(), "must be able to return value"); + scan_temp = L2; + sethi_temp = L3; + save_frame_and_mov(0, recv_klass, recv_2, intf_klass, intf_2); + recv_klass = recv_2; + intf_klass = intf_2; + did_save = true; + } + // Compute start of first itableOffsetEntry (which is at the end of the vtable) int vtable_base = InstanceKlass::vtable_start_offset() * wordSize; int scan_step = itableOffsetEntry::size() * wordSize; @@ -2981,7 +2977,7 @@ // result = (klass + scan->offset() + itable_index); // } // } - Label search, found_method; + Label L_search, L_found_method; for (int peel = 1; peel >= 0; peel--) { // %%%% Could load both offset and interface in one ldx, if they were @@ -2991,23 +2987,23 @@ // Check that this entry is non-null. A null entry means that // the receiver class doesn't implement the interface, and wasn't the // same as when the caller was compiled. - bpr(Assembler::rc_z, false, Assembler::pn, method_result, L_no_such_interface); + bpr(Assembler::rc_z, false, Assembler::pn, method_result, did_save ? L_no_such_interface_restore : L_no_such_interface); delayed()->cmp(method_result, intf_klass); if (peel) { - brx(Assembler::equal, false, Assembler::pt, found_method); + brx(Assembler::equal, false, Assembler::pt, L_found_method); } else { - brx(Assembler::notEqual, false, Assembler::pn, search); + brx(Assembler::notEqual, false, Assembler::pn, L_search); // (invert the test to fall through to found_method...) } delayed()->add(scan_temp, scan_step, scan_temp); if (!peel) break; - bind(search); + bind(L_search); } - bind(found_method); + bind(L_found_method); // Got a hit. int ito_offset = itableOffsetEntry::offset_offset_in_bytes(); @@ -3015,6 +3011,18 @@ ito_offset -= scan_step; lduw(scan_temp, ito_offset, scan_temp); ld_ptr(recv_klass, scan_temp, method_result); + + if (did_save) { + Label L_done; + ba(L_done); + delayed()->restore(); + + bind(L_no_such_interface_restore); + ba(L_no_such_interface); + delayed()->restore(); + + bind(L_done); + } } diff -r 7fd047780d47 -r a326d528f3e1 hotspot/src/cpu/sparc/vm/assembler_sparc.hpp --- a/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp Fri Sep 14 22:00:41 2012 -0700 +++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp Mon Sep 17 12:57:58 2012 -0700 @@ -2428,9 +2428,6 @@ static void test(); #endif - // convert an incoming arglist to varargs format; put the pointer in d - void set_varargs( Argument a, Register d ); - int total_frame_size_in_bytes(int extraWords); // used when extraWords known statically diff -r 7fd047780d47 -r a326d528f3e1 hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp Fri Sep 14 22:00:41 2012 -0700 +++ b/hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp Mon Sep 17 12:57:58 2012 -0700 @@ -121,6 +121,7 @@ void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register method, Register target, Register temp, bool for_compiler_entry) { assert(method == G5_method, "interpreter calling convention"); + assert_different_registers(method, target, temp); if (!for_compiler_entry && JvmtiExport::can_post_interpreter_events()) { Label run_compiled_code; @@ -153,19 +154,19 @@ BLOCK_COMMENT("jump_to_lambda_form {"); // This is the initial entry point of a lazy method handle. // After type checking, it picks up the invoker from the LambdaForm. - assert_different_registers(recv, method_temp, temp2, temp3); + assert_different_registers(recv, method_temp, temp2); // temp3 is only passed on assert(method_temp == G5_method, "required register for loading method"); //NOT_PRODUCT({ FlagSetting fs(TraceMethodHandles, true); trace_method_handle(_masm, "LZMH"); }); // Load the invoker, as MH -> MH.form -> LF.vmentry __ verify_oop(recv); - __ load_heap_oop(Address(recv, NONZERO(java_lang_invoke_MethodHandle::form_offset_in_bytes())), method_temp); + __ load_heap_oop(Address(recv, NONZERO(java_lang_invoke_MethodHandle::form_offset_in_bytes())), method_temp); __ verify_oop(method_temp); - __ load_heap_oop(Address(method_temp, NONZERO(java_lang_invoke_LambdaForm::vmentry_offset_in_bytes())), method_temp); + __ load_heap_oop(Address(method_temp, NONZERO(java_lang_invoke_LambdaForm::vmentry_offset_in_bytes())), method_temp); __ verify_oop(method_temp); // the following assumes that a Method* is normally compressed in the vmtarget field: - __ ld_ptr(Address(method_temp, NONZERO(java_lang_invoke_MemberName::vmtarget_offset_in_bytes())), method_temp); + __ ld_ptr( Address(method_temp, NONZERO(java_lang_invoke_MemberName::vmtarget_offset_in_bytes())), method_temp); if (VerifyMethodHandles && !for_compiler_entry) { // make sure recv is already on stack @@ -303,25 +304,25 @@ Register member_reg, bool for_compiler_entry) { assert(is_signature_polymorphic(iid), "expected invoke iid"); - // temps used in this code are not used in *either* compiled or interpreted calling sequences Register temp1 = (for_compiler_entry ? G1_scratch : O1); - Register temp2 = (for_compiler_entry ? G4_scratch : O4); - Register temp3 = G3_scratch; - Register temp4 = (for_compiler_entry ? noreg : O2); + Register temp2 = (for_compiler_entry ? G3_scratch : O2); + Register temp3 = (for_compiler_entry ? G4_scratch : O3); + Register temp4 = (for_compiler_entry ? noreg : O4); if (for_compiler_entry) { assert(receiver_reg == (iid == vmIntrinsics::_linkToStatic ? noreg : O0), "only valid assignment"); - assert_different_registers(temp1, O0, O1, O2, O3, O4, O5); - assert_different_registers(temp2, O0, O1, O2, O3, O4, O5); - assert_different_registers(temp3, O0, O1, O2, O3, O4, O5); - assert_different_registers(temp4, O0, O1, O2, O3, O4, O5); + assert_different_registers(temp1, O0, O1, O2, O3, O4, O5); + assert_different_registers(temp2, O0, O1, O2, O3, O4, O5); + assert_different_registers(temp3, O0, O1, O2, O3, O4, O5); + assert_different_registers(temp4, O0, O1, O2, O3, O4, O5); + } else { + assert_different_registers(temp1, temp2, temp3, temp4, O5_savedSP); // don't trash lastSP } if (receiver_reg != noreg) assert_different_registers(temp1, temp2, temp3, temp4, receiver_reg); if (member_reg != noreg) assert_different_registers(temp1, temp2, temp3, temp4, member_reg); - if (!for_compiler_entry) assert_different_registers(temp1, temp2, temp3, temp4, O5_savedSP); // don't trash lastSP if (iid == vmIntrinsics::_invokeBasic) { // indirect through MH.form.vmentry.vmtarget - jump_to_lambda_form(_masm, receiver_reg, G5_method, temp2, temp3, for_compiler_entry); + jump_to_lambda_form(_masm, receiver_reg, G5_method, temp1, temp2, for_compiler_entry); } else { // The method is a member invoker used by direct method handles. @@ -378,24 +379,22 @@ // member_reg - MemberName that was the trailing argument // temp1_recv_klass - klass of stacked receiver, if needed // O5_savedSP - interpreter linkage (if interpreted) - // O0..O7,G1,G4 - compiler arguments (if compiled) + // O0..O5 - compiler arguments (if compiled) - bool method_is_live = false; + Label L_incompatible_class_change_error; switch (iid) { case vmIntrinsics::_linkToSpecial: if (VerifyMethodHandles) { - verify_ref_kind(_masm, JVM_REF_invokeSpecial, member_reg, temp3); + verify_ref_kind(_masm, JVM_REF_invokeSpecial, member_reg, temp2); } __ ld_ptr(member_vmtarget, G5_method); - method_is_live = true; break; case vmIntrinsics::_linkToStatic: if (VerifyMethodHandles) { - verify_ref_kind(_masm, JVM_REF_invokeStatic, member_reg, temp3); + verify_ref_kind(_masm, JVM_REF_invokeStatic, member_reg, temp2); } __ ld_ptr(member_vmtarget, G5_method); - method_is_live = true; break; case vmIntrinsics::_linkToVirtual: @@ -404,7 +403,7 @@ // minus the CP setup and profiling: if (VerifyMethodHandles) { - verify_ref_kind(_masm, JVM_REF_invokeVirtual, member_reg, temp3); + verify_ref_kind(_masm, JVM_REF_invokeVirtual, member_reg, temp2); } // pick out the vtable index from the MemberName, and then we can discard it: @@ -423,7 +422,6 @@ // get target Method* & entry point __ lookup_virtual_method(temp1_recv_klass, temp2_index, G5_method); - method_is_live = true; break; } @@ -432,13 +430,13 @@ // same as TemplateTable::invokeinterface // (minus the CP setup and profiling, with different argument motion) if (VerifyMethodHandles) { - verify_ref_kind(_masm, JVM_REF_invokeInterface, member_reg, temp3); + verify_ref_kind(_masm, JVM_REF_invokeInterface, member_reg, temp2); } - Register temp3_intf = temp3; - __ load_heap_oop(member_clazz, temp3_intf); - load_klass_from_Class(_masm, temp3_intf, temp2, temp4); - __ verify_klass_ptr(temp3_intf); + Register temp2_intf = temp2; + __ load_heap_oop(member_clazz, temp2_intf); + load_klass_from_Class(_masm, temp2_intf, temp3, temp4); + __ verify_klass_ptr(temp2_intf); Register G5_index = G5_method; __ ld_ptr(member_vmindex, G5_index); @@ -450,37 +448,34 @@ } // given intf, index, and recv klass, dispatch to the implementation method - Label L_no_such_interface; - Register no_sethi_temp = noreg; - __ lookup_interface_method(temp1_recv_klass, temp3_intf, + __ lookup_interface_method(temp1_recv_klass, temp2_intf, // note: next two args must be the same: G5_index, G5_method, - temp2, no_sethi_temp, - L_no_such_interface); - - __ verify_method_ptr(G5_method); - jump_from_method_handle(_masm, G5_method, temp2, temp3, for_compiler_entry); - - __ bind(L_no_such_interface); - AddressLiteral icce(StubRoutines::throw_IncompatibleClassChangeError_entry()); - __ jump_to(icce, temp3); - __ delayed()->nop(); + temp3, temp4, + L_incompatible_class_change_error); break; } default: - fatal(err_msg("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid))); + fatal(err_msg_res("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid))); break; } - if (method_is_live) { - // live at this point: G5_method, O5_savedSP (if interpreted) + // Live at this point: + // G5_method + // O5_savedSP (if interpreted) - // After figuring out which concrete method to call, jump into it. - // Note that this works in the interpreter with no data motion. - // But the compiled version will require that rcx_recv be shifted out. - __ verify_method_ptr(G5_method); - jump_from_method_handle(_masm, G5_method, temp1, temp3, for_compiler_entry); + // After figuring out which concrete method to call, jump into it. + // Note that this works in the interpreter with no data motion. + // But the compiled version will require that rcx_recv be shifted out. + __ verify_method_ptr(G5_method); + jump_from_method_handle(_masm, G5_method, temp1, temp2, for_compiler_entry); + + if (iid == vmIntrinsics::_linkToInterface) { + __ BIND(L_incompatible_class_change_error); + AddressLiteral icce(StubRoutines::throw_IncompatibleClassChangeError_entry()); + __ jump_to(icce, temp1); + __ delayed()->nop(); } } } diff -r 7fd047780d47 -r a326d528f3e1 hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Fri Sep 14 22:00:41 2012 -0700 +++ b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Mon Sep 17 12:57:58 2012 -0700 @@ -364,9 +364,9 @@ // --------------------------------------------------------------------------- // The compiled Java calling convention. The Java convention always passes // 64-bit values in adjacent aligned locations (either registers or stack), -// floats in float registers and doubles in aligned float pairs. Values are -// packed in the registers. There is no backing varargs store for values in -// registers. In the 32-bit build, longs are passed in G1 and G4 (cannot be +// floats in float registers and doubles in aligned float pairs. There is +// no backing varargs store for values in registers. +// In the 32-bit build, longs are passed on the stack (cannot be // passed in I's, because longs in I's get their heads chopped off at // interrupt). int SharedRuntime::java_calling_convention(const BasicType *sig_bt, @@ -375,76 +375,13 @@ int is_outgoing) { assert(F31->as_VMReg()->is_reg(), "overlapping stack/register numbers"); - // Convention is to pack the first 6 int/oop args into the first 6 registers - // (I0-I5), extras spill to the stack. Then pack the first 8 float args - // into F0-F7, extras spill to the stack. Then pad all register sets to - // align. Then put longs and doubles into the same registers as they fit, - // else spill to the stack. const int int_reg_max = SPARC_ARGS_IN_REGS_NUM; const int flt_reg_max = 8; - // - // Where 32-bit 1-reg longs start being passed - // In tiered we must pass on stack because c1 can't use a "pair" in a single reg. - // So make it look like we've filled all the G regs that c2 wants to use. - Register g_reg = TieredCompilation ? noreg : G1; - - // Count int/oop and float args. See how many stack slots we'll need and - // where the longs & doubles will go. - int int_reg_cnt = 0; - int flt_reg_cnt = 0; - // int stk_reg_pairs = frame::register_save_words*(wordSize>>2); - // int stk_reg_pairs = SharedRuntime::out_preserve_stack_slots(); - int stk_reg_pairs = 0; - for (int i = 0; i < total_args_passed; i++) { - switch (sig_bt[i]) { - case T_LONG: // LP64, longs compete with int args - assert(sig_bt[i+1] == T_VOID, ""); -#ifdef _LP64 - if (int_reg_cnt < int_reg_max) int_reg_cnt++; -#endif - break; - case T_OBJECT: - case T_ARRAY: - case T_ADDRESS: // Used, e.g., in slow-path locking for the lock's stack address - if (int_reg_cnt < int_reg_max) int_reg_cnt++; -#ifndef _LP64 - else stk_reg_pairs++; -#endif - break; - case T_INT: - case T_SHORT: - case T_CHAR: - case T_BYTE: - case T_BOOLEAN: - if (int_reg_cnt < int_reg_max) int_reg_cnt++; - else stk_reg_pairs++; - break; - case T_FLOAT: - if (flt_reg_cnt < flt_reg_max) flt_reg_cnt++; - else stk_reg_pairs++; - break; - case T_DOUBLE: - assert(sig_bt[i+1] == T_VOID, ""); - break; - case T_VOID: - break; - default: - ShouldNotReachHere(); - } - } - - // This is where the longs/doubles start on the stack. - stk_reg_pairs = (stk_reg_pairs+1) & ~1; // Round - - int flt_reg_pairs = (flt_reg_cnt+1) & ~1; - - // int stk_reg = frame::register_save_words*(wordSize>>2); - // int stk_reg = SharedRuntime::out_preserve_stack_slots(); - int stk_reg = 0; + int int_reg = 0; int flt_reg = 0; - - // Now do the signature layout + int slot = 0; + for (int i = 0; i < total_args_passed; i++) { switch (sig_bt[i]) { case T_INT: @@ -461,11 +398,14 @@ Register r = is_outgoing ? as_oRegister(int_reg++) : as_iRegister(int_reg++); regs[i].set1(r->as_VMReg()); } else { - regs[i].set1(VMRegImpl::stack2reg(stk_reg++)); + regs[i].set1(VMRegImpl::stack2reg(slot++)); } break; #ifdef _LP64 + case T_LONG: + assert(sig_bt[i+1] == T_VOID, "expecting VOID in other half"); + // fall-through case T_OBJECT: case T_ARRAY: case T_ADDRESS: // Used, e.g., in slow-path locking for the lock's stack address @@ -473,78 +413,57 @@ Register r = is_outgoing ? as_oRegister(int_reg++) : as_iRegister(int_reg++); regs[i].set2(r->as_VMReg()); } else { - regs[i].set2(VMRegImpl::stack2reg(stk_reg_pairs)); - stk_reg_pairs += 2; + slot = round_to(slot, 2); // align + regs[i].set2(VMRegImpl::stack2reg(slot)); + slot += 2; } break; -#endif // _LP64 - +#else case T_LONG: assert(sig_bt[i+1] == T_VOID, "expecting VOID in other half"); -#ifdef _LP64 - if (int_reg < int_reg_max) { - Register r = is_outgoing ? as_oRegister(int_reg++) : as_iRegister(int_reg++); - regs[i].set2(r->as_VMReg()); - } else { - regs[i].set2(VMRegImpl::stack2reg(stk_reg_pairs)); - stk_reg_pairs += 2; - } -#else -#ifdef COMPILER2 - // For 32-bit build, can't pass longs in O-regs because they become - // I-regs and get trashed. Use G-regs instead. G1 and G4 are almost - // spare and available. This convention isn't used by the Sparc ABI or - // anywhere else. If we're tiered then we don't use G-regs because c1 - // can't deal with them as a "pair". (Tiered makes this code think g's are filled) - // G0: zero - // G1: 1st Long arg - // G2: global allocated to TLS - // G3: used in inline cache check - // G4: 2nd Long arg - // G5: used in inline cache check - // G6: used by OS - // G7: used by OS - - if (g_reg == G1) { - regs[i].set2(G1->as_VMReg()); // This long arg in G1 - g_reg = G4; // Where the next arg goes - } else if (g_reg == G4) { - regs[i].set2(G4->as_VMReg()); // The 2nd long arg in G4 - g_reg = noreg; // No more longs in registers - } else { - regs[i].set2(VMRegImpl::stack2reg(stk_reg_pairs)); - stk_reg_pairs += 2; - } -#else // COMPILER2 - regs[i].set2(VMRegImpl::stack2reg(stk_reg_pairs)); - stk_reg_pairs += 2; -#endif // COMPILER2 -#endif // _LP64 + // On 32-bit SPARC put longs always on the stack to keep the pressure off + // integer argument registers. They should be used for oops. + slot = round_to(slot, 2); // align + regs[i].set2(VMRegImpl::stack2reg(slot)); + slot += 2; +#endif break; case T_FLOAT: - if (flt_reg < flt_reg_max) regs[i].set1(as_FloatRegister(flt_reg++)->as_VMReg()); - else regs[i].set1(VMRegImpl::stack2reg(stk_reg++)); + if (flt_reg < flt_reg_max) { + FloatRegister r = as_FloatRegister(flt_reg++); + regs[i].set1(r->as_VMReg()); + } else { + regs[i].set1(VMRegImpl::stack2reg(slot++)); + } break; + case T_DOUBLE: assert(sig_bt[i+1] == T_VOID, "expecting half"); - if (flt_reg_pairs + 1 < flt_reg_max) { - regs[i].set2(as_FloatRegister(flt_reg_pairs)->as_VMReg()); - flt_reg_pairs += 2; + if (round_to(flt_reg, 2) + 1 < flt_reg_max) { + flt_reg = round_to(flt_reg, 2); // align + FloatRegister r = as_FloatRegister(flt_reg); + regs[i].set2(r->as_VMReg()); + flt_reg += 2; } else { - regs[i].set2(VMRegImpl::stack2reg(stk_reg_pairs)); - stk_reg_pairs += 2; + slot = round_to(slot, 2); // align + regs[i].set2(VMRegImpl::stack2reg(slot)); + slot += 2; } break; - case T_VOID: regs[i].set_bad(); break; // Halves of longs & doubles + + case T_VOID: + regs[i].set_bad(); // Halves of longs & doubles + break; + default: - ShouldNotReachHere(); + fatal(err_msg_res("unknown basic type %d", sig_bt[i])); + break; } } // retun the amount of stack space these arguments will need. - return stk_reg_pairs; - + return slot; } // Helper class mostly to avoid passing masm everywhere, and handle @@ -601,8 +520,7 @@ Label L; __ ld_ptr(G5_method, in_bytes(Method::code_offset()), G3_scratch); __ br_null(G3_scratch, false, Assembler::pt, L); - // Schedule the branch target address early. - __ delayed()->ld_ptr(G5_method, in_bytes(Method::interpreter_entry_offset()), G3_scratch); + __ delayed()->nop(); // Call into the VM to patch the caller, then jump to compiled callee __ save_frame(4); // Args in compiled layout; do not blow them @@ -645,7 +563,6 @@ __ ldx(FP, -8 + STACK_BIAS, G1); __ ldx(FP, -16 + STACK_BIAS, G4); __ mov(L5, G5_method); - __ ld_ptr(G5_method, in_bytes(Method::interpreter_entry_offset()), G3_scratch); #endif /* _LP64 */ __ restore(); // Restore args @@ -726,7 +643,7 @@ int comp_args_on_stack, // VMRegStackSlots const BasicType *sig_bt, const VMRegPair *regs, - Label& skip_fixup) { + Label& L_skip_fixup) { // Before we get into the guts of the C2I adapter, see if we should be here // at all. We've come from compiled code and are attempting to jump to the @@ -747,7 +664,7 @@ patch_callers_callsite(); - __ bind(skip_fixup); + __ bind(L_skip_fixup); // Since all args are passed on the stack, total_args_passed*wordSize is the // space we need. Add in varargs area needed by the interpreter. Round up @@ -757,46 +674,18 @@ (frame::varargs_offset - frame::register_save_words)*wordSize; const int extraspace = round_to(arg_size + varargs_area, 2*wordSize); - int bias = STACK_BIAS; + const int bias = STACK_BIAS; const int interp_arg_offset = frame::varargs_offset*wordSize + (total_args_passed-1)*Interpreter::stackElementSize; - Register base = SP; - -#ifdef _LP64 - // In the 64bit build because of wider slots and STACKBIAS we can run - // out of bits in the displacement to do loads and stores. Use g3 as - // temporary displacement. - if (!Assembler::is_simm13(extraspace)) { - __ set(extraspace, G3_scratch); - __ sub(SP, G3_scratch, SP); - } else { - __ sub(SP, extraspace, SP); - } + const Register base = SP; + + // Make some extra space on the stack. + __ sub(SP, __ ensure_simm13_or_reg(extraspace, G3_scratch), SP); set_Rdisp(G3_scratch); -#else - __ sub(SP, extraspace, SP); -#endif // _LP64 - - // First write G1 (if used) to where ever it must go - for (int i=0; ias_VMReg()) { - if (sig_bt[i] == T_OBJECT || sig_bt[i] == T_ARRAY) { - store_c2i_object(G1_scratch, base, st_off); - } else if (sig_bt[i] == T_LONG) { - assert(!TieredCompilation, "should not use register args for longs"); - store_c2i_long(G1_scratch, base, st_off, false); - } else { - store_c2i_int(G1_scratch, base, st_off); - } - } - } - - // Now write the args into the outgoing interpreter space - for (int i=0; iis_valid(), ""); continue; } - // Skip G1 if found as we did it first in order to free it up - if (r_1 == G1_scratch->as_VMReg()) { - continue; - } -#ifdef ASSERT - bool G1_forced = false; -#endif // ASSERT if (r_1->is_stack()) { // Pretend stack targets are loaded into G1 -#ifdef _LP64 - Register ld_off = Rdisp; - __ set(reg2offset(r_1) + extraspace + bias, ld_off); -#else - int ld_off = reg2offset(r_1) + extraspace + bias; -#endif // _LP64 -#ifdef ASSERT - G1_forced = true; -#endif // ASSERT + RegisterOrConstant ld_off = reg2offset(r_1) + extraspace + bias; + ld_off = __ ensure_simm13_or_reg(ld_off, Rdisp); r_1 = G1_scratch->as_VMReg();// as part of the load/store shuffle if (!r_2->is_valid()) __ ld (base, ld_off, G1_scratch); else __ ldx(base, ld_off, G1_scratch); @@ -831,11 +706,6 @@ if (sig_bt[i] == T_OBJECT || sig_bt[i] == T_ARRAY) { store_c2i_object(r, base, st_off); } else if (sig_bt[i] == T_LONG || sig_bt[i] == T_DOUBLE) { -#ifndef _LP64 - if (TieredCompilation) { - assert(G1_forced || sig_bt[i] != T_LONG, "should not use register args for longs"); - } -#endif // _LP64 store_c2i_long(r, base, st_off, r_2->is_stack()); } else { store_c2i_int(r, base, st_off); @@ -851,19 +721,12 @@ } } -#ifdef _LP64 - // Need to reload G3_scratch, used for temporary displacements. + // Load the interpreter entry point. __ ld_ptr(G5_method, in_bytes(Method::interpreter_entry_offset()), G3_scratch); // Pass O5_savedSP as an argument to the interpreter. // The interpreter will restore SP to this value before returning. - __ set(extraspace, G1); - __ add(SP, G1, O5_savedSP); -#else - // Pass O5_savedSP as an argument to the interpreter. - // The interpreter will restore SP to this value before returning. - __ add(SP, extraspace, O5_savedSP); -#endif // _LP64 + __ add(SP, __ ensure_simm13_or_reg(extraspace, G1), O5_savedSP); __ mov((frame::varargs_offset)*wordSize - 1*Interpreter::stackElementSize+bias+BytesPerWord, G1); @@ -971,7 +834,6 @@ // Outputs: // G2_thread - TLS - // G1, G4 - Outgoing long args in 32-bit build // O0-O5 - Outgoing args in compiled layout // O6 - Adjusted or restored SP // O7 - Valid return address @@ -1016,10 +878,10 @@ // +--------------+ <--- start of outgoing args // | pad, align | | // +--------------+ | - // | ints, floats | |---Outgoing stack args, packed low. - // +--------------+ | First few args in registers. - // : doubles : | - // | longs | | + // | ints, longs, | | + // | floats, | |---Outgoing stack args. + // : doubles : | First few args in registers. + // | | | // +--------------+ <--- SP' + 16*wordsize // | | // : window : @@ -1033,7 +895,6 @@ // Cut-out for having no stack args. Since up to 6 args are passed // in registers, we will commonly have no stack args. if (comp_args_on_stack > 0) { - // Convert VMReg stack slots to words. int comp_words_on_stack = round_to(comp_args_on_stack*VMRegImpl::stack_slot_size, wordSize)>>LogBytesPerWord; // Round up to miminum stack alignment, in wordSize @@ -1044,13 +905,9 @@ __ sub(SP, (comp_words_on_stack)*wordSize, SP); } - // 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. - __ ld_ptr(G5_method, in_bytes(Method::from_compiled_offset()), G3); - // Now generate the shuffle code. Pick up all register args and move the // rest through G1_scratch. - for (int i=0; iis_FloatRegister(), ""); if (!r_2->is_valid()) { - __ ldf(FloatRegisterImpl::S, Gargs, arg_slot(ld_off), r_1->as_FloatRegister()); + __ ldf(FloatRegisterImpl::S, Gargs, arg_slot(ld_off), r_1->as_FloatRegister()); } else { #ifdef _LP64 // In V9, doubles are given 2 64-bit slots in the interpreter, but the @@ -1104,11 +960,11 @@ // spare float register. RegisterOrConstant slot = (sig_bt[i] == T_LONG || sig_bt[i] == T_DOUBLE) ? next_arg_slot(ld_off) : arg_slot(ld_off); - __ ldf(FloatRegisterImpl::D, Gargs, slot, r_1->as_FloatRegister()); + __ ldf(FloatRegisterImpl::D, Gargs, slot, r_1->as_FloatRegister()); #else // Need to marshal 64-bit value from misaligned Lesp loads __ ldf(FloatRegisterImpl::S, Gargs, next_arg_slot(ld_off), r_1->as_FloatRegister()); - __ ldf(FloatRegisterImpl::S, Gargs, arg_slot(ld_off), r_2->as_FloatRegister()); + __ ldf(FloatRegisterImpl::S, Gargs, arg_slot(ld_off), r_2->as_FloatRegister()); #endif } } @@ -1124,76 +980,35 @@ else __ stf(FloatRegisterImpl::D, r_1->as_FloatRegister(), SP, slot); } } - bool made_space = false; -#ifndef _LP64 - // May need to pick up a few long args in G1/G4 - bool g4_crushed = false; - bool g3_crushed = false; - for (int i=0; iis_Register() && regs[i].second()->is_valid()) { - // Load in argument order going down - int ld_off = (total_args_passed-i)*Interpreter::stackElementSize; - // Need to marshal 64-bit value from misaligned Lesp loads - Register r = regs[i].first()->as_Register()->after_restore(); - if (r == G1 || r == G4) { - assert(!g4_crushed, "ordering problem"); - if (r == G4){ - g4_crushed = true; - __ lduw(Gargs, arg_slot(ld_off) , G3_scratch); // Load lo bits - __ ld (Gargs, next_arg_slot(ld_off), r); // Load hi bits - } else { - // better schedule this way - __ ld (Gargs, next_arg_slot(ld_off), r); // Load hi bits - __ lduw(Gargs, arg_slot(ld_off) , G3_scratch); // Load lo bits - } - g3_crushed = true; - __ sllx(r, 32, r); - __ or3(G3_scratch, r, r); - } else { - assert(r->is_out(), "longs passed in two O registers"); - __ ld (Gargs, arg_slot(ld_off) , r->successor()); // Load lo bits - __ ld (Gargs, next_arg_slot(ld_off), r); // Load hi bits - } - } - } -#endif // Jump to the compiled code just as if compiled code was doing it. - // -#ifndef _LP64 - if (g3_crushed) { - // Rats load was wasted, at least it is in cache... - __ ld_ptr(G5_method, Method::from_compiled_offset(), G3); - } -#endif /* _LP64 */ - - // 6243940 We might end up in handle_wrong_method if - // the callee is deoptimized as we race thru here. If that - // happens we don't want to take a safepoint because the - // caller frame will look interpreted and arguments are now - // "compiled" so it is much better to make this transition - // invisible to the stack walking code. Unfortunately if - // we try and find the callee by normal means a safepoint - // is possible. So we stash the desired callee in the thread - // and the vm will find there should this case occur. - Address callee_target_addr(G2_thread, JavaThread::callee_target_offset()); - __ st_ptr(G5_method, callee_target_addr); - - if (StressNonEntrant) { - // Open a big window for deopt failure - __ save_frame(0); - __ mov(G0, L0); - Label loop; - __ bind(loop); - __ sub(L0, 1, L0); - __ br_null_short(L0, Assembler::pt, loop); - - __ restore(); - } - - - __ jmpl(G3, 0, G0); - __ delayed()->nop(); + __ ld_ptr(G5_method, in_bytes(Method::from_compiled_offset()), G3); + + // 6243940 We might end up in handle_wrong_method if + // the callee is deoptimized as we race thru here. If that + // happens we don't want to take a safepoint because the + // caller frame will look interpreted and arguments are now + // "compiled" so it is much better to make this transition + // invisible to the stack walking code. Unfortunately if + // we try and find the callee by normal means a safepoint + // is possible. So we stash the desired callee in the thread + // and the vm will find there should this case occur. + Address callee_target_addr(G2_thread, JavaThread::callee_target_offset()); + __ st_ptr(G5_method, callee_target_addr); + + if (StressNonEntrant) { + // Open a big window for deopt failure + __ save_frame(0); + __ mov(G0, L0); + Label loop; + __ bind(loop); + __ sub(L0, 1, L0); + __ br_null_short(L0, Assembler::pt, loop); + __ restore(); + } + + __ jmpl(G3, 0, G0); + __ delayed()->nop(); } // --------------------------------------------------------------- @@ -1221,28 +1036,17 @@ // compiled code, which relys solely on SP and not FP, get sick). address c2i_unverified_entry = __ pc(); - Label skip_fixup; + Label L_skip_fixup; { -#if !defined(_LP64) && defined(COMPILER2) - Register R_temp = L0; // another scratch register -#else - Register R_temp = G1; // another scratch register -#endif + Register R_temp = G1; // another scratch register AddressLiteral ic_miss(SharedRuntime::get_ic_miss_stub()); __ verify_oop(O0); __ load_klass(O0, G3_scratch); -#if !defined(_LP64) && defined(COMPILER2) - __ save(SP, -frame::register_save_words*wordSize, SP); __ ld_ptr(G5_method, CompiledICHolder::holder_klass_offset(), R_temp); __ cmp(G3_scratch, R_temp); - __ restore(); -#else - __ ld_ptr(G5_method, CompiledICHolder::holder_klass_offset(), R_temp); - __ cmp(G3_scratch, R_temp); -#endif Label ok, ok2; __ brx(Assembler::equal, false, Assembler::pt, ok); @@ -1256,8 +1060,8 @@ // the call site corrected. __ ld_ptr(G5_method, in_bytes(Method::code_offset()), G3_scratch); __ bind(ok2); - __ br_null(G3_scratch, false, Assembler::pt, skip_fixup); - __ delayed()->ld_ptr(G5_method, in_bytes(Method::interpreter_entry_offset()), G3_scratch); + __ br_null(G3_scratch, false, Assembler::pt, L_skip_fixup); + __ delayed()->nop(); __ jump_to(ic_miss, G3_scratch); __ delayed()->nop(); @@ -1265,7 +1069,7 @@ address c2i_entry = __ pc(); - agen.gen_c2i_adapter(total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup); + agen.gen_c2i_adapter(total_args_passed, comp_args_on_stack, sig_bt, regs, L_skip_fixup); __ flush(); return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry); @@ -1985,12 +1789,12 @@ } static void verify_oop_args(MacroAssembler* masm, - int total_args_passed, + methodHandle method, const BasicType* sig_bt, const VMRegPair* regs) { Register temp_reg = G5_method; // not part of any compiled calling seq if (VerifyOops) { - for (int i = 0; i < total_args_passed; i++) { + for (int i = 0; i < method->size_of_parameters(); i++) { if (sig_bt[i] == T_OBJECT || sig_bt[i] == T_ARRAY) { VMReg r = regs[i].first(); @@ -2009,35 +1813,32 @@ } static void gen_special_dispatch(MacroAssembler* masm, - int total_args_passed, - int comp_args_on_stack, - vmIntrinsics::ID special_dispatch, + methodHandle method, const BasicType* sig_bt, const VMRegPair* regs) { - verify_oop_args(masm, total_args_passed, sig_bt, regs); + verify_oop_args(masm, method, sig_bt, regs); + vmIntrinsics::ID iid = method->intrinsic_id(); // Now write the args into the outgoing interpreter space bool has_receiver = false; Register receiver_reg = noreg; int member_arg_pos = -1; Register member_reg = noreg; - int ref_kind = MethodHandles::signature_polymorphic_intrinsic_ref_kind(special_dispatch); + int ref_kind = MethodHandles::signature_polymorphic_intrinsic_ref_kind(iid); if (ref_kind != 0) { - member_arg_pos = total_args_passed - 1; // trailing MemberName argument + member_arg_pos = method->size_of_parameters() - 1; // trailing MemberName argument member_reg = G5_method; // known to be free at this point has_receiver = MethodHandles::ref_kind_has_receiver(ref_kind); - } else if (special_dispatch == vmIntrinsics::_invokeBasic) { + } else if (iid == vmIntrinsics::_invokeBasic) { has_receiver = true; } else { - fatal(err_msg("special_dispatch=%d", special_dispatch)); + fatal(err_msg_res("unexpected intrinsic id %d", iid)); } if (member_reg != noreg) { // Load the member_arg into register, if necessary. - assert(member_arg_pos >= 0 && member_arg_pos < total_args_passed, "oob"); - assert(sig_bt[member_arg_pos] == T_OBJECT, "dispatch argument must be an object"); + SharedRuntime::check_member_name_argument_is_last_argument(method, sig_bt, regs); VMReg r = regs[member_arg_pos].first(); - assert(r->is_valid(), "bad member arg"); if (r->is_stack()) { RegisterOrConstant ld_off = reg2offset(r) + STACK_BIAS; ld_off = __ ensure_simm13_or_reg(ld_off, member_reg); @@ -2050,7 +1851,7 @@ if (has_receiver) { // Make sure the receiver is loaded into a register. - assert(total_args_passed > 0, "oob"); + assert(method->size_of_parameters() > 0, "oob"); assert(sig_bt[0] == T_OBJECT, "receiver argument must be an object"); VMReg r = regs[0].first(); assert(r->is_valid(), "bad receiver arg"); @@ -2058,7 +1859,7 @@ // Porting note: This assumes that compiled calling conventions always // pass the receiver oop in a register. If this is not true on some // platform, pick a temp and load the receiver from stack. - assert(false, "receiver always in a register"); + fatal("receiver always in a register"); receiver_reg = G3_scratch; // known to be free at this point RegisterOrConstant ld_off = reg2offset(r) + STACK_BIAS; ld_off = __ ensure_simm13_or_reg(ld_off, member_reg); @@ -2070,7 +1871,7 @@ } // Figure out which address we are really jumping to: - MethodHandles::generate_method_handle_dispatch(masm, special_dispatch, + MethodHandles::generate_method_handle_dispatch(masm, iid, receiver_reg, member_reg, /*for_compiler_entry:*/ true); } @@ -2103,11 +1904,9 @@ // transition back to thread_in_Java // return to caller // -nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler* masm, +nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, methodHandle method, int compile_id, - int total_in_args, - int comp_args_on_stack, // in VMRegStackSlots BasicType* in_sig_bt, VMRegPair* in_regs, BasicType ret_type) { @@ -2116,9 +1915,7 @@ intptr_t start = (intptr_t)__ pc(); int vep_offset = ((intptr_t)__ pc()) - start; gen_special_dispatch(masm, - total_in_args, - comp_args_on_stack, - method->intrinsic_id(), + method, in_sig_bt, in_regs); int frame_complete = ((intptr_t)__ pc()) - start; // not complete, period @@ -2220,6 +2017,7 @@ // we convert the java signature to a C signature by inserting // the hidden arguments as arg[0] and possibly arg[1] (static method) + const int total_in_args = method->size_of_parameters(); int total_c_args = total_in_args; int total_save_slots = 6 * VMRegImpl::slots_per_word; if (!is_critical_native) { diff -r 7fd047780d47 -r a326d528f3e1 hotspot/src/cpu/x86/vm/methodHandles_x86.cpp --- a/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp Fri Sep 14 22:00:41 2012 -0700 +++ b/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp Mon Sep 17 12:57:58 2012 -0700 @@ -327,10 +327,11 @@ assert_different_registers(temp3, rcx, rdx); } #endif + else { + assert_different_registers(temp1, temp2, temp3, saved_last_sp_register()); // don't trash lastSP + } assert_different_registers(temp1, temp2, temp3, receiver_reg); assert_different_registers(temp1, temp2, temp3, member_reg); - if (!for_compiler_entry) - assert_different_registers(temp1, temp2, temp3, saved_last_sp_register()); // don't trash lastSP if (iid == vmIntrinsics::_invokeBasic) { // indirect through MH.form.vmentry.vmtarget @@ -392,14 +393,13 @@ // rsi/r13 - interpreter linkage (if interpreted) // rcx, rdx, rsi, rdi, r8, r8 - compiler arguments (if compiled) - bool method_is_live = false; + Label L_incompatible_class_change_error; switch (iid) { case vmIntrinsics::_linkToSpecial: if (VerifyMethodHandles) { verify_ref_kind(_masm, JVM_REF_invokeSpecial, member_reg, temp3); } __ movptr(rbx_method, member_vmtarget); - method_is_live = true; break; case vmIntrinsics::_linkToStatic: @@ -407,7 +407,6 @@ verify_ref_kind(_masm, JVM_REF_invokeStatic, member_reg, temp3); } __ movptr(rbx_method, member_vmtarget); - method_is_live = true; break; case vmIntrinsics::_linkToVirtual: @@ -436,7 +435,6 @@ // get target Method* & entry point __ lookup_virtual_method(temp1_recv_klass, temp2_index, rbx_method); - method_is_live = true; break; } @@ -464,35 +462,32 @@ } // given intf, index, and recv klass, dispatch to the implementation method - Label L_no_such_interface; __ lookup_interface_method(temp1_recv_klass, temp3_intf, // note: next two args must be the same: rbx_index, rbx_method, temp2, - L_no_such_interface); - - __ verify_method_ptr(rbx_method); - jump_from_method_handle(_masm, rbx_method, temp2, for_compiler_entry); - __ hlt(); - - __ bind(L_no_such_interface); - __ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry())); + L_incompatible_class_change_error); break; } default: - fatal(err_msg("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid))); + fatal(err_msg_res("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid))); break; } - if (method_is_live) { - // live at this point: rbx_method, rsi/r13 (if interpreted) + // Live at this point: + // rbx_method + // rsi/r13 (if interpreted) - // After figuring out which concrete method to call, jump into it. - // Note that this works in the interpreter with no data motion. - // But the compiled version will require that rcx_recv be shifted out. - __ verify_method_ptr(rbx_method); - jump_from_method_handle(_masm, rbx_method, temp1, for_compiler_entry); + // After figuring out which concrete method to call, jump into it. + // Note that this works in the interpreter with no data motion. + // But the compiled version will require that rcx_recv be shifted out. + __ verify_method_ptr(rbx_method); + jump_from_method_handle(_masm, rbx_method, temp1, for_compiler_entry); + + if (iid == vmIntrinsics::_linkToInterface) { + __ bind(L_incompatible_class_change_error); + __ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry())); } } } diff -r 7fd047780d47 -r a326d528f3e1 hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Fri Sep 14 22:00:41 2012 -0700 +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Mon Sep 17 12:57:58 2012 -0700 @@ -1346,12 +1346,12 @@ } static void verify_oop_args(MacroAssembler* masm, - int total_args_passed, + methodHandle method, const BasicType* sig_bt, const VMRegPair* regs) { Register temp_reg = rbx; // not part of any compiled calling seq if (VerifyOops) { - for (int i = 0; i < total_args_passed; i++) { + for (int i = 0; i < method->size_of_parameters(); i++) { if (sig_bt[i] == T_OBJECT || sig_bt[i] == T_ARRAY) { VMReg r = regs[i].first(); @@ -1368,35 +1368,32 @@ } static void gen_special_dispatch(MacroAssembler* masm, - int total_args_passed, - int comp_args_on_stack, - vmIntrinsics::ID special_dispatch, + methodHandle method, const BasicType* sig_bt, const VMRegPair* regs) { - verify_oop_args(masm, total_args_passed, sig_bt, regs); + verify_oop_args(masm, method, sig_bt, regs); + vmIntrinsics::ID iid = method->intrinsic_id(); // Now write the args into the outgoing interpreter space bool has_receiver = false; Register receiver_reg = noreg; int member_arg_pos = -1; Register member_reg = noreg; - int ref_kind = MethodHandles::signature_polymorphic_intrinsic_ref_kind(special_dispatch); + int ref_kind = MethodHandles::signature_polymorphic_intrinsic_ref_kind(iid); if (ref_kind != 0) { - member_arg_pos = total_args_passed - 1; // trailing MemberName argument + member_arg_pos = method->size_of_parameters() - 1; // trailing MemberName argument member_reg = rbx; // known to be free at this point has_receiver = MethodHandles::ref_kind_has_receiver(ref_kind); - } else if (special_dispatch == vmIntrinsics::_invokeBasic) { + } else if (iid == vmIntrinsics::_invokeBasic) { has_receiver = true; } else { - guarantee(false, err_msg("special_dispatch=%d", special_dispatch)); + fatal(err_msg_res("unexpected intrinsic id %d", iid)); } if (member_reg != noreg) { // Load the member_arg into register, if necessary. - assert(member_arg_pos >= 0 && member_arg_pos < total_args_passed, "oob"); - assert(sig_bt[member_arg_pos] == T_OBJECT, "dispatch argument must be an object"); + SharedRuntime::check_member_name_argument_is_last_argument(method, sig_bt, regs); VMReg r = regs[member_arg_pos].first(); - assert(r->is_valid(), "bad member arg"); if (r->is_stack()) { __ movptr(member_reg, Address(rsp, r->reg2stack() * VMRegImpl::stack_slot_size + wordSize)); } else { @@ -1407,7 +1404,7 @@ if (has_receiver) { // Make sure the receiver is loaded into a register. - assert(total_args_passed > 0, "oob"); + assert(method->size_of_parameters() > 0, "oob"); assert(sig_bt[0] == T_OBJECT, "receiver argument must be an object"); VMReg r = regs[0].first(); assert(r->is_valid(), "bad receiver arg"); @@ -1415,7 +1412,7 @@ // Porting note: This assumes that compiled calling conventions always // pass the receiver oop in a register. If this is not true on some // platform, pick a temp and load the receiver from stack. - assert(false, "receiver always in a register"); + fatal("receiver always in a register"); receiver_reg = rcx; // known to be free at this point __ movptr(receiver_reg, Address(rsp, r->reg2stack() * VMRegImpl::stack_slot_size + wordSize)); } else { @@ -1425,7 +1422,7 @@ } // Figure out which address we are really jumping to: - MethodHandles::generate_method_handle_dispatch(masm, special_dispatch, + MethodHandles::generate_method_handle_dispatch(masm, iid, receiver_reg, member_reg, /*for_compiler_entry:*/ true); } @@ -1461,8 +1458,6 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, methodHandle method, int compile_id, - int total_in_args, - int comp_args_on_stack, BasicType* in_sig_bt, VMRegPair* in_regs, BasicType ret_type) { @@ -1471,9 +1466,7 @@ intptr_t start = (intptr_t)__ pc(); int vep_offset = ((intptr_t)__ pc()) - start; gen_special_dispatch(masm, - total_in_args, - comp_args_on_stack, - method->intrinsic_id(), + method, in_sig_bt, in_regs); int frame_complete = ((intptr_t)__ pc()) - start; // not complete, period @@ -1506,6 +1499,7 @@ // we convert the java signature to a C signature by inserting // the hidden arguments as arg[0] and possibly arg[1] (static method) + const int total_in_args = method->size_of_parameters(); int total_c_args = total_in_args; if (!is_critical_native) { total_c_args += 1; diff -r 7fd047780d47 -r a326d528f3e1 hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp --- a/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Fri Sep 14 22:00:41 2012 -0700 +++ b/hotspot/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Mon Sep 17 12:57:58 2012 -0700 @@ -1593,12 +1593,12 @@ }; static void verify_oop_args(MacroAssembler* masm, - int total_args_passed, + methodHandle method, const BasicType* sig_bt, const VMRegPair* regs) { Register temp_reg = rbx; // not part of any compiled calling seq if (VerifyOops) { - for (int i = 0; i < total_args_passed; i++) { + for (int i = 0; i < method->size_of_parameters(); i++) { if (sig_bt[i] == T_OBJECT || sig_bt[i] == T_ARRAY) { VMReg r = regs[i].first(); @@ -1615,35 +1615,32 @@ } static void gen_special_dispatch(MacroAssembler* masm, - int total_args_passed, - int comp_args_on_stack, - vmIntrinsics::ID special_dispatch, + methodHandle method, const BasicType* sig_bt, const VMRegPair* regs) { - verify_oop_args(masm, total_args_passed, sig_bt, regs); + verify_oop_args(masm, method, sig_bt, regs); + vmIntrinsics::ID iid = method->intrinsic_id(); // Now write the args into the outgoing interpreter space bool has_receiver = false; Register receiver_reg = noreg; int member_arg_pos = -1; Register member_reg = noreg; - int ref_kind = MethodHandles::signature_polymorphic_intrinsic_ref_kind(special_dispatch); + int ref_kind = MethodHandles::signature_polymorphic_intrinsic_ref_kind(iid); if (ref_kind != 0) { - member_arg_pos = total_args_passed - 1; // trailing MemberName argument + member_arg_pos = method->size_of_parameters() - 1; // trailing MemberName argument member_reg = rbx; // known to be free at this point has_receiver = MethodHandles::ref_kind_has_receiver(ref_kind); - } else if (special_dispatch == vmIntrinsics::_invokeBasic) { + } else if (iid == vmIntrinsics::_invokeBasic) { has_receiver = true; } else { - guarantee(false, err_msg("special_dispatch=%d", special_dispatch)); + fatal(err_msg_res("unexpected intrinsic id %d", iid)); } if (member_reg != noreg) { // Load the member_arg into register, if necessary. - assert(member_arg_pos >= 0 && member_arg_pos < total_args_passed, "oob"); - assert(sig_bt[member_arg_pos] == T_OBJECT, "dispatch argument must be an object"); + SharedRuntime::check_member_name_argument_is_last_argument(method, sig_bt, regs); VMReg r = regs[member_arg_pos].first(); - assert(r->is_valid(), "bad member arg"); if (r->is_stack()) { __ movptr(member_reg, Address(rsp, r->reg2stack() * VMRegImpl::stack_slot_size + wordSize)); } else { @@ -1654,7 +1651,7 @@ if (has_receiver) { // Make sure the receiver is loaded into a register. - assert(total_args_passed > 0, "oob"); + assert(method->size_of_parameters() > 0, "oob"); assert(sig_bt[0] == T_OBJECT, "receiver argument must be an object"); VMReg r = regs[0].first(); assert(r->is_valid(), "bad receiver arg"); @@ -1662,7 +1659,7 @@ // Porting note: This assumes that compiled calling conventions always // pass the receiver oop in a register. If this is not true on some // platform, pick a temp and load the receiver from stack. - assert(false, "receiver always in a register"); + fatal("receiver always in a register"); receiver_reg = j_rarg0; // known to be free at this point __ movptr(receiver_reg, Address(rsp, r->reg2stack() * VMRegImpl::stack_slot_size + wordSize)); } else { @@ -1672,7 +1669,7 @@ } // Figure out which address we are really jumping to: - MethodHandles::generate_method_handle_dispatch(masm, special_dispatch, + MethodHandles::generate_method_handle_dispatch(masm, iid, receiver_reg, member_reg, /*for_compiler_entry:*/ true); } @@ -1708,8 +1705,6 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, methodHandle method, int compile_id, - int total_in_args, - int comp_args_on_stack, BasicType* in_sig_bt, VMRegPair* in_regs, BasicType ret_type) { @@ -1718,9 +1713,7 @@ intptr_t start = (intptr_t)__ pc(); int vep_offset = ((intptr_t)__ pc()) - start; gen_special_dispatch(masm, - total_in_args, - comp_args_on_stack, - method->intrinsic_id(), + method, in_sig_bt, in_regs); int frame_complete = ((intptr_t)__ pc()) - start; // not complete, period @@ -1754,6 +1747,7 @@ // we convert the java signature to a C signature by inserting // the hidden arguments as arg[0] and possibly arg[1] (static method) + const int total_in_args = method->size_of_parameters(); int total_c_args = total_in_args; if (!is_critical_native) { total_c_args += 1; diff -r 7fd047780d47 -r a326d528f3e1 hotspot/src/share/vm/asm/register.hpp --- a/hotspot/src/share/vm/asm/register.hpp Fri Sep 14 22:00:41 2012 -0700 +++ b/hotspot/src/share/vm/asm/register.hpp Mon Sep 17 12:57:58 2012 -0700 @@ -103,8 +103,8 @@ ) { assert( a != b, - err_msg("registers must be different: a=%d, b=%d", - a, b) + err_msg_res("registers must be different: a=%d, b=%d", + a, b) ); } @@ -117,8 +117,8 @@ assert( a != b && a != c && b != c, - err_msg("registers must be different: a=%d, b=%d, c=%d", - a, b, c) + err_msg_res("registers must be different: a=%d, b=%d, c=%d", + a, b, c) ); } @@ -133,8 +133,8 @@ a != b && a != c && a != d && b != c && b != d && c != d, - err_msg("registers must be different: a=%d, b=%d, c=%d, d=%d", - a, b, c, d) + err_msg_res("registers must be different: a=%d, b=%d, c=%d, d=%d", + a, b, c, d) ); } @@ -151,8 +151,8 @@ && b != c && b != d && b != e && c != d && c != e && d != e, - err_msg("registers must be different: a=%d, b=%d, c=%d, d=%d, e=%d", - a, b, c, d, e) + err_msg_res("registers must be different: a=%d, b=%d, c=%d, d=%d, e=%d", + a, b, c, d, e) ); } @@ -171,8 +171,8 @@ && c != d && c != e && c != f && d != e && d != f && e != f, - err_msg("registers must be different: a=%d, b=%d, c=%d, d=%d, e=%d, f=%d", - a, b, c, d, e, f) + err_msg_res("registers must be different: a=%d, b=%d, c=%d, d=%d, e=%d, f=%d", + a, b, c, d, e, f) ); } @@ -193,8 +193,8 @@ && d != e && d != f && d != g && e != f && e != g && f != g, - err_msg("registers must be different: a=%d, b=%d, c=%d, d=%d, e=%d, f=%d, g=%d", - a, b, c, d, e, f, g) + err_msg_res("registers must be different: a=%d, b=%d, c=%d, d=%d, e=%d, f=%d, g=%d", + a, b, c, d, e, f, g) ); } @@ -217,8 +217,8 @@ && e != f && e != g && e != h && f != g && f != h && g != h, - err_msg("registers must be different: a=%d, b=%d, c=%d, d=%d, e=%d, f=%d, g=%d, h=%d", - a, b, c, d, e, f, g, h) + err_msg_res("registers must be different: a=%d, b=%d, c=%d, d=%d, e=%d, f=%d, g=%d, h=%d", + a, b, c, d, e, f, g, h) ); } @@ -243,8 +243,8 @@ && f != g && f != h && f != i && g != h && g != i && h != i, - err_msg("registers must be different: a=%d, b=%d, c=%d, d=%d, e=%d, f=%d, g=%d, h=%d, i=%d", - a, b, c, d, e, f, g, h, i) + err_msg_res("registers must be different: a=%d, b=%d, c=%d, d=%d, e=%d, f=%d, g=%d, h=%d, i=%d", + a, b, c, d, e, f, g, h, i) ); } diff -r 7fd047780d47 -r a326d528f3e1 hotspot/src/share/vm/code/nmethod.cpp --- a/hotspot/src/share/vm/code/nmethod.cpp Fri Sep 14 22:00:41 2012 -0700 +++ b/hotspot/src/share/vm/code/nmethod.cpp Mon Sep 17 12:57:58 2012 -0700 @@ -700,7 +700,9 @@ // then print the requested information if (PrintNativeNMethods) { print_code(); - oop_maps->print(); + if (oop_maps != NULL) { + oop_maps->print(); + } } if (PrintRelocations) { print_relocations(); diff -r 7fd047780d47 -r a326d528f3e1 hotspot/src/share/vm/runtime/sharedRuntime.cpp --- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp Fri Sep 14 22:00:41 2012 -0700 +++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp Mon Sep 17 12:57:58 2012 -0700 @@ -1618,6 +1618,31 @@ return callee_method; } +#ifdef ASSERT +void SharedRuntime::check_member_name_argument_is_last_argument(methodHandle method, + const BasicType* sig_bt, + const VMRegPair* regs) { + ResourceMark rm; + const int total_args_passed = method->size_of_parameters(); + const VMRegPair* regs_with_member_name = regs; + VMRegPair* regs_without_member_name = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed - 1); + + const int member_arg_pos = total_args_passed - 1; + assert(member_arg_pos >= 0 && member_arg_pos < total_args_passed, "oob"); + assert(sig_bt[member_arg_pos] == T_OBJECT, "dispatch argument must be an object"); + + const bool is_outgoing = method->is_method_handle_intrinsic(); + int comp_args_on_stack = java_calling_convention(sig_bt, regs_without_member_name, total_args_passed - 1, is_outgoing); + + for (int i = 0; i < member_arg_pos; i++) { + VMReg a = regs_with_member_name[i].first(); + VMReg b = regs_without_member_name[i].first(); + assert(a->value() == b->value(), err_msg_res("register allocation mismatch: a=%d, b=%d", a->value(), b->value())); + } + assert(regs_with_member_name[member_arg_pos].first()->is_valid(), "bad member arg"); +} +#endif + // --------------------------------------------------------------------------- // We are calling the interpreter via a c2i. Normally this would mean that // we were called by a compiled method. However we could have lost a race @@ -2546,10 +2571,10 @@ MacroAssembler _masm(&buffer); // Fill in the signature array, for the calling-convention call. - int total_args_passed = method->size_of_parameters(); - - BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType,total_args_passed); - VMRegPair* regs = NEW_RESOURCE_ARRAY(VMRegPair,total_args_passed); + const int total_args_passed = method->size_of_parameters(); + + BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_args_passed); + VMRegPair* regs = NEW_RESOURCE_ARRAY(VMRegPair, total_args_passed); int i=0; if( !method->is_static() ) // Pass in receiver first sig_bt[i++] = T_OBJECT; @@ -2559,7 +2584,7 @@ if( ss.type() == T_LONG || ss.type() == T_DOUBLE ) sig_bt[i++] = T_VOID; // Longs & doubles take 2 Java slots } - assert( i==total_args_passed, "" ); + assert(i == total_args_passed, ""); BasicType ret_type = ss.type(); // Now get the compiled-Java layout as input (or output) arguments. @@ -2572,9 +2597,8 @@ nm = SharedRuntime::generate_native_wrapper(&_masm, method, compile_id, - total_args_passed, - comp_args_on_stack, - sig_bt,regs, + sig_bt, + regs, ret_type); } } diff -r 7fd047780d47 -r a326d528f3e1 hotspot/src/share/vm/runtime/sharedRuntime.hpp --- a/hotspot/src/share/vm/runtime/sharedRuntime.hpp Fri Sep 14 22:00:41 2012 -0700 +++ b/hotspot/src/share/vm/runtime/sharedRuntime.hpp Mon Sep 17 12:57:58 2012 -0700 @@ -345,7 +345,11 @@ // the bottom of the frame the first 16 words will be skipped and SharedInfo::stack0 // will be just above it. ( // return value is the maximum number of VMReg stack slots the convention will use. - static int java_calling_convention(const BasicType *sig_bt, VMRegPair *regs, int total_args_passed, int is_outgoing); + static int java_calling_convention(const BasicType* sig_bt, VMRegPair* regs, int total_args_passed, int is_outgoing); + + static void check_member_name_argument_is_last_argument(methodHandle method, + const BasicType* sig_bt, + const VMRegPair* regs) NOT_DEBUG_RETURN; // Ditto except for calling C static int c_calling_convention(const BasicType *sig_bt, VMRegPair *regs, int total_args_passed); @@ -425,13 +429,11 @@ // The wrapper may contain special-case code if the given method // is a JNI critical method, or a compiled method handle adapter, // such as _invokeBasic, _linkToVirtual, etc. - static nmethod *generate_native_wrapper(MacroAssembler* masm, + static nmethod* generate_native_wrapper(MacroAssembler* masm, methodHandle method, int compile_id, - int total_args_passed, - int max_arg, - BasicType *sig_bt, - VMRegPair *regs, + BasicType* sig_bt, + VMRegPair* regs, BasicType ret_type ); // Block before entering a JNI critical method