aoqi@1: /* aoqi@1: * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. aoqi@1: * Copyright (c) 2015, 2016, Loongson Technology. All rights reserved. aoqi@1: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@1: * aoqi@1: * This code is free software; you can redistribute it and/or modify it aoqi@1: * under the terms of the GNU General Public License version 2 only, as aoqi@1: * published by the Free Software Foundation. aoqi@1: * aoqi@1: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@1: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@1: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@1: * version 2 for more details (a copy is included in the LICENSE file that aoqi@1: * accompanied this code). aoqi@1: * aoqi@1: * You should have received a copy of the GNU General Public License version aoqi@1: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@1: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@1: * aoqi@1: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@1: * or visit www.oracle.com if you need additional information or have any aoqi@1: * questions. aoqi@1: * aoqi@1: */ aoqi@1: aoqi@1: #include "precompiled.hpp" aoqi@1: #include "asm/macroAssembler.hpp" aoqi@1: #include "memory/resourceArea.hpp" aoqi@1: #include "nativeInst_mips.hpp" aoqi@1: #include "oops/oop.inline.hpp" aoqi@1: #include "runtime/handles.hpp" aoqi@1: #include "runtime/sharedRuntime.hpp" aoqi@1: #include "runtime/stubRoutines.hpp" aoqi@1: #include "utilities/ostream.hpp" aoqi@1: #ifdef COMPILER1 aoqi@1: #include "c1/c1_Runtime1.hpp" aoqi@1: #endif aoqi@1: aoqi@1: #include aoqi@1: aoqi@1: void NativeInstruction::wrote(int offset) { aoqi@1: ICache::invalidate_word(addr_at(offset)); aoqi@1: } aoqi@1: aoqi@1: void NativeInstruction::set_long_at(int offset, long i) { aoqi@1: address addr = addr_at(offset); aoqi@1: *(long*)addr = i; aoqi@1: //ICache::invalidate_word(addr); aoqi@1: } aoqi@1: aoqi@1: static int illegal_instruction_bits = 0; aoqi@1: aoqi@1: int NativeInstruction::illegal_instruction() { aoqi@1: if (illegal_instruction_bits == 0) { aoqi@1: ResourceMark rm; aoqi@1: char buf[40]; aoqi@1: CodeBuffer cbuf((address)&buf[0], 20); aoqi@1: MacroAssembler* a = new MacroAssembler(&cbuf); aoqi@1: address ia = a->pc(); aoqi@1: a->brk(11); aoqi@1: int bits = *(int*)ia; aoqi@1: illegal_instruction_bits = bits; aoqi@1: } aoqi@1: return illegal_instruction_bits; aoqi@1: } aoqi@1: aoqi@1: bool NativeInstruction::is_int_branch() { aoqi@1: switch(Assembler::opcode(insn_word())) { aoqi@1: case Assembler::beq_op: aoqi@1: case Assembler::beql_op: aoqi@1: case Assembler::bgtz_op: aoqi@1: case Assembler::bgtzl_op: aoqi@1: case Assembler::blez_op: aoqi@1: case Assembler::blezl_op: aoqi@1: case Assembler::bne_op: aoqi@1: case Assembler::bnel_op: aoqi@1: return true; aoqi@1: case Assembler::regimm_op: aoqi@1: switch(Assembler::rt(insn_word())) { aoqi@1: case Assembler::bgez_op: aoqi@1: case Assembler::bgezal_op: aoqi@1: case Assembler::bgezall_op: aoqi@1: case Assembler::bgezl_op: aoqi@1: case Assembler::bltz_op: aoqi@1: case Assembler::bltzal_op: aoqi@1: case Assembler::bltzall_op: aoqi@1: case Assembler::bltzl_op: aoqi@1: return true; aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: return false; aoqi@1: } aoqi@1: aoqi@1: bool NativeInstruction::is_float_branch() { aoqi@1: if (!is_op(Assembler::cop1_op) || aoqi@1: !is_rs((Register)Assembler::bc_op)) return false; aoqi@1: aoqi@1: switch(Assembler::rt(insn_word())) { aoqi@1: case Assembler::bcf_op: aoqi@1: case Assembler::bcfl_op: aoqi@1: case Assembler::bct_op: aoqi@1: case Assembler::bctl_op: aoqi@1: return true; aoqi@1: } aoqi@1: aoqi@1: return false; aoqi@1: } aoqi@1: aoqi@1: aoqi@1: //------------------------------------------------------------------- aoqi@1: aoqi@1: void NativeCall::verify() { aoqi@1: // make sure code pattern is actually a call instruction aoqi@1: #ifndef _LP64 aoqi@1: if ( !is_op(Assembler::lui_op) || aoqi@1: !is_op(int_at(4), Assembler::addiu_op) || aoqi@1: !is_special_op(int_at(8), Assembler::jalr_op) ) { aoqi@1: fatal("not a call"); aoqi@1: } aoqi@1: #else aoqi@1: /* li64 or li48 */ aoqi@1: int li_64 = 0; aoqi@1: int li_48 = 0; aoqi@1: aoqi@1: if ( is_op (Assembler::lui_op) && aoqi@1: is_op (int_at(4), Assembler::ori_op) && aoqi@1: is_special_op(int_at(8), Assembler::dsll_op) && aoqi@1: is_op (int_at(12), Assembler::ori_op) && aoqi@1: is_special_op(int_at(16), Assembler::dsll_op) && aoqi@1: is_op (int_at(20), Assembler::ori_op) && aoqi@1: is_special_op(int_at(24), Assembler::jalr_op) ) { aoqi@1: li_64 = 1; aoqi@1: } aoqi@1: aoqi@1: if ( is_op (Assembler::lui_op) && aoqi@1: is_op (int_at(4), Assembler::ori_op) && aoqi@1: is_special_op(int_at(8), Assembler::dsll_op) && aoqi@1: is_op (int_at(12), Assembler::ori_op) && aoqi@1: is_special_op(int_at(16), Assembler::jalr_op) ) { aoqi@1: li_48 = 1; aoqi@1: } aoqi@1: aoqi@1: if (!li_64 && !li_48) { aoqi@1: tty->print_cr("NativeCall::verify addr=%lx", addr_at(0)); aoqi@1: fatal("not a call"); aoqi@1: } aoqi@1: #endif aoqi@1: } aoqi@1: aoqi@1: address NativeCall::destination() const { aoqi@1: #ifndef _LP64 aoqi@1: return (address)Assembler::merge(int_at(4)&0xffff, long_at(0)&0xffff); aoqi@1: #else aoqi@1: /* li64 or li48 */ aoqi@1: if (is_special_op(int_at(16), Assembler::dsll_op)) { aoqi@1: return (address)Assembler::merge( (intptr_t)(int_at(20) & 0xffff), aoqi@1: (intptr_t)(int_at(12) & 0xffff), aoqi@1: (intptr_t)(int_at(4) & 0xffff), aoqi@1: (intptr_t)(int_at(0) & 0xffff)); aoqi@1: } else if (is_special_op(int_at(16), Assembler::jalr_op)) { aoqi@1: return (address)Assembler::merge( (intptr_t)(int_at(12) & 0xffff), aoqi@1: (intptr_t)(int_at(4) & 0xffff), aoqi@1: (intptr_t)(int_at(0) & 0xffff), aoqi@1: (intptr_t)0); aoqi@1: } aoqi@1: #endif aoqi@1: } aoqi@1: aoqi@1: /* 2013/6/14 Jin: manual implementation of GSSQ aoqi@1: * aoqi@1: * 00000001200009c0 : aoqi@1: * 1200009c0: 0085202d daddu a0, a0, a1 aoqi@1: * 1200009c4: e8860027 gssq a2, a3, 0(a0) aoqi@1: * 1200009c8: 03e00008 jr ra aoqi@1: * 1200009cc: 00000000 nop aoqi@1: */ aoqi@1: typedef void (* atomic_store128_ptr)(long *addr, int offset, long low64, long hi64); aoqi@1: aoqi@1: static int *buf; aoqi@1: aoqi@1: static atomic_store128_ptr get_atomic_store128_func() aoqi@1: { aoqi@1: static atomic_store128_ptr p = NULL; aoqi@1: if (p != NULL) aoqi@1: return p; aoqi@1: aoqi@1: buf = (int *)mmap(NULL, 1024, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, aoqi@1: -1, 0); aoqi@1: buf[0] = 0x0085202d; aoqi@1: buf[1] = (0x3a << 26) | (4 << 21) | (6 << 16) | 0x27; /* gssq $a2, $a3, 0($a0) */ aoqi@1: buf[2] = 0x03e00008; aoqi@1: buf[3] = 0; aoqi@1: aoqi@1: p = (atomic_store128_ptr)buf; aoqi@1: return p; aoqi@1: } aoqi@1: aoqi@1: void NativeCall::set_destination(address dest) { aoqi@1: #ifndef _LP64 aoqi@1: OrderAccess::fence(); aoqi@1: set_int_at(0, (int_at(0) & 0xffff0000) | (Assembler::split_high((intptr_t)dest) & 0xffff)); aoqi@1: set_int_at(4, (int_at(4) & 0xffff0000) | (Assembler::split_low((intptr_t)dest) & 0xffff)); aoqi@1: ICache::invalidate_range(addr_at(0), 8); aoqi@1: #else aoqi@1: OrderAccess::fence(); aoqi@1: /* 2013/6/13 Jin: ensure 100% atomicity */ aoqi@1: guarantee(!os::is_MP() || (((long)addr_at(0) % 16) == 0), "destination must be aligned for GSSD"); aoqi@1: aoqi@1: /* li64 or li48 */ aoqi@1: if (is_special_op(int_at(16), Assembler::dsll_op)) { aoqi@1: int first_word = int_at(0); aoqi@1: set_int_at(0, 0x1000ffff); /* .1: b .1 */ aoqi@1: set_int_at(4, (int_at(4) & 0xffff0000) | (Assembler::split_low((intptr_t)dest >> 32) & 0xffff)); aoqi@1: set_int_at(12, (int_at(12) & 0xffff0000) | (Assembler::split_low((intptr_t)dest >> 16) & 0xffff)); aoqi@1: set_int_at(20, (int_at(20) & 0xffff0000) | (Assembler::split_low((intptr_t)dest) & 0xffff)); aoqi@1: set_int_at(0, (first_word & 0xffff0000) | (Assembler::split_low((intptr_t)dest >> 48) & 0xffff)); aoqi@1: ICache::invalidate_range(addr_at(0), 24); aoqi@1: } else if (is_special_op(int_at(16), Assembler::jalr_op)) { aoqi@1: int insts[4]; aoqi@1: insts[0] = (int_at(0) & 0xffff0000) | (Assembler::split_low((intptr_t)dest >> 32) & 0xffff); aoqi@1: insts[1] = (int_at(4) & 0xffff0000) | (Assembler::split_low((intptr_t)dest >> 16) & 0xffff); aoqi@1: insts[2] = int_at(8); aoqi@1: insts[3] = (int_at(12) & 0xffff0000) | (Assembler::split_low((intptr_t)dest) & 0xffff); aoqi@1: aoqi@1: atomic_store128_ptr func = get_atomic_store128_func(); aoqi@1: (*func)((long *)addr_at(0), 0, *(long *)&insts[0], *(long *)&insts[2]); aoqi@1: } else { aoqi@1: fatal("not a call"); aoqi@1: } aoqi@1: #endif aoqi@1: } aoqi@1: aoqi@1: void NativeCall::print() { aoqi@1: tty->print_cr(PTR_FORMAT ": call " PTR_FORMAT, aoqi@1: instruction_address(), destination()); aoqi@1: } aoqi@1: aoqi@1: // Inserts a native call instruction at a given pc aoqi@1: void NativeCall::insert(address code_pos, address entry) { aoqi@1: NativeCall *call = nativeCall_at(code_pos); aoqi@1: CodeBuffer cb(call->addr_at(0), instruction_size); aoqi@1: MacroAssembler masm(&cb); aoqi@1: #define __ masm. aoqi@1: #ifndef _LP64 aoqi@1: __ lui(T9, Assembler::split_high((int)entry)); aoqi@1: __ addiu(T9, T9, Assembler::split_low((int)entry)); aoqi@1: #else aoqi@1: __ li48(T9, (long)entry); aoqi@1: #endif aoqi@1: __ jalr (); aoqi@1: __ delayed()->nop(); aoqi@1: #undef __ aoqi@1: aoqi@1: ICache::invalidate_range(call->addr_at(0), instruction_size); aoqi@1: } aoqi@1: aoqi@1: // MT-safe patching of a call instruction. aoqi@1: // First patches first word of instruction to two jmp's that jmps to them aoqi@1: // selfs (spinlock). Then patches the last byte, and then atomicly replaces aoqi@1: // the jmp's with the first 4 byte of the new instruction. aoqi@1: void NativeCall::replace_mt_safe(address instr_addr, address code_buffer) { aoqi@1: Unimplemented(); aoqi@1: } aoqi@1: aoqi@1: //------------------------------------------------------------------- aoqi@1: aoqi@1: void NativeMovConstReg::verify() { aoqi@1: #ifndef _LP64 aoqi@1: if ( !is_op(Assembler::lui_op) || aoqi@1: !is_op(int_at(4), Assembler::addiu_op) ) aoqi@1: fatal("not a mov reg, imm32") aoqi@1: #else aoqi@1: /* li64 or li48 */ aoqi@1: int li_64 = 0; aoqi@1: int li_48 = 0; aoqi@1: aoqi@1: if ( is_op(Assembler::lui_op) && aoqi@1: is_op(int_at(4), Assembler::ori_op) && aoqi@1: is_special_op(int_at(8), Assembler::dsll_op) && aoqi@1: is_op(int_at(12), Assembler::ori_op) && aoqi@1: is_special_op(int_at(16), Assembler::dsll_op) && aoqi@1: is_op(int_at(20), Assembler::ori_op) ) aoqi@1: { aoqi@1: li_64 = 1; aoqi@1: } aoqi@1: aoqi@1: if ( is_op(Assembler::lui_op) && aoqi@1: is_op (int_at(4), Assembler::ori_op) && aoqi@1: is_special_op(int_at(8), Assembler::dsll_op) && aoqi@1: is_op (int_at(12), Assembler::ori_op) ) { aoqi@1: li_48 = 1; aoqi@1: } aoqi@1: aoqi@1: if (!li_64 && !li_48) { aoqi@1: fatal("not a mov reg, imm64/imm48"); aoqi@1: } aoqi@1: #endif aoqi@1: } aoqi@1: aoqi@1: void NativeMovConstReg::print() { aoqi@1: tty->print_cr(PTR_FORMAT ": mov reg, " INTPTR_FORMAT, aoqi@1: instruction_address(), data()); aoqi@1: } aoqi@1: aoqi@1: intptr_t NativeMovConstReg::data() const { aoqi@1: #ifndef _LP64 aoqi@1: return Assembler::merge(int_at(4)&0xffff, long_at(0)&0xffff); aoqi@1: #else aoqi@1: /* li64 or li48 */ aoqi@1: if (is_special_op(int_at(16), Assembler::dsll_op) && is_op(long_at(20), Assembler::ori_op)) { aoqi@1: return Assembler::merge( (intptr_t)(int_at(20) & 0xffff), aoqi@1: (intptr_t)(int_at(12) & 0xffff), aoqi@1: (intptr_t)(int_at(4) & 0xffff), aoqi@1: (intptr_t)(int_at(0) & 0xffff)); aoqi@1: } else { aoqi@1: return Assembler::merge( (intptr_t)(int_at(12) & 0xffff), aoqi@1: (intptr_t)(int_at(4) & 0xffff), aoqi@1: (intptr_t)(int_at(0) & 0xffff), aoqi@1: (intptr_t)0); aoqi@1: } aoqi@1: #endif aoqi@1: } aoqi@1: aoqi@1: void NativeMovConstReg::set_data(intptr_t x) { aoqi@1: /* aoqi@1: #ifndef CORE aoqi@1: // also store the value into an oop_Relocation cell, if any aoqi@1: CodeBlob* cb = CodeCache::find_blob(instruction_address()); aoqi@1: nmethod* nm = cb ? cb->as_nmethod_or_null() : NULL; aoqi@1: if (nm != NULL) { aoqi@1: RelocIterator iter(nm, instruction_address(), instruction_address() + 1); aoqi@1: oop* oop_addr = NULL; aoqi@1: while (iter.next()) { aoqi@1: if (iter.type() == relocInfo::oop_type) { aoqi@1: oop_Relocation *r = iter.oop_reloc(); aoqi@1: if (oop_addr == NULL && r->oop_index()!=0) { aoqi@1: oop_addr = r->oop_addr(); aoqi@1: *oop_addr = (oop)x; aoqi@1: } else { aoqi@1: assert(oop_addr == r->oop_addr(), "must be only one set-oop here"); aoqi@1: } aoqi@1: } aoqi@1: } aoqi@1: } aoqi@1: #endif aoqi@1: */ aoqi@1: aoqi@1: #ifndef _LP64 aoqi@1: set_int_at(0, (int_at(0) & 0xffff0000) | (Assembler::split_high(x) & 0xffff)); aoqi@1: set_int_at(4, (int_at(4) & 0xffff0000) | (Assembler::split_low(x) & 0xffff)); aoqi@1: ICache::invalidate_range(addr_at(0), 8); aoqi@1: #else aoqi@1: /* li64 or li48 */ aoqi@1: if (is_special_op(int_at(16), Assembler::dsll_op) && is_op(long_at(20), Assembler::ori_op)) { aoqi@1: set_int_at(0, (int_at(0) & 0xffff0000) | (Assembler::split_low((intptr_t)x >> 48) & 0xffff)); aoqi@1: set_int_at(4, (int_at(4) & 0xffff0000) | (Assembler::split_low((intptr_t)x >> 32) & 0xffff)); aoqi@1: set_int_at(12, (int_at(12) & 0xffff0000) | (Assembler::split_low((intptr_t)x >> 16) & 0xffff)); aoqi@1: set_int_at(20, (int_at(20) & 0xffff0000) | (Assembler::split_low((intptr_t)x) & 0xffff)); aoqi@1: } else { aoqi@1: //assert(is_simm16(dest >> 32), "Not a 48-bit address"); aoqi@1: set_int_at(0, (int_at(0) & 0xffff0000) | (Assembler::split_low((intptr_t)x >> 32) & 0xffff)); aoqi@1: set_int_at(4, (int_at(4) & 0xffff0000) | (Assembler::split_low((intptr_t)x >> 16) & 0xffff)); aoqi@1: set_int_at(12, (int_at(12) & 0xffff0000) | (Assembler::split_low((intptr_t)x) & 0xffff)); aoqi@1: } aoqi@1: ICache::invalidate_range(addr_at(0), 24); aoqi@1: #endif aoqi@1: } aoqi@1: aoqi@1: //------------------------------------------------------------------- aoqi@1: aoqi@1: int NativeMovRegMem::offset() const{ aoqi@1: if (is_immediate()) aoqi@1: return (short)(int_at(instruction_offset)&0xffff); aoqi@1: else aoqi@1: return Assembler::merge(int_at(hiword_offset)&0xffff, long_at(instruction_offset)&0xffff); aoqi@1: } aoqi@1: aoqi@1: void NativeMovRegMem::set_offset(int x) { aoqi@1: if (is_immediate()) { aoqi@1: assert(Assembler::is_simm16(x), "just check"); aoqi@1: set_int_at(0, (int_at(0)&0xffff0000) | (x&0xffff) ); aoqi@1: if (is_64ldst()) { aoqi@1: assert(Assembler::is_simm16(x+4), "just check"); aoqi@1: set_int_at(4, (int_at(4)&0xffff0000) | ((x+4)&0xffff) ); aoqi@1: } aoqi@1: } else { aoqi@1: set_int_at(0, (int_at(0) & 0xffff0000) | (Assembler::split_high(x) & 0xffff)); aoqi@1: set_int_at(4, (int_at(4) & 0xffff0000) | (Assembler::split_low(x) & 0xffff)); aoqi@1: } aoqi@1: ICache::invalidate_range(addr_at(0), 8); aoqi@1: } aoqi@1: aoqi@1: void NativeMovRegMem::verify() { aoqi@1: int offset = 0; aoqi@1: aoqi@1: if ( Assembler::opcode(int_at(0)) == Assembler::lui_op ) { aoqi@1: #ifndef _LP64 aoqi@1: if ( (Assembler::opcode(int_at(4)) != Assembler::addiu_op) || aoqi@1: (Assembler::opcode(int_at(8)) != Assembler::special_op) || aoqi@1: (Assembler::special(int_at(8)) != Assembler::add_op)) aoqi@1: #else aoqi@1: /* Jin: fit MIPS64 */ aoqi@1: if ( (Assembler::opcode(int_at(4)) != Assembler::addiu_op && aoqi@1: Assembler::opcode(int_at(4)) != Assembler::daddiu_op ) || aoqi@1: (Assembler::opcode(int_at(8)) != Assembler::special_op) || aoqi@1: (Assembler::special(int_at(8)) != Assembler::add_op aoqi@1: && Assembler::special(int_at(8)) != Assembler::dadd_op)) aoqi@1: #endif aoqi@1: fatal ("not a mov [reg+offs], reg instruction"); aoqi@1: offset += 12; aoqi@1: } aoqi@1: aoqi@1: switch(Assembler::opcode(int_at(offset))) { aoqi@1: case Assembler::lb_op: aoqi@1: case Assembler::lbu_op: aoqi@1: case Assembler::lh_op: aoqi@1: case Assembler::lhu_op: aoqi@1: case Assembler::lw_op: aoqi@1: LP64_ONLY(case Assembler::ld_op:) aoqi@1: case Assembler::lwc1_op: aoqi@1: LP64_ONLY(case Assembler::ldc1_op:) aoqi@1: case Assembler::sb_op: aoqi@1: case Assembler::sh_op: aoqi@1: case Assembler::sw_op: aoqi@1: LP64_ONLY(case Assembler::sd_op:) aoqi@1: case Assembler::swc1_op: aoqi@1: LP64_ONLY(case Assembler::sdc1_op:) aoqi@1: break; aoqi@1: default: aoqi@1: fatal ("not a mov [reg+offs], reg instruction"); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: aoqi@1: void NativeMovRegMem::print() { aoqi@1: tty->print_cr("0x%x: mov reg, [reg + %x]", instruction_address(), offset()); aoqi@1: } aoqi@1: aoqi@1: aoqi@1: aoqi@1: void NativeIllegalInstruction::insert(address code_pos) { aoqi@1: CodeBuffer cb(code_pos, instruction_size); aoqi@1: MacroAssembler masm(&cb); aoqi@1: #define __ masm. aoqi@1: __ brk(11); aoqi@1: #undef __ aoqi@1: aoqi@1: ICache::invalidate_range(code_pos, instruction_size); aoqi@1: } aoqi@1: aoqi@1: void NativeGeneralJump::verify() { aoqi@1: assert(((NativeInstruction *)this)->is_jump() || aoqi@1: ((NativeInstruction *)this)->is_cond_jump(), "not a general jump instruction"); aoqi@1: } aoqi@1: aoqi@1: aoqi@1: void NativeGeneralJump::set_jump_destination(address dest) { aoqi@1: //tty->print_cr("NativeGeneralJump::set_jump_destination dest=%lx", dest); aoqi@1: OrderAccess::fence(); aoqi@1: aoqi@1: if (is_short()) { aoqi@1: assert(Assembler::is_simm16(dest-addr_at(4)), "change this code"); aoqi@1: set_int_at(0, (int_at(0) & 0xffff0000) | (dest - addr_at(4)) & 0xffff ); aoqi@1: ICache::invalidate_range(addr_at(0), 4); aoqi@1: #ifdef _LP64 aoqi@1: } else if (is_b_far()) { aoqi@1: int offset = dest - addr_at(12); aoqi@1: set_int_at(12, (int_at(12) & 0xffff0000) | (offset >> 16)); aoqi@1: set_int_at(16, (int_at(16) & 0xffff0000) | (offset & 0xffff)); aoqi@1: #endif aoqi@1: } else { aoqi@1: #ifndef _LP64 aoqi@1: set_int_at(0, (int_at(0) & 0xffff0000) | (Assembler::split_high((intptr_t)dest) & 0xffff)); aoqi@1: set_int_at(4, (int_at(4) & 0xffff0000) | (Assembler::split_low((intptr_t)dest) & 0xffff)); aoqi@1: ICache::invalidate_range(addr_at(0), 8); aoqi@1: #else aoqi@1: /* li64 or li48 */ aoqi@1: if (is_special_op(int_at(16), Assembler::dsll_op)) { aoqi@1: set_int_at(0, (int_at(0) & 0xffff0000) | (Assembler::split_low((intptr_t)dest >> 48) & 0xffff)); aoqi@1: set_int_at(4, (int_at(4) & 0xffff0000) | (Assembler::split_low((intptr_t)dest >> 32) & 0xffff)); aoqi@1: set_int_at(12, (int_at(12) & 0xffff0000) | (Assembler::split_low((intptr_t)dest >> 16) & 0xffff)); aoqi@1: set_int_at(20, (int_at(20) & 0xffff0000) | (Assembler::split_low((intptr_t)dest) & 0xffff)); aoqi@1: } else { aoqi@1: int jr_word = int_at(16); aoqi@1: set_int_at(16, 0x1000fffb); /* .1: --; --; --; --; b .1; nop */ aoqi@1: aoqi@1: set_int_at(0, (int_at(0) & 0xffff0000) | (Assembler::split_low((intptr_t)dest >> 32) & 0xffff)); aoqi@1: set_int_at(4, (int_at(4) & 0xffff0000) | (Assembler::split_low((intptr_t)dest >> 16) & 0xffff)); aoqi@1: set_int_at(12, (int_at(12) & 0xffff0000) | (Assembler::split_low((intptr_t)dest) & 0xffff)); aoqi@1: set_int_at(16, jr_word); /* .1: --; --; --; --; jr ; nop */ aoqi@1: } aoqi@1: aoqi@1: ICache::invalidate_range(addr_at(0), 24); aoqi@1: #endif aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: // we now use b to do this. be careful when using this method aoqi@1: // by yjl 9/16/2005 aoqi@1: void NativeGeneralJump::insert_unconditional(address code_pos, address entry) { aoqi@1: CodeBuffer cb(code_pos, instruction_size); aoqi@1: MacroAssembler masm(&cb); aoqi@1: #define __ masm. aoqi@1: #ifdef _LP64 aoqi@1: if (Assembler::is_simm16((entry - code_pos - 4) / 4)) aoqi@1: { aoqi@1: __ b(entry); aoqi@1: __ delayed()->nop(); aoqi@1: } aoqi@1: else aoqi@1: { aoqi@1: /* a simplified b_far */ aoqi@1: int offset = entry - code_pos; aoqi@1: aoqi@1: // FIXME: need to preserve RA? aoqi@1: __ emit_long(0x4110001); //__ emit_long(Assembler::insn_ORRI(Assembler::regimm_op, 0, Assembler::bgezal_op, 1)); aoqi@1: __ lui(T9, (offset - 8) >> 16); // delay slot aoqi@1: __ ori(T9, T9, (offset - 8) & 0xffff); aoqi@1: __ daddu(T9, T9, RA); aoqi@1: __ jr(T9); aoqi@1: __ nop(); aoqi@1: } aoqi@1: #else aoqi@1: __ b(entry); aoqi@1: __ delayed()->nop(); aoqi@1: #endif aoqi@1: #undef __ aoqi@1: aoqi@1: ICache::invalidate_range(code_pos, instruction_size); aoqi@1: } aoqi@1: aoqi@1: #ifdef _LP64 aoqi@1: bool NativeGeneralJump::is_b_far() { aoqi@1: /* aoqi@1: 0x000000556809f198: dadd at, ra, zero aoqi@1: 0x000000556809f19c: [4110001]bgezal zero, 0x000000556809f1a4 aoqi@1: aoqi@1: 0x000000556809f1a0: nop aoqi@1: 0x000000556809f1a4: lui t9, 0xfffffffd aoqi@1: 0x000000556809f1a8: ori t9, t9, 0x14dc aoqi@1: 0x000000556809f1ac: daddu t9, t9, ra aoqi@1: 0x000000556809f1b0: dadd ra, at, zero aoqi@1: 0x000000556809f1b4: jr t9 aoqi@1: 0x000000556809f1b8: nop aoqi@1: ;; ImplicitNullCheckStub slow case aoqi@1: 0x000000556809f1bc: lui t9, 0x55 aoqi@1: */ aoqi@1: return is_op(int_at(12), Assembler::lui_op); aoqi@1: } aoqi@1: #endif aoqi@1: aoqi@1: address NativeGeneralJump::jump_destination() { aoqi@1: if ( is_short() ) { aoqi@1: return addr_at(4) + Assembler::imm_off(int_at(instruction_offset)) * 4; aoqi@1: } aoqi@1: #ifndef _LP64 aoqi@1: return (address)Assembler::merge(int_at(4)&0xffff, long_at(instruction_offset)&0xffff); aoqi@1: #else aoqi@1: /* 2012/4/19 Jin: Assembler::merge() is not correct in MIPS_64! aoqi@1: aoqi@1: Example: aoqi@1: hi16 = 0xfffd, aoqi@1: lo16 = f7a4, aoqi@1: aoqi@1: offset=0xfffdf7a4 (Right) aoqi@1: Assembler::merge = 0xfffcf7a4 (Wrong) aoqi@1: */ aoqi@1: if ( is_b_far() ) { aoqi@1: int hi16 = int_at(12)&0xffff; aoqi@1: int low16 = int_at(16)&0xffff; aoqi@1: address target = addr_at(12) + (hi16 << 16) + low16; aoqi@1: return target; aoqi@1: } aoqi@1: aoqi@1: /* li64 or li48 */ aoqi@1: if (is_special_op(int_at(16), Assembler::dsll_op)) { aoqi@1: return (address)Assembler::merge( (intptr_t)(int_at(20) & 0xffff), aoqi@1: (intptr_t)(int_at(12) & 0xffff), aoqi@1: (intptr_t)(int_at(4) & 0xffff), aoqi@1: (intptr_t)(int_at(0) & 0xffff)); aoqi@1: } else { aoqi@1: return (address)Assembler::merge( (intptr_t)(int_at(12) & 0xffff), aoqi@1: (intptr_t)(int_at(4) & 0xffff), aoqi@1: (intptr_t)(int_at(0) & 0xffff), aoqi@1: ((int_at(0) & 0xffff) >= 0x8000) ? (intptr_t)0xffff : (intptr_t)0); /* sign-extended to 64-bit*/ aoqi@1: } aoqi@1: #endif aoqi@1: } aoqi@1: aoqi@1: // MT-safe patching of a long jump instruction. aoqi@1: // First patches first word of instruction to two jmp's that jmps to them aoqi@1: // selfs (spinlock). Then patches the last byte, and then atomicly replaces aoqi@1: // the jmp's with the first 4 byte of the new instruction. aoqi@1: void NativeGeneralJump::replace_mt_safe(address instr_addr, address code_buffer) { aoqi@1: NativeGeneralJump* h_jump = nativeGeneralJump_at (instr_addr); aoqi@1: assert(NativeGeneralJump::instruction_size == NativeCall::instruction_size, aoqi@1: "note::Runtime1::patch_code uses NativeCall::instruction_size"); aoqi@1: aoqi@1: /* 2013/6/13 Jin: ensure 100% atomicity */ aoqi@1: guarantee(!os::is_MP() || (((long)instr_addr % BytesPerWord) == 0), "destination must be aligned for SD"); aoqi@1: aoqi@1: int *p = (int *)instr_addr; aoqi@1: int jr_word = p[4]; aoqi@1: aoqi@1: p[4] = 0x1000fffb; /* .1: --; --; --; --; b .1; nop */ aoqi@1: memcpy(instr_addr, code_buffer, NativeCall::instruction_size - 8); aoqi@1: *(long *)(instr_addr + 16) = *(long *)(code_buffer + 16); aoqi@1: } aoqi@1: aoqi@1: /* Must ensure atomicity */ aoqi@1: void NativeGeneralJump::patch_verified_entry(address entry, address verified_entry, address dest) { aoqi@1: /* 2013/11/5 Jin: ensure 100% atomicity. aoqi@1: * The destination is fixed and can be cached in JavaThread. aoqi@1: */ aoqi@1: guarantee(!os::is_MP() || (((long)verified_entry % BytesPerWord) == 0), "destination must be aligned for SD"); aoqi@1: aoqi@1: int code_buffer[4]; aoqi@1: aoqi@1: CodeBuffer cb((address)code_buffer, instruction_size); aoqi@1: MacroAssembler masm(&cb); aoqi@1: #define __ masm. aoqi@1: __ ld(T9, TREG, in_bytes(JavaThread::handle_wrong_method_stub_offset())); aoqi@1: __ jr(T9); aoqi@1: __ delayed()->nop(); aoqi@1: __ nop(); aoqi@1: aoqi@1: atomic_store128_ptr func = get_atomic_store128_func(); aoqi@1: (*func)((long *)verified_entry, 0, *(long *)&code_buffer[0], *(long *)&code_buffer[2]); aoqi@1: aoqi@1: ICache::invalidate_range(verified_entry, instruction_size); aoqi@1: } aoqi@1: aoqi@1: bool NativeInstruction::is_jump() aoqi@1: { aoqi@1: #ifndef _LP64 aoqi@1: return ((int_at(0) & NativeGeneralJump::b_mask) == NativeGeneralJump::beq_opcode) || aoqi@1: (is_op(int_at(0), Assembler::lui_op) && aoqi@1: is_op(int_at(4), Assembler::addiu_op) && aoqi@1: is_special_op(int_at(8), Assembler::jr_op)); aoqi@1: #else aoqi@1: // lui rd, imm(63...48); aoqi@1: // ori rd, rd, imm(47...32); aoqi@1: // dsll rd, rd, 16; aoqi@1: // ori rd, rd, imm(31...16); aoqi@1: // dsll rd, rd, 16; aoqi@1: // ori rd, rd, imm(15...0); aoqi@1: // jalr rd aoqi@1: // nop aoqi@1: // aoqi@1: if ((int_at(0) & NativeGeneralJump::b_mask) == NativeGeneralJump::beq_opcode) aoqi@1: return true; aoqi@1: if (is_op(int_at(4), Assembler::lui_op)) /* simplified b_far */ aoqi@1: return true; aoqi@1: if (is_op(int_at(12), Assembler::lui_op)) /* original b_far */ aoqi@1: return true; aoqi@1: if (is_op(int_at(0), Assembler::lui_op) && aoqi@1: is_op(int_at(4), Assembler::ori_op) && aoqi@1: is_special_op(int_at(8), Assembler::dsll_op) && aoqi@1: is_op(int_at(12), Assembler::ori_op) && aoqi@1: is_special_op(int_at(16), Assembler::dsll_op) && aoqi@1: is_op(int_at(20), Assembler::ori_op)) aoqi@1: return true; aoqi@1: if (is_op(int_at(0), Assembler::lui_op) && aoqi@1: is_op(int_at(4), Assembler::ori_op) && aoqi@1: is_special_op(int_at(8), Assembler::dsll_op) && aoqi@1: is_op(int_at(12), Assembler::ori_op)) aoqi@1: return true; aoqi@1: return false; aoqi@1: #endif aoqi@1: } aoqi@1: aoqi@1: bool NativeInstruction::is_dtrace_trap() { aoqi@1: //return (*(int32_t*)this & 0xff) == 0xcc; aoqi@1: Unimplemented(); aoqi@1: return false; aoqi@1: } aoqi@1: aoqi@1: // is mips we have to use two instruction to poll, however, we don't want to bother checking two instructions aoqi@1: // instead, we use a lw $0, at() as the second instruction, and only check this. aoqi@1: // change ZERO -> AT, only in godson-2e @jerome,11/25/2006 aoqi@1: bool NativeInstruction::is_safepoint_poll() { aoqi@1: #ifdef _LP64 aoqi@1: /* aoqi@1: 0x0000005565d28868: lui t2, 0x0 ; -24 aoqi@1: 0x0000005565d2886c: ori t2, t2, 0x55 ; -20 aoqi@1: 0x0000005565d28870: dsll t2, t2, 16 ; -16 aoqi@1: 0x0000005565d28874: ori t2, t2, 0x6428 ; -12 aoqi@1: 0x0000005565d28878: dsll t2, t2, 16 ; -8 aoqi@1: 0x0000005565d2887c: ori t2, t2, 0x100 ; -4 aoqi@1: 0x0000005565d28880: lw at, 0x0(t2) <-- PC aoqi@1: */ aoqi@1: #ifndef OPT_SAFEPOINT aoqi@1: /* li64 or li48 */ aoqi@1: if (is_op(Assembler::lw_op) && is_rt(AT)) { aoqi@1: return true; aoqi@1: } else if (is_special_op(long_at(-16), Assembler::dsll_op)) { aoqi@1: /* li64 */ aoqi@1: return (is_op(int_at(-24), Assembler::lui_op) && aoqi@1: is_op(int_at(-20), Assembler::ori_op) && aoqi@1: is_special_op(int_at(-16), Assembler::dsll_op) && aoqi@1: is_op(int_at(-12), Assembler::ori_op) && aoqi@1: is_special_op(int_at(-8), Assembler::dsll_op) && aoqi@1: is_op(int_at(-4), Assembler::ori_op) && aoqi@1: is_op(Assembler::lw_op) && aoqi@1: is_rt(AT)); aoqi@1: } else if (is_op(int_at(-16), Assembler::lui_op)) { aoqi@1: /* li48 */ aoqi@1: return is_op(int_at(-16), Assembler::lui_op) && aoqi@1: is_op(int_at(-12), Assembler::ori_op) && aoqi@1: is_special_op(int_at(-8), Assembler::dsll_op) && aoqi@1: is_op(int_at(-4), Assembler::ori_op) && aoqi@1: is_op(Assembler::lw_op) && aoqi@1: is_rt(AT); aoqi@1: } else { aoqi@1: return false; aoqi@1: } aoqi@1: #else // OPT_SAFEPOINT aoqi@1: return is_op(int_at(-4), Assembler::lui_op) && aoqi@1: is_op(Assembler::lw_op) && aoqi@1: is_rt(AT); aoqi@1: #endif aoqi@1: #else aoqi@1: return is_op(int_at(-4), Assembler::lui_op) && aoqi@1: is_op(Assembler::lw_op) && aoqi@1: is_rt(AT); aoqi@1: #endif aoqi@1: }