# HG changeset patch # User YANG Yongqiang # Date 1288840553 -28800 # Node ID 388ae1bd0bddfbb14926f3e4e47d253f9775c9be # Parent a7a1c6bde40ac1334885ce3abdfd58e9249060d1 Fix 2 bugs related to patching and make some codes more readable. 1. In MIPS, oops-table used by relocating must be updated accordingly when patching. 2. Allocate enough space for patching. 3. Make NativeInstructions more readable. NativeCall's size is 16 bytes instead of 12. If 12 is used, we must fix it by adding 4 explicitly. diff -r a7a1c6bde40a -r 388ae1bd0bdd hotspot/src/cpu/mips/vm/c1_CodeStubs_mips.cpp --- a/hotspot/src/cpu/mips/vm/c1_CodeStubs_mips.cpp Tue Nov 02 10:34:12 2010 +0800 +++ b/hotspot/src/cpu/mips/vm/c1_CodeStubs_mips.cpp Thu Nov 04 11:15:53 2010 +0800 @@ -273,7 +273,7 @@ // - in runtime: after initializing class, restore original code, reexecute instruction //int PatchingStub::_patch_info_offset = -NativeGeneralJump::instruction_size; -int PatchingStub::_patch_info_offset = -(NativeCall::instruction_size + 4); +int PatchingStub::_patch_info_offset = -NativeCall::instruction_size; void PatchingStub::align_patch_site(MacroAssembler* masm) { // We're patching a 5-7 byte instruction on intel and we need to @@ -289,7 +289,7 @@ } void PatchingStub::emit_code(LIR_Assembler* ce) { -// assert(NativeCall::instruction_size <= _bytes_to_copy && _bytes_to_copy <= 0xFF, "not enough room for call"); + assert(NativeCall::instruction_size <= _bytes_to_copy && _bytes_to_copy <= 0xFF, "not enough room for call"); assert(_bytes_to_copy <= 0xFF, "not enough room for call"); Label call_patch; @@ -311,6 +311,9 @@ __ relocate(rspec); __ lui(_obj, Assembler::split_high((int)o)); __ addiu(_obj, _obj, Assembler::split_low((int)o)); + while ((intx)__ pc() - (intx)start < NativeCall::instruction_size) { + __ nop(); + } #ifdef ASSERT for (int i = 0; i < _bytes_to_copy; i++) { address ptr = (address)(_pc_start + i); @@ -322,11 +325,15 @@ // make a copy the code which is going to be patched. assert((_bytes_to_copy&3)==0, "change this code"); + address start = __ pc(); for ( int i = 0; i < _bytes_to_copy; i+=4) { __ a_long (*(int*)(_pc_start + i)); //make the site look like a nop, @jerome *(int*)(_pc_start + i)=0; } + while ((intx)__ pc() - (intx)start < NativeCall::instruction_size) { + __ nop(); + } } address end_of_patch = __ pc(); @@ -393,7 +400,7 @@ assert(patch_info_pc - end_of_patch == bytes_to_skip, "incorrect patch info"); address entry = __ pc(); - NativeGeneralJump::insert_unconditional((address)_pc_start, entry); + NativeGeneralJump::insert_unconditional((address)_pc_start, entry); address target = NULL; switch (_id) { case access_field_id: target = Runtime1::entry_for(Runtime1::access_field_patching_id); break; @@ -418,13 +425,14 @@ __ delayed()->nop(); // Add enough nops so deoptimization can overwrite the jmp above with a call // and not destroy the world. - for (int j = __ offset() ; j < jmp_off + NativeCall::instruction_size + 4 ; j+=4 ) { + for (int j = __ offset(); j < jmp_off + NativeCall::instruction_size; j += 4 ) { __ nop(); } if (_id == load_klass_id) { CodeSection* cs = __ code_section(); - RelocIterator iter(cs, (address)_pc_start, (address)(_pc_start + 1)); - relocInfo::change_reloc_info_for_address(&iter, (address) _pc_start, relocInfo::oop_type, relocInfo::none); + address pc = (address)_pc_start; + RelocIterator iter(cs, pc, pc + 1); + relocInfo::change_reloc_info_for_address(&iter, pc, relocInfo::oop_type, relocInfo::none); } } diff -r a7a1c6bde40a -r 388ae1bd0bdd hotspot/src/cpu/mips/vm/c1_LIRAssembler_mips.cpp --- a/hotspot/src/cpu/mips/vm/c1_LIRAssembler_mips.cpp Tue Nov 02 10:34:12 2010 +0800 +++ b/hotspot/src/cpu/mips/vm/c1_LIRAssembler_mips.cpp Thu Nov 04 11:15:53 2010 +0800 @@ -546,8 +546,8 @@ void LIR_Assembler::const2reg(LIR_Opr src, LIR_Opr dest, LIR_PatchCode patch_code, CodeEmitInfo* info) { assert(src->is_constant(), "should not call otherwise"); - assert(dest->is_register(), "should not call otherwise"); - LIR_Const* c = src->as_constant_ptr(); + assert(dest->is_register(), "should not call otherwise"); + LIR_Const* c = src->as_constant_ptr(); switch (c->type()) { case T_INT: { @@ -585,21 +585,7 @@ case T_OBJECT: { if (patch_code == lir_patch_none) { - if (c->as_jobject() == NULL) { - NEEDS_CLEANUP - int oop_index = __ oop_recorder()->allocate_index(c->as_jobject()); - RelocationHolder rspec = oop_Relocation::spec(oop_index); - __ relocate(rspec); - __ lui(dest->as_register(), Assembler::split_high((int) c->as_jobject() )); - __ addiu( dest->as_register() , dest->as_register() , - Assembler::split_low((int) c->as_jobject())); - } else { - int oop_index = __ oop_recorder()->find_index(c->as_jobject()); - RelocationHolder rspec = oop_Relocation::spec(oop_index); - __ relocate(rspec); - __ lui(dest->as_register(), Assembler::split_high((int)c->as_jobject())); - __ addiu(dest->as_register(), dest->as_register(), Assembler::split_low((int)c->as_jobject())); - } + jobject2reg(c->as_jobject(), dest->as_register()); } else { jobject2reg_with_patching(dest->as_register(), info); } @@ -4188,10 +4174,6 @@ // This seems wrong as we do not emit relocInfo // for classes that are not loaded yet, i.e., they will be // never GC'd - NEEDS_CLEANUP - int oop_index = __ oop_recorder()->allocate_index(o); - RelocationHolder rspec = oop_Relocation::spec(oop_index); - __ relocate(rspec); __ lui(reg, Assembler::split_high((int)o)); __ addiu(reg, reg, Assembler::split_low((int)o)); } else { diff -r a7a1c6bde40a -r 388ae1bd0bdd hotspot/src/cpu/mips/vm/c1_Runtime1_mips.cpp --- a/hotspot/src/cpu/mips/vm/c1_Runtime1_mips.cpp Tue Nov 02 10:34:12 2010 +0800 +++ b/hotspot/src/cpu/mips/vm/c1_Runtime1_mips.cpp Thu Nov 04 11:15:53 2010 +0800 @@ -220,21 +220,19 @@ // account. // enum reg_save_layout { - //F0_off = 0, - //F31_off = F0_off + 31, - //T0_off = F31_off + 1, T0_off = 0, -// T8_off = T0_off + 8, -// T9_off, S0_off = T0_off + 8, FP_off = S0_off + 8, + T8_off, + T9_off, SP_off, V0_off, V1_off, -/* A0_off, + A0_off, A1_off, A2_off, - A3_off,*/ + A3_off, + GP_off, //temp_2_off, temp_1_off, saved_fp_off, @@ -279,6 +277,14 @@ for (Register r = S0; r != S7->successor(); r = r->successor() ) { map->set_callee_saved(VMRegImpl::stack2reg(S0_off + num_rt_args + i++), r->as_VMReg()); } + map->set_callee_saved(VMRegImpl::stack2reg(FP_off + num_rt_args), FP->as_VMReg()); + map->set_callee_saved(VMRegImpl::stack2reg(GP_off + num_rt_args), GP->as_VMReg()); + map->set_callee_saved(VMRegImpl::stack2reg(T8_off + num_rt_args), T8->as_VMReg()); + map->set_callee_saved(VMRegImpl::stack2reg(T9_off + num_rt_args), T9->as_VMReg()); + map->set_callee_saved(VMRegImpl::stack2reg(A0_off + num_rt_args), A0->as_VMReg()); + map->set_callee_saved(VMRegImpl::stack2reg(A1_off + num_rt_args), A1->as_VMReg()); + map->set_callee_saved(VMRegImpl::stack2reg(A2_off + num_rt_args), A2->as_VMReg()); + map->set_callee_saved(VMRegImpl::stack2reg(A3_off + num_rt_args), A3->as_VMReg()); return map; } @@ -298,9 +304,17 @@ for (Register r = S0; r != S7->successor(); r = r->successor() ) { __ sw(r, SP, (r->encoding() - S0->encoding() + S0_off) * wordSize); } + __ sw(FP, SP, FP_off * wordSize); + __ sw(GP, SP, GP_off * wordSize); + __ sw(T8, SP, T8_off * wordSize); + __ sw(T9, SP, T9_off * wordSize); + __ sw(A0, SP, A0_off * wordSize); + __ sw(A1, SP, A1_off * wordSize); + __ sw(A2, SP, A2_off * wordSize); + __ sw(A3, SP, A3_off * wordSize); __ sw(V0, SP, V0_off * wordSize); __ sw(V1, SP, V1_off * wordSize); - + return generate_oop_map(sasm, num_rt_args, save_fpu_registers, describe_fpu_registers); } @@ -312,6 +326,16 @@ for (Register r = S0; r != S7->successor(); r = r->successor() ) { __ lw(r, SP, (r->encoding() - S0->encoding() + S0_off) * wordSize); } + __ lw(FP, SP, FP_off * wordSize); + __ lw(GP, SP, GP_off * wordSize); + + __ lw(T8, SP, T8_off * wordSize); + __ lw(T9, SP, T9_off * wordSize); + __ lw(A0, SP, A0_off * wordSize); + __ lw(A1, SP, A1_off * wordSize); + __ lw(A2, SP, A2_off * wordSize); + __ lw(A3, SP, A3_off * wordSize); + __ lw(V0, SP, V0_off * wordSize); __ lw(V1, SP, V1_off * wordSize); __ addiu(SP, SP, (reg_save_frame_size - 2) * wordSize); @@ -332,6 +356,15 @@ for (Register r = S0; r != S7->successor(); r = r->successor() ) { __ lw(r, SP, (r->encoding() - S0->encoding() + S0_off) * wordSize); } + __ lw(FP, SP, FP_off * wordSize); + __ lw(GP, SP, GP_off * wordSize); + + __ lw(T8, SP, T8_off * wordSize); + __ lw(T9, SP, T9_off * wordSize); + __ lw(A0, SP, A0_off * wordSize); + __ lw(A1, SP, A1_off * wordSize); + __ lw(A2, SP, A2_off * wordSize); + __ lw(A3, SP, A3_off * wordSize); __ lw(V1, SP, V1_off * wordSize); __ addiu(SP, SP, (reg_save_frame_size - 2)* wordSize); @@ -561,10 +594,9 @@ // distinguish each RT-Call. // Note: This number affects also the RT-Call in generate_handle_exception because // the oop-map is shared for all calls. - //FIXME,for mips, I do not think it is need + - const int num_rt_args = 1; // thread - // const int num_rt_args = 2; // for x86 version, thread + dummy ,push (eax) + DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob(); assert(deopt_blob != NULL, "deoptimization blob must have been created"); @@ -582,6 +614,7 @@ #endif __ move(A0, thread); + /* * NOTE: this frame should be compiled frame, but at this point, the pc in frame-anchor * is contained in interpreter. It should be wrong, and should be cleared but is not. @@ -589,7 +622,7 @@ * is not right. It depends on that the caller pc is stored in *(sp - 1) but it's not the case */ __ set_last_Java_frame(thread, NOREG, FP, NULL); - __ addi(SP, SP, (-1) * wordSize); + __ addiu(SP, SP, (-1) * wordSize); __ move(AT, -8); __ andr(SP, SP, AT); __ relocate(relocInfo::internal_pc_type); @@ -681,7 +714,6 @@ __ bind(L); } - // Runtime will return true if the nmethod has been deoptimized during // the patching process. In that case we must do a deopt reexecute instead. @@ -693,12 +725,14 @@ // Will reexecute. Proper return address is already on the stack we just restore // registers, pop all of our frame but the return address and jump to the deopt blob restore_live_registers(sasm); + __ leave(); __ jmp(deopt_blob->unpack_with_reexecution(), relocInfo::runtime_call_type); __ delayed()->nop(); __ bind(cont); restore_live_registers(sasm); + __ leave(); __ jr(RA); __ delayed()->nop(); @@ -1216,6 +1250,7 @@ StubFrame f(sasm, "access_field_patching", dont_gc_arguments); // we should set up register map oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, access_field_patching)); + } break; diff -r a7a1c6bde40a -r 388ae1bd0bdd hotspot/src/cpu/mips/vm/nativeInst_mips.cpp --- a/hotspot/src/cpu/mips/vm/nativeInst_mips.cpp Tue Nov 02 10:34:12 2010 +0800 +++ b/hotspot/src/cpu/mips/vm/nativeInst_mips.cpp Thu Nov 04 11:15:53 2010 +0800 @@ -125,6 +125,7 @@ __ lui(T9, Assembler::split_high((int)entry)); __ addiu(T9, T9, Assembler::split_low((int)entry)); __ jalr (); + __ delayed()->nop(); #undef __ ICache::invalidate_range(call->addr_at(0), instruction_size); @@ -153,11 +154,7 @@ } 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()); @@ -172,12 +169,15 @@ *oop_addr = (oop)x; } else { assert(oop_addr == r->oop_addr(), "must be only one set-oop here"); - } } + } } } +#endif -#endif + 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); } //------------------------------------------------------------------- @@ -272,18 +272,14 @@ // 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); + CodeBuffer cb(code_pos, instruction_size); 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); + ICache::invalidate_range(code_pos, instruction_size); } @@ -293,20 +289,9 @@ // 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 - + assert(NativeGeneralJump::instruction_size == NativeCall::instruction_size, + "note::Runtime1::patch_code uses NativeCall::instruction_size"); + memcpy(instr_addr, code_buffer, NativeCall::instruction_size); ICache::invalidate_range(h_jump->addr_at(0), instruction_size); } @@ -341,7 +326,7 @@ *(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_range(verified_entry, instruction_size); //ICache::invalidate_all(); } diff -r a7a1c6bde40a -r 388ae1bd0bdd hotspot/src/cpu/mips/vm/nativeInst_mips.hpp --- a/hotspot/src/cpu/mips/vm/nativeInst_mips.hpp Tue Nov 02 10:34:12 2010 +0800 +++ b/hotspot/src/cpu/mips/vm/nativeInst_mips.hpp Thu Nov 04 11:15:53 2010 +0800 @@ -135,7 +135,7 @@ enum mips_specific_constants { //instruction_code = 0xE8, instruction_offset = 0, - instruction_size = 12, + instruction_size = 16, return_address_offset = 16, displacement_offset = 0 }; @@ -347,23 +347,25 @@ // lui reg, split_high(addr) // addiu reg, split_low(addr) // jr reg +// nop // or // beq ZERO, ZERO, offset +// nop class NativeGeneralJump: public NativeInstruction { public: enum mips_specific_constants { instruction_offset = 0, beq_opcode = 0x10000000,//000100|00000|00000|offset b_mask = 0xffff0000, - short_size = 4, - instruction_size = 12 + short_size = 8, + instruction_size = 16 }; bool is_short() const { return (long_at(instruction_offset) & b_mask) == beq_opcode; } address instruction_address() const { return addr_at(instruction_offset); } address jump_destination() const { if ( is_short() ) { - return addr_at(short_size) + Assembler::imm_off(long_at(instruction_offset)) * 4; + return addr_at(4) + Assembler::imm_off(long_at(instruction_offset)) * 4; } return (address)Assembler::merge(long_at(4)&0xffff, long_at(instruction_offset)&0xffff); } @@ -416,12 +418,14 @@ }; // return instruction that does not pop values of the stack +// jr RA +// delay slot class NativeReturn: public NativeInstruction { public: - enum Intel_specific_constants { - instruction_size = 4, + enum mips_specific_constants { + instruction_size = 8, instruction_offset = 0, - next_instruction_offset = 4 + next_instruction_offset = 8 }; }; @@ -477,8 +481,7 @@ return ((long_at(0) & NativeGeneralJump::b_mask) == NativeGeneralJump::beq_opcode) || (is_op(long_at(0), Assembler::lui_op) && is_op(long_at(4), Assembler::addiu_op) && - is_special_op(long_at(8), Assembler::jr_op) && - !is_rs(long_at(8), RA) ); + is_special_op(long_at(8), Assembler::jr_op)); } inline bool NativeInstruction::is_cond_jump() { return is_int_branch() || is_float_branch(); } diff -r a7a1c6bde40a -r 388ae1bd0bdd hotspot/src/share/vm/c1/c1_LIRAssembler.cpp --- a/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp Tue Nov 02 10:34:12 2010 +0800 +++ b/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp Thu Nov 04 11:15:53 2010 +0800 @@ -28,12 +28,9 @@ void LIR_Assembler::patching_epilog(PatchingStub* patch, LIR_PatchCode patch_code, Register obj, CodeEmitInfo* info) { // we must have enough patching space so that call can be inserted -#ifndef MIPS32 while ((intx) _masm->pc() - (intx) patch->pc_start() < NativeCall::instruction_size) { _masm->nop(); } -#endif - patch->install(_masm, patch_code, obj, info); append_patching_stub(patch); diff -r a7a1c6bde40a -r 388ae1bd0bdd hotspot/src/share/vm/c1/c1_Runtime1.cpp --- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp Tue Nov 02 10:34:12 2010 +0800 +++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp Thu Nov 04 11:15:53 2010 +0800 @@ -874,7 +874,7 @@ NativeGeneralJump* jump = nativeGeneralJump_at(caller_frame.pc()); address instr_pc = jump->jump_destination(); NativeInstruction* ni = nativeInstruction_at(instr_pc); - if (ni->is_jump() ) { + if (ni->is_jump()) { // the jump has not been patched yet // The jump destination is slow case and therefore not part of the stubs // (stubs are only for StaticCalls) @@ -993,7 +993,28 @@ RelocIterator iter(nm, (address)instr_pc, (address)(instr_pc + 1)); relocInfo::change_reloc_info_for_address(&iter, (address) instr_pc, relocInfo::none, relocInfo::oop_type); -#if defined(SPARC) +#ifdef MIPS32 + // Update the oop location in the nmethod with the proper + // oop. When the code was generated, a NULL was stuffed + // in the oop table and that table needs to be update to + // have the right value. On intel the value is kept + // directly in the instruction instead of in the oop + // table, so set_data above effectively updated the value. + RelocIterator oops(nm, instr_pc, instr_pc + 1); + bool found = false; + while (oops.next() && !found) { + if (oops.type() == relocInfo::oop_type) { + oop_Relocation* r = oops.oop_reloc(); + oop* oop_adr = r->oop_addr(); + *oop_adr = load_klass(); + r->fix_oop_relocation(); + found = true; + } + } + assert(found, "the oop must exist!"); +#endif + +#if defined(SPARC) // Sparc takes two relocations for an oop so update the second one. address instr_pc2 = instr_pc + NativeMovConstReg::add_offset; RelocIterator iter2(nm, instr_pc2, instr_pc2 + 1);