--- old/src/hotspot/cpu/sparc/nativeInst_sparc.cpp 2020-05-20 18:09:08.504605467 -0700 +++ /dev/null 2020-03-09 18:57:19.455001459 -0700 @@ -1,912 +0,0 @@ -/* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. 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. - * - */ - -#include "precompiled.hpp" -#include "asm/macroAssembler.inline.hpp" -#include "code/codeCache.hpp" -#include "code/compiledIC.hpp" -#include "memory/resourceArea.hpp" -#include "nativeInst_sparc.hpp" -#include "oops/oop.inline.hpp" -#include "runtime/handles.hpp" -#include "runtime/sharedRuntime.hpp" -#include "runtime/stubRoutines.hpp" -#include "utilities/ostream.hpp" -#ifdef COMPILER1 -#include "c1/c1_Runtime1.hpp" -#endif - -void NativeInstruction::set_data64_sethi(address instaddr, intptr_t x) { - ResourceMark rm; - CodeBuffer buf(instaddr, 10 * BytesPerInstWord ); - MacroAssembler* _masm = new MacroAssembler(&buf); - Register destreg; - - destreg = inv_rd(*(unsigned int *)instaddr); - // Generate a the new sequence - _masm->patchable_sethi(x, destreg); - ICache::invalidate_range(instaddr, 7 * BytesPerInstWord); -} - -void NativeInstruction::verify_data64_sethi(address instaddr, intptr_t x) { - ResourceMark rm; - unsigned char buffer[10 * BytesPerInstWord]; - CodeBuffer buf(buffer, 10 * BytesPerInstWord); - MacroAssembler masm(&buf); - - Register destreg = inv_rd(*(unsigned int *)instaddr); - // Generate the proper sequence into a temporary buffer and compare - // it with the original sequence. - masm.patchable_sethi(x, destreg); - int len = buffer - masm.pc(); - for (int i = 0; i < len; i++) { - guarantee(instaddr[i] == buffer[i], "instructions must match"); - } -} - -void NativeInstruction::verify() { - // make sure code pattern is actually an instruction address - address addr = addr_at(0); - if (addr == 0 || ((intptr_t)addr & 3) != 0) { - fatal("not an instruction address"); - } -} - -void NativeInstruction::print() { - tty->print_cr(INTPTR_FORMAT ": 0x%x", p2i(addr_at(0)), long_at(0)); -} - -void NativeInstruction::set_long_at(int offset, int i) { - address addr = addr_at(offset); - *(int*)addr = i; - ICache::invalidate_word(addr); -} - -void NativeInstruction::set_jlong_at(int offset, jlong i) { - address addr = addr_at(offset); - *(jlong*)addr = i; - // Don't need to invalidate 2 words here, because - // the flush instruction operates on doublewords. - ICache::invalidate_word(addr); -} - -void NativeInstruction::set_addr_at(int offset, address x) { - address addr = addr_at(offset); - assert( ((intptr_t)addr & (wordSize-1)) == 0, "set_addr_at bad address alignment"); - *(uintptr_t*)addr = (uintptr_t)x; - // Don't need to invalidate 2 words here in the 64-bit case, - // because the flush instruction operates on doublewords. - ICache::invalidate_word(addr); - // The Intel code has this assertion for NativeCall::set_destination, - // NativeMovConstReg::set_data, NativeMovRegMem::set_offset, - // NativeJump::set_jump_destination, and NativePushImm32::set_data - //assert (Patching_lock->owned_by_self(), "must hold lock to patch instruction") -} - -bool NativeInstruction::is_zero_test(Register ®) { - int x = long_at(0); - Assembler::op3s temp = (Assembler::op3s) (Assembler::sub_op3 | Assembler::cc_bit_op3); - if (is_op3(x, temp, Assembler::arith_op) && - inv_immed(x) && inv_rd(x) == G0) { - if (inv_rs1(x) == G0) { - reg = inv_rs2(x); - return true; - } else if (inv_rs2(x) == G0) { - reg = inv_rs1(x); - return true; - } - } - return false; -} - -bool NativeInstruction::is_load_store_with_small_offset(Register reg) { - int x = long_at(0); - if (is_op(x, Assembler::ldst_op) && - inv_rs1(x) == reg && inv_immed(x)) { - return true; - } - return false; -} - -void NativeCall::verify() { - NativeInstruction::verify(); - // make sure code pattern is actually a call instruction - int x = long_at(0); - if (!is_op(x, Assembler::call_op)) { - fatal("not a call: 0x%x @ " INTPTR_FORMAT, x, p2i(instruction_address())); - } -} - -void NativeCall::print() { - tty->print_cr(INTPTR_FORMAT ": call " INTPTR_FORMAT, p2i(instruction_address()), p2i(destination())); -} - - -// MT-safe patching of a call instruction (and following word). -// First patches the second word, and then atomicly replaces -// the first word with the first new instruction word. -// Other processors might briefly see the old first word -// followed by the new second word. This is OK if the old -// second word is harmless, and the new second word may be -// harmlessly executed in the delay slot of the call. -void NativeCall::replace_mt_safe(address instr_addr, address code_buffer) { - assert(Patching_lock->is_locked() || - SafepointSynchronize::is_at_safepoint(), "concurrent code patching"); - assert (instr_addr != NULL, "illegal address for code patching"); - NativeCall* n_call = nativeCall_at (instr_addr); // checking that it is a call - assert(NativeCall::instruction_size == 8, "wrong instruction size; must be 8"); - int i0 = ((int*)code_buffer)[0]; - int i1 = ((int*)code_buffer)[1]; - int* contention_addr = (int*) n_call->addr_at(1*BytesPerInstWord); - assert(inv_op(*contention_addr) == Assembler::arith_op || - *contention_addr == nop_instruction(), - "must not interfere with original call"); - // The set_long_at calls do the ICacheInvalidate so we just need to do them in reverse order - n_call->set_long_at(1*BytesPerInstWord, i1); - n_call->set_long_at(0*BytesPerInstWord, i0); - // NOTE: It is possible that another thread T will execute - // only the second patched word. - // In other words, since the original instruction is this - // call patching_stub; nop (NativeCall) - // and the new sequence from the buffer is this: - // sethi %hi(K), %r; add %r, %lo(K), %r (NativeMovConstReg) - // what T will execute is this: - // call patching_stub; add %r, %lo(K), %r - // thereby putting garbage into %r before calling the patching stub. - // This is OK, because the patching stub ignores the value of %r. - - // Make sure the first-patched instruction, which may co-exist - // briefly with the call, will do something harmless. - assert(inv_op(*contention_addr) == Assembler::arith_op || - *contention_addr == nop_instruction(), - "must not interfere with original call"); -} - -// Similar to replace_mt_safe, but just changes the destination. The -// important thing is that free-running threads are able to execute this -// call instruction at all times. Thus, the displacement field must be -// instruction-word-aligned. This is always true on SPARC. -// -// Used in the runtime linkage of calls; see class CompiledIC. -void NativeCall::set_destination_mt_safe(address dest) { - assert((Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) || - CompiledICLocker::is_safe(addr_at(0)), - "concurrent code patching"); - // set_destination uses set_long_at which does the ICache::invalidate - set_destination(dest); -} - -// Code for unit testing implementation of NativeCall class -void NativeCall::test() { -#ifdef ASSERT - ResourceMark rm; - CodeBuffer cb("test", 100, 100); - MacroAssembler* a = new MacroAssembler(&cb); - NativeCall *nc; - uint idx; - int offsets[] = { - 0x0, - (int)0xfffffff0, - (int)0x7ffffff0, - (int)0x80000000, - 0x20, - 0x4000, - }; - - VM_Version::allow_all(); - - a->call( a->pc(), relocInfo::none ); - a->delayed()->nop(); - nc = nativeCall_at( cb.insts_begin() ); - nc->print(); - - nc = nativeCall_overwriting_at( nc->next_instruction_address() ); - for (idx = 0; idx < ARRAY_SIZE(offsets); idx++) { - nc->set_destination( cb.insts_begin() + offsets[idx] ); - assert(nc->destination() == (cb.insts_begin() + offsets[idx]), "check unit test"); - nc->print(); - } - - nc = nativeCall_before( cb.insts_begin() + 8 ); - nc->print(); - - VM_Version::revert(); -#endif -} -// End code for unit testing implementation of NativeCall class - -//------------------------------------------------------------------- - -void NativeFarCall::set_destination(address dest) { - // Address materialized in the instruction stream, so nothing to do. - return; -#if 0 // What we'd do if we really did want to change the destination - if (destination() == dest) { - return; - } - ResourceMark rm; - CodeBuffer buf(addr_at(0), instruction_size + 1); - MacroAssembler* _masm = new MacroAssembler(&buf); - // Generate the new sequence - AddressLiteral(dest); - _masm->jumpl_to(dest, O7, O7); - ICache::invalidate_range(addr_at(0), instruction_size ); -#endif -} - -void NativeFarCall::verify() { - // make sure code pattern is actually a jumpl_to instruction - assert((int)instruction_size == (int)NativeJump::instruction_size, "same as jump_to"); - assert((int)jmpl_offset == (int)NativeMovConstReg::add_offset, "sethi size ok"); - nativeJump_at(addr_at(0))->verify(); -} - -bool NativeFarCall::is_call_at(address instr) { - return nativeInstruction_at(instr)->is_sethi(); -} - -void NativeFarCall::print() { - tty->print_cr(INTPTR_FORMAT ": call " INTPTR_FORMAT, p2i(instruction_address()), p2i(destination())); -} - -bool NativeFarCall::destination_is_compiled_verified_entry_point() { - nmethod* callee = CodeCache::find_nmethod(destination()); - if (callee == NULL) { - return false; - } else { - return destination() == callee->verified_entry_point(); - } -} - -// MT-safe patching of a far call. -void NativeFarCall::replace_mt_safe(address instr_addr, address code_buffer) { - Unimplemented(); -} - -// Code for unit testing implementation of NativeFarCall class -void NativeFarCall::test() { - Unimplemented(); -} -// End code for unit testing implementation of NativeFarCall class - -//------------------------------------------------------------------- - - -void NativeMovConstReg::verify() { - NativeInstruction::verify(); - // make sure code pattern is actually a "set_metadata" synthetic instruction - // see MacroAssembler::set_oop() - int i0 = long_at(sethi_offset); - int i1 = long_at(add_offset); - - // verify the pattern "sethi %hi22(imm), reg ; add reg, %lo10(imm), reg" - Register rd = inv_rd(i0); - if (!is_op2(i0, Assembler::sethi_op2) && rd != G0 ) { - fatal("not a set_metadata"); - } -} - - -void NativeMovConstReg::print() { - tty->print_cr(INTPTR_FORMAT ": mov reg, " INTPTR_FORMAT, p2i(instruction_address()), data()); -} - - -intptr_t NativeMovConstReg::data() const { - return data64(addr_at(sethi_offset), long_at(add_offset)); -} - - -void NativeMovConstReg::set_data(intptr_t x) { - set_data64_sethi(addr_at(sethi_offset), x); - set_long_at(add_offset, set_data32_simm13( long_at(add_offset), x)); - - // also store the value into an oop_Relocation cell, if any - CodeBlob* cb = CodeCache::find_blob(instruction_address()); - nmethod* nm = cb ? cb->as_nmethod_or_null() : NULL; - if (nm != NULL) { - RelocIterator iter(nm, instruction_address(), next_instruction_address()); - oop* oop_addr = NULL; - Metadata** metadata_addr = NULL; - while (iter.next()) { - if (iter.type() == relocInfo::oop_type) { - oop_Relocation *r = iter.oop_reloc(); - if (oop_addr == NULL) { - oop_addr = r->oop_addr(); - *oop_addr = cast_to_oop(x); - } else { - assert(oop_addr == r->oop_addr(), "must be only one set-oop here"); - } - } - if (iter.type() == relocInfo::metadata_type) { - metadata_Relocation *r = iter.metadata_reloc(); - if (metadata_addr == NULL) { - metadata_addr = r->metadata_addr(); - *metadata_addr = (Metadata*)x; - } else { - assert(metadata_addr == r->metadata_addr(), "must be only one set-metadata here"); - } - } - } - } -} - - -// Code for unit testing implementation of NativeMovConstReg class -void NativeMovConstReg::test() { -#ifdef ASSERT - ResourceMark rm; - CodeBuffer cb("test", 100, 100); - MacroAssembler* a = new MacroAssembler(&cb); - NativeMovConstReg* nm; - uint idx; - int offsets[] = { - 0x0, - (int)0x7fffffff, - (int)0x80000000, - (int)0xffffffff, - 0x20, - 4096, - 4097, - }; - - VM_Version::allow_all(); - - AddressLiteral al1(0xaaaabbbb, relocInfo::external_word_type); - a->sethi(al1, I3); - a->add(I3, al1.low10(), I3); - AddressLiteral al2(0xccccdddd, relocInfo::external_word_type); - a->sethi(al2, O2); - a->add(O2, al2.low10(), O2); - - nm = nativeMovConstReg_at( cb.insts_begin() ); - nm->print(); - - nm = nativeMovConstReg_at( nm->next_instruction_address() ); - for (idx = 0; idx < ARRAY_SIZE(offsets); idx++) { - nm->set_data( offsets[idx] ); - assert(nm->data() == offsets[idx], "check unit test"); - } - nm->print(); - - VM_Version::revert(); -#endif -} -// End code for unit testing implementation of NativeMovConstReg class - -//------------------------------------------------------------------- - -void NativeMovConstReg32::verify() { - NativeInstruction::verify(); - // make sure code pattern is actually a "set_metadata" synthetic instruction - // see MacroAssembler::set_oop() - int i0 = long_at(sethi_offset); - int i1 = long_at(add_offset); - - // verify the pattern "sethi %hi22(imm), reg ; add reg, %lo10(imm), reg" - Register rd = inv_rd(i0); - if (!is_op2(i0, Assembler::sethi_op2) && rd != G0 ) { - fatal("not a set_metadata"); - } -} - - -void NativeMovConstReg32::print() { - tty->print_cr(INTPTR_FORMAT ": mov reg, " INTPTR_FORMAT, p2i(instruction_address()), data()); -} - - -intptr_t NativeMovConstReg32::data() const { - return data32(long_at(sethi_offset), long_at(add_offset)); -} - - -void NativeMovConstReg32::set_data(intptr_t x) { - set_long_at(sethi_offset, set_data32_sethi( long_at(sethi_offset), x)); - set_long_at(add_offset, set_data32_simm13( long_at(add_offset), x)); - - // also store the value into an oop_Relocation cell, if any - CodeBlob* cb = CodeCache::find_blob(instruction_address()); - nmethod* nm = cb ? cb->as_nmethod_or_null() : NULL; - if (nm != NULL) { - RelocIterator iter(nm, instruction_address(), next_instruction_address()); - oop* oop_addr = NULL; - Metadata** metadata_addr = NULL; - while (iter.next()) { - if (iter.type() == relocInfo::oop_type) { - oop_Relocation *r = iter.oop_reloc(); - if (oop_addr == NULL) { - oop_addr = r->oop_addr(); - *oop_addr = cast_to_oop(x); - } else { - assert(oop_addr == r->oop_addr(), "must be only one set-oop here"); - } - } - if (iter.type() == relocInfo::metadata_type) { - metadata_Relocation *r = iter.metadata_reloc(); - if (metadata_addr == NULL) { - metadata_addr = r->metadata_addr(); - *metadata_addr = (Metadata*)x; - } else { - assert(metadata_addr == r->metadata_addr(), "must be only one set-metadata here"); - } - } - } - } -} - -//------------------------------------------------------------------- - -void NativeMovConstRegPatching::verify() { - NativeInstruction::verify(); - // Make sure code pattern is sethi/nop/add. - int i0 = long_at(sethi_offset); - int i1 = long_at(nop_offset); - int i2 = long_at(add_offset); - assert((int)nop_offset == (int)NativeMovConstReg::add_offset, "sethi size ok"); - - // Verify the pattern "sethi %hi22(imm), reg; nop; add reg, %lo10(imm), reg" - // The casual reader should note that on Sparc a nop is a special case if sethi - // in which the destination register is %g0. - Register rd0 = inv_rd(i0); - Register rd1 = inv_rd(i1); - if (!(is_op2(i0, Assembler::sethi_op2) && rd0 != G0 && - is_op2(i1, Assembler::sethi_op2) && rd1 == G0 && // nop is a special case of sethi - is_op3(i2, Assembler::add_op3, Assembler::arith_op) && - inv_immed(i2) && (unsigned)get_simm13(i2) < (1 << 10) && - rd0 == inv_rs1(i2) && rd0 == inv_rd(i2))) { - fatal("not a set_metadata"); - } -} - - -void NativeMovConstRegPatching::print() { - tty->print_cr(INTPTR_FORMAT ": mov reg, 0x%x", p2i(instruction_address()), data()); -} - - -int NativeMovConstRegPatching::data() const { - return data64(addr_at(sethi_offset), long_at(add_offset)); -} - - -void NativeMovConstRegPatching::set_data(int x) { - set_data64_sethi(addr_at(sethi_offset), x); - set_long_at(add_offset, set_data32_simm13(long_at(add_offset), x)); - - // also store the value into an oop_Relocation cell, if any - CodeBlob* cb = CodeCache::find_blob(instruction_address()); - nmethod* nm = cb ? cb->as_nmethod_or_null() : NULL; - if (nm != NULL) { - RelocIterator iter(nm, instruction_address(), next_instruction_address()); - oop* oop_addr = NULL; - Metadata** metadata_addr = NULL; - while (iter.next()) { - if (iter.type() == relocInfo::oop_type) { - oop_Relocation *r = iter.oop_reloc(); - if (oop_addr == NULL) { - oop_addr = r->oop_addr(); - *oop_addr = cast_to_oop(x); - } else { - assert(oop_addr == r->oop_addr(), "must be only one set-oop here"); - } - } - if (iter.type() == relocInfo::metadata_type) { - metadata_Relocation *r = iter.metadata_reloc(); - if (metadata_addr == NULL) { - metadata_addr = r->metadata_addr(); - *metadata_addr = (Metadata*)x; - } else { - assert(metadata_addr == r->metadata_addr(), "must be only one set-metadata here"); - } - } - } - } -} - - -// Code for unit testing implementation of NativeMovConstRegPatching class -void NativeMovConstRegPatching::test() { -#ifdef ASSERT - ResourceMark rm; - CodeBuffer cb("test", 100, 100); - MacroAssembler* a = new MacroAssembler(&cb); - NativeMovConstRegPatching* nm; - uint idx; - int offsets[] = { - 0x0, - (int)0x7fffffff, - (int)0x80000000, - (int)0xffffffff, - 0x20, - 4096, - 4097, - }; - - VM_Version::allow_all(); - - AddressLiteral al1(0xaaaabbbb, relocInfo::external_word_type); - a->sethi(al1, I3); - a->nop(); - a->add(I3, al1.low10(), I3); - AddressLiteral al2(0xccccdddd, relocInfo::external_word_type); - a->sethi(al2, O2); - a->nop(); - a->add(O2, al2.low10(), O2); - - nm = nativeMovConstRegPatching_at( cb.insts_begin() ); - nm->print(); - - nm = nativeMovConstRegPatching_at( nm->next_instruction_address() ); - for (idx = 0; idx < ARRAY_SIZE(offsets); idx++) { - nm->set_data( offsets[idx] ); - assert(nm->data() == offsets[idx], "check unit test"); - } - nm->print(); - - VM_Version::revert(); -#endif // ASSERT -} -// End code for unit testing implementation of NativeMovConstRegPatching class - - -//------------------------------------------------------------------- - - -void NativeMovRegMem::verify() { - NativeInstruction::verify(); - // make sure code pattern is actually a "ld" or "st" of some sort. - int i0 = long_at(0); - int op3 = inv_op3(i0); - - assert((int)add_offset == NativeMovConstReg::add_offset, "sethi size ok"); - - if (!(is_op(i0, Assembler::ldst_op) && - inv_immed(i0) && - 0 != (op3 < op3_ldst_int_limit - ? (1 << op3 ) & (op3_mask_ld | op3_mask_st) - : (1 << (op3 - op3_ldst_int_limit)) & (op3_mask_ldf | op3_mask_stf)))) - { - int i1 = long_at(ldst_offset); - Register rd = inv_rd(i0); - - op3 = inv_op3(i1); - if (!is_op(i1, Assembler::ldst_op) && rd == inv_rs2(i1) && - 0 != (op3 < op3_ldst_int_limit - ? (1 << op3 ) & (op3_mask_ld | op3_mask_st) - : (1 << (op3 - op3_ldst_int_limit)) & (op3_mask_ldf | op3_mask_stf))) { - fatal("not a ld* or st* op"); - } - } -} - - -void NativeMovRegMem::print() { - if (is_immediate()) { - // offset is a signed 13-bit immediate, so casting it to int will not lose significant bits - tty->print_cr(INTPTR_FORMAT ": mov reg, [reg + %d]", p2i(instruction_address()), (int)offset()); - } else { - tty->print_cr(INTPTR_FORMAT ": mov reg, [reg + reg]", p2i(instruction_address())); - } -} - - -// Code for unit testing implementation of NativeMovRegMem class -void NativeMovRegMem::test() { -#ifdef ASSERT - ResourceMark rm; - CodeBuffer cb("test", 1000, 1000); - MacroAssembler* a = new MacroAssembler(&cb); - NativeMovRegMem* nm; - uint idx = 0; - uint idx1; - int offsets[] = { - 0x0, - (int)0xffffffff, - (int)0x7fffffff, - (int)0x80000000, - 4096, - 4097, - 0x20, - 0x4000, - }; - - VM_Version::allow_all(); - - AddressLiteral al1(0xffffffff, relocInfo::external_word_type); - AddressLiteral al2(0xaaaabbbb, relocInfo::external_word_type); - a->ldsw( G5, al1.low10(), G4 ); idx++; - a->sethi(al2, I3); a->add(I3, al2.low10(), I3); - a->ldsw( G5, I3, G4 ); idx++; - a->ldsb( G5, al1.low10(), G4 ); idx++; - a->sethi(al2, I3); a->add(I3, al2.low10(), I3); - a->ldsb( G5, I3, G4 ); idx++; - a->ldsh( G5, al1.low10(), G4 ); idx++; - a->sethi(al2, I3); a->add(I3, al2.low10(), I3); - a->ldsh( G5, I3, G4 ); idx++; - a->lduw( G5, al1.low10(), G4 ); idx++; - a->sethi(al2, I3); a->add(I3, al2.low10(), I3); - a->lduw( G5, I3, G4 ); idx++; - a->ldub( G5, al1.low10(), G4 ); idx++; - a->sethi(al2, I3); a->add(I3, al2.low10(), I3); - a->ldub( G5, I3, G4 ); idx++; - a->lduh( G5, al1.low10(), G4 ); idx++; - a->sethi(al2, I3); a->add(I3, al2.low10(), I3); - a->lduh( G5, I3, G4 ); idx++; - a->ldx( G5, al1.low10(), G4 ); idx++; - a->sethi(al2, I3); a->add(I3, al2.low10(), I3); - a->ldx( G5, I3, G4 ); idx++; - a->ldd( G5, al1.low10(), G4 ); idx++; - a->sethi(al2, I3); a->add(I3, al2.low10(), I3); - a->ldd( G5, I3, G4 ); idx++; - a->ldf( FloatRegisterImpl::D, O2, -1, F14 ); idx++; - a->sethi(al2, I3); a->add(I3, al2.low10(), I3); - a->ldf( FloatRegisterImpl::S, O0, I3, F15 ); idx++; - - a->stw( G5, G4, al1.low10() ); idx++; - a->sethi(al2, I3); a->add(I3, al2.low10(), I3); - a->stw( G5, G4, I3 ); idx++; - a->stb( G5, G4, al1.low10() ); idx++; - a->sethi(al2, I3); a->add(I3, al2.low10(), I3); - a->stb( G5, G4, I3 ); idx++; - a->sth( G5, G4, al1.low10() ); idx++; - a->sethi(al2, I3); a->add(I3, al2.low10(), I3); - a->sth( G5, G4, I3 ); idx++; - a->stx( G5, G4, al1.low10() ); idx++; - a->sethi(al2, I3); a->add(I3, al2.low10(), I3); - a->stx( G5, G4, I3 ); idx++; - a->std( G5, G4, al1.low10() ); idx++; - a->sethi(al2, I3); a->add(I3, al2.low10(), I3); - a->std( G5, G4, I3 ); idx++; - a->stf( FloatRegisterImpl::S, F18, O2, -1 ); idx++; - a->sethi(al2, I3); a->add(I3, al2.low10(), I3); - a->stf( FloatRegisterImpl::S, F15, O0, I3 ); idx++; - - nm = nativeMovRegMem_at( cb.insts_begin() ); - nm->print(); - nm->set_offset( low10(0) ); - nm->print(); - nm->add_offset_in_bytes( low10(0xbb) * wordSize ); - nm->print(); - - while (--idx) { - nm = nativeMovRegMem_at( nm->next_instruction_address() ); - nm->print(); - for (idx1 = 0; idx1 < ARRAY_SIZE(offsets); idx1++) { - nm->set_offset( nm->is_immediate() ? low10(offsets[idx1]) : offsets[idx1] ); - assert(nm->offset() == (nm->is_immediate() ? low10(offsets[idx1]) : offsets[idx1]), - "check unit test"); - nm->print(); - } - nm->add_offset_in_bytes( low10(0xbb) * wordSize ); - nm->print(); - } - - VM_Version::revert(); -#endif // ASSERT -} - -// End code for unit testing implementation of NativeMovRegMem class - - -//-------------------------------------------------------------------------------- - - -void NativeJump::verify() { - NativeInstruction::verify(); - int i0 = long_at(sethi_offset); - int i1 = long_at(jmpl_offset); - assert((int)jmpl_offset == (int)NativeMovConstReg::add_offset, "sethi size ok"); - // verify the pattern "sethi %hi22(imm), treg ; jmpl treg, %lo10(imm), lreg" - Register rd = inv_rd(i0); - // In LP64, the jump instruction location varies for non relocatable - // jumps, for example is could be sethi, xor, jmp instead of the - // 7 instructions for sethi. So let's check sethi only. - if (!is_op2(i0, Assembler::sethi_op2) && rd != G0 ) { - fatal("not a jump_to instruction"); - } -} - - -void NativeJump::print() { - tty->print_cr(INTPTR_FORMAT ": jmpl reg, " INTPTR_FORMAT, p2i(instruction_address()), p2i(jump_destination())); -} - - -// Code for unit testing implementation of NativeJump class -void NativeJump::test() { -#ifdef ASSERT - ResourceMark rm; - CodeBuffer cb("test", 100, 100); - MacroAssembler* a = new MacroAssembler(&cb); - NativeJump* nj; - uint idx; - int offsets[] = { - 0x0, - (int)0xffffffff, - (int)0x7fffffff, - (int)0x80000000, - 4096, - 4097, - 0x20, - 0x4000, - }; - - VM_Version::allow_all(); - - AddressLiteral al(0x7fffbbbb, relocInfo::external_word_type); - a->sethi(al, I3); - a->jmpl(I3, al.low10(), G0, RelocationHolder::none); - a->delayed()->nop(); - a->sethi(al, I3); - a->jmpl(I3, al.low10(), L3, RelocationHolder::none); - a->delayed()->nop(); - - nj = nativeJump_at( cb.insts_begin() ); - nj->print(); - - nj = nativeJump_at( nj->next_instruction_address() ); - for (idx = 0; idx < ARRAY_SIZE(offsets); idx++) { - nj->set_jump_destination( nj->instruction_address() + offsets[idx] ); - assert(nj->jump_destination() == (nj->instruction_address() + offsets[idx]), "check unit test"); - nj->print(); - } - - VM_Version::revert(); -#endif // ASSERT -} -// End code for unit testing implementation of NativeJump class - - -void NativeJump::insert(address code_pos, address entry) { - Unimplemented(); -} - -// MT safe inserting of a jump over an unknown instruction sequence (used by nmethod::makeZombie) -// The problem: jump_to is a 3-word instruction (including its delay slot). -// Atomic write can be only with 1 word. -void NativeJump::patch_verified_entry(address entry, address verified_entry, address dest) { - // Here's one way to do it: Pre-allocate a three-word jump sequence somewhere - // in the header of the nmethod, within a short branch's span of the patch point. - // Set up the jump sequence using NativeJump::insert, and then use an annulled - // unconditional branch at the target site (an atomic 1-word update). - // Limitations: You can only patch nmethods, with any given nmethod patched at - // most once, and the patch must be in the nmethod's header. - // It's messy, but you can ask the CodeCache for the nmethod containing the - // target address. - - // %%%%% For now, do something MT-stupid: - ResourceMark rm; - int code_size = 1 * BytesPerInstWord; - CodeBuffer cb(verified_entry, code_size + 1); - MacroAssembler* a = new MacroAssembler(&cb); - a->ldsw(G0, 0, O7); // "ld" must agree with code in the signal handler - ICache::invalidate_range(verified_entry, code_size); -} - - -void NativeIllegalInstruction::insert(address code_pos) { - NativeIllegalInstruction* nii = (NativeIllegalInstruction*) nativeInstruction_at(code_pos); - nii->set_long_at(0, illegal_instruction()); -} - -static int illegal_instruction_bits = 0; - -int NativeInstruction::illegal_instruction() { - if (illegal_instruction_bits == 0) { - ResourceMark rm; - char buf[40]; - CodeBuffer cbuf((address)&buf[0], 20); - MacroAssembler* a = new MacroAssembler(&cbuf); - address ia = a->pc(); - a->trap(ST_RESERVED_FOR_USER_0 + 1); - int bits = *(int*)ia; - assert(is_op3(bits, Assembler::trap_op3, Assembler::arith_op), "bad instruction"); - illegal_instruction_bits = bits; - assert(illegal_instruction_bits != 0, "oops"); - } - return illegal_instruction_bits; -} - -static int ic_miss_trap_bits = 0; - -bool NativeInstruction::is_ic_miss_trap() { - if (ic_miss_trap_bits == 0) { - ResourceMark rm; - char buf[40]; - CodeBuffer cbuf((address)&buf[0], 20); - MacroAssembler* a = new MacroAssembler(&cbuf); - address ia = a->pc(); - a->trap(Assembler::notEqual, Assembler::ptr_cc, G0, ST_RESERVED_FOR_USER_0 + 2); - int bits = *(int*)ia; - assert(is_op3(bits, Assembler::trap_op3, Assembler::arith_op), "bad instruction"); - ic_miss_trap_bits = bits; - assert(ic_miss_trap_bits != 0, "oops"); - } - return long_at(0) == ic_miss_trap_bits; -} - - -bool NativeInstruction::is_illegal() { - if (illegal_instruction_bits == 0) { - return false; - } - return long_at(0) == illegal_instruction_bits; -} - - -void NativeGeneralJump::verify() { - assert(((NativeInstruction *)this)->is_jump() || - ((NativeInstruction *)this)->is_cond_jump(), "not a general jump instruction"); -} - - -void NativeGeneralJump::insert_unconditional(address code_pos, address entry) { - Assembler::Condition condition = Assembler::always; - int x = Assembler::op2(Assembler::br_op2) | Assembler::annul(false) | - Assembler::cond(condition) | Assembler::wdisp((intptr_t)entry, (intptr_t)code_pos, 22); - NativeGeneralJump* ni = (NativeGeneralJump*) nativeInstruction_at(code_pos); - ni->set_long_at(0, x); -} - - -// MT-safe patching of a jmp instruction (and following word). -// First patches the second word, and then atomicly replaces -// the first word with the first new instruction word. -// Other processors might briefly see the old first word -// followed by the new second word. This is OK if the old -// second word is harmless, and the new second word may be -// harmlessly executed in the delay slot of the call. -void NativeGeneralJump::replace_mt_safe(address instr_addr, address code_buffer) { - assert(Patching_lock->is_locked() || - SafepointSynchronize::is_at_safepoint(), "concurrent code patching"); - assert (instr_addr != NULL, "illegal address for code patching"); - NativeGeneralJump* h_jump = nativeGeneralJump_at (instr_addr); // checking that it is a call - assert(NativeGeneralJump::instruction_size == 8, "wrong instruction size; must be 8"); - int i0 = ((int*)code_buffer)[0]; - int i1 = ((int*)code_buffer)[1]; - int* contention_addr = (int*) h_jump->addr_at(1*BytesPerInstWord); - assert(inv_op(*contention_addr) == Assembler::arith_op || - *contention_addr == nop_instruction(), - "must not interfere with original call"); - // The set_long_at calls do the ICacheInvalidate so we just need to do them in reverse order - h_jump->set_long_at(1*BytesPerInstWord, i1); - h_jump->set_long_at(0*BytesPerInstWord, i0); - // NOTE: It is possible that another thread T will execute - // only the second patched word. - // In other words, since the original instruction is this - // jmp patching_stub; nop (NativeGeneralJump) - // and the new sequence from the buffer is this: - // sethi %hi(K), %r; add %r, %lo(K), %r (NativeMovConstReg) - // what T will execute is this: - // jmp patching_stub; add %r, %lo(K), %r - // thereby putting garbage into %r before calling the patching stub. - // This is OK, because the patching stub ignores the value of %r. - - // Make sure the first-patched instruction, which may co-exist - // briefly with the call, will do something harmless. - assert(inv_op(*contention_addr) == Assembler::arith_op || - *contention_addr == nop_instruction(), - "must not interfere with original call"); -}