Quellcode-Bibliothek macroAssembler_ppc.cpp
Sprache: C
/* * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2022 SAP SE. 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 * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. *
*/
#ifdef ASSERT // On RISC, there's no benefit to verifying instruction boundaries. bool AbstractAssembler::pd_check_instruction_mark() { returnfalse; } #endif
void MacroAssembler::ld_largeoffset_unchecked(Register d, int si31, Register a, int emit_filler_nop) {
assert(Assembler::is_simm(si31, 31) && si31 >= 0, "si31 out of range"); if (Assembler::is_simm(si31, 16)) {
ld(d, si31, a); if (emit_filler_nop) nop();
} else { constint hi = MacroAssembler::largeoffset_si16_si16_hi(si31); constint lo = MacroAssembler::largeoffset_si16_si16_lo(si31);
addis(d, a, hi);
ld(d, lo, d);
}
}
void MacroAssembler::ld_largeoffset(Register d, int si31, Register a, int emit_filler_nop) {
assert_different_registers(d, a);
ld_largeoffset_unchecked(d, si31, a, emit_filler_nop);
}
// Issue instructions that calculate given TOC from global TOC. void MacroAssembler::calculate_address_from_global_toc(Register dst, address addr, bool hi16, bool lo16, bool add_relocation, bool emit_dummy_addr) { int offset = -1; if (emit_dummy_addr) {
offset = -128; // dummy address
} elseif (addr != (address)(intptr_t)-1) {
offset = MacroAssembler::offset_to_global_toc(addr);
}
if (hi16) {
addis(dst, R29_TOC, MacroAssembler::largeoffset_si16_si16_hi(offset));
} if (lo16) { if (add_relocation) { // Relocate at the addi to avoid confusion with a load from the method's TOC.
relocate(internal_word_Relocation::spec(addr));
}
addi(dst, dst, MacroAssembler::largeoffset_si16_si16_lo(offset));
}
}
// The relocation points to the second instruction, the addi, // and the addi reads and writes the same register dst. constint dst = inv_rt_field(inst2);
assert(is_addi(inst2) && inv_ra_field(inst2) == dst, "must be addi reading and writing dst");
// Now, find the preceding addis which writes to dst. int inst1 = 0;
address inst1_addr = inst2_addr - BytesPerInstWord; while (inst1_addr >= bound) {
inst1 = *(int *) inst1_addr; if (is_addis(inst1) && inv_rt_field(inst1) == dst) { // Stop, found the addis which writes dst. break;
}
inst1_addr -= BytesPerInstWord;
}
assert(is_addis(inst1) && inv_ra_field(inst1) == 29 /* R29 */, "source must be global TOC");
set_imm((int *)inst1_addr, MacroAssembler::largeoffset_si16_si16_hi(offset));
set_imm((int *)inst2_addr, MacroAssembler::largeoffset_si16_si16_lo(offset)); return inst1_addr;
}
// The relocation points to the second instruction, the addi, // and the addi reads and writes the same register dst. constint dst = inv_rt_field(inst2);
assert(is_addi(inst2) && inv_ra_field(inst2) == dst, "must be addi reading and writing dst");
// Now, find the preceding addis which writes to dst. int inst1 = 0;
address inst1_addr = inst2_addr - BytesPerInstWord; while (inst1_addr >= bound) {
inst1 = *(int *) inst1_addr; if (is_addis(inst1) && inv_rt_field(inst1) == dst) { // stop, found the addis which writes dst break;
}
inst1_addr -= BytesPerInstWord;
}
assert(is_addis(inst1) && inv_ra_field(inst1) == 29 /* R29 */, "source must be global TOC");
int offset = (get_imm(inst1_addr, 0) << 16) + get_imm(inst2_addr, 0); // -1 is a special case if (offset == -1) { return (address)(intptr_t)-1;
} else { return global_toc() + offset;
}
}
#ifdef _LP64 // Patch compressed oops or klass constants. // Assembler sequence is // 1) compressed oops: // lis rx = const.hi // ori rx = rx | const.lo // 2) compressed klass: // lis rx = const.hi // clrldi rx = rx & 0xFFFFffff // clearMS32b, optional // ori rx = rx | const.lo // Clrldi will be passed by.
address MacroAssembler::patch_set_narrow_oop(address a, address bound, narrowOop data) {
assert(UseCompressedOops, "Should only patch compressed oops");
// The relocation points to the second instruction, the ori, // and the ori reads and writes the same register dst. constint dst = inv_rta_field(inst2);
assert(is_ori(inst2) && inv_rs_field(inst2) == dst, "must be ori reading and writing dst"); // Now, find the preceding addis which writes to dst. int inst1 = 0;
address inst1_addr = inst2_addr - BytesPerInstWord; bool inst1_found = false; while (inst1_addr >= bound) {
inst1 = *(int *)inst1_addr; if (is_lis(inst1) && inv_rs_field(inst1) == dst) { inst1_found = true; break; }
inst1_addr -= BytesPerInstWord;
}
assert(inst1_found, "inst is not lis");
uint32_t data_value = CompressedOops::narrow_oop_value(data); int xc = (data_value >> 16) & 0xffff; int xd = (data_value >> 0) & 0xffff;
set_imm((int *)inst1_addr, (short)(xc)); // see enc_load_con_narrow_hi/_lo
set_imm((int *)inst2_addr, (xd)); // unsigned int return inst1_addr;
}
// Get compressed oop constant.
narrowOop MacroAssembler::get_narrow_oop(address a, address bound) {
assert(UseCompressedOops, "Should only patch compressed oops");
// The relocation points to the second instruction, the ori, // and the ori reads and writes the same register dst. constint dst = inv_rta_field(inst2);
assert(is_ori(inst2) && inv_rs_field(inst2) == dst, "must be ori reading and writing dst"); // Now, find the preceding lis which writes to dst. int inst1 = 0;
address inst1_addr = inst2_addr - BytesPerInstWord; bool inst1_found = false;
while (inst1_addr >= bound) {
inst1 = *(int *) inst1_addr; if (is_lis(inst1) && inv_rs_field(inst1) == dst) { inst1_found = true; break;}
inst1_addr -= BytesPerInstWord;
}
assert(inst1_found, "inst is not lis");
// Returns true if successful. bool MacroAssembler::load_const_from_method_toc(Register dst, AddressLiteral& a, Register toc, bool fixed_size) { int toc_offset = 0; // Use RelocationHolder::none for the constant pool entry, otherwise // we will end up with a failing NativeCall::verify(x) where x is // the address of the constant pool entry. // FIXME: We should insert relocation information for oops at the constant // pool entries instead of inserting it at the loads; patching of a constant // pool entry should be less expensive.
address const_address = address_constant((address)a.value(), RelocationHolder::none); if (const_address == NULL) { returnfalse; } // allocation failure // Relocate at the pc of the load.
relocate(a.rspec());
toc_offset = (int)(const_address - code()->consts()->start());
ld_largeoffset_unchecked(dst, toc_offset, toc, fixed_size); returntrue;
}
// The relocation points to the ld or the addis. return (is_ld(inst1)) ||
(is_addis(inst1) && inv_ra_field(inst1) != 0);
}
int MacroAssembler::get_offset_of_load_const_from_method_toc_at(address a) {
assert(is_load_const_from_method_toc_at(a), "must be load_const_from_method_toc");
// Conditional far branch for destinations encodable in 24+2 bits. void MacroAssembler::bc_far(int boint, int biint, Label& dest, int optimize) {
// If requested by flag optimize, relocate the bc_far as a // runtime_call and prepare for optimizing it when the code gets // relocated. if (optimize == bc_far_optimize_on_relocate) {
relocate(relocInfo::runtime_call_type);
}
// We emit two branches. // First, a conditional branch which jumps around the far branch. const address not_taken_pc = pc() + 2 * BytesPerInstWord; const address bc_pc = pc();
bc(opposite_boint, biint, not_taken_pc);
// Second, an unconditional far branch which jumps to dest. // Note: target(dest) remembers the current pc (see CodeSection::target) // and returns the current pc if the label is not bound yet; when // the label gets bound, the unconditional far branch will be patched. const address target_pc = target(dest); const address b_pc = pc();
b(target_pc);
if (is_bc_far_variant3_at(instruction_addr)) { // variant 3, far cond branch to the next instruction, already patched to nops: // // nop // endgroup // SKIP/DEST: // return;
}
// first, extract boint and biint from the current branch int boint = 0; int biint = 0;
ResourceMark rm; constint code_size = 2 * BytesPerInstWord;
CodeBuffer buf(instruction_addr, code_size);
MacroAssembler masm(&buf); if (is_bc_far_variant2_at(instruction_addr) && dest == instruction_addr + 8) { // Far branch to next instruction: Optimize it by patching nops (produce variant 3).
masm.nop();
masm.endgroup();
} else { if (is_bc_far_variant1_at(instruction_addr)) { // variant 1, the 1st instruction contains the destination address: // // bcxx DEST // nop // constint instruction_1 = *(int*)(instruction_addr);
boint = inv_bo_field(instruction_1);
biint = inv_bi_field(instruction_1);
} elseif (is_bc_far_variant2_at(instruction_addr)) { // variant 2, the 2nd instruction contains the destination address: // // b!cxx SKIP // bxx DEST // SKIP: // constint instruction_1 = *(int*)(instruction_addr);
boint = add_bhint_to_boint(opposite_bhint(inv_boint_bhint(inv_bo_field(instruction_1))),
opposite_bcond(inv_boint_bcond(inv_bo_field(instruction_1))));
biint = inv_bi_field(instruction_1);
} else { // variant 4???
ShouldNotReachHere();
}
// second, set the new branch destination and optimize the code if (dest != instruction_addr + 4 && // the bc_far is still unbound!
masm.is_within_range_of_bcxx(dest, instruction_addr)) { // variant 1: // // bcxx DEST // nop //
masm.bc(boint, biint, dest);
masm.nop();
} else { // variant 2: // // b!cxx SKIP // bxx DEST // SKIP: // constint opposite_boint = add_bhint_to_boint(opposite_bhint(inv_boint_bhint(boint)),
opposite_bcond(inv_boint_bcond(boint))); const address not_taken_pc = masm.pc() + 2 * BytesPerInstWord;
masm.bc(opposite_boint, biint, not_taken_pc);
masm.b(dest);
}
}
ICache::ppc64_flush_icache_bytes(instruction_addr, code_size);
}
// Emit a NOT mt-safe patchable 64 bit absolute call/jump. void MacroAssembler::bxx64_patchable(address dest, relocInfo::relocType rt, bool link) { // get current pc
uint64_t start_pc = (uint64_t) pc();
const address pc_of_bl = (address) (start_pc + (6*BytesPerInstWord)); // bl is last const address pc_of_b = (address) (start_pc + (0*BytesPerInstWord)); // b is first
// relocate here if (rt != relocInfo::none) {
relocate(rt);
}
if ( ReoptimizeCallSequences &&
(( link && is_within_range_of_b(dest, pc_of_bl)) ||
(!link && is_within_range_of_b(dest, pc_of_b)))) { // variant 2: // Emit an optimized, pc-relative call/jump.
if (link) { // some padding
nop();
nop();
nop();
nop();
nop();
nop();
// do the call
assert(pc() == pc_of_bl, "just checking");
bl(dest, relocInfo::none);
} else { // do the jump
assert(pc() == pc_of_b, "just checking");
b(dest, relocInfo::none);
// some padding
nop();
nop();
nop();
nop();
nop();
nop();
}
// Assert that we can identify the emitted call/jump.
assert(is_bxx64_patchable_variant2_at((address)start_pc, link), "can't identify emitted call");
} else { // variant 1:
mr(R0, R11); // spill R11 -> R0.
// Load the destination address into CTR, // calculate destination relative to global toc.
calculate_address_from_global_toc(R11, dest, true, true, false);
// do the call/jump if (link) {
bctrl();
} else{
bctr();
} // Assert that we can identify the emitted call/jump.
assert(is_bxx64_patchable_variant1b_at((address)start_pc, link), "can't identify emitted call");
}
// Assert that we can identify the emitted call/jump.
assert(is_bxx64_patchable_at((address)start_pc, link), "can't identify emitted call");
assert(get_dest_of_bxx64_patchable_at((address)start_pc, link) == dest, "wrong encoding of dest address");
}
// Does the call64_patchable instruction use a pc-relative encoding of // the call destination? bool MacroAssembler::is_bxx64_patchable_pcrelative_at(address instruction_addr, bool link) { // variant 2 is pc-relative return is_bxx64_patchable_variant2_at(instruction_addr, link);
}
// Preserve stack pointer register (R1_SP) and system thread id register (R13); // although they're technically volatile for (int i = 2; i < 13; i++) { Register reg = as_Register(i); if (reg == excluded_register) { continue;
}
void MacroAssembler::save_LR_CR(Register tmp) {
mfcr(tmp);
std(tmp, _abi0(cr), R1_SP);
mflr(tmp);
std(tmp, _abi0(lr), R1_SP); // Tmp must contain lr on exit! (see return_addr and prolog in ppc64.ad)
}
// Push a frame of size `bytes'. void MacroAssembler::push_frame(unsignedint bytes, Register tmp) { long offset = align_addr(bytes, frame::alignment_in_bytes); if (is_simm(-offset, 16)) {
stdu(R1_SP, -offset, R1_SP);
} else {
load_const_optimized(tmp, -offset);
stdux(R1_SP, R1_SP, tmp);
}
}
// Push a frame of size `bytes' plus abi_reg_args on top. void MacroAssembler::push_frame_reg_args(unsignedint bytes, Register tmp) {
push_frame(bytes + frame::abi_reg_args_size, tmp);
}
// Setup up a new C frame with a spill area for non-volatile GPRs and // additional space for local variables. void MacroAssembler::push_frame_reg_args_nonvolatiles(unsignedint bytes, Register tmp) {
push_frame(bytes + frame::abi_reg_args_size + frame::spill_nonvolatiles_size, tmp);
}
// Pop current C frame. void MacroAssembler::pop_frame() {
ld(R1_SP, _abi0(callers_sp), R1_SP);
}
#ifdefined(ABI_ELFv2)
address MacroAssembler::branch_to(Register r_function_entry, bool and_link) { // TODO(asmundak): make sure the caller uses R12 as function descriptor // most of the times. if (R12 != r_function_entry) {
mr(R12, r_function_entry);
}
mtctr(R12); // Do a call or a branch. if (and_link) {
bctrl();
} else {
bctr();
}
_last_calls_return_pc = pc();
return _last_calls_return_pc;
}
// Call a C function via a function descriptor and use full C // calling conventions. Updates and returns _last_calls_return_pc.
address MacroAssembler::call_c(Register r_function_entry) { return branch_to(r_function_entry, /*and_link=*/true);
}
// For tail calls: only branch, don't link, so callee returns to caller of this function.
address MacroAssembler::call_c_and_return_to_caller(Register r_function_entry) { return branch_to(r_function_entry, /*and_link=*/false);
}
#else // Generic version of a call to C function via a function descriptor // with variable support for C calling conventions (TOC, ENV, etc.). // Updates and returns _last_calls_return_pc.
address MacroAssembler::branch_to(Register function_descriptor, bool and_link, bool save_toc_before_call, bool restore_toc_after_call, bool load_toc_of_callee, bool load_env_of_callee) { // we emit standard ptrgl glue code here
assert((function_descriptor != R0), "function_descriptor cannot be R0");
// retrieve necessary entries from the function descriptor
ld(R0, in_bytes(FunctionDescriptor::entry_offset()), function_descriptor);
mtctr(R0);
if (load_toc_of_callee) {
ld(R2_TOC, in_bytes(FunctionDescriptor::toc_offset()), function_descriptor);
} if (load_env_of_callee) {
ld(R11, in_bytes(FunctionDescriptor::env_offset()), function_descriptor);
} elseif (load_toc_of_callee) {
li(R11, 0);
}
// do a call or a branch if (and_link) {
bctrl();
} else {
bctr();
}
_last_calls_return_pc = pc();
return _last_calls_return_pc;
}
// Call a C function via a function descriptor and use full C calling // conventions. // We don't use the TOC in generated code, so there is no need to save // and restore its value.
address MacroAssembler::call_c(Register fd) { return branch_to(fd, /*and_link=*/true, /*save toc=*/false, /*restore toc=*/false, /*load toc=*/true, /*load env=*/true);
}
address MacroAssembler::call_c(const FunctionDescriptor* fd, relocInfo::relocType rt) { if (rt != relocInfo::none) { // this call needs to be relocatable if (!ReoptimizeCallSequences
|| (rt != relocInfo::runtime_call_type && rt != relocInfo::none)
|| fd == NULL // support code-size estimation
|| !fd->is_friend_function()
|| fd->entry() == NULL) { // it's not a friend function as defined by class FunctionDescriptor, // so do a full call-c here.
load_const(R11, (address)fd, R0);
bool has_env = (fd != NULL && fd->env() != NULL); return branch_to(R11, /*and_link=*/true, /*save toc=*/false, /*restore toc=*/false, /*load toc=*/true, /*load env=*/has_env);
} else { // It's a friend function. Load the entry point and don't care about // toc and env. Use an optimizable call instruction, but ensure the // same code-size as in the case of a non-friend function.
nop();
nop();
nop();
bl64_patchable(fd->entry(), rt);
_last_calls_return_pc = pc(); return _last_calls_return_pc;
}
} else { // This call does not need to be relocatable, do more aggressive // optimizations. if (!ReoptimizeCallSequences
|| !fd->is_friend_function()) { // It's not a friend function as defined by class FunctionDescriptor, // so do a full call-c here.
load_const(R11, (address)fd, R0); return branch_to(R11, /*and_link=*/true, /*save toc=*/false, /*restore toc=*/false, /*load toc=*/true, /*load env=*/true);
} else { // it's a friend function, load the entry point and don't care about // toc and env.
address dest = fd->entry(); if (is_within_range_of_b(dest, pc())) {
bl(dest);
} else {
bl64_patchable(dest, rt);
}
_last_calls_return_pc = pc(); return _last_calls_return_pc;
}
}
}
// Call a C function. All constants needed reside in TOC. // // Read the address to call from the TOC. // Read env from TOC, if fd specifies an env. // Read new TOC from TOC.
address MacroAssembler::call_c_using_toc(const FunctionDescriptor* fd,
relocInfo::relocType rt, Register toc) { if (!ReoptimizeCallSequences
|| (rt != relocInfo::runtime_call_type && rt != relocInfo::none)
|| !fd->is_friend_function()) { // It's not a friend function as defined by class FunctionDescriptor, // so do a full call-c here.
assert(fd->entry() != NULL, "function must be linked");
AddressLiteral fd_entry(fd->entry()); bool success = load_const_from_method_toc(R11, fd_entry, toc, /*fixed_size*/ true);
mtctr(R11); if (fd->env() == NULL) {
li(R11, 0);
nop();
} else {
AddressLiteral fd_env(fd->env());
success = success && load_const_from_method_toc(R11, fd_env, toc, /*fixed_size*/ true);
}
AddressLiteral fd_toc(fd->toc()); // Set R2_TOC (load from toc)
success = success && load_const_from_method_toc(R2_TOC, fd_toc, toc, /*fixed_size*/ true);
bctrl();
_last_calls_return_pc = pc(); if (!success) { return NULL; }
} else { // It's a friend function, load the entry point and don't care about // toc and env. Use an optimizable call instruction, but ensure the // same code-size as in the case of a non-friend function.
nop();
bl64_patchable(fd->entry(), rt);
_last_calls_return_pc = pc();
} return _last_calls_return_pc;
} #endif// ABI_ELFv2
void MacroAssembler::post_call_nop() { // Make inline again when loom is always enabled. if (!Continuations::enabled()) { return;
}
nop();
}
// Check whether instruction is a read access to the polling page // which was emitted by load_from_polling_page(..). bool MacroAssembler::is_load_from_polling_page(int instruction, void* ucontext,
address* polling_address_ptr) { if (!is_ld(instruction)) returnfalse; // It's not a ld. Fail.
int rt = inv_rt_field(instruction); int ra = inv_ra_field(instruction); int ds = inv_ds_field(instruction); if (!(ds == 0 && ra != 0 && rt == 0)) { returnfalse; // It's not a ld(r0, X, ra). Fail.
}
if (!ucontext) { // Set polling address. if (polling_address_ptr != NULL) {
*polling_address_ptr = NULL;
} returntrue; // No ucontext given. Can't check value of ra. Assume true.
}
#ifdef LINUX // Ucontext given. Check that register ra contains the address of // the safepoing polling page.
ucontext_t* uc = (ucontext_t*) ucontext; // Set polling address.
address addr = (address)uc->uc_mcontext.regs->gpr[ra] + (ssize_t)ds; if (polling_address_ptr != NULL) {
*polling_address_ptr = addr;
} return SafepointMechanism::is_poll_address(addr); #else // Not on Linux, ucontext must be NULL.
ShouldNotReachHere(); returnfalse; #endif
}
void MacroAssembler::bang_stack_with_offset(int offset) { // When increasing the stack, the old stack pointer will be written // to the new top of stack according to the PPC64 abi. // Therefore, stack banging is not necessary when increasing // the stack by <= os::vm_page_size() bytes. // When increasing the stack by a larger amount, this method is // called repeatedly to bang the intermediate pages.
// Stack grows down, caller passes positive offset.
assert(offset > 0, "must bang with positive offset");
long stdoffset = -offset;
if (is_simm(stdoffset, 16)) { // Signed 16 bit offset, a simple std is ok. if (UseLoadInstructionsForStackBangingPPC64) {
ld(R0, (int)(signedshort)stdoffset, R1_SP);
} else {
std(R0,(int)(signedshort)stdoffset, R1_SP);
}
} elseif (is_simm(stdoffset, 31)) { constint hi = MacroAssembler::largeoffset_si16_si16_hi(stdoffset); constint lo = MacroAssembler::largeoffset_si16_si16_lo(stdoffset);
// Temps and addr_base are killed if size < 4 and processor does not support respective instructions. // Only signed types are supported with size < 4. // Atomic add always kills tmp1. void MacroAssembler::atomic_get_and_modify_generic(Register dest_current_value, Register exchange_value, Register addr_base, Register tmp1, Register tmp2, Register tmp3, bool cmpxchgx_hint, bool is_add, int size) { // Sub-word instructions are available since Power 8. // For older processors, instruction_type != size holds, and we // emulate the sub-word instructions by constructing a 4-byte value // that leaves the other bytes unchanged. constint instruction_type = VM_Version::has_lqarx() ? size : 4;
switch (instruction_type) { case 4: lwarx(val32, addr_base, cmpxchgx_hint); break; case 2: lharx(val32, addr_base, cmpxchgx_hint); break; case 1: lbarx(val32, addr_base, cmpxchgx_hint); break; default: ShouldNotReachHere();
}
if (instruction_type != size) {
srw(dest_current_value, val32, shift_amount);
}
if (is_add) { add(modval, dest_current_value, exchange_value); }
if (instruction_type != size) { // Transform exchange value such that the replacement can be done by one xor instruction.
xorr(modval, dest_current_value, is_add ? modval : exchange_value);
clrldi(modval, modval, (size == 1) ? 56 : 48);
slw(modval, modval, shift_amount);
xorr(modval, val32, modval);
}
switch (instruction_type) { case 4: stwcx_(modval, addr_base); break; case 2: sthcx_(modval, addr_base); break; case 1: stbcx_(modval, addr_base); break; default: ShouldNotReachHere();
}
// Temps, addr_base and exchange_value are killed if size < 4 and processor does not support respective instructions. // Only signed types are supported with size < 4. void MacroAssembler::cmpxchg_loop_body(ConditionRegister flag, Register dest_current_value, Register compare_value, Register exchange_value, Register addr_base, Register tmp1, Register tmp2,
Label &retry, Label &failed, bool cmpxchgx_hint, int size) { // Sub-word instructions are available since Power 8. // For older processors, instruction_type != size holds, and we // emulate the sub-word instructions by constructing a 4-byte value // that leaves the other bytes unchanged. constint instruction_type = VM_Version::has_lqarx() ? size : 4;
// Save one branch if result is returned via register and // result register is different from the other ones. bool use_result_reg = (int_flag_success != noreg); bool preset_result_reg = (int_flag_success != dest_current_value && int_flag_success != compare_value &&
int_flag_success != exchange_value && int_flag_success != addr_base &&
int_flag_success != tmp1 && int_flag_success != tmp2);
assert(!weak || flag == CCR0, "weak only supported with CCR0");
assert(size == 1 || size == 2 || size == 4, "unsupported");
if (use_result_reg && preset_result_reg) {
li(int_flag_success, 0); // preset (assume cas failed)
}
// Add simple guard in order to reduce risk of starving under high contention (recommended by IBM). if (contention_hint) { // Don't try to reserve if cmp fails. switch (size) { case 1: lbz(dest_current_value, 0, addr_base); extsb(dest_current_value, dest_current_value); break; case 2: lha(dest_current_value, 0, addr_base); break; case 4: lwz(dest_current_value, 0, addr_base); break; default: ShouldNotReachHere();
}
cmpw(flag, dest_current_value, compare_value);
bne(flag, failed);
}
// release/fence semantics if (semantics & MemBarRel) {
release();
}
// Result in register (must do this at the end because int_flag_success can be the // same register as one above). if (use_result_reg) {
li(int_flag_success, 1);
}
// Performs atomic compare exchange: // if (compare_value == *addr_base) // *addr_base = exchange_value // int_flag_success = 1; // else // int_flag_success = 0; // // ConditionRegister flag = cmp(compare_value, *addr_base) // Register dest_current_value = *addr_base // Register compare_value Used to compare with value in memory // Register exchange_value Written to memory if compare_value == *addr_base // Register addr_base The memory location to compareXChange // Register int_flag_success Set to 1 if exchange_value was written to *addr_base // // To avoid the costly compare exchange the value is tested beforehand. // Several special cases exist to avoid that unnecessary information is generated. // void MacroAssembler::cmpxchgd(ConditionRegister flag, Register dest_current_value, RegisterOrConstant compare_value, Register exchange_value, Register addr_base, int semantics, bool cmpxchgx_hint, Register int_flag_success, Label* failed_ext, bool contention_hint, bool weak) {
Label retry;
Label failed_int;
Label& failed = (failed_ext != NULL) ? *failed_ext : failed_int;
Label done;
// Save one branch if result is returned via register and result register is different from the other ones. bool use_result_reg = (int_flag_success!=noreg); bool preset_result_reg = (int_flag_success!=dest_current_value && int_flag_success!=compare_value.register_or_noreg() &&
int_flag_success!=exchange_value && int_flag_success!=addr_base);
assert(!weak || flag == CCR0, "weak only supported with CCR0");
assert(int_flag_success == noreg || failed_ext == NULL, "cannot have both");
if (use_result_reg && preset_result_reg) {
li(int_flag_success, 0); // preset (assume cas failed)
}
// Add simple guard in order to reduce risk of starving under high contention (recommended by IBM). if (contention_hint) { // Don't try to reserve if cmp fails.
ld(dest_current_value, 0, addr_base);
cmpd(flag, compare_value, dest_current_value);
bne(flag, failed);
}
// release/fence semantics if (semantics & MemBarRel) {
release();
}
// result in register (must do this at the end because int_flag_success can be the same register as one above) if (use_result_reg) {
li(int_flag_success, 1);
}
// Look up the method for a megamorphic invokeinterface call. // The target method is determined by <intf_klass, itable_index>. // The receiver klass is in recv_klass. // On success, the result will be in method_result, and execution falls through. // On failure, execution transfers to the given label. void MacroAssembler::lookup_interface_method(Register recv_klass, Register intf_klass,
RegisterOrConstant itable_index, Register method_result, Register scan_temp, Register temp2,
Label& L_no_such_interface, bool return_method) {
assert_different_registers(recv_klass, intf_klass, method_result, scan_temp);
// Compute start of first itableOffsetEntry (which is at the end of the vtable). int vtable_base = in_bytes(Klass::vtable_start_offset()); int itentry_off = itableMethodEntry::method_offset_in_bytes(); int logMEsize = exact_log2(itableMethodEntry::size() * wordSize); int scan_step = itableOffsetEntry::size() * wordSize; int log_vte_size= exact_log2(vtableEntry::size_in_bytes());
lwz(scan_temp, in_bytes(Klass::vtable_length_offset()), recv_klass); // %%% We should store the aligned, prescaled offset in the klassoop. // Then the next several instructions would fold away.
// Adjust recv_klass by scaled itable_index, so we can free itable_index. if (return_method) { if (itable_index.is_register()) { Register itable_offset = itable_index.as_register();
sldi(method_result, itable_offset, logMEsize); if (itentry_off) { addi(method_result, method_result, itentry_off); }
add(method_result, method_result, recv_klass);
} else {
--> --------------------
--> maximum size reached
--> --------------------
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.76Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.