changeset 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 142b74086f40
children d0a60cd6d61c
files hotspot/src/cpu/mips/vm/c1_CodeStubs_mips.cpp hotspot/src/cpu/mips/vm/c1_LIRAssembler_mips.cpp hotspot/src/cpu/mips/vm/nativeInst_mips.cpp hotspot/src/share/vm/c1/c1_Runtime1.cpp
diffstat 4 files changed, 20 insertions(+), 208 deletions(-) [+]
line wrap: on
line diff
--- 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;
 
--- 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);
 
--- 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
--- 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;