# HG changeset patch # User YANG Yongqiang # Date 1288604478 -28800 # Node ID 7a9f890eafefc0e44098e029c6b8fcbbf83d5c6f # Parent 142b74086f40a529022a4d24064f965758ab9399 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. diff -r 142b74086f40 -r 7a9f890eafef hotspot/src/cpu/mips/vm/c1_CodeStubs_mips.cpp --- a/hotspot/src/cpu/mips/vm/c1_CodeStubs_mips.cpp Fri Oct 29 09:44:58 2010 +0800 +++ b/hotspot/src/cpu/mips/vm/c1_CodeStubs_mips.cpp Mon Nov 01 17:41:18 2010 +0800 @@ -373,14 +373,11 @@ } if (CommentedAssembly) { - __ block_comment("patch data encoded as movl"); + __ block_comment("patch data"); } // Now emit the patch record telling the runtime how to find the - // pieces of the patch. We only need 3 bytes but for readability of - // the disassembly we make the data look like a movl reg, imm32, - // which requires 5 bytes - //int sizeof_patch_record = 5; - //for mips, I use a move instruction instead @jerome, 12/29, 06 + // pieces of the patch. We only need 3 bytes but for alignment, we + // need 4 bytes int sizeof_patch_record = 4; bytes_to_skip += sizeof_patch_record; diff -r 142b74086f40 -r 7a9f890eafef hotspot/src/cpu/mips/vm/c1_LIRAssembler_mips.cpp --- a/hotspot/src/cpu/mips/vm/c1_LIRAssembler_mips.cpp Fri Oct 29 09:44:58 2010 +0800 +++ b/hotspot/src/cpu/mips/vm/c1_LIRAssembler_mips.cpp Mon Nov 01 17:41:18 2010 +0800 @@ -2479,13 +2479,14 @@ jobject2reg(k->encoding(),k_RInfo); } assert(obj != k_RInfo, "must be different"); + int the_pc; if (op->profiled_method() != NULL) { ciMethod* method = op->profiled_method(); int bci = op->profiled_bci(); Label profile_done; // __ jcc(Assembler::notEqual, profile_done); - __ bne(obj, ZERO, done); + __ bne(obj, ZERO, profile_done); __ delayed()->nop(); // Object is null; update methodDataOop @@ -2498,16 +2499,12 @@ assert(data != NULL, "need data for checkcast"); assert(data->is_BitData(), "need BitData for checkcast"); Register mdo = klass_RInfo; - // __ movl(mdo, md->encoding()); - //__ move(mdo, md->encoding()); int oop_index = __ oop_recorder()->find_index(md->encoding()); RelocationHolder rspec = oop_Relocation::spec(oop_index); __ relocate(rspec); __ lui(mdo, Assembler::split_high((int)md->encoding())); __ addiu(mdo, mdo, Assembler::split_low((int)md->encoding())); - - Address data_addr(mdo, md->byte_offset_of_slot(data, DataLayout::header_offset())); //FIXME, it very ineffictive to replace orl with 3 mips instruction @jerome, 12/27,06 //__ orl(data_addr, BitData::null_flag_constant()); @@ -2521,7 +2518,6 @@ } else { __ beq(obj, ZERO, done); __ delayed()->nop(); - } __ verify_oop(obj); diff -r 142b74086f40 -r 7a9f890eafef hotspot/src/cpu/mips/vm/nativeInst_mips.cpp --- a/hotspot/src/cpu/mips/vm/nativeInst_mips.cpp Fri Oct 29 09:44:58 2010 +0800 +++ b/hotspot/src/cpu/mips/vm/nativeInst_mips.cpp Mon Nov 01 17:41:18 2010 +0800 @@ -37,15 +37,6 @@ } void NativeCall::verify() { -/* - // Make sure code pattern is actually a call imm32 instruction. - int inst = ubyte_at(0); - if (inst != instruction_code) { - tty->print_cr("Addr: " INTPTR_FORMAT " Code: 0x%x", instruction_address(), - inst); - fatal("not a call disp32"); - } -*/ // make sure code pattern is actually a call instruction if ( !is_op(Assembler::lui_op) || !is_op(long_at(4), Assembler::addiu_op) || @@ -145,136 +136,9 @@ // 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) { -/* - 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 - if (os::is_MP()) { - guarantee((intptr_t)instr_addr % BytesPerWord == 0, "must be aligned"); - } - - // First patch dummy jmp in place - unsigned char patch[4]; - assert(sizeof(patch)==sizeof(jint), "sanity check"); - patch[0] = 0xEB; // jmp rel8 - patch[1] = 0xFE; // jmp to self - patch[2] = 0xEB; - patch[3] = 0xFE; - - // First patch dummy jmp in place - *(jint*)instr_addr = *(jint *)patch; - - // Invalidate. Opteron requires a flush after every write. - n_call->wrote(0); - - // Patch 4th byte - instr_addr[4] = code_buffer[4]; - - n_call->wrote(4); - - // Patch bytes 0-3 - *(jint*)instr_addr = *(jint *)code_buffer; - - n_call->wrote(0); - -#ifdef ASSERT - // verify patching - for ( int i = 0; i < instruction_size; i++) { - address ptr = (address)((intptr_t)code_buffer + i); - int a_byte = (*ptr) & 0xFF; - assert(*((address)((intptr_t)instr_addr + i)) == a_byte, "mt safe patching failed"); - } -#endif -*/ Unimplemented(); } -/* -// 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. If the displacement field is aligned -// we can simply rely on atomicity of 32-bit writes to make sure other threads -// will see no intermediate states. Otherwise, the first two bytes of the -// call are guaranteed to be aligned, and can be atomically patched to a -// self-loop to guard the instruction while we change the other bytes. - -// We cannot rely on locks here, since the free-running threads must run at -// full speed. -// -// Used in the runtime linkage of calls; see class CompiledIC. -// (Cf. 4506997 and 4479829, where threads witnessed garbage displacements.) -void NativeCall::set_destination_mt_safe(address dest) { - debug_only(verify()); - // Make sure patching code is locked. No two threads can patch at the same - // time but one may be executing this code. - assert(Patching_lock->is_locked() || - SafepointSynchronize::is_at_safepoint(), "concurrent code patching"); - // Both C1 and C2 should now be generating code which aligns the patched address - // to be within a single cache line except that C1 does not do the alignment on - // uniprocessor systems. - bool is_aligned = ((uintptr_t)displacement_address() + 0) / cache_line_size == - ((uintptr_t)displacement_address() + 3) / cache_line_size; - - guarantee(!os::is_MP() || is_aligned, "destination must be aligned"); - - if (is_aligned) { - // Simple case: The destination lies within a single cache line. - set_destination(dest); - } else if ((uintptr_t)instruction_address() / cache_line_size == - ((uintptr_t)instruction_address()+1) / cache_line_size) { - // Tricky case: The instruction prefix lies within a single cache line. - intptr_t disp = dest - return_address(); -#ifdef AMD64 - guarantee(disp == (intptr_t)(jint)disp, "must be 32-bit offset"); -#endif // AMD64 - - int call_opcode = instruction_address()[0]; - - // First patch dummy jump in place: - { - u_char patch_jump[2]; - patch_jump[0] = 0xEB; // jmp rel8 - patch_jump[1] = 0xFE; // jmp to self - - assert(sizeof(patch_jump)==sizeof(short), "sanity check"); - *(short*)instruction_address() = *(short*)patch_jump; - } - // Invalidate. Opteron requires a flush after every write. - wrote(0); - - // (Note: We assume any reader which has already started to read - // the unpatched call will completely read the whole unpatched call - // without seeing the next writes we are about to make.) - - // Next, patch the last three bytes: - u_char patch_disp[5]; - patch_disp[0] = call_opcode; - *(int32_t*)&patch_disp[1] = (int32_t)disp; - assert(sizeof(patch_disp)==instruction_size, "sanity check"); - for (int i = sizeof(short); i < instruction_size; i++) - instruction_address()[i] = patch_disp[i]; - - // Invalidate. Opteron requires a flush after every write. - wrote(sizeof(short)); - - // (Note: We assume that any reader which reads the opcode we are - // about to repatch will also read the writes we just made.) - - // Finally, overwrite the jump: - *(short*)instruction_address() = *(short*)patch_disp; - // Invalidate. Opteron requires a flush after every write. - wrote(0); - - debug_only(verify()); - guarantee(destination() == dest, "patch succeeded"); - } else { - // Impossible: One or the other must be atomically writable. - ShouldNotReachHere(); - } -} -*/ void NativeMovConstReg::verify() { if ( !is_op(Assembler::lui_op) || @@ -317,51 +181,6 @@ } //------------------------------------------------------------------- -/* -int NativeMovRegMem::instruction_start() const { - int off = 0; - u_char instr_0 = ubyte_at(off); - - // First check to see if we have a (prefixed or not) xor - if ( instr_0 >= instruction_prefix_wide_lo && // 0x40 - instr_0 <= instruction_prefix_wide_hi) { // 0x4f - off++; - instr_0 = ubyte_at(off); - } - - if (instr_0 == instruction_code_xor) { - off += 2; - instr_0 = ubyte_at(off); - } - - // Now look for the real instruction and the many prefix/size specifiers. - - if (instr_0 == instruction_operandsize_prefix ) { // 0x66 - off++; // Not SSE instructions - instr_0 = ubyte_at(off); - } - - if ( instr_0 == instruction_code_xmm_ss_prefix || // 0xf3 - instr_0 == instruction_code_xmm_sd_prefix) { // 0xf2 - off++; - instr_0 = ubyte_at(off); - } - - if ( instr_0 >= instruction_prefix_wide_lo && // 0x40 - instr_0 <= instruction_prefix_wide_hi) { // 0x4f - off++; - instr_0 = ubyte_at(off); - } - - - if (instr_0 == instruction_extended_prefix ) { // 0x0f - off++; - } - - return off; -} -*/ - int NativeMovRegMem::offset() const{ if (is_immediate()) @@ -456,10 +275,10 @@ CodeBuffer cb(code_pos, instruction_size + 4); MacroAssembler masm(&cb); #define __ masm. - //__ move (rs, (int)entry); - //__ lui(AT, Assembler::split_high((int)entry)); - //__ addiu(AT, AT, Assembler::split_low((int)entry)); - //__ jr (AT); +// __ lui(AT, Assembler::split_high((int)entry)); +// __ addiu(AT, AT, Assembler::split_low((int)entry)); +// __ jr (AT); +// __ delayed()->nop(); __ b(entry); __ delayed()->nop(); #undef __ @@ -474,20 +293,21 @@ // 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 = ((int*)code_buffer)[0]; - int i1 = ((int*)code_buffer)[1]; - int i2 = ((int*)code_buffer)[2]; + 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 - //h_jump->set_long_at(0*BytesPerInstWord, 0x1000ffff); - h_jump->set_long_at(2*BytesPerInstWord, i2); - h_jump->set_long_at(1*BytesPerInstWord, i1); - h_jump->set_long_at(0*BytesPerInstWord, i0); - + ICache::invalidate_range(h_jump->addr_at(0), instruction_size); - - //ICache::invalidate_all(); } // NOTE : here i use T9 as the destination register, maybe i should get some hint from entry. FIXME diff -r 142b74086f40 -r 7a9f890eafef hotspot/src/share/vm/c1/c1_Runtime1.cpp --- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp Fri Oct 29 09:44:58 2010 +0800 +++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp Mon Nov 01 17:41:18 2010 +0800 @@ -973,7 +973,6 @@ if (do_patch) { // replace instructions // first replace the tail, then the call - for (int i = NativeCall::instruction_size; i < *byte_count; i++) { address ptr = copy_buff + i; int a_byte = (*ptr) & 0xFF;