Mercurial > hg > openjdk6-mips
view hotspot/src/cpu/mips/vm/c1_CodeStubs_mips.cpp @ 10:7eeee95a5a53
Fix five bugs related to safepoint_poll, double-precision operand, verify_oop operation and safepoint_return respectively.
1. pc_offset for oopMap at safepoint_poll used by add_debug_info_branch
must be the offset of the instruction which causes an exception.
2. To avoid the failure of type-checking, when value of LIRConst, which
is single-precision or double-precision, is got through a common path.
However, as_jint_lo_bits and as_jint_hi_bits, which are much more
general, should be used.
3. In the stack2reg function, when operand is double-precision, two
float registers are filled with content of the same stack address. We
should not do that. Fix it.
4. In the verify_oop_addr function, the address of the object to be
verified may use SP, so the object must be loaded before changing SP.
5. Let safepoint_return use AT.
6. Do some codes cleaning work.
author | YANG Yongqiang <yangyongqiang@loongson.cn> |
---|---|
date | Sat, 23 Oct 2010 21:08:56 +0000 |
parents | c1e1428eff7c |
children | 7a9f890eafef |
line wrap: on
line source
/* * Copyright 1999-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/_c1_CodeStubs_mips.cpp.incl" #define __ ce->masm()-> float ConversionStub::float_zero = 0.0; double ConversionStub::double_zero = 0.0; void ConversionStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); assert(bytecode() == Bytecodes::_f2i || bytecode() == Bytecodes::_d2i, "other conversions do not require stub"); } #ifdef TIERED void CounterOverflowStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); ce->store_parameter(_bci, 0); //__ call(RuntimeAddress(Runtime1::entry_for(Runtime1::counter_overflow_id))); __ call(Runtime1::entry_for(Runtime1::counter_overflow_id), relocInfo::runtime_call_type); ce->add_call_info_here(_info); ce->verify_oop_map(_info); //__ jmp(_continuation); __ b(_continuation); __ delayed()->nop(); } #endif // TIERED RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index, bool throw_index_out_of_bounds_exception) : _throw_index_out_of_bounds_exception(throw_index_out_of_bounds_exception) , _index(index) { _info = info == NULL ? NULL : new CodeEmitInfo(info); } void RangeCheckStub::emit_code(LIR_Assembler* ce) { #ifdef OPT_RANGECHECK if (_throw_pc != -1) { ce->compilation()->null_check_table()->append(_throw_pc, __ offset()); } #endif __ bind(_entry); //// Pass the array index in eax since the runtime stub will add register state to the stack // pass the array index on stack because all registers must be preserved if (_index->is_cpu_register()) { ce->store_parameter(_index->as_register(), 0); } else { ce->store_parameter(_index->as_jint(), 0); } if (_throw_index_out_of_bounds_exception) { __ call(Runtime1::entry_for(Runtime1::throw_index_exception_id), relocInfo::runtime_call_type); } else { __ call(Runtime1::entry_for(Runtime1::throw_range_check_failed_id), relocInfo::runtime_call_type); } __ delayed()->nop(); ce->add_call_info_here(_info); debug_only(__ should_not_reach_here()); } void DivByZeroStub::emit_code(LIR_Assembler* ce) { if (_offset != -1) { // ce->compilation()->null_check_table()->append(_offset, __ offset()); ce->compilation()->implicit_exception_table()->append(_offset, __ offset()); } __ bind(_entry); __ call(Runtime1::entry_for(Runtime1::throw_div0_exception_id), relocInfo::runtime_call_type); __ delayed()->nop(); ce->add_call_info_here(_info); debug_only(__ should_not_reach_here()); } // Implementation of NewInstanceStub NewInstanceStub::NewInstanceStub(LIR_Opr klass_reg, LIR_Opr result, ciInstanceKlass* klass, CodeEmitInfo* info, Runtime1::StubID stub_id) { _result = result; _klass = klass; _klass_reg = klass_reg; _info = new CodeEmitInfo(info); assert(stub_id == Runtime1::new_instance_id || stub_id == Runtime1::fast_new_instance_id || stub_id == Runtime1::fast_new_instance_init_check_id, "need new_instance id"); _stub_id = stub_id; } // i use T4 as klass register, V0 as result register. MUST accord with Runtime1::generate_code_for. void NewInstanceStub::emit_code(LIR_Assembler* ce) { assert(__ sp_offset() == 0, "frame size should be fixed"); __ bind(_entry); //__ movptr(rdx, _klass_reg->as_register()); //__ call(RuntimeAddress(Runtime1::entry_for(_stub_id))); assert(_klass_reg->as_register() == T4, "klass_reg must in T4"); __ call(Runtime1::entry_for(_stub_id), relocInfo::runtime_call_type); __ delayed()->nop(); ce->add_call_info_here(_info); ce->verify_oop_map(_info); assert(_result->as_register() == V0, "result must in V0,"); __ b(_continuation); __ delayed()->nop(); } // Implementation of NewTypeArrayStub NewTypeArrayStub::NewTypeArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result, CodeEmitInfo* info) { _klass_reg = klass_reg; _length = length; _result = result; _info = new CodeEmitInfo(info); } // i use T2 as length register, T4 as klass register, V0 as result register. // MUST accord with Runtime1::generate_code_for void NewTypeArrayStub::emit_code(LIR_Assembler* ce) { assert(__ sp_offset() == 0, "frame size should be fixed"); __ bind(_entry); assert(_length->as_register() == T2, "length must in T2,"); assert(_klass_reg->as_register() == T4, "klass_reg must in T4"); //__ call(RuntimeAddress(Runtime1::entry_for(Runtime1::new_type_array_id))); __ call(Runtime1::entry_for(Runtime1::new_type_array_id), relocInfo::runtime_call_type); __ delayed()->nop(); ce->add_call_info_here(_info); ce->verify_oop_map(_info); assert(_result->as_register() == V0, "result must in V0,"); __ b(_continuation); __ delayed()->nop(); } // Implementation of NewObjectArrayStub NewObjectArrayStub::NewObjectArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result, CodeEmitInfo* info) { _klass_reg = klass_reg; _result = result; _length = length; _info = new CodeEmitInfo(info); } void NewObjectArrayStub::emit_code(LIR_Assembler* ce) { assert(__ sp_offset() == 0, "frame size should be fixed"); __ bind(_entry); //assert(_length->as_register() == rbx, "length must in rbx,"); //assert(_klass_reg->as_register() == rdx, "klass_reg must in rdx"); //__ call(RuntimeAddress(Runtime1::entry_for(Runtime1::new_object_array_id))); assert(_length->as_register() == T2, "length must in ebx"); assert(_klass_reg->as_register() == T4, "klass_reg must in edx"); __ call(Runtime1::entry_for(Runtime1::new_object_array_id), relocInfo::runtime_call_type); __ delayed()->nop(); ce->add_call_info_here(_info); ce->verify_oop_map(_info); //assert(_result->as_register() == rax, "result must in rax,"); //__ jmp(_continuation); assert(_result->as_register() == V0, "result must in eax"); __ b(_continuation); __ delayed()->nop(); } // Implementation of MonitorAccessStubs MonitorEnterStub::MonitorEnterStub(LIR_Opr obj_reg, LIR_Opr lock_reg, CodeEmitInfo* info) : MonitorAccessStub(obj_reg, lock_reg) { _info = new CodeEmitInfo(info); } void MonitorEnterStub::emit_code(LIR_Assembler* ce) { assert(__ sp_offset() == 0, "frame size should be fixed"); __ bind(_entry); ce->store_parameter(_obj_reg->as_register(), 1); ce->store_parameter(_lock_reg->as_register(), 0); /* Runtime1::StubID enter_id; if (ce->compilation()->has_fpu_code()) { enter_id = Runtime1::monitorenter_id; } else { enter_id = Runtime1::monitorenter_nofpu_id; } __ call(RuntimeAddress(Runtime1::entry_for(enter_id))); */ if (ce->compilation()->has_fpu_code()) { __ call(Runtime1::entry_for(Runtime1::monitorenter_id), relocInfo::runtime_call_type); } else { __ call(Runtime1::entry_for(Runtime1::monitorenter_nofpu_id), relocInfo::runtime_call_type); } __ delayed()->nop(); ce->add_call_info_here(_info); ce->verify_oop_map(_info); //__ jmp(_continuation); __ b(_continuation); __ delayed()->nop(); } void MonitorExitStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); if (_compute_lock) { // lock_reg was destroyed by fast unlocking attempt => recompute it ce->monitor_address(_monitor_ix, _lock_reg); } ce->store_parameter(_lock_reg->as_register(), 0); // note: non-blocking leaf routine => no call info needed /* Runtime1::StubID exit_id; if (ce->compilation()->has_fpu_code()) { exit_id = Runtime1::monitorexit_id; } else { exit_id = Runtime1::monitorexit_nofpu_id; } __ call(RuntimeAddress(Runtime1::entry_for(exit_id))); __ jmp(_continuation); */ if (ce->compilation()->has_fpu_code()) { __ call(Runtime1::entry_for(Runtime1::monitorexit_id), relocInfo::runtime_call_type); } else { __ call(Runtime1::entry_for(Runtime1::monitorexit_nofpu_id), relocInfo::runtime_call_type); } __ delayed()->nop(); //__ jmp(_continuation); __ b(_continuation); __ delayed()->nop(); } // Implementation of patching: // - Copy the code at given offset to an inlined buffer (first the bytes, then the number of bytes) // - Replace original code with a call to the stub // At Runtime: // - call to stub, jump to runtime // - in runtime: preserve all registers (especially objects, i.e., source and destination object) // - 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); void PatchingStub::align_patch_site(MacroAssembler* masm) { // We're patching a 5-7 byte instruction on intel and we need to // make sure that we don't see a piece of the instruction. It // appears mostly impossible on Intel to simply invalidate other // processors caches and since they may do aggressive prefetch it's // very hard to make a guess about what code might be in the icache. // Force the instruction to be double word aligned so that it // doesn't span a cache line. // the NativeJump is not finished, i am not sure what to do here. FIXME //masm->align(round_to(NativeGeneralJump::instruction_size, wordSize)); } void PatchingStub::emit_code(LIR_Assembler* ce) { // 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; // static field accesses have special semantics while the class // initializer is being run so we emit a test which can be used to // check that this code is being executed by the initializing // thread. address being_initialized_entry = __ pc(); if (CommentedAssembly) { __ block_comment(" patch template"); } if (_id == load_klass_id) { // produce a copy of the load klass instruction for use by the being initialized case address start = __ pc(); jobject o = NULL; int oop_index = __ oop_recorder()->allocate_index(o); RelocationHolder rspec = oop_Relocation::spec(oop_index); __ relocate(rspec); __ lui(_obj, Assembler::split_high((int)o)); __ addiu(_obj, _obj, Assembler::split_low((int)o)); #ifdef ASSERT for (int i = 0; i < _bytes_to_copy; i++) { address ptr = (address)(_pc_start + i); int a_byte = (*ptr) & 0xFF; assert(a_byte == *start++, "should be the same code"); } #endif } else { // make a copy the code which is going to be patched. assert((_bytes_to_copy&3)==0, "change this code"); 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; } } address end_of_patch = __ pc(); int bytes_to_skip = 0; if (_id == load_klass_id) { int offset = __ offset(); if (CommentedAssembly) { __ block_comment(" being_initialized check"); } /* assert(_obj != noreg, "must be a valid register"); Register tmp = eax; if (_obj == tmp) tmp = ebx; __ pushl(tmp); __ get_thread(tmp); __ cmpl(tmp, Address(_obj, instanceKlass::init_thread_offset_in_bytes() + sizeof(klassOopDesc))); __ popl(tmp); __ jcc(Assembler::notEqual, call_patch); */ assert(_obj != NOREG, "must be a valid register"); #ifndef OPT_THREAD //FIXME, T8 need be saved ? Register thread = T8; __ get_thread(thread); #else Register thread = TREG; #endif __ lw(AT, _obj, instanceKlass::init_thread_offset_in_bytes() + sizeof(klassOopDesc)); __ bne(thread, AT, call_patch); __ delayed()->nop(); // access_field patches may execute the patched code before it's // copied back into place so we need to jump back into the main // code of the nmethod to continue execution. /* address temppc = __ pc(); __ b(_patch_site_continuation); __ delayed()->nop(); bytes_to_skip += (__ pc() - temppc); */ __ b(_patch_site_continuation); __ delayed()->nop(); bytes_to_skip += __ offset() - offset; } if (CommentedAssembly) { __ block_comment("patch data encoded as movl"); } // 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 int sizeof_patch_record = 4; bytes_to_skip += sizeof_patch_record; // emit the offsets needed to find the code to patch int being_initialized_entry_offset = __ pc() - being_initialized_entry + patch_info_size; // patch_info_pc offset | size of b instruction(8)| patched code size assert((char)being_initialized_entry_offset==being_initialized_entry_offset, "just check"); assert((char)bytes_to_skip==bytes_to_skip, "just check"); assert((char)_bytes_to_copy==_bytes_to_copy, "just check"); __ a_long(being_initialized_entry_offset<<8 | (bytes_to_skip<<16) | (_bytes_to_copy<<24) ); address patch_info_pc = __ pc(); assert(patch_info_pc - end_of_patch == bytes_to_skip, "incorrect patch info"); address entry = __ pc(); 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; case load_klass_id: target = Runtime1::entry_for(Runtime1::load_klass_patching_id); break; default: ShouldNotReachHere(); } __ bind(call_patch); if (CommentedAssembly) { __ block_comment("patch entry point"); } //__ call(RuntimeAddress(target)); __ lui(T9, Assembler::split_high((int)target)); __ addiu(T9, T9, Assembler::split_low((int)target)); __ jalr(T9); __ delayed()->nop(); assert(_patch_info_offset == (patch_info_pc - __ pc()), "must not change"); ce->add_call_info_here(_info); int jmp_off = __ offset(); __ b(_patch_site_entry); __ 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 ) { __ 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); } } void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) { ce->compilation()->implicit_exception_table()->append(_offset, __ offset()); __ bind(_entry); __ call(Runtime1::entry_for(Runtime1::throw_null_pointer_exception_id), relocInfo::runtime_call_type); __ delayed()->nop(); ce->add_call_info_here(_info); debug_only(__ should_not_reach_here()); } // i dont know which register to use here, i just assume A1 here. FIXME void SimpleExceptionStub::emit_code(LIR_Assembler* ce) { assert(__ sp_offset() == 0, "frame size should be fixed"); __ bind(_entry); // pass the object on stack because all registers must be preserved if (_obj->is_cpu_register()) { ce->store_parameter(_obj->as_register(), 0); } __ call(Runtime1::entry_for(_stub), relocInfo::runtime_call_type); __ delayed()->nop(); ce->add_call_info_here(_info); debug_only(__ should_not_reach_here()); } ArrayStoreExceptionStub::ArrayStoreExceptionStub(CodeEmitInfo* info): _info(info) { } void ArrayStoreExceptionStub::emit_code(LIR_Assembler* ce) { assert(__ sp_offset() == 0, "frame size should be fixed"); __ bind(_entry); //__ call(RuntimeAddress(Runtime1::entry_for(Runtime1::throw_array_store_exception_id))); __ call(Runtime1::entry_for(Runtime1::throw_array_store_exception_id), relocInfo::runtime_call_type); __ delayed()->nop(); ce->add_call_info_here(_info); debug_only(__ should_not_reach_here()); } void ArrayCopyStub::emit_code(LIR_Assembler* ce) { //---------------slow case: call to native----------------- __ bind(_entry); // Figure out where the args should go // This should really convert the IntrinsicID to the methodOop and signature // but I don't know how to do that. // VMRegPair args[5]; BasicType signature[5] = { T_OBJECT, T_INT, T_OBJECT, T_INT, T_INT}; SharedRuntime::java_calling_convention(signature, args, 5, true); // push parameters // (src, src_pos, dest, destPos, length) Register r[5]; r[0] = src()->as_register(); r[1] = src_pos()->as_register(); r[2] = dst()->as_register(); r[3] = dst_pos()->as_register(); r[4] = length()->as_register(); // next registers will get stored on the stack for (int i = 0; i < 5 ; i++ ) { VMReg r_1 = args[i].first(); if (r_1->is_stack()) { int st_off = r_1->reg2stack() * wordSize; //__ movptr (Address(rsp, st_off), r[i]); __ sw( r[i], SP, st_off); } else { assert(r[i] == args[i].first()->as_Register(), "Wrong register for arg "); } } ce->align_call(lir_static_call); ce->emit_static_call_stub(); //AddressLiteral resolve(SharedRuntime::get_resolve_static_call_stub(), // relocInfo::static_call_type); //__ call(resolve); __ call(SharedRuntime::get_resolve_static_call_stub(), relocInfo::static_call_type); __ delayed()->nop(); ce->add_call_info_here(info()); #ifndef PRODUCT //__ incrementl(ExternalAddress((address)&Runtime1::_arraycopy_slowcase_cnt)); __ lui(T8, Assembler::split_high((int)&Runtime1::_arraycopy_slowcase_cnt)); __ lw(AT, T8, Assembler::split_low((int)&Runtime1::_arraycopy_slowcase_cnt)); __ addiu(AT, AT, 1); __ sw(AT, T8, Assembler::split_low((int)&Runtime1::_arraycopy_slowcase_cnt)); #endif __ b(_continuation); __ delayed()->nop(); } ///////////////////////////////////////////////////////////////////////////// #ifndef SERIALGC void G1PreBarrierStub::emit_code(LIR_Assembler* ce) { Unimplemented(); } /* jbyte* G1PostBarrierStub::_byte_map_base = NULL; jbyte* G1PostBarrierStub::byte_map_base_slow() { BarrierSet* bs = Universe::heap()->barrier_set(); assert(bs->is_a(BarrierSet::G1SATBCTLogging), "Must be if we're using this."); return ((G1SATBCardTableModRefBS*)bs)->byte_map_base; } */ void G1PostBarrierStub::emit_code(LIR_Assembler* ce) { Unimplemented(); } #endif // SERIALGC ///////////////////////////////////////////////////////////////////////////// #undef __