mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 22:34:27 +02:00
7196262: JSR 292: java/lang/invoke/PrivateInvokeTest.java fails on solaris-sparc
Reviewed-by: kvn, jrose, bdelsart
This commit is contained in:
parent
c188598ddd
commit
b0d292378a
11 changed files with 292 additions and 483 deletions
|
@ -364,9 +364,9 @@ static VMRegPair reg64_to_VMRegPair(Register r) {
|
|||
// ---------------------------------------------------------------------------
|
||||
// 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 SharedRuntime::java_calling_convention(const BasicType *sig_bt,
|
|||
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;
|
||||
int slot = 0;
|
||||
|
||||
// Now do the signature layout
|
||||
for (int i = 0; i < total_args_passed; i++) {
|
||||
switch (sig_bt[i]) {
|
||||
case T_INT:
|
||||
|
@ -461,11 +398,14 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt,
|
|||
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 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt,
|
|||
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++));
|
||||
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 (flt_reg < flt_reg_max) {
|
||||
FloatRegister r = as_FloatRegister(flt_reg++);
|
||||
regs[i].set1(r->as_VMReg());
|
||||
} else {
|
||||
regs[i].set2(VMRegImpl::stack2reg(stk_reg_pairs));
|
||||
stk_reg_pairs += 2;
|
||||
regs[i].set1(VMRegImpl::stack2reg(slot++));
|
||||
}
|
||||
break;
|
||||
case T_VOID: regs[i].set_bad(); break; // Halves of longs & doubles
|
||||
|
||||
case T_DOUBLE:
|
||||
assert(sig_bt[i+1] == T_VOID, "expecting half");
|
||||
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 {
|
||||
slot = round_to(slot, 2); // align
|
||||
regs[i].set2(VMRegImpl::stack2reg(slot));
|
||||
slot += 2;
|
||||
}
|
||||
break;
|
||||
|
||||
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 @@ void AdapterGenerator::patch_callers_callsite() {
|
|||
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 @@ void AdapterGenerator::patch_callers_callsite() {
|
|||
__ 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 @@ void AdapterGenerator::gen_c2i_adapter(
|
|||
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 @@ void AdapterGenerator::gen_c2i_adapter(
|
|||
|
||||
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 @@ void AdapterGenerator::gen_c2i_adapter(
|
|||
(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;
|
||||
const 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);
|
||||
}
|
||||
// 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; i<total_args_passed; i++) {
|
||||
const int st_off = interp_arg_offset - (i*Interpreter::stackElementSize) + bias;
|
||||
VMReg r_1 = regs[i].first();
|
||||
VMReg r_2 = regs[i].second();
|
||||
if (r_1 == G1_scratch->as_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; i<total_args_passed; i++) {
|
||||
// Write the args into the outgoing interpreter space.
|
||||
for (int i = 0; i < total_args_passed; i++) {
|
||||
const int st_off = interp_arg_offset - (i*Interpreter::stackElementSize) + bias;
|
||||
VMReg r_1 = regs[i].first();
|
||||
VMReg r_2 = regs[i].second();
|
||||
|
@ -804,23 +693,9 @@ void AdapterGenerator::gen_c2i_adapter(
|
|||
assert(!r_2->is_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 @@ void AdapterGenerator::gen_c2i_adapter(
|
|||
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 @@ void AdapterGenerator::gen_c2i_adapter(
|
|||
}
|
||||
}
|
||||
|
||||
#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 @@ void AdapterGenerator::gen_i2c_adapter(
|
|||
|
||||
// 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 @@ void AdapterGenerator::gen_i2c_adapter(
|
|||
// +--------------+ <--- 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 @@ void AdapterGenerator::gen_i2c_adapter(
|
|||
// 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 @@ void AdapterGenerator::gen_i2c_adapter(
|
|||
__ 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; i<total_args_passed; i++) {
|
||||
for (int i = 0; i < total_args_passed; i++) {
|
||||
if (sig_bt[i] == T_VOID) {
|
||||
// Longs and doubles are passed in native word order, but misaligned
|
||||
// in the 32-bit build.
|
||||
|
@ -1088,14 +945,13 @@ void AdapterGenerator::gen_i2c_adapter(
|
|||
next_arg_slot(ld_off) : arg_slot(ld_off);
|
||||
__ ldx(Gargs, slot, r);
|
||||
#else
|
||||
// Need to load a 64-bit value into G1/G4, but G1/G4 is being used in the
|
||||
// stack shuffle. Load the first 2 longs into G1/G4 later.
|
||||
fatal("longs should be on stack");
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
assert(r_1->is_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 @@ void AdapterGenerator::gen_i2c_adapter(
|
|||
// 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 @@ void AdapterGenerator::gen_i2c_adapter(
|
|||
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; i<total_args_passed; i++) {
|
||||
if (regs[i].first()->is_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 */
|
||||
__ 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);
|
||||
// 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);
|
||||
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();
|
||||
}
|
||||
|
||||
__ restore();
|
||||
}
|
||||
|
||||
|
||||
__ jmpl(G3, 0, G0);
|
||||
__ delayed()->nop();
|
||||
__ jmpl(G3, 0, G0);
|
||||
__ delayed()->nop();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
@ -1221,28 +1036,17 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
|||
// 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 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
|||
// 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 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm
|
|||
|
||||
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 unpack_array_argument(MacroAssembler* masm, VMRegPair reg, BasicType
|
|||
}
|
||||
|
||||
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 verify_oop_args(MacroAssembler* masm,
|
|||
}
|
||||
|
||||
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 @@ static void gen_special_dispatch(MacroAssembler* masm,
|
|||
|
||||
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 @@ static void gen_special_dispatch(MacroAssembler* masm,
|
|||
// 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 @@ static void gen_special_dispatch(MacroAssembler* masm,
|
|||
}
|
||||
|
||||
// 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 @@ static void gen_special_dispatch(MacroAssembler* masm,
|
|||
// 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 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
|
|||
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 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
|
|||
// 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) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue