Mercurial > hg > openjdk6-mips
view hotspot/src/cpu/mips/vm/nativeInst_mips.cpp @ 20:7a9f890eafef
Fix 2 bugs which are related to patching.
NativeGeneralJump represents both long and short jump instructions,
so they must be dealed respectively in patching. Otherwise patching
produces wrong results.
author | YANG Yongqiang <yangyongqiang@loongson.cn> |
---|---|
date | Mon, 01 Nov 2010 17:41:18 +0800 |
parents | c1e1428eff7c |
children | 388ae1bd0bdd |
line wrap: on
line source
/* * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. * Copyright 2010 Lemote, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. * */ # include "incls/_precompiled.incl" # include "incls/_nativeInst_mips.cpp.incl" void NativeInstruction::wrote(int offset) { ICache::invalidate_word(addr_at(offset)); } void NativeInstruction::set_long_at(int offset, int i) { address addr = addr_at(offset); *(int*)addr = i; //ICache::invalidate_word(addr); } void NativeCall::verify() { // make sure code pattern is actually a call instruction if ( !is_op(Assembler::lui_op) || !is_op(long_at(4), Assembler::addiu_op) || !is_special_op(long_at(8), Assembler::jalr_op) ) { fatal("not a call"); } } 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->brk(11); int bits = *(int*)ia; illegal_instruction_bits = bits; } return illegal_instruction_bits; } bool NativeInstruction::is_int_branch() { switch(Assembler::opcode(insn_word())) { case Assembler::beq_op: case Assembler::beql_op: case Assembler::bgtz_op: case Assembler::bgtzl_op: case Assembler::blez_op: case Assembler::blezl_op: case Assembler::bne_op: case Assembler::bnel_op: return true; case Assembler::regimm_op: switch(Assembler::rt(insn_word())) { case Assembler::bgez_op: case Assembler::bgezal_op: case Assembler::bgezall_op: case Assembler::bgezl_op: case Assembler::bltz_op: case Assembler::bltzal_op: case Assembler::bltzall_op: case Assembler::bltzl_op: return true; } } return false; } bool NativeInstruction::is_float_branch() { if (!is_op(Assembler::cop1_op) || !is_rs((Register)Assembler::bc_op)) return false; switch(Assembler::rt(insn_word())) { case Assembler::bcf_op: case Assembler::bcfl_op: case Assembler::bct_op: case Assembler::bctl_op: return true; } return false; } address NativeCall::destination() const { return (address)Assembler::merge(long_at(4)&0xffff, long_at(0)&0xffff); } void NativeCall::print() { tty->print_cr(PTR_FORMAT ": call " PTR_FORMAT, instruction_address(), destination()); } // Inserts a native call instruction at a given pc void NativeCall::insert(address code_pos, address entry) { NativeCall *call = nativeCall_at(code_pos); CodeBuffer cb(call->addr_at(0), instruction_size); MacroAssembler masm(&cb); #define __ masm. //__ move (T9, (int)entry); __ lui(T9, Assembler::split_high((int)entry)); __ addiu(T9, T9, Assembler::split_low((int)entry)); __ jalr (); #undef __ ICache::invalidate_range(call->addr_at(0), instruction_size); // ICache::invalidate_all(); } // MT-safe patching of a call instruction. // First patches first word of instruction to two jmp's that jmps to them // selfs (spinlock). Then patches the last byte, and then atomicly replaces // the jmp's with the first 4 byte of the new instruction. void NativeCall::replace_mt_safe(address instr_addr, address code_buffer) { Unimplemented(); } void NativeMovConstReg::verify() { if ( !is_op(Assembler::lui_op) || !is_op(long_at(4), Assembler::addiu_op) ) fatal("not a mov reg, imm32") } void NativeMovConstReg::print() { tty->print_cr(PTR_FORMAT ": mov reg, " INTPTR_FORMAT, instruction_address(), data()); } void NativeMovConstReg::set_data(int x) { set_long_at(0, (long_at(0) & 0xffff0000) | (Assembler::split_high(x) & 0xffff)); set_long_at(4, (long_at(4) & 0xffff0000) | (Assembler::split_low(x) & 0xffff)); ICache::invalidate_range(addr_at(0), 8); // ICache::invalidate_all(); #ifndef CORE // also store the value into an oop_Relocation cell, if any CodeBlob* nm = CodeCache::find_blob(instruction_address()); if (nm != NULL) { RelocIterator iter(nm, instruction_address(), instruction_address() + 1); oop* oop_addr = NULL; while (iter.next()) { if (iter.type() == relocInfo::oop_type) { oop_Relocation *r = iter.oop_reloc(); if (oop_addr == NULL && r->oop_index()!=0) { oop_addr = r->oop_addr(); *oop_addr = (oop)x; } else { assert(oop_addr == r->oop_addr(), "must be only one set-oop here"); } } } } #endif } //------------------------------------------------------------------- int NativeMovRegMem::offset() const{ if (is_immediate()) return (short)(long_at(instruction_offset)&0xffff); else return Assembler::merge(long_at(hiword_offset)&0xffff, long_at(instruction_offset)&0xffff); } void NativeMovRegMem::set_offset(int x) { if (is_immediate()) { assert(Assembler::is_simm16(x), "just check"); set_long_at(0, (long_at(0)&0xffff0000) | (x&0xffff) ); if (is_64ldst()) { assert(Assembler::is_simm16(x+4), "just check"); set_long_at(4, (long_at(4)&0xffff0000) | ((x+4)&0xffff) ); } } else { set_long_at(0, (long_at(0) & 0xffff0000) | (Assembler::split_high(x) & 0xffff)); set_long_at(4, (long_at(4) & 0xffff0000) | (Assembler::split_low(x) & 0xffff)); } ICache::invalidate_range(addr_at(0), 8); } void NativeMovRegMem::verify() { int offset = 0; if ( Assembler::opcode(long_at(0)) == Assembler::lui_op ) { if ( (Assembler::opcode(long_at(4)) != Assembler::addiu_op) || (Assembler::opcode(long_at(8)) != Assembler::special_op) || (Assembler::special(long_at(8)) != Assembler::add_op)) fatal ("not a mov [reg+offs], reg instruction"); offset += 12; } switch(Assembler::opcode(long_at(offset))) { case Assembler::lb_op: case Assembler::lbu_op: case Assembler::lh_op: case Assembler::lhu_op: case Assembler::lw_op: case Assembler::lwc1_op: case Assembler::sb_op: case Assembler::sh_op: case Assembler::sw_op: case Assembler::swc1_op: break; default: fatal ("not a mov [reg+offs], reg instruction"); } } void NativeMovRegMem::print() { tty->print_cr("0x%x: mov reg, [reg + %x]", instruction_address(), offset()); } void NativeIllegalInstruction::insert(address code_pos) { CodeBuffer cb(code_pos, instruction_size); MacroAssembler masm(&cb); #define __ masm. __ brk(11); #undef __ ICache::invalidate_range(code_pos, instruction_size); } void NativeGeneralJump::verify() { assert(((NativeInstruction *)this)->is_jump() || ((NativeInstruction *)this)->is_cond_jump(), "not a general jump instruction"); } void NativeGeneralJump::set_jump_destination(address dest) { OrderAccess::fence(); if (is_short()) { assert(Assembler::is_simm16(dest-addr_at(4)), "change this code"); set_long_at(0, (long_at(0) & 0xffff0000) | (dest - addr_at(4)) & 0xffff ); ICache::invalidate_range(addr_at(0), 4); } else { set_long_at(0, (long_at(0) & 0xffff0000) | (Assembler::split_high((int)dest) & 0xffff)); set_long_at(4, (long_at(4) & 0xffff0000) | (Assembler::split_low((int)dest) & 0xffff)); ICache::invalidate_range(addr_at(0), 8); } } // we now use b to do this. be careful when using this method // by yjl 9/16/2005 void NativeGeneralJump::insert_unconditional(address code_pos, address entry) { CodeBuffer cb(code_pos, instruction_size + 4); MacroAssembler masm(&cb); #define __ masm. // __ lui(AT, Assembler::split_high((int)entry)); // __ addiu(AT, AT, Assembler::split_low((int)entry)); // __ jr (AT); // __ delayed()->nop(); __ b(entry); __ delayed()->nop(); #undef __ ICache::invalidate_range(code_pos, instruction_size + 4); } // MT-safe patching of a long jump instruction. // First patches first word of instruction to two jmp's that jmps to them // selfs (spinlock). Then patches the last byte, and then atomicly replaces // the jmp's with the first 4 byte of the new instruction. void NativeGeneralJump::replace_mt_safe(address instr_addr, address code_buffer) { NativeGeneralJump* h_jump = nativeGeneralJump_at (instr_addr); int i0, i1 , i2; if(!h_jump->is_short()) { i2 = ((int*)code_buffer)[2]; h_jump->set_long_at(2 * BytesPerInstWord, i2); } i1 = ((int*)code_buffer)[1]; h_jump->set_long_at(1 * BytesPerInstWord, i1); i0 = ((int*)code_buffer)[0]; h_jump->set_long_at(0 * BytesPerInstWord, i0); // beq ZERO, ZERO, -1 // 0001 0000 0000 0000 1111 1111 1111 1111 ICache::invalidate_range(h_jump->addr_at(0), instruction_size); } // NOTE : here i use T9 as the destination register, maybe i should get some hint from entry. FIXME // by yjl 8/30/2005 void NativeGeneralJump::patch_verified_entry(address entry, address verified_entry, address dest) { unsigned int code_buffer[4]; address tmp = (address)code_buffer; // lui(T9, Assembler::split_high(dest)) // 0011 1100 0001 1001 Assembler::split_high(dest) *(unsigned short *)tmp = (unsigned short)Assembler::split_high((int)dest); tmp += 2; *(unsigned short *)tmp = (unsigned short)(0x3c19); tmp += 2; //addiu(T9, T9, Assembler::split_low(dest)) *(unsigned short *)tmp = (unsigned short)Assembler::split_low((int)dest); tmp += 2; *(unsigned short *)tmp = (unsigned short)(0x2739); tmp += 2; // jr(T9) *(unsigned int *)tmp = (unsigned int)0x03200008; tmp += 4; // nop *(unsigned int *)tmp = (unsigned int)0; #ifndef CORE check_verified_entry_alignment(entry, verified_entry); #endif /* CORE */ *(unsigned int *)(verified_entry + 0) = code_buffer[0]; *(unsigned int *)(verified_entry + 4) = code_buffer[1]; *(unsigned int *)(verified_entry + 8) = code_buffer[2]; *(unsigned int *)(verified_entry + 12) = code_buffer[3]; ICache::invalidate_range(verified_entry, instruction_size + 4); //ICache::invalidate_all(); } bool NativeInstruction::is_dtrace_trap() { //return (*(int32_t*)this & 0xff) == 0xcc; Unimplemented(); return false; }