aoqi@1: /* aoqi@1: * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. aoqi@1: * Copyright (c) 2015, 2016, Loongson Technology. All rights reserved. aoqi@1: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@1: * aoqi@1: * This code is free software; you can redistribute it and/or modify it aoqi@1: * under the terms of the GNU General Public License version 2 only, as aoqi@1: * published by the Free Software Foundation. aoqi@1: * aoqi@1: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@1: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@1: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@1: * version 2 for more details (a copy is included in the LICENSE file that aoqi@1: * accompanied this code). aoqi@1: * aoqi@1: * You should have received a copy of the GNU General Public License version aoqi@1: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@1: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@1: * aoqi@1: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@1: * or visit www.oracle.com if you need additional information or have any aoqi@1: * questions. aoqi@1: * aoqi@1: */ aoqi@1: aoqi@1: #include "precompiled.hpp" aoqi@1: #include "interp_masm_mips_64.hpp" aoqi@1: #include "interpreter/interpreter.hpp" aoqi@1: #include "interpreter/interpreterRuntime.hpp" aoqi@1: #include "oops/arrayOop.hpp" aoqi@1: #include "oops/markOop.hpp" aoqi@1: #include "oops/methodData.hpp" aoqi@1: #include "oops/method.hpp" aoqi@1: #include "prims/jvmtiExport.hpp" aoqi@1: #include "prims/jvmtiRedefineClassesTrace.hpp" aoqi@1: #include "prims/jvmtiThreadState.hpp" aoqi@1: #include "runtime/basicLock.hpp" aoqi@1: #include "runtime/biasedLocking.hpp" aoqi@1: #include "runtime/sharedRuntime.hpp" aoqi@1: #include "runtime/thread.inline.hpp" aoqi@1: aoqi@1: aoqi@1: // Implementation of InterpreterMacroAssembler aoqi@1: aoqi@1: #ifdef CC_INTERP aoqi@1: void InterpreterMacroAssembler::get_method(Register reg) { aoqi@1: } aoqi@1: #endif // CC_INTERP aoqi@1: aoqi@16: void InterpreterMacroAssembler::get_2_byte_integer_at_bcp(Register reg, Register tmp, int offset) { aoqi@16: /* 2016/5/6 Jin: the runtime address of BCP may be unaligned. aoqi@16: * Refer to the SPARC implementation. */ aoqi@16: lbu(reg, BCP, offset+1); aoqi@16: lbu(tmp, BCP, offset); aoqi@16: #ifdef _LP64 aoqi@16: dsll(reg, reg, 8); aoqi@16: daddu(reg, tmp, reg); aoqi@16: #else aoqi@16: sll(reg, reg, 8); aoqi@16: addu(reg, tmp, reg); aoqi@16: #endif aoqi@16: } aoqi@16: aoqi@16: void InterpreterMacroAssembler::get_4_byte_integer_at_bcp(Register reg, Register tmp, int offset) { aoqi@16: assert(reg != tmp, "need separate temp register"); aoqi@16: if (offset & 3) { // Offset unaligned? aoqi@16: lbu(reg, BCP, offset+3); aoqi@16: lbu(tmp, BCP, offset+2); aoqi@16: #ifdef _LP64 aoqi@16: dsll(reg, reg, 8); aoqi@16: daddu(reg, tmp, reg); aoqi@16: lbu(tmp, BCP, offset+1); aoqi@16: dsll(reg, reg, 8); aoqi@16: daddu(reg, tmp, reg); aoqi@16: lbu(tmp, BCP, offset); aoqi@16: dsll(reg, reg, 8); aoqi@16: daddu(reg, tmp, reg); aoqi@16: #else aoqi@16: sll(reg, reg, 8); aoqi@16: addu(reg, tmp, reg); aoqi@16: lbu(tmp, BCP, offset+1); aoqi@16: sll(reg, reg, 8); aoqi@16: addu(reg, tmp, reg); aoqi@16: lbu(tmp, BCP, offset); aoqi@16: sll(reg, reg, 8); aoqi@16: addu(reg, tmp, reg); aoqi@16: #endif aoqi@16: } else { aoqi@16: lwu(reg, BCP, offset); aoqi@16: } aoqi@16: } aoqi@16: aoqi@1: #ifndef CC_INTERP aoqi@1: aoqi@1: void InterpreterMacroAssembler::call_VM_leaf_base(address entry_point, aoqi@1: int number_of_arguments) { aoqi@1: // interpreter specific aoqi@1: // aoqi@1: // Note: No need to save/restore bcp & locals (r13 & r14) pointer aoqi@1: // since these are callee saved registers and no blocking/ aoqi@1: // GC can happen in leaf calls. aoqi@1: // Further Note: DO NOT save/restore bcp/locals. If a caller has aoqi@1: // already saved them so that it can use esi/edi as temporaries aoqi@1: // then a save/restore here will DESTROY the copy the caller aoqi@1: // saved! There used to be a save_bcp() that only happened in aoqi@1: // the ASSERT path (no restore_bcp). Which caused bizarre failures aoqi@1: // when jvm built with ASSERTs. aoqi@1: /* aoqi@1: #ifdef ASSERT aoqi@1: { aoqi@1: Label L; aoqi@1: cmpptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD); aoqi@1: jcc(Assembler::equal, L); aoqi@1: stop("InterpreterMacroAssembler::call_VM_leaf_base:" aoqi@1: " last_sp != NULL"); aoqi@1: bind(L); aoqi@1: } aoqi@1: #endif aoqi@1: // super call aoqi@1: MacroAssembler::call_VM_leaf_base(entry_point, number_of_arguments); aoqi@1: // interpreter specific aoqi@1: // Used to ASSERT that r13/r14 were equal to frame's bcp/locals aoqi@1: // but since they may not have been saved (and we don't want to aoqi@1: // save thme here (see note above) the assert is invalid. aoqi@1: */ aoqi@1: #ifdef ASSERT aoqi@1: save_bcp(); aoqi@1: { Label L; aoqi@1: //cmpl(Address(ebp, frame::interpreter_frame_last_sp_offset * wordSize), aoqi@1: //NULL_WORD); aoqi@1: ld(AT,FP,frame::interpreter_frame_last_sp_offset * wordSize); aoqi@1: // jcc(Assembler::equal, L); aoqi@1: beq(AT,R0,L); aoqi@1: delayed()->nop(); aoqi@1: stop("InterpreterMacroAssembler::call_VM_leaf_base: last_sp != NULL"); aoqi@1: bind(L); aoqi@1: } aoqi@1: #endif aoqi@1: // super call aoqi@1: MacroAssembler::call_VM_leaf_base(entry_point, number_of_arguments); aoqi@1: // interpreter specific aoqi@1: #ifdef ASSERT aoqi@1: { Label L; aoqi@1: ld(T3, FP, frame::interpreter_frame_bcx_offset * wordSize); aoqi@1: Assembler::beq(BCP, T3, L); aoqi@1: delayed()->nop(); aoqi@1: stop("InterpreterMacroAssembler::call_VM_leaf_base: esi not callee saved?"); aoqi@1: bind(L); aoqi@1: } aoqi@1: { Label L; aoqi@1: ld(T3, FP, frame::interpreter_frame_locals_offset * wordSize); aoqi@1: Assembler::beq(LVP, T3, L); aoqi@1: delayed()->nop(); aoqi@1: stop("InterpreterMacroAssembler::call_VM_leaf_base: edi not callee saved?"); aoqi@1: bind(L); aoqi@1: } aoqi@1: #endif aoqi@1: } aoqi@1: aoqi@1: void InterpreterMacroAssembler::call_VM_base(Register oop_result, aoqi@1: Register java_thread, aoqi@1: Register last_java_sp, aoqi@1: address entry_point, aoqi@1: int number_of_arguments, aoqi@1: bool check_exceptions) { aoqi@1: #if 0 aoqi@1: // interpreter specific aoqi@1: // aoqi@1: // Note: Could avoid restoring locals ptr (callee saved) - however doesn't aoqi@1: // really make a difference for these runtime calls, since they are aoqi@1: // slow anyway. Btw., bcp must be saved/restored since it may change aoqi@1: // due to GC. aoqi@1: // assert(java_thread == noreg , "not expecting a precomputed java thread"); aoqi@1: save_bcp(); aoqi@1: #ifdef ASSERT aoqi@1: { aoqi@1: Label L; aoqi@1: cmpptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), (int32_t)NULL_WORD); aoqi@1: jcc(Assembler::equal, L); aoqi@1: stop("InterpreterMacroAssembler::call_VM_leaf_base:" aoqi@1: " last_sp != NULL"); aoqi@1: bind(L); aoqi@1: } aoqi@1: #endif /* ASSERT */ aoqi@1: // super call aoqi@1: MacroAssembler::call_VM_base(oop_result, noreg, last_java_sp, aoqi@1: entry_point, number_of_arguments, aoqi@1: check_exceptions); aoqi@1: // interpreter specific aoqi@1: restore_bcp(); aoqi@1: restore_locals(); aoqi@1: #endif aoqi@1: #ifdef ASSERT aoqi@1: { Label L; aoqi@1: // cmpl(Address(ebp, frame::interpreter_frame_last_sp_offset * wordSize), aoqi@1: // NULL_WORD); aoqi@1: // jcc(Assembler::equal, L); aoqi@1: ld(AT, FP, frame::interpreter_frame_last_sp_offset * wordSize); aoqi@1: beq(AT, R0, L); aoqi@1: delayed()->nop(); aoqi@1: stop("InterpreterMacroAssembler::call_VM_base: last_sp != NULL"); aoqi@1: bind(L); aoqi@1: } aoqi@1: #endif /* ASSERT */ aoqi@1: // interpreter specific aoqi@1: // aoqi@1: // Note: Could avoid restoring locals ptr (callee saved) - however doesn't aoqi@1: // really make a difference for these runtime calls, since they are aoqi@1: // slow anyway. Btw., bcp must be saved/restored since it may change aoqi@1: // due to GC. aoqi@1: assert(java_thread == noreg , "not expecting a precomputed java thread"); aoqi@1: save_bcp(); aoqi@1: // super call aoqi@1: MacroAssembler::call_VM_base(oop_result, java_thread, last_java_sp, entry_point, number_of_arguments, check_exceptions); aoqi@1: restore_bcp(); aoqi@1: restore_locals(); aoqi@1: } aoqi@1: aoqi@1: aoqi@1: void InterpreterMacroAssembler::check_and_handle_popframe(Register java_thread) { aoqi@1: if (JvmtiExport::can_pop_frame()) { aoqi@1: Label L; aoqi@1: // Initiate popframe handling only if it is not already being aoqi@1: // processed. If the flag has the popframe_processing bit set, it aoqi@1: // means that this code is called *during* popframe handling - we aoqi@1: // don't want to reenter. aoqi@1: // This method is only called just after the call into the vm in aoqi@1: // call_VM_base, so the arg registers are available. aoqi@1: /* aoqi@1: movl(c_rarg0, Address(r15_thread, JavaThread::popframe_condition_offset())); aoqi@1: testl(c_rarg0, JavaThread::popframe_pending_bit); aoqi@1: jcc(Assembler::zero, L); aoqi@1: testl(c_rarg0, JavaThread::popframe_processing_bit); aoqi@1: jcc(Assembler::notZero, L); aoqi@1: // Call Interpreter::remove_activation_preserving_args_entry() to get the aoqi@1: // address of the same-named entrypoint in the generated interpreter code. aoqi@1: call_VM_leaf(CAST_FROM_FN_PTR(address, Interpreter::remove_activation_preserving_args_entry)); aoqi@1: jmp(rax); aoqi@1: bind(L); aoqi@1: */ aoqi@1: Register pop_cond = java_thread; aoqi@1: // Not clear if any other register is available... aoqi@1: lw(pop_cond, java_thread, in_bytes(JavaThread::popframe_condition_offset())); aoqi@1: andi(AT, pop_cond, JavaThread::popframe_pending_bit); aoqi@1: beq(AT, R0, L); aoqi@1: delayed()->andi(AT, pop_cond, JavaThread::popframe_processing_bit); aoqi@1: bne(AT, R0, L); aoqi@1: delayed()->nop(); aoqi@1: call( CAST_FROM_FN_PTR(address, Interpreter::remove_activation_preserving_args_entry), relocInfo::runtime_call_type); aoqi@1: delayed()->nop(); aoqi@1: jr(V0); aoqi@1: delayed()->nop(); aoqi@1: bind(L); aoqi@1: get_thread(java_thread); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: aoqi@1: void InterpreterMacroAssembler::load_earlyret_value(TosState state) { aoqi@1: //T8, thread aoqi@1: get_thread(T8); aoqi@1: ld_ptr(T8, T8,in_bytes(JavaThread::jvmti_thread_state_offset())); aoqi@1: /* aoqi@1: const Address tos_addr (ecx, JvmtiThreadState::earlyret_tos_offset()); aoqi@1: const Address oop_addr (ecx, JvmtiThreadState::earlyret_oop_offset()); aoqi@1: const Address val_addr (ecx, JvmtiThreadState::earlyret_value_offset()); aoqi@1: const Address val_addr1(ecx, JvmtiThreadState::earlyret_value_offset() aoqi@1: + in_ByteSize(wordSize)); aoqi@1: */ aoqi@1: const Address tos_addr (T8, in_bytes(JvmtiThreadState::earlyret_tos_offset())); aoqi@1: const Address oop_addr (T8, in_bytes(JvmtiThreadState::earlyret_oop_offset())); aoqi@1: const Address val_addr (T8, in_bytes(JvmtiThreadState::earlyret_value_offset())); aoqi@1: //V0, oop_addr,V1,val_addr aoqi@1: switch (state) { aoqi@1: case atos: aoqi@1: //movl(eax, oop_addr); aoqi@1: ld_ptr(V0, oop_addr); aoqi@1: // movl(oop_addr, NULL_WORD); aoqi@1: st_ptr(R0, oop_addr); aoqi@1: //verify_oop(eax, state); break; aoqi@1: verify_oop(V0, state); aoqi@1: break; aoqi@1: case ltos: aoqi@1: // movl(edx, val_addr1); // fall through aoqi@1: ld_ptr(V0, val_addr); // fall through aoqi@1: break; aoqi@1: case btos: // fall through aoqi@1: case ctos: // fall through aoqi@1: case stos: // fall through aoqi@1: case itos: aoqi@1: // movl(eax, val_addr); aoqi@1: lw(V0, val_addr); aoqi@1: break; aoqi@1: //FIXME ,I hava no idear fld store to where @jerome aoqi@1: case ftos: aoqi@1: //fld_s(val_addr); aoqi@1: lwc1(F0,T8, in_bytes(JvmtiThreadState::earlyret_value_offset())); aoqi@1: break; aoqi@1: case dtos: aoqi@1: //fld_d(val_addr); aoqi@1: ldc1(F0,T8, in_bytes(JvmtiThreadState::earlyret_value_offset())); aoqi@1: break; aoqi@1: case vtos: /* nothing to do */ break; aoqi@1: default : ShouldNotReachHere(); aoqi@1: } aoqi@1: // Clean up tos value in the thread object aoqi@1: // movl(tos_addr, (int) ilgl); aoqi@1: //addi(AT,R0,(int)ilgl); aoqi@1: move(AT, (int)ilgl); aoqi@1: sw(AT, tos_addr); aoqi@1: // movl(val_addr, NULL_WORD); aoqi@1: sw(R0,T8, in_bytes(JvmtiThreadState::earlyret_value_offset())); aoqi@1: } aoqi@1: aoqi@1: aoqi@1: void InterpreterMacroAssembler::check_and_handle_earlyret(Register java_thread) { aoqi@1: if (JvmtiExport::can_force_early_return()) { aoqi@1: Label L; aoqi@1: Register tmp = T9; aoqi@1: aoqi@1: //movptr(c_rarg0, Address(r15_thread, JavaThread::jvmti_thread_state_offset())); aoqi@1: ld_ptr(AT,java_thread, in_bytes(JavaThread::jvmti_thread_state_offset())); aoqi@1: //testptr(c_rarg0, c_rarg0); aoqi@1: //jcc(Assembler::zero, L); // if (thread->jvmti_thread_state() == NULL) exit; aoqi@1: beq(AT,R0,L); aoqi@1: delayed()->nop(); aoqi@1: aoqi@1: // Initiate earlyret handling only if it is not already being processed. aoqi@1: // If the flag has the earlyret_processing bit set, it means that this code aoqi@1: // is called *during* earlyret handling - we don't want to reenter. aoqi@1: //movl(c_rarg0, Address(c_rarg0, JvmtiThreadState::earlyret_state_offset())); aoqi@1: lw(AT, AT, in_bytes(JvmtiThreadState::earlyret_state_offset())); aoqi@1: //cmpl(c_rarg0, JvmtiThreadState::earlyret_pending); aoqi@1: //jcc(Assembler::notEqual, L); aoqi@1: move(tmp, JvmtiThreadState::earlyret_pending); aoqi@1: bne(tmp, AT, L); aoqi@1: delayed()->nop(); aoqi@1: get_thread(java_thread); aoqi@1: aoqi@1: // Call Interpreter::remove_activation_early_entry() to get the address of the aoqi@1: // same-named entrypoint in the generated interpreter code. aoqi@1: //movptr(c_rarg0, Address(r15_thread, JavaThread::jvmti_thread_state_offset())); aoqi@1: ld_ptr(tmp,java_thread, in_bytes(JavaThread::jvmti_thread_state_offset())); aoqi@1: //movl(c_rarg0, Address(c_rarg0, JvmtiThreadState::earlyret_tos_offset())); aoqi@1: lw(AT,tmp, in_bytes(JvmtiThreadState::earlyret_tos_offset())); aoqi@1: move(A0, AT); aoqi@1: //push(AT); aoqi@1: call(CAST_FROM_FN_PTR(address, Interpreter::remove_activation_early_entry), aoqi@1: relocInfo::runtime_call_type); aoqi@1: //call_VM_leaf(CAST_FROM_FN_PTR(address, Interpreter::remove_activation_early_entry), c_rarg0); aoqi@1: //jmp(rax); aoqi@1: //bind(L); aoqi@1: jr(V0); aoqi@1: delayed()->nop(); aoqi@1: bind(L); aoqi@1: get_thread(java_thread); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: aoqi@1: void InterpreterMacroAssembler::get_unsigned_2_byte_index_at_bcp( aoqi@16: Register reg, aoqi@16: int bcp_offset) { aoqi@16: assert(bcp_offset >= 0, "bcp is still pointing to start of bytecode"); aoqi@16: get_2_byte_integer_at_bcp(reg, AT, bcp_offset); aoqi@16: hswap(reg); aoqi@1: } aoqi@1: aoqi@1: aoqi@1: void InterpreterMacroAssembler::get_cache_and_index_at_bcp(Register cache, aoqi@1: Register index, aoqi@1: int bcp_offset, aoqi@1: size_t index_size) { aoqi@1: assert_different_registers(cache, index); aoqi@1: get_cache_index_at_bcp(index, bcp_offset, index_size); aoqi@1: ld(cache, FP, frame::interpreter_frame_cache_offset * wordSize); aoqi@1: assert(sizeof(ConstantPoolCacheEntry) == 4 * wordSize, "adjust code below"); aoqi@1: assert(exact_log2(in_words(ConstantPoolCacheEntry::size())) == 2, "else change next line"); aoqi@1: shl(index, 2); aoqi@1: } aoqi@1: aoqi@1: void InterpreterMacroAssembler::get_cache_and_index_and_bytecode_at_bcp(Register cache, aoqi@1: Register index, aoqi@1: Register bytecode, aoqi@1: int byte_no, aoqi@1: int bcp_offset, aoqi@1: size_t index_size) { aoqi@1: get_cache_and_index_at_bcp(cache, index, bcp_offset, index_size); aoqi@1: // We use a 32-bit load here since the layout of 64-bit words on aoqi@1: // little-endian machines allow us that. aoqi@1: dsll(AT, index, Address::times_ptr); aoqi@1: dadd(AT, cache, AT); aoqi@1: lw(bytecode, AT, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset())); aoqi@1: aoqi@1: const int shift_count = (1 + byte_no) * BitsPerByte; aoqi@1: assert((byte_no == TemplateTable::f1_byte && shift_count == ConstantPoolCacheEntry::bytecode_1_shift) || aoqi@1: (byte_no == TemplateTable::f2_byte && shift_count == ConstantPoolCacheEntry::bytecode_2_shift), aoqi@1: "correct shift count"); aoqi@1: dsrl(bytecode, bytecode, shift_count); aoqi@1: assert(ConstantPoolCacheEntry::bytecode_1_mask == ConstantPoolCacheEntry::bytecode_2_mask, "common mask"); aoqi@1: move(AT, ConstantPoolCacheEntry::bytecode_1_mask); aoqi@1: andr(bytecode, bytecode, AT); aoqi@1: } aoqi@1: aoqi@1: void InterpreterMacroAssembler::get_cache_entry_pointer_at_bcp(Register cache, aoqi@1: Register tmp, aoqi@1: int bcp_offset, size_t index_size) { aoqi@1: assert(bcp_offset > 0, "bcp is still pointing to start of bytecode"); aoqi@1: assert(cache != tmp, "must use different register"); aoqi@1: aoqi@1: get_cache_index_at_bcp(tmp, bcp_offset, index_size); aoqi@1: assert(sizeof(ConstantPoolCacheEntry) == 4 * wordSize, "adjust code below"); aoqi@1: // convert from field index to ConstantPoolCacheEntry index aoqi@1: // and from word offset to byte offset aoqi@1: dsll(tmp, tmp, 2+LogBytesPerWord); aoqi@1: ld(cache, FP, frame::interpreter_frame_cache_offset * wordSize); aoqi@1: // skip past the header aoqi@1: daddi(cache, cache, in_bytes(ConstantPoolCache::base_offset())); aoqi@1: dadd(cache, cache, AT); aoqi@1: } aoqi@1: aoqi@1: void InterpreterMacroAssembler::get_cache_index_at_bcp(Register index, aoqi@1: int bcp_offset, aoqi@1: size_t index_size) { aoqi@1: assert(bcp_offset > 0, "bcp is still pointing to start of bytecode"); aoqi@1: if (index_size == sizeof(u2)) { aoqi@16: get_2_byte_integer_at_bcp(index, AT, bcp_offset); aoqi@1: } else if (index_size == sizeof(u4)) { aoqi@1: assert(EnableInvokeDynamic, "giant index used only for JSR 292"); aoqi@14: get_4_byte_integer_at_bcp(index, AT, bcp_offset); aoqi@1: // Check if the secondary index definition is still ~x, otherwise aoqi@1: // we have to change the following assembler code to calculate the aoqi@1: // plain index. aoqi@1: assert(ConstantPool::decode_invokedynamic_index(~123) == 123, "else change next line"); aoqi@1: nor(index, index, R0); aoqi@1: sll(index, index, 0); aoqi@1: } else if (index_size == sizeof(u1)) { aoqi@1: lbu(index, BCP, bcp_offset); aoqi@1: } else { aoqi@1: ShouldNotReachHere(); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: void InterpreterMacroAssembler::get_method_counters(Register method, aoqi@1: Register mcs, Label& skip) { aoqi@1: Label has_counters; aoqi@1: ld(mcs, method, in_bytes(Method::method_counters_offset())); aoqi@1: bne(mcs, R0, has_counters); aoqi@1: nop(); aoqi@1: call_VM(noreg, CAST_FROM_FN_PTR(address, aoqi@1: InterpreterRuntime::build_method_counters), method); aoqi@1: ld(mcs, method, in_bytes(Method::method_counters_offset())); aoqi@1: beq(mcs, R0, skip); // No MethodCounters allocated, OutOfMemory aoqi@1: nop(); aoqi@1: bind(has_counters); aoqi@1: } aoqi@1: aoqi@1: // Load object from cpool->resolved_references(index) aoqi@1: void InterpreterMacroAssembler::load_resolved_reference_at_index( aoqi@1: Register result, Register index) { aoqi@1: assert_different_registers(result, index); aoqi@1: // convert from field index to resolved_references() index and from aoqi@1: // word index to byte offset. Since this is a java object, it can be compressed aoqi@1: Register tmp = index; // reuse aoqi@1: shl(tmp, LogBytesPerHeapOop); aoqi@1: aoqi@1: get_constant_pool(result); aoqi@1: // load pointer for resolved_references[] objArray aoqi@1: ld(result, result, ConstantPool::resolved_references_offset_in_bytes()); aoqi@1: // JNIHandles::resolve(obj); aoqi@1: // movptr(result, Address(result, 0)); aoqi@1: ld(result, result, 0); //? is needed? aoqi@1: // Add in the index aoqi@1: dadd(result, result, tmp); aoqi@1: load_heap_oop(result, Address(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT))); aoqi@1: } aoqi@1: aoqi@1: // Resets LVP to locals. Register sub_klass cannot be any of the above. aoqi@1: void InterpreterMacroAssembler::gen_subtype_check( Register Rsup_klass, Register Rsub_klass, Label &ok_is_subtype ) { aoqi@1: assert( Rsub_klass != Rsup_klass, "Rsup_klass holds superklass" ); aoqi@1: assert( Rsub_klass != T1, "T1 holds 2ndary super array length" ); aoqi@1: assert( Rsub_klass != T0, "T0 holds 2ndary super array scan ptr" ); aoqi@1: // Profile the not-null value's klass. aoqi@1: // [20130904] Fu: Here T9 and T1 are used as temporary registers. aoqi@1: profile_typecheck(T9, Rsub_klass, T1); // blows rcx, reloads rdi aoqi@1: aoqi@1: // Do the check. aoqi@1: check_klass_subtype(Rsub_klass, Rsup_klass, T1, ok_is_subtype); // blows rcx aoqi@1: aoqi@1: // Profile the failure of the check. aoqi@1: profile_typecheck_failed(T9); // blows rcx aoqi@1: } aoqi@1: aoqi@1: aoqi@1: aoqi@1: // Java Expression Stack aoqi@1: aoqi@1: void InterpreterMacroAssembler::pop_ptr(Register r) { aoqi@1: pop(r); aoqi@1: //if (TaggedStackInterpreter) addptr(rsp, 1 * wordSize); aoqi@1: // if (TaggedStackInterpreter) addi(SP,SP, 1 * wordSize); aoqi@1: } aoqi@1: /* aoqi@1: void InterpreterMacroAssembler::pop_ptr(Register r, Register tag) { aoqi@1: pop(r); aoqi@1: // if (TaggedStackInterpreter) pop(tag); aoqi@1: }*/ aoqi@1: aoqi@1: void InterpreterMacroAssembler::pop_i(Register r) { aoqi@1: // XXX can't use pop currently, upper half non clean aoqi@1: //movl(r, Address(rsp, 0)); aoqi@1: //addptr(rsp, wordSize); aoqi@1: lw(r, SP, 0); aoqi@1: daddi(SP, SP, 8); aoqi@1: //if (TaggedStackInterpreter) addptr(rsp, 1 * wordSize); aoqi@1: // if (TaggedStackInterpreter) addi(SP,SP, 1 * wordSize); aoqi@1: } aoqi@1: /* aoqi@1: void InterpreterMacroAssembler::pop_l(Register r) { aoqi@1: //movq(r, Address(rsp, 0)); aoqi@1: //addptr(rsp, 2 * Interpreter::stackElementSize()); aoqi@1: //FIXME, this directly call assembler. by aoqi aoqi@1: ld(r, SP, 0); aoqi@1: addi(SP, SP, 8); aoqi@1: if (TaggedStackInterpreter) addi(SP,SP, 2 * wordSize); aoqi@1: } aoqi@1: */ aoqi@1: //FIXME How many registers do push_l & pop_l use? aoqi aoqi@1: void InterpreterMacroAssembler::pop_l(Register lo, Register hi) { aoqi@1: pop(lo); aoqi@1: //if (TaggedStackInterpreter) daddi(SP,SP, 1 * wordSize); aoqi@1: pop(hi); aoqi@1: //if (TaggedStackInterpreter) daddi(SP,SP, 1 * wordSize); aoqi@1: } aoqi@1: aoqi@1: void InterpreterMacroAssembler::pop_f() { aoqi@1: lwc1(FSF, SP, 0); aoqi@1: daddi(SP, SP, 1 * wordSize); aoqi@1: // if (TaggedStackInterpreter) addi(SP,SP, 1 * wordSize); aoqi@1: } aoqi@1: aoqi@1: void InterpreterMacroAssembler::pop_d() { aoqi@1: pop_dtos_to_esp(); aoqi@1: ldc1(FSF, SP, 0); aoqi@1: daddi(SP, SP, 2 * wordSize); aoqi@1: } aoqi@1: aoqi@1: // Pop the top of the java expression stack to execution stack (which aoqi@1: // happens to be the same place). aoqi@1: //FIXME ,I hava no idea which register to use aoqi@1: void InterpreterMacroAssembler::pop_dtos_to_esp() { aoqi@1: /* if (TaggedStackInterpreter) { aoqi@1: // Pop double value into scratch registers aoqi@1: // popl(eax); aoqi@1: pop(V0); aoqi@1: //addl(esp, 1* wordSize); aoqi@1: addi(SP,SP, 1* wordSize); aoqi@1: //popl(edx); aoqi@1: pop(V1); aoqi@1: //addl(esp, 1* wordSize); aoqi@1: addi(SP,SP, 1* wordSize); aoqi@1: // pushl(edx); aoqi@1: push(V1); aoqi@1: //pushl(eax); aoqi@1: push(V0); aoqi@1: }*/ aoqi@1: } aoqi@1: aoqi@1: void InterpreterMacroAssembler::pop_ftos_to_esp() { aoqi@1: /* if (TaggedStackInterpreter) { aoqi@1: // popl(eax); aoqi@1: pop(V0); aoqi@1: //addl(esp, 1 * wordSize); aoqi@1: addi(SP,SP, 1 * wordSize); aoqi@1: // pushl(eax); // ftos is at esp aoqi@1: push(V0); // ftos is at esp aoqi@1: }*/ aoqi@1: } aoqi@1: aoqi@1: void InterpreterMacroAssembler::push_ptr(Register r) { aoqi@1: //if (TaggedStackInterpreter) push(frame::TagReference); aoqi@1: /* if (TaggedStackInterpreter) { aoqi@1: move(AT, frame::TagReference); aoqi@1: push(AT); aoqi@1: }//pushl(r);*/ aoqi@1: push(r); aoqi@1: } aoqi@1: /* aoqi@1: void InterpreterMacroAssembler::push_ptr(Register r, Register tag) { aoqi@1: //if (TaggedStackInterpreter) push(tag); aoqi@1: if (TaggedStackInterpreter){ aoqi@1: move(AT, tag); aoqi@1: push(AT); // tag first aoqi@1: } aoqi@1: push(r); aoqi@1: }*/ aoqi@1: aoqi@1: void InterpreterMacroAssembler::push_i(Register r) { aoqi@1: //if (TaggedStackInterpreter) push(frame::TagValue); aoqi@1: /* if (TaggedStackInterpreter) { aoqi@1: move(AT, frame::TagValue); aoqi@1: push(AT); aoqi@1: }*/ aoqi@1: push(r); aoqi@1: } aoqi@1: /* aoqi@1: void InterpreterMacroAssembler::push_l(Register r) { aoqi@1: if (TaggedStackInterpreter) { aoqi@1: //push(frame::TagValue); aoqi@1: //subptr(rsp, 1 * wordSize); aoqi@1: //push(frame::TagValue); aoqi@1: //subptr(rsp, 1 * wordSize); aoqi@1: move(AT, frame::TagValue); aoqi@1: push(AT); aoqi@1: } else { aoqi@1: addi(SP, SP, (-2) * wordSize); aoqi@1: } aoqi@1: //movq(Address(rsp, 0), r); aoqi@1: //FIXME, same as pop_l aoqi@1: sd(r, SP, 0); aoqi@1: } aoqi@1: */ aoqi@1: //FIXME How many registers do push_l & pop_l use? aoqi aoqi@1: void InterpreterMacroAssembler::push_l(Register lo, Register hi) { aoqi@1: //if (TaggedStackInterpreter) pushl(frame::TagValue); aoqi@1: /*if (TaggedStackInterpreter) { aoqi@1: move(AT, frame::TagValue); aoqi@1: push(AT); aoqi@1: }*/ aoqi@1: //pushl(hi); aoqi@1: push(hi); aoqi@1: //if (TaggedStackInterpreter) pushl(frame::TagValue); aoqi@1: /* if (TaggedStackInterpreter) { aoqi@1: move(AT, frame::TagValue); aoqi@1: push(AT); aoqi@1: }*/ aoqi@1: //pushl(lo); aoqi@1: push(lo); aoqi@1: } aoqi@1: //void InterpreterMacroAssembler::push_f(XMMRegister r) { aoqi@1: void InterpreterMacroAssembler::push_f() { aoqi@1: /* if (TaggedStackInterpreter) { aoqi@1: move(AT, frame::TagValue); aoqi@1: push(AT); aoqi@1: }// Do not schedule for no AGI! Never write beyond esp!*/ aoqi@1: daddi(SP, SP, (-1) * wordSize); aoqi@1: swc1(FSF, SP, 0 * wordSize); aoqi@1: sw(R0, SP, 4); aoqi@1: } aoqi@1: aoqi@1: //FIXME. aoqi aoqi@1: void InterpreterMacroAssembler::push_d(FloatRegister r) { aoqi@1: /* if (TaggedStackInterpreter) { aoqi@1: move(AT, frame::TagValue); aoqi@1: push(AT); aoqi@1: addi(SP, SP, (-3) * wordSize); aoqi@1: swc1(FSF, SP, 0 * wordSize); aoqi@1: swc1(SSF, SP, 1 * wordSize); aoqi@1: aoqi@1: lwc1(r, SP, 1*wordSize); aoqi@1: swc1(r, SP, 2*wordSize); aoqi@1: move(AT, frame::TagValue); aoqi@1: sw(AT, SP, 1*wordSize); aoqi@1: } else {*/ aoqi@1: daddi(SP, SP, (-2) * wordSize); aoqi@1: sdc1(FSF, SP, 0 * wordSize); aoqi@1: sdc1(SSF, SP, 1 * wordSize); aoqi@1: // } aoqi@1: } aoqi@1: aoqi@1: void InterpreterMacroAssembler::pop(TosState state) { aoqi@1: switch (state) { aoqi@1: case atos: pop(FSR); break; aoqi@1: case btos: aoqi@1: case ctos: aoqi@1: case stos: aoqi@1: case itos: aoqi@1: pop_i(FSR); aoqi@1: break; aoqi@1: case ltos: aoqi@1: pop_l(FSR, SSR); aoqi@1: break; aoqi@1: case ftos: pop_f(); break; aoqi@1: case dtos: pop_d(); break; aoqi@1: case vtos: /* nothing to do */ break; aoqi@1: default: ShouldNotReachHere(); aoqi@1: } aoqi@1: verify_oop(V0, state); aoqi@1: } aoqi@1: aoqi@1: //FSR=V0,SSR=V1 aoqi@1: void InterpreterMacroAssembler::push(TosState state) { aoqi@1: verify_oop(V0, state); aoqi@1: switch (state) { aoqi@1: case atos: push(FSR); break; aoqi@1: case btos: // fall through aoqi@1: case ctos: // fall through aoqi@1: case stos: // fall through aoqi@1: case itos: aoqi@1: push_i(FSR); aoqi@1: break; aoqi@1: case ltos: aoqi@1: //FIXME aoqi. aoqi@1: daddi(SP, SP, (-2) * wordSize); aoqi@1: //sd(SSR, SP, 1 * wordSize); aoqi@1: sd(R0, SP, 1 * wordSize); aoqi@1: sd(FSR, SP, 0 * wordSize); aoqi@1: break; aoqi@1: case ftos: aoqi@1: push_f(); aoqi@1: break; aoqi@1: case dtos: aoqi@1: //FIXME, I have no idea which register to use aoqi@1: push_d(FSF); aoqi@1: break; aoqi@1: case vtos: /* nothing to do */ break; aoqi@1: default : ShouldNotReachHere(); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: aoqi@1: aoqi@1: aoqi@1: // Tagged stack helpers for swap and dup aoqi@1: void InterpreterMacroAssembler::load_ptr(int n, Register val) { aoqi@1: ld(val, SP, Interpreter::expr_offset_in_bytes(n)); aoqi@1: /*if (TaggedStackInterpreter) { aoqi@1: ld(tag, SP, Interpreter::expr_tag_offset_in_bytes(n)); aoqi@1: }*/ aoqi@1: } aoqi@1: aoqi@1: void InterpreterMacroAssembler::store_ptr(int n, Register val) { aoqi@1: sd(val, SP, Interpreter::expr_offset_in_bytes(n)); aoqi@1: /* if (TaggedStackInterpreter) { aoqi@1: //movptr(Address(rsp, Interpreter::expr_tag_offset_in_bytes(n)), tag); aoqi@1: sd(tag, SP, Interpreter::expr_tag_offset_in_bytes(n)); aoqi@1: }*/ aoqi@1: } aoqi@1: aoqi@1: /* aoqi@1: // Tagged local support aoqi@1: //LVP=S7, local variable pointer register , FIXME aoqi@1: void InterpreterMacroAssembler::tag_local(frame::Tag tag, int n) { aoqi@1: if (TaggedStackInterpreter) { aoqi@1: if (tag == frame::TagCategory2) { aoqi@1: //movptr(Address(r14, Interpreter::local_tag_offset_in_bytes(n+1)), aoqi@1: // (int32_t)frame::TagValue); aoqi@1: move(AT, (int)frame::TagValue); aoqi@1: sw(AT,LVP, Interpreter::local_tag_offset_in_bytes(n+1)); aoqi@1: //movptr(Address(r14, Interpreter::local_tag_offset_in_bytes(n)), aoqi@1: // (int32_t)frame::TagValue); aoqi@1: sw(AT,LVP, Interpreter::local_tag_offset_in_bytes(n)); aoqi@1: } else { aoqi@1: //movptr(Address(r14, Interpreter::local_tag_offset_in_bytes(n)), (int32_t)tag); aoqi@1: move(AT, (int)tag); aoqi@1: sw(AT,LVP, Interpreter::local_tag_offset_in_bytes(n)); aoqi@1: } aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: void InterpreterMacroAssembler::tag_local(frame::Tag tag, Register idx) { aoqi@1: if (TaggedStackInterpreter) { aoqi@1: if (tag == frame::TagCategory2) { aoqi@1: //movptr(Address(r14, idx, Address::times_8, aoqi@1: // Interpreter::local_tag_offset_in_bytes(1)), (int32_t)frame::TagValue); aoqi@1: //movptr(Address(r14, idx, Address::times_8, aoqi@1: // Interpreter::local_tag_offset_in_bytes(0)), (int32_t)frame::TagValue); aoqi@1: shl(idx, 3); aoqi@1: add(idx,LVP,idx); aoqi@1: move(AT,(int)frame::TagValue); aoqi@1: sw(AT, idx, Interpreter::local_tag_offset_in_bytes(1)); aoqi@1: shl(idx, 3); aoqi@1: add(idx,LVP,idx); aoqi@1: move(AT,(int)frame::TagValue); aoqi@1: sw(AT, idx, Interpreter::local_tag_offset_in_bytes(0)); aoqi@1: } else { aoqi@1: //movptr(Address(r14, idx, Address::times_8, Interpreter::local_tag_offset_in_bytes(0)), aoqi@1: // (int32_t)tag); aoqi@1: shl(idx, 3); aoqi@1: add(idx,LVP,idx); aoqi@1: move(AT,(int)tag); aoqi@1: sw(AT, idx, Interpreter::local_tag_offset_in_bytes(0)); aoqi@1: } aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: void InterpreterMacroAssembler::tag_local(Register tag, Register idx) { aoqi@1: if (TaggedStackInterpreter) { aoqi@1: // can only be TagValue or TagReference aoqi@1: //movptr(Address(r14, idx, Address::times_8, Interpreter::local_tag_offset_in_bytes(0)), tag); aoqi@1: shl(idx, 3); aoqi@1: add(idx,LVP,idx); aoqi@1: sw(tag, idx, Interpreter::local_tag_offset_in_bytes(0)); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: aoqi@1: void InterpreterMacroAssembler::tag_local(Register tag, int n) { aoqi@1: if (TaggedStackInterpreter) { aoqi@1: // can only be TagValue or TagReference aoqi@1: //movptr(Address(r14, Interpreter::local_tag_offset_in_bytes(n)), tag); aoqi@1: sw(tag, LVP, Interpreter::local_tag_offset_in_bytes(n)); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: #ifdef ASSERT aoqi@1: void InterpreterMacroAssembler::verify_local_tag(frame::Tag tag, int n) { aoqi@1: if (TaggedStackInterpreter) { aoqi@1: frame::Tag t = tag; aoqi@1: if (tag == frame::TagCategory2) { aoqi@1: Label nbl; aoqi@1: t = frame::TagValue; // change to what is stored in locals aoqi@1: //cmpptr(Address(r14, Interpreter::local_tag_offset_in_bytes(n+1)), (int32_t)t); aoqi@1: //jcc(Assembler::equal, nbl); aoqi@1: lw(AT, LVP, Interpreter::local_tag_offset_in_bytes(n+1)); aoqi@1: addi(AT,AT, -(int)t); aoqi@1: beq(AT, R0, nbl); aoqi@1: delayed()->nop(); aoqi@1: stop("Local tag is bad for long/double"); aoqi@1: bind(nbl); aoqi@1: } aoqi@1: Label notBad; aoqi@1: //cmpq(Address(r14, Interpreter::local_tag_offset_in_bytes(n)), (int32_t)t); aoqi@1: //jcc(Assembler::equal, notBad); aoqi@1: lw(AT, LVP, Interpreter::local_tag_offset_in_bytes(n)); aoqi@1: addi(AT,AT, -(int)t); aoqi@1: beq(AT, R0, notBad); aoqi@1: delayed()->nop(); aoqi@1: aoqi@1: // Also compare if the local value is zero, then the tag might aoqi@1: // not have been set coming from deopt. aoqi@1: //cmpptr(Address(r14, Interpreter::local_offset_in_bytes(n)), 0); aoqi@1: //jcc(Assembler::equal, notBad); aoqi@1: lw(AT, LVP, Interpreter::local_tag_offset_in_bytes(n+1)); aoqi@1: beq(AT, R0, notBad); aoqi@1: delayed()->nop(); aoqi@1: stop("Local tag is bad"); aoqi@1: bind(notBad); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: void InterpreterMacroAssembler::verify_local_tag(frame::Tag tag, Register idx) { aoqi@1: if (TaggedStackInterpreter) { aoqi@1: frame::Tag t = tag; aoqi@1: if (tag == frame::TagCategory2) { aoqi@1: Label nbl; aoqi@1: t = frame::TagValue; // change to what is stored in locals aoqi@1: //cmpptr(Address(r14, idx, Address::times_8, Interpreter::local_tag_offset_in_bytes(1)), (int32_t)t); aoqi@1: //jcc(Assembler::equal, nbl); aoqi@1: shl(idx, 3); aoqi@1: add(idx,LVP,idx); aoqi@1: lw(AT, idx, Interpreter::local_tag_offset_in_bytes(1)); aoqi@1: addi(AT,AT, -(int)t); aoqi@1: beq(AT,R0, nbl); aoqi@1: delayed()->nop(); aoqi@1: stop("Local tag is bad for long/double"); aoqi@1: bind(nbl); aoqi@1: } aoqi@1: Label notBad; aoqi@1: //cmpptr(Address(r14, idx, Address::times_8, Interpreter::local_tag_offset_in_bytes(0)), (int32_t)t); aoqi@1: //jcc(Assembler::equal, notBad); aoqi@1: shl(idx, 3); aoqi@1: add(idx,LVP,idx); aoqi@1: lw(AT, idx, Interpreter::local_tag_offset_in_bytes(0)); aoqi@1: addi(AT,AT, -(int)t); aoqi@1: beq(AT,R0, notBad); aoqi@1: delayed()->nop(); aoqi@1: aoqi@1: // Also compare if the local value is zero, then the tag might aoqi@1: // not have been set coming from deopt. aoqi@1: //cmpptr(Address(r14, idx, Address::times_8, Interpreter::local_offset_in_bytes(0)), 0); aoqi@1: //jcc(Assembler::equal, notBad); aoqi@1: shl(idx, 3); aoqi@1: add(idx,LVP,idx); aoqi@1: lw(AT, idx, Interpreter::local_tag_offset_in_bytes(0)); aoqi@1: beq(AT,R0, notBad); aoqi@1: delayed()->nop(); aoqi@1: stop("Local tag is bad"); aoqi@1: bind(notBad); aoqi@1: } aoqi@1: } aoqi@1: #endif // ASSERT aoqi@1: */ aoqi@1: /* aoqi@1: void InterpreterMacroAssembler::super_call_VM_leaf(address entry_point) { aoqi@1: MacroAssembler::call_VM_leaf_base(entry_point, 0); aoqi@1: } aoqi@1: aoqi@1: aoqi@1: void InterpreterMacroAssembler::super_call_VM_leaf(address entry_point, aoqi@1: Register arg_1) { aoqi@1: if (arg_1 != A0) move(A0, arg_1); aoqi@1: MacroAssembler::call_VM_leaf_base(entry_point, 1); aoqi@1: } aoqi@1: aoqi@1: aoqi@1: void InterpreterMacroAssembler::super_call_VM_leaf(address entry_point, aoqi@1: Register arg_1, aoqi@1: Register arg_2) { aoqi@1: if (arg_1 != A0) move(A0, arg_1); aoqi@1: if (arg_2 != A1) move(A1, arg_2); assert(arg_2 != A0, "smashed argument"); aoqi@1: MacroAssembler::call_VM_leaf_base(entry_point, 2); aoqi@1: } aoqi@1: aoqi@1: void InterpreterMacroAssembler::super_call_VM_leaf(address entry_point, aoqi@1: Register arg_1, aoqi@1: Register arg_2, aoqi@1: Register arg_3) { aoqi@1: if (arg_1 != A0) move(A0, arg_1); aoqi@1: if (arg_2 != A1) move(A1, arg_2); assert(arg_2 != A0, "smashed argument"); aoqi@1: if (arg_3 != A2) move(A2, arg_3); assert(arg_3 != A0 && arg_3 != A1, "smashed argument"); aoqi@1: MacroAssembler::call_VM_leaf_base(entry_point, 3); aoqi@1: } aoqi@1: */ aoqi@1: // Jump to from_interpreted entry of a call unless single stepping is possible aoqi@1: // in this thread in which case we must call the i2i entry aoqi@1: void InterpreterMacroAssembler::jump_from_interpreted(Register method, Register temp) { aoqi@1: // record last_sp aoqi@1: move(Rsender, SP); aoqi@1: sd(SP, FP, frame::interpreter_frame_last_sp_offset * wordSize); aoqi@1: aoqi@1: if (JvmtiExport::can_post_interpreter_events()) { aoqi@1: Label run_compiled_code; aoqi@1: // JVMTI events, such as single-stepping, are implemented partly by avoiding running aoqi@1: // compiled code in threads for which the event is enabled. Check here for aoqi@1: // interp_only_mode if these events CAN be enabled. aoqi@1: #ifndef OPT_THREAD aoqi@1: get_thread(temp); aoqi@1: #else aoqi@1: move(temp, TREG); aoqi@1: #endif aoqi@1: // interp_only is an int, on little endian it is sufficient to test the byte only aoqi@1: // Is a cmpl faster (ce aoqi@1: //cmpb(Address(temp, JavaThread::interp_only_mode_offset()), 0); aoqi@1: //jcc(Assembler::zero, run_compiled_code); aoqi@1: lw(AT, temp, in_bytes(JavaThread::interp_only_mode_offset())); aoqi@1: beq(AT, R0, run_compiled_code); aoqi@1: delayed()->nop(); aoqi@1: //jmp(Address(method, methodOopDesc::interpreter_entry_offset())); aoqi@1: ld(AT, method, in_bytes(Method::interpreter_entry_offset())); aoqi@1: jr(AT); aoqi@1: delayed()->nop(); aoqi@1: bind(run_compiled_code); aoqi@1: } aoqi@1: aoqi@1: ld(AT, method, in_bytes(Method::from_interpreted_offset())); aoqi@1: jr(AT); aoqi@1: delayed()->nop(); aoqi@1: } aoqi@1: aoqi@1: aoqi@1: // The following two routines provide a hook so that an implementation aoqi@1: // can schedule the dispatch in two parts. amd64 does not do this. aoqi@1: void InterpreterMacroAssembler::dispatch_prolog(TosState state, int step) { aoqi@1: // Nothing amd64 specific to be done here aoqi@1: } aoqi@1: aoqi@1: void InterpreterMacroAssembler::dispatch_epilog(TosState state, int step) { aoqi@1: dispatch_next(state, step); aoqi@1: } aoqi@1: aoqi@1: // assume the next bytecode in T8. aoqi@1: void InterpreterMacroAssembler::dispatch_base(TosState state, aoqi@1: address* table, aoqi@1: bool verifyoop) { aoqi@1: if (VerifyActivationFrameSize) { aoqi@1: Label L; aoqi@1: aoqi@1: dsub(T2, FP, SP); aoqi@1: int min_frame_size = (frame::link_offset - aoqi@1: frame::interpreter_frame_initial_sp_offset) * wordSize; aoqi@1: daddi(T2, T2,- min_frame_size); aoqi@1: bgez(T2, L); aoqi@1: delayed()->nop(); aoqi@1: stop("broken stack frame"); aoqi@1: bind(L); aoqi@1: } aoqi@1: // FIXME: I do not know which register should pass to verify_oop aoqi@1: if (verifyoop) verify_oop(FSR, state); aoqi@1: dsll(T2, Rnext, LogBytesPerWord); aoqi@1: aoqi@1: if((long)table >= (long)Interpreter::dispatch_table(btos) && aoqi@1: (long)table <= (long)Interpreter::dispatch_table(vtos) aoqi@1: ) { aoqi@1: int table_size = (long)Interpreter::dispatch_table(ctos) - (long)Interpreter::dispatch_table(btos); aoqi@1: int table_offset = ((int)state - (int)itos) * table_size; aoqi@1: aoqi@1: // 2013/12/17 Fu: GP points to the starting address of Interpreter::dispatch_table(itos). aoqi@1: // See StubGenerator::generate_call_stub(address& return_address) for the initialization of GP. aoqi@1: if(table_offset != 0) { aoqi@1: daddiu(T3, GP, table_offset); aoqi@1: gsldx(T3, T2, T3, 0); // 2013/5/7 Jin: Godson3 extension instruction aoqi@1: } else { aoqi@1: gsldx(T3, T2, GP, 0); aoqi@1: } aoqi@1: } else { aoqi@1: li(T3, (long)table); aoqi@1: gsldx(T3, T2, T3, 0); aoqi@1: } aoqi@1: aoqi@1: jr(T3); aoqi@1: delayed()->nop(); aoqi@1: } aoqi@1: aoqi@1: void InterpreterMacroAssembler::dispatch_only(TosState state) { aoqi@1: dispatch_base(state, Interpreter::dispatch_table(state)); aoqi@1: } aoqi@1: aoqi@1: void InterpreterMacroAssembler::dispatch_only_normal(TosState state) { aoqi@1: dispatch_base(state, Interpreter::normal_table(state)); aoqi@1: } aoqi@1: aoqi@1: void InterpreterMacroAssembler::dispatch_only_noverify(TosState state) { aoqi@1: dispatch_base(state, Interpreter::normal_table(state), false); aoqi@1: } aoqi@1: aoqi@1: aoqi@1: void InterpreterMacroAssembler::dispatch_next(TosState state, int step) { aoqi@1: // load next bytecode (load before advancing r13 to prevent AGI) aoqi@1: lbu(Rnext, BCP, step); aoqi@1: increment(BCP, step); aoqi@1: dispatch_base(state, Interpreter::dispatch_table(state)); aoqi@1: } aoqi@1: aoqi@1: void InterpreterMacroAssembler::dispatch_via(TosState state, address* table) { aoqi@1: // load current bytecode aoqi@1: lbu(Rnext, BCP, 0); aoqi@1: dispatch_base(state, table); aoqi@1: } aoqi@1: aoqi@1: // remove activation aoqi@1: // aoqi@1: // Unlock the receiver if this is a synchronized method. aoqi@1: // Unlock any Java monitors from syncronized blocks. aoqi@1: // Remove the activation from the stack. aoqi@1: // aoqi@1: // If there are locked Java monitors aoqi@1: // If throw_monitor_exception aoqi@1: // throws IllegalMonitorStateException aoqi@1: // Else if install_monitor_exception aoqi@1: // installs IllegalMonitorStateException aoqi@1: // Else aoqi@1: // no error processing aoqi@1: // used registers : T1, T2, T3, T8 aoqi@1: // T1 : thread, method access flags aoqi@1: // T2 : monitor entry pointer aoqi@1: // T3 : method, monitor top aoqi@1: // T8 : unlock flag aoqi@1: void InterpreterMacroAssembler::remove_activation( aoqi@1: TosState state, aoqi@1: Register ret_addr, aoqi@1: bool throw_monitor_exception, aoqi@1: bool install_monitor_exception, aoqi@1: bool notify_jvmdi) { aoqi@1: // Note: Registers V0, V1 and F0, F1 may be in use for the result aoqi@1: // check if synchronized method aoqi@1: Label unlocked, unlock, no_unlock; aoqi@1: aoqi@1: // get the value of _do_not_unlock_if_synchronized into T8 aoqi@1: #ifndef OPT_THREAD aoqi@1: Register thread = T1; aoqi@1: get_thread(thread); aoqi@1: #else aoqi@1: Register thread = TREG; aoqi@1: #endif aoqi@1: lb(T8, thread, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset())); aoqi@1: // reset the flag aoqi@1: sb(R0, thread, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset())); aoqi@1: // get method access flags aoqi@1: ld(T3, FP, frame::interpreter_frame_method_offset * wordSize); aoqi@1: lw(T1, T3, in_bytes(Method::access_flags_offset())); aoqi@1: andi(T1, T1, JVM_ACC_SYNCHRONIZED); aoqi@1: beq(T1, R0, unlocked); aoqi@1: delayed()->nop(); aoqi@1: aoqi@1: // Don't unlock anything if the _do_not_unlock_if_synchronized flag is set. aoqi@1: bne(T8, R0, no_unlock); aoqi@1: delayed()->nop(); aoqi@1: // unlock monitor aoqi@1: push(state); // save result aoqi@1: aoqi@1: // BasicObjectLock will be first in list, aoqi@1: // since this is a synchronized method. However, need aoqi@1: // to check that the object has not been unlocked by an explicit monitorexit bytecode. aoqi@1: daddiu(c_rarg0, FP, frame::interpreter_frame_initial_sp_offset * wordSize aoqi@1: - (int)sizeof(BasicObjectLock)); aoqi@1: // address of first monitor aoqi@1: lw(T1, c_rarg0, BasicObjectLock::obj_offset_in_bytes()); aoqi@1: bne(T1, R0, unlock); aoqi@1: delayed()->nop(); aoqi@1: pop(state); aoqi@1: if (throw_monitor_exception) { aoqi@1: // Entry already unlocked, need to throw exception aoqi@1: //I think mips do not need empty_FPU_stack aoqi@1: // remove possible return value from FPU-stack, otherwise stack could overflow aoqi@1: aoqi@1: empty_FPU_stack(); aoqi@1: call_VM(NOREG, CAST_FROM_FN_PTR(address, aoqi@1: InterpreterRuntime::throw_illegal_monitor_state_exception)); aoqi@1: should_not_reach_here(); aoqi@1: } else { aoqi@1: // Monitor already unlocked during a stack unroll. aoqi@1: // If requested, install an illegal_monitor_state_exception. aoqi@1: // Continue with stack unrolling. aoqi@1: if (install_monitor_exception) { aoqi@1: // remove possible return value from FPU-stack, aoqi@1: // otherwise stack could overflow aoqi@1: empty_FPU_stack(); aoqi@1: call_VM(NOREG, CAST_FROM_FN_PTR(address, aoqi@1: InterpreterRuntime::new_illegal_monitor_state_exception)); aoqi@1: aoqi@1: } aoqi@1: aoqi@1: b(unlocked); aoqi@1: delayed()->nop(); aoqi@1: } aoqi@1: aoqi@1: bind(unlock); aoqi@1: aoqi@1: unlock_object(c_rarg0); aoqi@1: pop(state); aoqi@1: // Check that for block-structured locking (i.e., that all locked objects has been unlocked) aoqi@1: bind(unlocked); aoqi@1: aoqi@1: // V0, V1: Might contain return value aoqi@1: aoqi@1: // Check that all monitors are unlocked aoqi@1: { aoqi@1: Label loop, exception, entry, restart; aoqi@1: const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; aoqi@1: const Address monitor_block_top(FP, aoqi@1: frame::interpreter_frame_monitor_block_top_offset * wordSize); aoqi@1: aoqi@1: bind(restart); aoqi@1: // points to current entry, starting with top-most entry (ecx) aoqi@1: ld(c_rarg0, monitor_block_top); aoqi@1: // points to word before bottom of monitor block (ebx) aoqi@1: daddiu(T3, FP, frame::interpreter_frame_initial_sp_offset * wordSize); aoqi@1: // lw(AT, R0, 12); aoqi@1: b(entry); aoqi@1: delayed()->nop(); aoqi@1: aoqi@1: // Entry already locked, need to throw exception aoqi@1: bind(exception); aoqi@1: aoqi@1: if (throw_monitor_exception) { aoqi@1: // Throw exception aoqi@1: // remove possible return value from FPU-stack, aoqi@1: // otherwise stack could overflow aoqi@1: empty_FPU_stack(); aoqi@1: MacroAssembler::call_VM(NOREG, CAST_FROM_FN_PTR(address, aoqi@1: InterpreterRuntime::throw_illegal_monitor_state_exception)); aoqi@1: should_not_reach_here(); aoqi@1: } else { aoqi@1: // Stack unrolling. Unlock object and install illegal_monitor_exception aoqi@1: // Unlock does not block, so don't have to worry about the frame aoqi@1: // We don't have to preserve eax, edx since we are going to aoqi@1: // throw an exception aoqi@1: unlock_object(c_rarg0); aoqi@1: if (install_monitor_exception) { aoqi@1: empty_FPU_stack(); aoqi@1: call_VM(NOREG, CAST_FROM_FN_PTR(address, aoqi@1: InterpreterRuntime::new_illegal_monitor_state_exception)); aoqi@1: } aoqi@1: aoqi@1: b(restart); aoqi@1: delayed()->nop(); aoqi@1: } aoqi@1: aoqi@1: bind(loop); aoqi@1: // stop("before object excetpion"); aoqi@1: aoqi@1: ld(T1, c_rarg0, BasicObjectLock::obj_offset_in_bytes()); aoqi@1: bne(T1, R0, exception);// check if current entry is used aoqi@1: delayed()->nop(); aoqi@1: aoqi@1: aoqi@1: daddiu(c_rarg0, c_rarg0, entry_size);// otherwise advance to next entry aoqi@1: bind(entry); aoqi@1: bne(c_rarg0, T3, loop); // check if bottom reached aoqi@1: delayed()->nop(); // if not at bottom then check this entry aoqi@1: } aoqi@1: aoqi@1: bind(no_unlock); aoqi@1: aoqi@1: // jvmpi support (jvmdi does not generate MethodExit on exception / popFrame) aoqi@1: if (notify_jvmdi) { aoqi@1: //notify_method_exit(state); // preserve TOSCA aoqi@1: notify_method_exit(false,state,NotifyJVMTI); // preserve TOSCA aoqi@1: } else { aoqi@1: // notify_jvmpi_method_exit(state); // preserve TOSCA aoqi@1: notify_method_exit(false,state,SkipNotifyJVMTI);// preserve TOSCA aoqi@1: } aoqi@1: aoqi@1: // remove activation aoqi@1: ld(SP, FP, frame::interpreter_frame_sender_sp_offset * wordSize); aoqi@1: ld(ret_addr, FP, frame::interpreter_frame_return_addr_offset * wordSize); aoqi@1: ld(FP, FP, frame::interpreter_frame_sender_fp_offset * wordSize); aoqi@1: } aoqi@1: aoqi@1: #endif // C_INTERP aoqi@1: aoqi@1: // Lock object aoqi@1: // aoqi@1: // Args: aoqi@1: // c_rarg1: BasicObjectLock to be used for locking aoqi@1: // aoqi@1: // Kills: aoqi@1: // rax aoqi@1: // c_rarg0, c_rarg1, c_rarg2, c_rarg3, .. (param regs) aoqi@1: // rscratch1, rscratch2 (scratch regs) aoqi@1: void InterpreterMacroAssembler::lock_object(Register lock_reg) { aoqi@1: assert(lock_reg == c_rarg0, "The argument is only for looks. It must be c_rarg0"); aoqi@1: aoqi@1: if (UseHeavyMonitors) { aoqi@1: call_VM(NOREG, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), aoqi@1: lock_reg); aoqi@1: } else { aoqi@1: aoqi@1: Label done; aoqi@1: aoqi@1: const Register swap_reg = T2; // Must use eax for cmpxchg instruction aoqi@1: const Register obj_reg = T1; // Will contain the oop aoqi@1: aoqi@1: const int obj_offset = BasicObjectLock::obj_offset_in_bytes(); aoqi@1: const int lock_offset = BasicObjectLock::lock_offset_in_bytes (); aoqi@1: const int mark_offset = lock_offset aoqi@1: + BasicLock::displaced_header_offset_in_bytes(); aoqi@1: aoqi@1: Label slow_case; aoqi@1: // Load object pointer into obj_reg %ecx aoqi@1: ld(obj_reg, lock_reg, obj_offset); aoqi@1: if (UseBiasedLocking) { aoqi@1: // Note: we use noreg for the temporary register since it's hard aoqi@1: // to come up with a free register on all incoming code paths aoqi@1: biased_locking_enter(lock_reg, obj_reg, swap_reg, noreg, false, aoqi@1: done, &slow_case); aoqi@1: } aoqi@1: aoqi@1: aoqi@1: // Load (object->mark() | 1) into swap_reg %eax aoqi@1: ld(AT, obj_reg, 0); aoqi@1: ori(swap_reg, AT, 1); aoqi@1: aoqi@1: aoqi@1: // Save (object->mark() | 1) into BasicLock's displaced header aoqi@1: sd(swap_reg, lock_reg, mark_offset); aoqi@1: aoqi@1: assert(lock_offset == 0, "displached header must be first word in BasicObjectLock"); aoqi@29: //if (os::is_MP()) { aoqi@1: // lock(); aoqi@29: //} aoqi@1: cmpxchg(lock_reg, Address(obj_reg, 0), swap_reg); aoqi@1: aoqi@1: if (PrintBiasedLockingStatistics) { aoqi@29: Label L; aoqi@29: beq(AT, R0, L); aoqi@29: delayed()->nop(); aoqi@29: push(T0); aoqi@29: push(T1); aoqi@29: atomic_inc32((address)BiasedLocking::fast_path_entry_count_addr(), 1, T0, T1); aoqi@29: pop(T1); aoqi@29: pop(T0); aoqi@29: bind(L); aoqi@1: } aoqi@1: aoqi@1: bne(AT, R0, done); aoqi@29: delayed()->nop(); aoqi@1: aoqi@1: // Test if the oopMark is an obvious stack pointer, i.e., aoqi@1: // 1) (mark & 3) == 0, and aoqi@1: // 2) SP <= mark < SP + os::pagesize() aoqi@1: // aoqi@1: // These 3 tests can be done by evaluating the following aoqi@1: // expression: ((mark - esp) & (3 - os::vm_page_size())), aoqi@1: // assuming both stack pointer and pagesize have their aoqi@1: // least significant 2 bits clear. aoqi@1: // NOTE: the oopMark is in swap_reg %eax as the result of cmpxchg aoqi@1: aoqi@1: dsub(swap_reg, swap_reg, SP); aoqi@1: move(AT, 3 - os::vm_page_size()); aoqi@1: andr(swap_reg, swap_reg, AT); aoqi@1: // Save the test result, for recursive case, the result is zero aoqi@1: sd(swap_reg, lock_reg, mark_offset); aoqi@1: if (PrintBiasedLockingStatistics) { aoqi@29: Label L; aoqi@29: bne(swap_reg, R0, L); aoqi@29: delayed()->nop(); aoqi@29: push(T0); aoqi@29: push(T1); aoqi@29: atomic_inc32((address)BiasedLocking::fast_path_entry_count_addr(), 1, T0, T1); aoqi@29: pop(T1); aoqi@29: pop(T0); aoqi@29: bind(L); aoqi@1: } aoqi@1: aoqi@1: beq(swap_reg, R0, done); aoqi@1: delayed()->nop(); aoqi@1: bind(slow_case); aoqi@1: // Call the runtime routine for slow case aoqi@1: call_VM(NOREG, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), lock_reg); aoqi@1: aoqi@1: bind(done); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: aoqi@1: // Unlocks an object. Used in monitorexit bytecode and aoqi@1: // remove_activation. Throws an IllegalMonitorException if object is aoqi@1: // not locked by current thread. aoqi@1: // aoqi@1: // Args: aoqi@1: // c_rarg1: BasicObjectLock for lock aoqi@1: // aoqi@1: // Kills: aoqi@1: // rax aoqi@1: // c_rarg0, c_rarg1, c_rarg2, c_rarg3, ... (param regs) aoqi@1: // rscratch1, rscratch2 (scratch regs) aoqi@1: // Argument: T6 : Points to BasicObjectLock structure for lock aoqi@1: // Argument: c_rarg0 : Points to BasicObjectLock structure for lock aoqi@1: // Throw an IllegalMonitorException if object is not locked by current thread aoqi@1: void InterpreterMacroAssembler::unlock_object(Register lock_reg) { aoqi@1: assert(lock_reg == c_rarg0, "The argument is only for looks. It must be c_rarg0"); aoqi@1: aoqi@1: if (UseHeavyMonitors) { aoqi@1: call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), lock_reg); aoqi@1: } else { aoqi@1: Label done; aoqi@1: aoqi@1: const Register swap_reg = T2; // Must use eax for cmpxchg instruction aoqi@1: const Register header_reg = T3; // Will contain the old oopMark aoqi@1: const Register obj_reg = T1; // Will contain the oop aoqi@1: aoqi@1: save_bcp(); // Save in case of exception aoqi@1: aoqi@1: // Convert from BasicObjectLock structure to object and BasicLock structure aoqi@1: // Store the BasicLock address into %eax aoqi@1: daddi(swap_reg, lock_reg, BasicObjectLock::lock_offset_in_bytes()); aoqi@1: aoqi@1: // Load oop into obj_reg(%ecx) aoqi@1: ld(obj_reg, lock_reg, BasicObjectLock::obj_offset_in_bytes ()); aoqi@1: //free entry aoqi@1: sd(R0, lock_reg, BasicObjectLock::obj_offset_in_bytes()); aoqi@1: if (UseBiasedLocking) { aoqi@1: biased_locking_exit(obj_reg, header_reg, done); aoqi@1: } aoqi@1: aoqi@1: // Load the old header from BasicLock structure aoqi@1: ld(header_reg, swap_reg, BasicLock::displaced_header_offset_in_bytes()); aoqi@1: /* aoqi@1: // Free entry aoqi@1: sw(R0, lock_reg, BasicObjectLock::obj_offset_in_bytes()); aoqi@1: */ aoqi@1: // zero for recursive case aoqi@1: beq(header_reg, R0, done); aoqi@1: delayed()->nop(); aoqi@1: aoqi@1: // Atomic swap back the old header aoqi@1: if (os::is_MP()); //lock(); aoqi@1: cmpxchg(header_reg, Address(obj_reg, 0), swap_reg); aoqi@1: aoqi@1: // zero for recursive case aoqi@1: bne(AT, R0, done); aoqi@1: delayed()->nop(); aoqi@1: aoqi@1: // Call the runtime routine for slow case. aoqi@1: sd(obj_reg, lock_reg, BasicObjectLock::obj_offset_in_bytes()); // restore obj aoqi@1: call_VM(NOREG, CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), aoqi@1: lock_reg); aoqi@1: aoqi@1: bind(done); aoqi@1: aoqi@1: restore_bcp(); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: #ifndef CC_INTERP aoqi@1: aoqi@1: void InterpreterMacroAssembler::test_method_data_pointer(Register mdp, aoqi@1: Label& zero_continue) { aoqi@1: assert(ProfileInterpreter, "must be profiling interpreter"); aoqi@1: ld(mdp, Address(FP, frame::interpreter_frame_mdx_offset * wordSize)); aoqi@1: beq(mdp, R0, zero_continue); aoqi@1: delayed()->nop(); aoqi@1: } aoqi@1: aoqi@1: aoqi@1: // Set the method data pointer for the current bcp. aoqi@1: void InterpreterMacroAssembler::set_method_data_pointer_for_bcp() { aoqi@1: assert(ProfileInterpreter, "must be profiling interpreter"); aoqi@1: Label set_mdp; aoqi@1: aoqi@1: // V0 and T0 will be used as two temporary registers. aoqi@1: sd(V0, SP, (-1) * wordSize); aoqi@1: sd(T0, SP, (-2) * wordSize); aoqi@1: daddiu(SP, SP, (-2) * wordSize); aoqi@1: aoqi@1: get_method(T0); aoqi@1: // Test MDO to avoid the call if it is NULL. aoqi@1: ld(V0, T0, in_bytes(Method::method_data_offset())); aoqi@1: beq(V0, R0, set_mdp); aoqi@1: delayed()->nop(); aoqi@1: aoqi@1: // method: T0 aoqi@1: // bcp: BCP --> S0 aoqi@1: call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::bcp_to_di), T0, BCP); aoqi@1: // mdi: V0 aoqi@1: // mdo is guaranteed to be non-zero here, we checked for it before the call. aoqi@1: /* Jin: reload T0 */ aoqi@1: get_method(T0); aoqi@1: ld(T0, T0, in_bytes(Method::method_data_offset())); aoqi@1: daddiu(T0, T0, in_bytes(MethodData::data_offset())); aoqi@1: daddu(V0, T0, V0); aoqi@1: aoqi@1: bind(set_mdp); aoqi@1: aoqi@1: sd(V0, FP, frame::interpreter_frame_mdx_offset * wordSize); aoqi@1: aoqi@1: daddiu(SP, SP, 2 * wordSize); aoqi@1: ld(V0, SP, (-1) * wordSize); aoqi@1: ld(T0, SP, (-2) * wordSize); aoqi@1: } aoqi@1: aoqi@1: void InterpreterMacroAssembler::verify_method_data_pointer() { aoqi@1: assert(ProfileInterpreter, "must be profiling interpreter"); aoqi@1: #ifdef ASSERT aoqi@1: Label verify_continue; aoqi@1: Register method = V0; aoqi@1: Register mdp = V1; aoqi@1: Register tmp = A0; aoqi@1: push(method); aoqi@1: push(mdp); aoqi@1: push(tmp); aoqi@1: test_method_data_pointer(mdp, verify_continue); // If mdp is zero, continue aoqi@1: get_method(method); aoqi@1: aoqi@1: // If the mdp is valid, it will point to a DataLayout header which is aoqi@1: // consistent with the bcp. The converse is highly probable also. Jin@4: lhu(tmp, mdp, in_bytes(DataLayout::bci_offset())); aoqi@1: ld(AT, method, in_bytes(Method::const_offset())); aoqi@1: daddu(tmp, tmp, AT); aoqi@1: daddiu(tmp, tmp, in_bytes(ConstMethod::codes_offset())); aoqi@1: beq(tmp, BCP, verify_continue); aoqi@1: nop(); aoqi@1: call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::verify_mdp), method, BCP, mdp); aoqi@1: bind(verify_continue); aoqi@1: pop(tmp); aoqi@1: pop(mdp); aoqi@1: pop(method); aoqi@1: #endif // ASSERT aoqi@1: } aoqi@1: aoqi@1: aoqi@1: void InterpreterMacroAssembler::set_mdp_data_at(Register mdp_in, aoqi@1: int constant, aoqi@1: Register value) { aoqi@1: assert(ProfileInterpreter, "must be profiling interpreter"); aoqi@1: Address data(mdp_in, constant); aoqi@1: sd(value, data); aoqi@1: } aoqi@1: aoqi@1: aoqi@1: void InterpreterMacroAssembler::increment_mdp_data_at(Register mdp_in, aoqi@1: int constant, aoqi@1: bool decrement) { aoqi@1: // Counter address aoqi@1: Address data(mdp_in, constant); aoqi@1: aoqi@1: increment_mdp_data_at(data, decrement); aoqi@1: } aoqi@1: aoqi@1: void InterpreterMacroAssembler::increment_mdp_data_at(Address data, aoqi@1: bool decrement) { aoqi@1: assert(ProfileInterpreter, "must be profiling interpreter"); aoqi@1: // %%% this does 64bit counters at best it is wasting space aoqi@1: // at worst it is a rare bug when counters overflow aoqi@1: Register tmp = S0; aoqi@1: push(tmp); aoqi@1: if (decrement) { aoqi@1: // Decrement the register. aoqi@1: ld(AT, data); aoqi@1: daddiu(tmp, AT, (int32_t) -DataLayout::counter_increment); aoqi@1: // If the decrement causes the counter to overflow, stay negative aoqi@1: Label L; aoqi@1: slt(AT, tmp, R0); aoqi@1: bne(AT, R0, L); aoqi@1: nop(); aoqi@1: daddi(tmp, tmp, (int32_t) DataLayout::counter_increment); aoqi@1: bind(L); aoqi@1: sd(tmp, data); aoqi@1: } else { aoqi@1: assert(DataLayout::counter_increment == 1, aoqi@1: "flow-free idiom only works with 1"); aoqi@1: ld(AT, data); aoqi@1: // Increment the register. aoqi@1: daddiu(tmp, AT, DataLayout::counter_increment); aoqi@1: // If the increment causes the counter to overflow, pull back by 1. aoqi@1: slt(AT, tmp, R0); aoqi@1: dsubu(tmp, tmp, AT); aoqi@1: sd(tmp, data); aoqi@1: } aoqi@1: pop(tmp); aoqi@1: } aoqi@1: aoqi@1: aoqi@1: void InterpreterMacroAssembler::increment_mdp_data_at(Register mdp_in, aoqi@1: Register reg, aoqi@1: int constant, aoqi@1: bool decrement) { aoqi@1: Register tmp = S0; aoqi@1: push(S0); aoqi@1: if (decrement) { aoqi@1: // Decrement the register. aoqi@1: daddu(AT, mdp_in, reg); aoqi@1: assert(Assembler::is_simm16(constant), "constant is not a simm16 !"); aoqi@1: ld(AT, AT, constant); aoqi@1: aoqi@1: daddiu(tmp, AT, (int32_t) -DataLayout::counter_increment); aoqi@1: // If the decrement causes the counter to overflow, stay negative aoqi@1: Label L; aoqi@1: slt(AT, tmp, R0); aoqi@1: bne(AT, R0, L); aoqi@1: nop(); aoqi@1: daddi(tmp, tmp, (int32_t) DataLayout::counter_increment); aoqi@1: bind(L); aoqi@1: aoqi@1: daddu(AT, mdp_in, reg); aoqi@1: sd(tmp, AT, constant); aoqi@1: } else { aoqi@1: daddu(AT, mdp_in, reg); aoqi@1: assert(Assembler::is_simm16(constant), "constant is not a simm16 !"); aoqi@1: ld(AT, AT, constant); aoqi@1: aoqi@1: // Increment the register. aoqi@1: daddiu(tmp, AT, DataLayout::counter_increment); aoqi@1: // If the increment causes the counter to overflow, pull back by 1. aoqi@1: slt(AT, tmp, R0); aoqi@1: dsubu(tmp, tmp, AT); aoqi@1: aoqi@1: daddu(AT, mdp_in, reg); aoqi@1: sd(tmp, AT, constant); aoqi@1: } aoqi@1: pop(S0); aoqi@1: } aoqi@1: aoqi@1: void InterpreterMacroAssembler::set_mdp_flag_at(Register mdp_in, aoqi@1: int flag_byte_constant) { aoqi@1: assert(ProfileInterpreter, "must be profiling interpreter"); aoqi@1: int header_offset = in_bytes(DataLayout::header_offset()); aoqi@1: int header_bits = DataLayout::flag_mask_to_header_mask(flag_byte_constant); aoqi@1: // Set the flag aoqi@1: lw(AT, Address(mdp_in, header_offset)); aoqi@1: if(Assembler::is_simm16(header_bits)) { aoqi@1: ori(AT, AT, header_bits); aoqi@1: } else { aoqi@1: push(T8); aoqi@1: // T8 is used as a temporary register. aoqi@1: move(T8, header_bits); aoqi@1: orr(AT, AT, T8); aoqi@1: pop(T8); aoqi@1: } aoqi@1: sw(AT, Address(mdp_in, header_offset)); aoqi@1: } aoqi@1: aoqi@1: aoqi@1: aoqi@1: void InterpreterMacroAssembler::test_mdp_data_at(Register mdp_in, aoqi@1: int offset, aoqi@1: Register value, aoqi@1: Register test_value_out, aoqi@1: Label& not_equal_continue) { aoqi@1: assert(ProfileInterpreter, "must be profiling interpreter"); aoqi@1: if (test_value_out == noreg) { aoqi@1: ld(AT, Address(mdp_in, offset)); aoqi@1: bne(AT, value, not_equal_continue); aoqi@1: nop(); aoqi@1: } else { aoqi@1: // Put the test value into a register, so caller can use it: aoqi@1: ld(test_value_out, Address(mdp_in, offset)); aoqi@1: bne(value, test_value_out, not_equal_continue); aoqi@1: nop(); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: aoqi@1: void InterpreterMacroAssembler::update_mdp_by_offset(Register mdp_in, aoqi@1: int offset_of_disp) { aoqi@1: assert(ProfileInterpreter, "must be profiling interpreter"); aoqi@1: assert(Assembler::is_simm16(offset_of_disp), "offset is not an simm16"); aoqi@1: ld(AT, mdp_in, offset_of_disp); aoqi@1: daddu(mdp_in, mdp_in, AT); aoqi@1: sd(mdp_in, Address(FP, frame::interpreter_frame_mdx_offset * wordSize)); aoqi@1: } aoqi@1: aoqi@1: aoqi@1: void InterpreterMacroAssembler::update_mdp_by_offset(Register mdp_in, aoqi@1: Register reg, aoqi@1: int offset_of_disp) { aoqi@1: assert(ProfileInterpreter, "must be profiling interpreter"); aoqi@1: // Attention: Until now (20121217), we do not support this kind of addressing on Loongson. aoqi@1: // Address disp_address(mdp_in, reg, Address::times_1, offset_of_disp); aoqi@1: daddu(AT, reg, mdp_in); aoqi@1: assert(Assembler::is_simm16(offset_of_disp), "offset is not an simm16"); aoqi@1: ld(AT, AT, offset_of_disp); aoqi@1: daddu(mdp_in, mdp_in, AT); aoqi@1: sd(mdp_in, Address(FP, frame::interpreter_frame_mdx_offset * wordSize)); aoqi@1: } aoqi@1: aoqi@1: aoqi@1: void InterpreterMacroAssembler::update_mdp_by_constant(Register mdp_in, aoqi@1: int constant) { aoqi@1: assert(ProfileInterpreter, "must be profiling interpreter"); aoqi@1: if(Assembler::is_simm16(constant)) { aoqi@1: daddiu(mdp_in, mdp_in, constant); aoqi@1: } else { aoqi@1: move(AT, constant); aoqi@1: daddu(mdp_in, mdp_in, AT); aoqi@1: } aoqi@1: sd(mdp_in, Address(FP, frame::interpreter_frame_mdx_offset * wordSize)); aoqi@1: } aoqi@1: aoqi@1: aoqi@1: void InterpreterMacroAssembler::update_mdp_for_ret(Register return_bci) { aoqi@1: assert(ProfileInterpreter, "must be profiling interpreter"); aoqi@1: push(return_bci); // save/restore across call_VM aoqi@1: call_VM(noreg, aoqi@1: CAST_FROM_FN_PTR(address, InterpreterRuntime::update_mdp_for_ret), aoqi@1: return_bci); aoqi@1: pop(return_bci); aoqi@1: } aoqi@1: aoqi@1: aoqi@1: void InterpreterMacroAssembler::profile_taken_branch(Register mdp, aoqi@1: Register bumped_count) { aoqi@1: if (ProfileInterpreter) { aoqi@1: Label profile_continue; aoqi@1: aoqi@1: // If no method data exists, go to profile_continue. aoqi@1: // Otherwise, assign to mdp aoqi@1: test_method_data_pointer(mdp, profile_continue); aoqi@1: aoqi@1: // We are taking a branch. Increment the taken count. aoqi@1: //increment_mdp_data_at(mdp, in_bytes(JumpData::taken_offset())); aoqi@1: // We inline increment_mdp_data_at to return bumped_count in a register aoqi@1: ld(bumped_count, mdp, in_bytes(JumpData::taken_offset())); aoqi@1: assert(DataLayout::counter_increment == 1, aoqi@1: "flow-free idiom only works with 1"); aoqi@1: push(T8); aoqi@1: // T8 is used as a temporary register. aoqi@1: daddiu(T8, bumped_count, DataLayout::counter_increment); aoqi@1: slt(AT, T8, R0); aoqi@1: dsubu(bumped_count, T8, AT); aoqi@1: pop(T8); aoqi@1: sd(bumped_count, mdp, in_bytes(JumpData::taken_offset())); // Store back out aoqi@1: // The method data pointer needs to be updated to reflect the new target. aoqi@1: update_mdp_by_offset(mdp, in_bytes(JumpData::displacement_offset())); aoqi@1: bind(profile_continue); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: aoqi@1: void InterpreterMacroAssembler::profile_not_taken_branch(Register mdp) { aoqi@1: if (ProfileInterpreter) { aoqi@1: Label profile_continue; aoqi@1: aoqi@1: // If no method data exists, go to profile_continue. aoqi@1: test_method_data_pointer(mdp, profile_continue); aoqi@1: aoqi@1: // We are taking a branch. Increment the not taken count. aoqi@1: increment_mdp_data_at(mdp, in_bytes(BranchData::not_taken_offset())); aoqi@1: aoqi@1: // The method data pointer needs to be updated to correspond to aoqi@1: // the next bytecode aoqi@1: update_mdp_by_constant(mdp, in_bytes(BranchData::branch_data_size())); aoqi@1: bind(profile_continue); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: aoqi@1: void InterpreterMacroAssembler::profile_call(Register mdp) { aoqi@1: if (ProfileInterpreter) { aoqi@1: Label profile_continue; aoqi@1: aoqi@1: // If no method data exists, go to profile_continue. aoqi@1: test_method_data_pointer(mdp, profile_continue); aoqi@1: aoqi@1: // We are making a call. Increment the count. aoqi@1: increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); aoqi@1: aoqi@1: // The method data pointer needs to be updated to reflect the new target. aoqi@1: update_mdp_by_constant(mdp, in_bytes(CounterData::counter_data_size())); aoqi@1: bind(profile_continue); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: aoqi@1: void InterpreterMacroAssembler::profile_final_call(Register mdp) { aoqi@1: if (ProfileInterpreter) { aoqi@1: Label profile_continue; aoqi@1: aoqi@1: // If no method data exists, go to profile_continue. aoqi@1: test_method_data_pointer(mdp, profile_continue); aoqi@1: // We are making a call. Increment the count. aoqi@1: increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); aoqi@1: aoqi@1: // The method data pointer needs to be updated to reflect the new target. aoqi@1: update_mdp_by_constant(mdp, in_bytes(VirtualCallData:: virtual_call_data_size())); aoqi@1: bind(profile_continue); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: aoqi@1: void InterpreterMacroAssembler::profile_virtual_call(Register receiver, aoqi@1: Register mdp, aoqi@1: Register reg2, aoqi@1: bool receiver_can_be_null) { aoqi@1: if (ProfileInterpreter) { aoqi@1: Label profile_continue; aoqi@1: aoqi@1: // If no method data exists, go to profile_continue. aoqi@1: test_method_data_pointer(mdp, profile_continue); aoqi@1: aoqi@1: Label skip_receiver_profile; aoqi@1: if (receiver_can_be_null) { aoqi@1: Label not_null; aoqi@1: bne(receiver, R0, not_null); aoqi@1: nop(); aoqi@1: // We are making a call. Increment the count. aoqi@1: increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); aoqi@1: beq(R0, R0, skip_receiver_profile); aoqi@1: nop(); aoqi@1: bind(not_null); aoqi@1: } aoqi@1: aoqi@1: // Record the receiver type. aoqi@1: record_klass_in_profile(receiver, mdp, reg2, true); aoqi@1: bind(skip_receiver_profile); aoqi@1: aoqi@1: // The method data pointer needs to be updated to reflect the new target. aoqi@1: update_mdp_by_constant(mdp, in_bytes(VirtualCallData::virtual_call_data_size())); aoqi@1: bind(profile_continue); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: void InterpreterMacroAssembler::profile_checkcast(bool is_null, Register mdp) { aoqi@1: // In x86, this method does not exist. aoqi@1: #ifndef CORE aoqi@1: if (ProfileInterpreter) { aoqi@1: Label profile_continue; aoqi@1: aoqi@1: // If no method data exists, go to profile_continue. aoqi@1: test_method_data_pointer(mdp, profile_continue); aoqi@1: aoqi@1: if (is_null) // Set the flag to true. aoqi@1: set_mdp_flag_at(mdp, BitData::null_seen_byte_constant()); aoqi@1: //set_mdp_flag_at(mdp, BitData::null_flag_constant()); aoqi@1: aoqi@1: // The method data pointer needs to be updated. aoqi@1: update_mdp_by_constant(mdp, in_bytes(BitData::bit_data_size())); aoqi@1: aoqi@1: bind (profile_continue); aoqi@1: } aoqi@1: #endif // !CORE aoqi@1: } aoqi@1: aoqi@1: // This routine creates a state machine for updating the multi-row aoqi@1: // type profile at a virtual call site (or other type-sensitive bytecode). aoqi@1: // The machine visits each row (of receiver/count) until the receiver type aoqi@1: // is found, or until it runs out of rows. At the same time, it remembers aoqi@1: // the location of the first empty row. (An empty row records null for its aoqi@1: // receiver, and can be allocated for a newly-observed receiver type.) aoqi@1: // Because there are two degrees of freedom in the state, a simple linear aoqi@1: // search will not work; it must be a decision tree. Hence this helper aoqi@1: // function is recursive, to generate the required tree structured code. aoqi@1: // It's the interpreter, so we are trading off code space for speed. aoqi@1: // See below for example code. aoqi@1: void InterpreterMacroAssembler::record_klass_in_profile_helper( aoqi@1: Register receiver, Register mdp, aoqi@1: Register reg2, aoqi@1: int start_row, Label& done, bool is_virtual_call) { aoqi@1: if (TypeProfileWidth == 0) { aoqi@1: if (is_virtual_call) { aoqi@1: increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); aoqi@1: } aoqi@1: return; aoqi@1: } aoqi@1: aoqi@1: int last_row = VirtualCallData::row_limit() - 1; aoqi@1: assert(start_row <= last_row, "must be work left to do"); aoqi@1: // Test this row for both the receiver and for null. aoqi@1: // Take any of three different outcomes: aoqi@1: // 1. found receiver => increment count and goto done aoqi@1: // 2. found null => keep looking for case 1, maybe allocate this cell aoqi@1: // 3. found something else => keep looking for cases 1 and 2 aoqi@1: // Case 3 is handled by a recursive call. aoqi@1: for (int row = start_row; row <= last_row; row++) { aoqi@1: Label next_test; aoqi@1: bool test_for_null_also = (row == start_row); aoqi@1: aoqi@1: // See if the receiver is receiver[n]. aoqi@1: int recvr_offset = in_bytes(VirtualCallData::receiver_offset(row)); aoqi@1: test_mdp_data_at(mdp, recvr_offset, receiver, aoqi@1: (test_for_null_also ? reg2 : noreg), aoqi@1: next_test); aoqi@1: // (Reg2 now contains the receiver from the CallData.) aoqi@1: aoqi@1: // The receiver is receiver[n]. Increment count[n]. aoqi@1: int count_offset = in_bytes(VirtualCallData::receiver_count_offset(row)); aoqi@1: increment_mdp_data_at(mdp, count_offset); aoqi@1: beq(R0, R0, done); aoqi@1: nop(); aoqi@1: bind(next_test); aoqi@1: aoqi@1: if (test_for_null_also) { aoqi@1: Label found_null; aoqi@1: // Failed the equality check on receiver[n]... Test for null. aoqi@1: if (start_row == last_row) { aoqi@1: // The only thing left to do is handle the null case. aoqi@1: if (is_virtual_call) { aoqi@1: beq(reg2, R0, found_null); aoqi@1: nop(); aoqi@1: // Receiver did not match any saved receiver and there is no empty row for it. aoqi@1: // Increment total counter to indicate polymorphic case. aoqi@1: increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); aoqi@1: beq(R0, R0, done); aoqi@1: nop(); aoqi@1: bind(found_null); aoqi@1: } else { aoqi@1: bne(reg2, R0, done); aoqi@1: nop(); aoqi@1: } aoqi@1: break; aoqi@1: } aoqi@1: // Since null is rare, make it be the branch-taken case. aoqi@1: beq(reg2, R0, found_null); aoqi@1: nop(); aoqi@1: aoqi@1: // Put all the "Case 3" tests here. aoqi@1: record_klass_in_profile_helper(receiver, mdp, reg2, start_row + 1, done, is_virtual_call); aoqi@1: aoqi@1: // Found a null. Keep searching for a matching receiver, aoqi@1: // but remember that this is an empty (unused) slot. aoqi@1: bind(found_null); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: // In the fall-through case, we found no matching receiver, but we aoqi@1: // observed the receiver[start_row] is NULL. aoqi@1: aoqi@1: // Fill in the receiver field and increment the count. aoqi@1: int recvr_offset = in_bytes(VirtualCallData::receiver_offset(start_row)); aoqi@1: set_mdp_data_at(mdp, recvr_offset, receiver); aoqi@1: int count_offset = in_bytes(VirtualCallData::receiver_count_offset(start_row)); aoqi@1: move(reg2, DataLayout::counter_increment); aoqi@1: set_mdp_data_at(mdp, count_offset, reg2); aoqi@1: if (start_row > 0) { aoqi@1: beq(R0, R0, done); aoqi@1: nop(); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: // Example state machine code for three profile rows: aoqi@1: // // main copy of decision tree, rooted at row[1] aoqi@1: // if (row[0].rec == rec) { row[0].incr(); goto done; } aoqi@1: // if (row[0].rec != NULL) { aoqi@1: // // inner copy of decision tree, rooted at row[1] aoqi@1: // if (row[1].rec == rec) { row[1].incr(); goto done; } aoqi@1: // if (row[1].rec != NULL) { aoqi@1: // // degenerate decision tree, rooted at row[2] aoqi@1: // if (row[2].rec == rec) { row[2].incr(); goto done; } aoqi@1: // if (row[2].rec != NULL) { goto done; } // overflow aoqi@1: // row[2].init(rec); goto done; aoqi@1: // } else { aoqi@1: // // remember row[1] is empty aoqi@1: // if (row[2].rec == rec) { row[2].incr(); goto done; } aoqi@1: // row[1].init(rec); goto done; aoqi@1: // } aoqi@1: // } else { aoqi@1: // // remember row[0] is empty aoqi@1: // if (row[1].rec == rec) { row[1].incr(); goto done; } aoqi@1: // if (row[2].rec == rec) { row[2].incr(); goto done; } aoqi@1: // row[0].init(rec); goto done; aoqi@1: // } aoqi@1: aoqi@1: void InterpreterMacroAssembler::record_klass_in_profile(Register receiver, aoqi@1: Register mdp, aoqi@1: Register reg2, bool is_virtual_call) { aoqi@1: assert(ProfileInterpreter, "must be profiling"); aoqi@1: Label done; aoqi@1: aoqi@1: record_klass_in_profile_helper(receiver, mdp, reg2, 0, done, is_virtual_call); aoqi@1: aoqi@1: bind (done); aoqi@1: } aoqi@1: aoqi@1: void InterpreterMacroAssembler::profile_ret(Register return_bci, aoqi@1: Register mdp) { aoqi@1: if (ProfileInterpreter) { aoqi@1: Label profile_continue; aoqi@1: uint row; aoqi@1: aoqi@1: // If no method data exists, go to profile_continue. aoqi@1: test_method_data_pointer(mdp, profile_continue); aoqi@1: aoqi@1: // Update the total ret count. aoqi@1: increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); aoqi@1: aoqi@1: for (row = 0; row < RetData::row_limit(); row++) { aoqi@1: Label next_test; aoqi@1: aoqi@1: // See if return_bci is equal to bci[n]: aoqi@1: test_mdp_data_at(mdp, aoqi@1: in_bytes(RetData::bci_offset(row)), aoqi@1: return_bci, noreg, aoqi@1: next_test); aoqi@1: aoqi@1: // return_bci is equal to bci[n]. Increment the count. aoqi@1: increment_mdp_data_at(mdp, in_bytes(RetData::bci_count_offset(row))); aoqi@1: aoqi@1: // The method data pointer needs to be updated to reflect the new target. aoqi@1: update_mdp_by_offset(mdp, aoqi@1: in_bytes(RetData::bci_displacement_offset(row))); aoqi@1: beq(R0, R0, profile_continue); aoqi@1: nop(); aoqi@1: bind(next_test); aoqi@1: } aoqi@1: aoqi@1: update_mdp_for_ret(return_bci); aoqi@1: aoqi@1: bind(profile_continue); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: aoqi@1: void InterpreterMacroAssembler::profile_null_seen(Register mdp) { aoqi@1: if (ProfileInterpreter) { aoqi@1: Label profile_continue; aoqi@1: aoqi@1: // If no method data exists, go to profile_continue. aoqi@1: test_method_data_pointer(mdp, profile_continue); aoqi@1: aoqi@1: set_mdp_flag_at(mdp, BitData::null_seen_byte_constant()); aoqi@1: aoqi@1: // The method data pointer needs to be updated. aoqi@1: int mdp_delta = in_bytes(BitData::bit_data_size()); aoqi@1: if (TypeProfileCasts) { aoqi@1: mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size()); aoqi@1: } aoqi@1: update_mdp_by_constant(mdp, mdp_delta); aoqi@1: aoqi@1: bind(profile_continue); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: aoqi@1: void InterpreterMacroAssembler::profile_typecheck_failed(Register mdp) { aoqi@1: if (ProfileInterpreter && TypeProfileCasts) { aoqi@1: Label profile_continue; aoqi@1: aoqi@1: // If no method data exists, go to profile_continue. aoqi@1: test_method_data_pointer(mdp, profile_continue); aoqi@1: aoqi@1: int count_offset = in_bytes(CounterData::count_offset()); aoqi@1: // Back up the address, since we have already bumped the mdp. aoqi@1: count_offset -= in_bytes(VirtualCallData::virtual_call_data_size()); aoqi@1: aoqi@1: // *Decrement* the counter. We expect to see zero or small negatives. aoqi@1: increment_mdp_data_at(mdp, count_offset, true); aoqi@1: aoqi@1: bind (profile_continue); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: aoqi@1: void InterpreterMacroAssembler::profile_typecheck(Register mdp, Register klass, Register reg2) { aoqi@1: if (ProfileInterpreter) { aoqi@1: Label profile_continue; aoqi@1: aoqi@1: // If no method data exists, go to profile_continue. aoqi@1: test_method_data_pointer(mdp, profile_continue); aoqi@1: aoqi@1: // The method data pointer needs to be updated. aoqi@1: int mdp_delta = in_bytes(BitData::bit_data_size()); aoqi@1: if (TypeProfileCasts) { aoqi@1: aoqi@1: mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size()); aoqi@1: aoqi@1: // Record the object type. aoqi@1: record_klass_in_profile(klass, mdp, reg2, false); aoqi@1: } aoqi@1: update_mdp_by_constant(mdp, mdp_delta); aoqi@1: aoqi@1: bind(profile_continue); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: aoqi@1: void InterpreterMacroAssembler::profile_switch_default(Register mdp) { aoqi@1: if (ProfileInterpreter) { aoqi@1: Label profile_continue; aoqi@1: aoqi@1: // If no method data exists, go to profile_continue. aoqi@1: test_method_data_pointer(mdp, profile_continue); aoqi@1: aoqi@1: // Update the default case count aoqi@1: increment_mdp_data_at(mdp, in_bytes(MultiBranchData::default_count_offset())); aoqi@1: aoqi@1: // The method data pointer needs to be updated. aoqi@1: update_mdp_by_offset(mdp, in_bytes(MultiBranchData:: default_displacement_offset())); aoqi@1: aoqi@1: bind(profile_continue); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: aoqi@1: void InterpreterMacroAssembler::profile_switch_case(Register index, aoqi@1: Register mdp, aoqi@1: Register reg2) { aoqi@1: if (ProfileInterpreter) { aoqi@1: Label profile_continue; aoqi@1: aoqi@1: // If no method data exists, go to profile_continue. aoqi@1: test_method_data_pointer(mdp, profile_continue); aoqi@1: aoqi@1: // Build the base (index * per_case_size_in_bytes()) + case_array_offset_in_bytes() aoqi@1: move(reg2, in_bytes(MultiBranchData::per_case_size())); aoqi@1: dmult(index, reg2); aoqi@1: mflo(index); aoqi@1: // addptr(index, in_bytes(MultiBranchData::case_array_offset())); // XXX l ? aoqi@1: daddiu(index, index, in_bytes(MultiBranchData::case_array_offset())); aoqi@1: aoqi@1: // Update the case count aoqi@1: increment_mdp_data_at(mdp, index, in_bytes(MultiBranchData::relative_count_offset())); aoqi@1: aoqi@1: // The method data pointer needs to be updated. aoqi@1: update_mdp_by_offset(mdp, index, in_bytes(MultiBranchData:: relative_displacement_offset())); aoqi@1: aoqi@1: bind(profile_continue); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr) { aoqi@1: Label update, next, none; aoqi@1: aoqi@1: verify_oop(obj); aoqi@1: aoqi@1: //testptr(obj, obj); aoqi@1: //jccb(Assembler::notZero, update); aoqi@1: bne(obj, R0, update); aoqi@1: nop(); aoqi@1: aoqi@1: //orptr(mdo_addr, TypeEntries::null_seen); aoqi@1: push(T1); aoqi@1: if (mdo_addr.index() == noreg) { aoqi@1: ld(T1, mdo_addr); aoqi@1: } else { aoqi@1: guarantee(T1 != mdo_addr.base(), "The base register will be corrupted !"); aoqi@1: guarantee(T1 != mdo_addr.index(), "The index register will be corrupted !"); aoqi@1: aoqi@1: dsll(AT, mdo_addr.index(), mdo_addr.scale()); aoqi@1: daddu(AT, AT, mdo_addr.base()); aoqi@1: ld(T1, AT, mdo_addr.disp()); aoqi@1: } aoqi@1: li(AT, TypeEntries::null_seen); aoqi@1: orr(AT, T1, AT); aoqi@1: if (mdo_addr.index() == noreg) { aoqi@1: sd(AT, mdo_addr); aoqi@1: } else { aoqi@1: guarantee(T1 != mdo_addr.base(), "The base register will be corrupted !"); aoqi@1: guarantee(T1 != mdo_addr.index(), "The index register will be corrupted !"); aoqi@1: aoqi@1: dsll(T1, mdo_addr.index(), mdo_addr.scale()); aoqi@1: daddu(T1, T1, mdo_addr.base()); aoqi@1: sd(AT, T1, mdo_addr.disp()); aoqi@1: } aoqi@1: pop(T1); aoqi@1: aoqi@1: //jmpb(next); aoqi@1: beq(R0, R0, next); aoqi@1: nop(); aoqi@1: aoqi@1: bind(update); aoqi@1: load_klass(obj, obj); aoqi@1: aoqi@1: //xorptr(obj, mdo_addr); aoqi@1: if (mdo_addr.index() == noreg) { aoqi@1: ld(AT, mdo_addr); aoqi@1: } else { aoqi@1: dsll(AT, mdo_addr.index(), mdo_addr.scale()); aoqi@1: daddu(AT, AT, mdo_addr.base()); aoqi@1: ld(AT, AT, mdo_addr.disp()); aoqi@1: } aoqi@1: xorr(obj, obj, AT); aoqi@1: aoqi@1: //testptr(obj, TypeEntries::type_klass_mask); aoqi@1: //jccb(Assembler::zero, next); // klass seen before, nothing to aoqi@1: // do. The unknown bit may have been aoqi@1: // set already but no need to check. aoqi@1: li(AT, TypeEntries::type_klass_mask); aoqi@1: andr(AT, obj, AT); aoqi@1: beq(AT, R0, next); aoqi@1: nop(); aoqi@1: aoqi@1: //testptr(obj, TypeEntries::type_unknown); aoqi@1: //jccb(Assembler::notZero, next); // already unknown. Nothing to do anymore. aoqi@1: li(AT, TypeEntries::type_unknown); aoqi@1: andr(AT, AT, obj); aoqi@1: bne(AT, R0, next); aoqi@1: nop(); aoqi@1: aoqi@1: //cmpptr(mdo_addr, 0); aoqi@1: //jccb(Assembler::equal, none); aoqi@1: if (mdo_addr.index() == noreg) { aoqi@1: ld(AT, mdo_addr); aoqi@1: } else { aoqi@1: dsll(AT, mdo_addr.index(), mdo_addr.scale()); aoqi@1: daddu(AT, AT, mdo_addr.base()); aoqi@1: ld(AT, AT, mdo_addr.disp()); aoqi@1: } aoqi@1: beq(AT, R0, none); aoqi@1: nop(); aoqi@1: aoqi@1: aoqi@1: //cmpptr(mdo_addr, TypeEntries::null_seen); aoqi@1: //jccb(Assembler::equal, none); aoqi@1: push(T1); aoqi@1: if (mdo_addr.index() == noreg) { aoqi@1: ld(T1, mdo_addr); aoqi@1: } else { aoqi@1: guarantee(T1 != mdo_addr.base(), "The base register will be corrupted !"); aoqi@1: guarantee(T1 != mdo_addr.index(), "The index register will be corrupted !"); aoqi@1: aoqi@1: dsll(AT, mdo_addr.index(), mdo_addr.scale()); aoqi@1: daddu(AT, AT, mdo_addr.base()); aoqi@1: ld(T1, AT, mdo_addr.disp()); aoqi@1: } aoqi@1: li(AT, TypeEntries::null_seen); aoqi@1: subu(AT, AT, T1); aoqi@1: pop(T1); aoqi@1: beq(AT, R0, none); aoqi@1: nop(); aoqi@1: aoqi@1: // There is a chance that the checks above (re-reading profiling aoqi@1: // data from memory) fail if another thread has just set the aoqi@1: // profiling to this obj's klass aoqi@1: //xorptr(obj, mdo_addr); aoqi@1: //testptr(obj, TypeEntries::type_klass_mask); aoqi@1: //jccb(Assembler::zero, next); aoqi@1: if (mdo_addr.index() == noreg) { aoqi@1: ld(AT, mdo_addr); aoqi@1: } else { aoqi@1: dsll(AT, mdo_addr.index(), mdo_addr.scale()); aoqi@1: daddu(AT, AT, mdo_addr.base()); aoqi@1: ld(AT, AT, mdo_addr.disp()); aoqi@1: } aoqi@1: xorr(obj, obj, AT); aoqi@1: li(AT, TypeEntries::type_klass_mask); aoqi@1: andr(AT, obj, AT); aoqi@1: beq(AT, R0, next); aoqi@1: nop(); aoqi@1: aoqi@1: // different than before. Cannot keep accurate profile. aoqi@1: //orptr(mdo_addr, TypeEntries::type_unknown); aoqi@1: //jmpb(next); aoqi@1: push(T1); aoqi@1: if (mdo_addr.index() == noreg) { aoqi@1: ld(T1, mdo_addr); aoqi@1: } else { aoqi@1: guarantee(T1 != mdo_addr.base(), "The base register will be corrupted !"); aoqi@1: guarantee(T1 != mdo_addr.index(), "The index register will be corrupted !"); aoqi@1: aoqi@1: dsll(AT, mdo_addr.index(), mdo_addr.scale()); aoqi@1: daddu(AT, AT, mdo_addr.base()); aoqi@1: ld(T1, AT, mdo_addr.disp()); aoqi@1: } aoqi@1: li(AT, TypeEntries::type_unknown); aoqi@1: orr(AT, T1, AT); aoqi@1: if (mdo_addr.index() == noreg) { aoqi@1: sd(AT, mdo_addr); aoqi@1: } else { aoqi@1: guarantee(T1 != mdo_addr.base(), "The base register will be corrupted !"); aoqi@1: guarantee(T1 != mdo_addr.index(), "The index register will be corrupted !"); aoqi@1: aoqi@1: dsll(T1, mdo_addr.index(), mdo_addr.scale()); aoqi@1: daddu(T1, T1, mdo_addr.base()); aoqi@1: sd(AT, T1, mdo_addr.disp()); aoqi@1: } aoqi@1: pop(T1); aoqi@1: beq(R0, R0, next); aoqi@1: nop(); aoqi@1: aoqi@1: aoqi@1: bind(none); aoqi@1: // first time here. Set profile type. aoqi@1: //movptr(mdo_addr, obj); aoqi@1: if (mdo_addr.index() == noreg) { aoqi@1: sd(obj, mdo_addr); aoqi@1: } else { aoqi@1: dsll(AT, mdo_addr.index(), mdo_addr.scale()); aoqi@1: daddu(AT, AT, mdo_addr.base()); aoqi@1: sd(obj, AT, mdo_addr.disp()); aoqi@1: } aoqi@1: aoqi@1: bind(next); aoqi@1: } aoqi@1: aoqi@1: void InterpreterMacroAssembler::profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual) { aoqi@1: if (!ProfileInterpreter) { aoqi@1: return; aoqi@1: } aoqi@1: aoqi@1: if (MethodData::profile_arguments() || MethodData::profile_return()) { aoqi@1: Label profile_continue; aoqi@1: aoqi@1: test_method_data_pointer(mdp, profile_continue); aoqi@1: aoqi@1: int off_to_start = is_virtual ? in_bytes(VirtualCallData::virtual_call_data_size()) : in_bytes(CounterData::counter_data_size()); aoqi@1: aoqi@1: //cmpb(Address(mdp, in_bytes(DataLayout::tag_offset()) - off_to_start), is_virtual ? DataLayout::virtual_call_type_data_tag : DataLayout::call_type_data_tag); aoqi@1: //jcc(Assembler::notEqual, profile_continue); aoqi@1: lb(AT, mdp, in_bytes(DataLayout::tag_offset()) - off_to_start); aoqi@1: li(tmp, is_virtual ? DataLayout::virtual_call_type_data_tag : DataLayout::call_type_data_tag); aoqi@1: bne(tmp, AT, profile_continue); aoqi@1: nop(); aoqi@1: aoqi@1: aoqi@1: if (MethodData::profile_arguments()) { aoqi@1: Label done; aoqi@1: int off_to_args = in_bytes(TypeEntriesAtCall::args_data_offset()); aoqi@1: //addptr(mdp, off_to_args); aoqi@1: if (Assembler::is_simm16(off_to_args)) { aoqi@1: daddiu(mdp, mdp, off_to_args); aoqi@1: } else { aoqi@1: move(AT, off_to_args); aoqi@1: daddu(mdp, mdp, AT); aoqi@1: } aoqi@1: aoqi@1: aoqi@1: for (int i = 0; i < TypeProfileArgsLimit; i++) { aoqi@1: if (i > 0 || MethodData::profile_return()) { aoqi@1: // If return value type is profiled we may have no argument to profile aoqi@1: //movptr(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args)); aoqi@1: ld(tmp, mdp, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args); aoqi@1: aoqi@1: //subl(tmp, i*TypeStackSlotEntries::per_arg_count()); aoqi@1: if (Assembler::is_simm16(-1 * i * TypeStackSlotEntries::per_arg_count())) { aoqi@1: addiu32(tmp, tmp, -1 * i * TypeStackSlotEntries::per_arg_count()); aoqi@1: } else { aoqi@1: li(AT, i*TypeStackSlotEntries::per_arg_count()); aoqi@1: subu32(tmp, tmp, AT); aoqi@1: } aoqi@1: aoqi@1: //cmpl(tmp, TypeStackSlotEntries::per_arg_count()); aoqi@1: //jcc(Assembler::less, done); aoqi@1: li(AT, TypeStackSlotEntries::per_arg_count()); aoqi@1: slt(AT, tmp, AT); aoqi@1: bne(AT, R0, done); aoqi@1: nop(); aoqi@1: } aoqi@1: //movptr(tmp, Address(callee, Method::const_offset())); aoqi@1: ld(tmp, callee, in_bytes(Method::const_offset())); aoqi@1: aoqi@1: //load_unsigned_short(tmp, Address(tmp, ConstMethod::size_of_parameters_offset())); aoqi@1: lhu(tmp, tmp, in_bytes(ConstMethod::size_of_parameters_offset())); aoqi@1: aoqi@1: // stack offset o (zero based) from the start of the argument aoqi@1: // list, for n arguments translates into offset n - o - 1 from aoqi@1: // the end of the argument list aoqi@1: //subptr(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::stack_slot_offset(i))-off_to_args)); aoqi@1: ld(AT, mdp, in_bytes(TypeEntriesAtCall::stack_slot_offset(i))-off_to_args); aoqi@1: subu(tmp, tmp, AT); aoqi@1: aoqi@1: //subl(tmp, 1); aoqi@1: addiu32(tmp, tmp, -1); aoqi@1: aoqi@1: Address arg_addr = argument_address(tmp); aoqi@1: //movptr(tmp, arg_addr); aoqi@1: ld(tmp, arg_addr); aoqi@1: aoqi@1: Address mdo_arg_addr(mdp, in_bytes(TypeEntriesAtCall::argument_type_offset(i))-off_to_args); aoqi@1: profile_obj_type(tmp, mdo_arg_addr); aoqi@1: aoqi@1: int to_add = in_bytes(TypeStackSlotEntries::per_arg_size()); aoqi@1: //addptr(mdp, to_add); aoqi@1: if (Assembler::is_simm16(to_add)) { aoqi@1: daddiu(mdp, mdp, to_add); aoqi@1: } else { aoqi@1: move(AT, to_add); aoqi@1: daddu(mdp, mdp, AT); aoqi@1: } aoqi@1: aoqi@1: off_to_args += to_add; aoqi@1: } aoqi@1: aoqi@1: if (MethodData::profile_return()) { aoqi@1: //movptr(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args)); aoqi@1: ld(tmp, mdp, in_bytes(TypeEntriesAtCall::cell_count_offset())-off_to_args); aoqi@1: aoqi@1: //subl(tmp, TypeProfileArgsLimit*TypeStackSlotEntries::per_arg_count()); aoqi@1: int tmp_arg_counts = TypeProfileArgsLimit*TypeStackSlotEntries::per_arg_count(); aoqi@1: if (Assembler::is_simm16(-1 * tmp_arg_counts)) { aoqi@1: addiu32(tmp, tmp, -1 * tmp_arg_counts); aoqi@1: } else { aoqi@1: move(AT, tmp_arg_counts); aoqi@1: subu32(mdp, mdp, AT); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: bind(done); aoqi@1: aoqi@1: if (MethodData::profile_return()) { aoqi@1: // We're right after the type profile for the last aoqi@1: // argument. tmp is the number of cells left in the aoqi@1: // CallTypeData/VirtualCallTypeData to reach its end. Non null aoqi@1: // if there's a return to profile. aoqi@1: assert(ReturnTypeEntry::static_cell_count() < TypeStackSlotEntries::per_arg_count(), "can't move past ret type"); aoqi@1: //shll(tmp, exact_log2(DataLayout::cell_size)); aoqi@1: //addptr(mdp, tmp); aoqi@1: sll(tmp, tmp, exact_log2(DataLayout::cell_size)); aoqi@1: daddu(mdp, mdp, tmp); aoqi@1: } aoqi@1: //movptr(Address(rbp, frame::interpreter_frame_mdx_offset * wordSize), mdp); aoqi@1: sd(mdp, FP, frame::interpreter_frame_mdx_offset * wordSize); aoqi@1: } else { aoqi@1: assert(MethodData::profile_return(), "either profile call args or call ret"); aoqi@1: update_mdp_by_constant(mdp, in_bytes(TypeEntriesAtCall::return_only_size())); aoqi@1: } aoqi@1: aoqi@1: // mdp points right after the end of the aoqi@1: // CallTypeData/VirtualCallTypeData, right after the cells for the aoqi@1: // return value type if there's one aoqi@1: aoqi@1: bind(profile_continue); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: void InterpreterMacroAssembler::profile_return_type(Register mdp, Register ret, Register tmp) { aoqi@1: assert_different_registers(mdp, ret, tmp, _bcp_register); aoqi@1: if (ProfileInterpreter && MethodData::profile_return()) { aoqi@1: Label profile_continue, done; aoqi@1: aoqi@1: test_method_data_pointer(mdp, profile_continue); aoqi@1: aoqi@1: if (MethodData::profile_return_jsr292_only()) { aoqi@1: // If we don't profile all invoke bytecodes we must make sure aoqi@1: // it's a bytecode we indeed profile. We can't go back to the aoqi@1: // begining of the ProfileData we intend to update to check its aoqi@1: // type because we're right after it and we don't known its aoqi@1: // length aoqi@1: Label do_profile; aoqi@1: //cmpb(Address(_bcp_register, 0), Bytecodes::_invokedynamic); aoqi@1: //jcc(Assembler::equal, do_profile); aoqi@1: lb(AT, _bcp_register, 0); aoqi@1: daddiu(AT, AT, -1 * Bytecodes::_invokedynamic); aoqi@1: beq(AT, R0, do_profile); aoqi@1: nop(); aoqi@1: aoqi@1: //cmpb(Address(_bcp_register, 0), Bytecodes::_invokehandle); aoqi@1: //jcc(Assembler::equal, do_profile); aoqi@1: lb(AT, _bcp_register, 0); aoqi@1: daddiu(AT, AT, -1 * Bytecodes::_invokehandle); aoqi@1: beq(AT, R0, do_profile); aoqi@1: nop(); aoqi@1: aoqi@1: get_method(tmp); aoqi@1: //cmpb(Address(tmp, Method::intrinsic_id_offset_in_bytes()), vmIntrinsics::_compiledLambdaForm); aoqi@1: //jcc(Assembler::notEqual, profile_continue); aoqi@1: lb(tmp, tmp, Method::intrinsic_id_offset_in_bytes()); aoqi@1: li(AT, vmIntrinsics::_compiledLambdaForm); aoqi@1: bne(tmp, AT, profile_continue); aoqi@1: nop(); aoqi@1: aoqi@1: bind(do_profile); aoqi@1: } aoqi@1: aoqi@1: Address mdo_ret_addr(mdp, -in_bytes(ReturnTypeEntry::size())); aoqi@1: //mov(tmp, ret); aoqi@1: daddu(tmp, ret, R0); aoqi@1: profile_obj_type(tmp, mdo_ret_addr); aoqi@1: aoqi@1: bind(profile_continue); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: void InterpreterMacroAssembler::profile_parameters_type(Register mdp, Register tmp1, Register tmp2) { aoqi@1: guarantee(T9 == tmp1, "You are reqired to use T9 as the index register for MIPS !"); aoqi@1: aoqi@1: if (ProfileInterpreter && MethodData::profile_parameters()) { aoqi@1: Label profile_continue, done; aoqi@1: aoqi@1: test_method_data_pointer(mdp, profile_continue); aoqi@1: aoqi@1: // Load the offset of the area within the MDO used for aoqi@1: // parameters. If it's negative we're not profiling any parameters aoqi@1: //movl(tmp1, Address(mdp, in_bytes(MethodData::parameters_type_data_di_offset()) - in_bytes(MethodData::data_offset()))); aoqi@1: //testl(tmp1, tmp1); aoqi@1: //jcc(Assembler::negative, profile_continue); aoqi@1: lw(tmp1, mdp, in_bytes(MethodData::parameters_type_data_di_offset()) - in_bytes(MethodData::data_offset())); aoqi@1: bltz(tmp1, profile_continue); aoqi@1: nop(); aoqi@1: aoqi@1: // Compute a pointer to the area for parameters from the offset aoqi@1: // and move the pointer to the slot for the last aoqi@1: // parameters. Collect profiling from last parameter down. aoqi@1: // mdo start + parameters offset + array length - 1 aoqi@1: //addptr(mdp, tmp1); aoqi@1: //movptr(tmp1, Address(mdp, ArrayData::array_len_offset())); aoqi@1: daddu(mdp, mdp, tmp1); aoqi@1: ld(tmp1, mdp, in_bytes(ArrayData::array_len_offset())); aoqi@1: decrement(tmp1, TypeStackSlotEntries::per_arg_count()); aoqi@1: aoqi@1: aoqi@1: Label loop; aoqi@1: bind(loop); aoqi@1: aoqi@1: int off_base = in_bytes(ParametersTypeData::stack_slot_offset(0)); aoqi@1: int type_base = in_bytes(ParametersTypeData::type_offset(0)); aoqi@1: Address::ScaleFactor per_arg_scale = Address::times(DataLayout::cell_size); aoqi@1: //Address arg_off(mdp, tmp1, per_arg_scale, off_base); aoqi@1: Address arg_type(mdp, tmp1, per_arg_scale, type_base); aoqi@1: aoqi@1: // load offset on the stack from the slot for this parameter aoqi@1: //movptr(tmp2, arg_off); aoqi@1: dsll(AT, tmp1, per_arg_scale); aoqi@1: daddu(AT, AT, mdp); aoqi@1: ld(tmp2, AT, off_base); aoqi@1: aoqi@1: //negptr(tmp2); aoqi@1: subu(tmp2, R0, tmp2); aoqi@1: aoqi@1: // read the parameter from the local area aoqi@1: //movptr(tmp2, Address(_locals_register, tmp2, Interpreter::stackElementScale())); aoqi@1: dsll(AT, tmp2, Interpreter::stackElementScale()); aoqi@1: daddu(AT, AT, _locals_register); aoqi@1: ld(tmp2, AT, 0); aoqi@1: aoqi@1: // profile the parameter aoqi@1: profile_obj_type(tmp2, arg_type); aoqi@1: aoqi@1: // go to next parameter aoqi@1: decrement(tmp1, TypeStackSlotEntries::per_arg_count()); aoqi@1: //jcc(Assembler::positive, loop); aoqi@1: bgtz(tmp1, loop); aoqi@1: nop(); aoqi@1: aoqi@1: bind(profile_continue); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: void InterpreterMacroAssembler::verify_oop(Register reg, TosState state) { aoqi@1: if (state == atos) { aoqi@1: MacroAssembler::verify_oop(reg); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: void InterpreterMacroAssembler::verify_FPU(int stack_depth, TosState state) { aoqi@1: // only if +VerifyFPU && (state == ftos || state == dtos) aoqi@1: // For now, do nothing. aoqi@1: } aoqi@1: #endif // !CC_INTERP aoqi@1: aoqi@1: aoqi@1: //FIXME, aoqi:see UltraViolet aoqi@1: void InterpreterMacroAssembler::notify_method_entry() { aoqi@1: // Whenever JVMTI is interp_only_mode, method entry/exit events are sent to aoqi@1: // track stack depth. If it is possible to enter interp_only_mode we add aoqi@1: // the code to check if the event should be sent. aoqi@1: //Register tempreg = Rscratch0; aoqi@1: Register tempreg = T0; aoqi@1: if (JvmtiExport::can_post_interpreter_events()) { aoqi@1: Label L; aoqi@1: //movl(rdx, Address(r15_thread, JavaThread::interp_only_mode_offset())); aoqi@1: //testl(rdx, rdx); aoqi@1: //jcc(Assembler::zero, L); aoqi@1: //lw(tempreg, in_bytes(JavaThread::interp_only_mode_offset()), Rthread); aoqi@1: get_thread(AT); aoqi@1: lw(tempreg, AT, in_bytes(JavaThread::interp_only_mode_offset())); aoqi@1: beq(tempreg, R0, L); aoqi@1: delayed()->nop(); aoqi@1: call_VM(noreg, CAST_FROM_FN_PTR(address, aoqi@1: InterpreterRuntime::post_method_entry)); aoqi@1: bind(L); aoqi@1: } aoqi@1: aoqi@1: { aoqi@1: //SkipIfEqual skip_if(this, tempreg, R0, &DTraceMethodProbes, 1); aoqi@1: SkipIfEqual skip_if(this, &DTraceMethodProbes, 0); aoqi@1: call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry), aoqi@1: //Rthread, aoqi@1: AT, aoqi@1: //Rmethod); aoqi@1: S3); aoqi@1: } aoqi@1: aoqi@1: } aoqi@1: aoqi@1: //FIXME, aoqi:see UltraViolet aoqi@1: void InterpreterMacroAssembler::notify_method_exit( aoqi@1: //TosState state, NotifyMethodExitMode mode) { aoqi@1: bool is_native_method, TosState state, NotifyMethodExitMode mode) { aoqi@1: // Whenever JVMTI is interp_only_mode, method entry/exit events are sent to aoqi@1: // track stack depth. If it is possible to enter interp_only_mode we add aoqi@1: // the code to check if the event should be sent. aoqi@1: //Register tempreg = Rscratch0; aoqi@1: Register tempreg = T0; aoqi@1: if (mode == NotifyJVMTI && JvmtiExport::can_post_interpreter_events()) { aoqi@1: Label skip; aoqi@1: //lw(tempreg, in_bytes(JavaThread::interp_only_mode_offset()), Rthread); aoqi@1: get_thread(AT); aoqi@1: lw(tempreg, AT, in_bytes(JavaThread::interp_only_mode_offset())); aoqi@1: beq(tempreg, R0, skip); aoqi@1: delayed()->nop(); aoqi@1: // Note: frame::interpreter_frame_result has a dependency on how the aoqi@1: // method result is saved across the call to post_method_exit. If this aoqi@1: // is changed then the interpreter_frame_result implementation will aoqi@1: // need to be updated too. aoqi@1: aoqi@1: // For c++ interpreter the result is always stored at a known location in the frame aoqi@1: // template interpreter will leave it on the top of the stack. aoqi@1: save_return_value(state, is_native_method); aoqi@1: call_VM(noreg, aoqi@1: CAST_FROM_FN_PTR(address, InterpreterRuntime::post_method_exit)); aoqi@1: restore_return_value(state, is_native_method); aoqi@1: bind(skip); aoqi@1: } aoqi@1: aoqi@1: { aoqi@1: // Dtrace notification aoqi@1: //SkipIfEqual skip_if(this, tempreg, R0, &DTraceMethodProbes, equal); aoqi@1: SkipIfEqual skip_if(this, &DTraceMethodProbes, 0); aoqi@1: save_return_value(state, is_native_method); aoqi@1: call_VM_leaf( aoqi@1: CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit), aoqi@1: //Rthread, Rmethod); aoqi@1: AT, S3); aoqi@1: restore_return_value(state, is_native_method); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: //FIXME yyq native return 64 bits aoqi@1: void InterpreterMacroAssembler::save_return_value( aoqi@1: TosState state, bool is_native_call) { aoqi@1: if (is_native_call) { aoqi@1: // save any potential method result value aoqi@1: //sd(V0, frame::interpreter_frame_l_scratch_offset * wordSize, FP); aoqi@1: //sdc1(F0, frame::interpreter_frame_d_scratch_offset * wordSize, FP); aoqi@1: sw(V0, FP, (-9) * wordSize); aoqi@1: swc1(F0, FP, (-10) * wordSize); aoqi@1: aoqi@1: // sd(V0, FP, (-9) * wordSize); aoqi@1: // sdc1(F0, FP, (-10) * wordSize); aoqi@1: } else { aoqi@1: push(state); aoqi@1: } aoqi@1: } aoqi@1: aoqi@1: //FIXME yyq native return 64 bits aoqi@1: void InterpreterMacroAssembler::restore_return_value( aoqi@1: TosState state, bool is_native_call) { aoqi@1: if (is_native_call) { aoqi@1: // Restore any method result value aoqi@1: //ld(V0, frame::interpreter_frame_l_scratch_offset * wordSize, FP); aoqi@1: //ldc1(F0, frame::interpreter_frame_d_scratch_offset * wordSize, FP); aoqi@1: lw(V0, FP, (-9) * wordSize); aoqi@1: lwc1(F0, FP, (-10) * wordSize); aoqi@1: } else { aoqi@1: pop(state); aoqi@1: } aoqi@1: }