changeset 23:388ae1bd0bdd

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.
author YANG Yongqiang <yangyongqiang@loongson.cn>
date Thu, 04 Nov 2010 11:15:53 +0800
parents a7a1c6bde40a
children da31f361800f
files hotspot/src/cpu/mips/vm/c1_CodeStubs_mips.cpp hotspot/src/cpu/mips/vm/c1_LIRAssembler_mips.cpp hotspot/src/cpu/mips/vm/c1_Runtime1_mips.cpp hotspot/src/cpu/mips/vm/nativeInst_mips.cpp hotspot/src/cpu/mips/vm/nativeInst_mips.hpp hotspot/src/share/vm/c1/c1_LIRAssembler.cpp hotspot/src/share/vm/c1/c1_Runtime1.cpp
diffstat 7 files changed, 112 insertions(+), 81 deletions(-) [+]
line wrap: on
line diff
--- 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);
 	}
 }
 
--- 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 {
--- 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;
 
--- 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();
 }
--- 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(); }
--- 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);
 
--- 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);