inline void MacroAssembler::load_heap_oop(Register d, RegisterOrConstant offs, Register s1) { if (UseCompressedOops) { lwz(d, offs, s1); decode_heap_oop(d); } else { ld(d, offs, s1); } }
void CppInterpreterGenerator::generate_convert_result(address* converter_array) { __ load (r5, (intptr_t) converter_array); __ lwz (r0, Address(Rmethod, methodOopDesc::result_index_offset())); __ shift_left (r0, r0, LogBytesPerWord); __ load_indexed (r0, r5, r0); __ mtctr (r0); __ bctrl (); }
inline void MacroAssembler::load_heap_oop_not_null(Register d, RegisterOrConstant offs, Register s1) { if (UseCompressedOops) { lwz(d, offs, s1); // Attention: no null check here! decode_heap_oop_not_null(d); } else { ld(d, offs, s1); } }
address CppInterpreterGenerator::generate_stack_to_stack_converter( BasicType type) { const Register stack = r3; address start = __ pc(); switch (type) { case T_VOID: break; case T_BOOLEAN: case T_CHAR: case T_BYTE: case T_SHORT: case T_INT: case T_FLOAT: __ load (stack, STATE(_stack)); __ lwz (r0, Address(stack, wordSize)); __ stw (r0, Address(Rlocals, 0)); __ subi (Rlocals, Rlocals, wordSize); break; case T_LONG: case T_DOUBLE: __ load (stack, STATE(_stack)); __ load (r0, Address(stack, wordSize)); __ store (r0, Address(Rlocals, -wordSize)); #ifdef PPC32 __ load (r0, Address(stack, wordSize * 2)); __ store (r0, Address(Rlocals, 0)); #endif __ subi (Rlocals, Rlocals, wordSize * 2); break; case T_OBJECT: __ load (stack, STATE(_stack)); __ load (r0, Address(stack, wordSize)); __ verify_oop (r0); __ store (r0, Address(Rlocals, 0)); __ subi (Rlocals, Rlocals, wordSize); break; default: ShouldNotReachHere(); } __ blr (); return start; }
void C1_MacroAssembler::initialize_object( Register obj, // result: pointer to object after successful allocation Register klass, // object klass Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise int con_size_in_bytes, // object size in bytes if known at compile time Register t1, // temp register Register t2 // temp register ) { const int hdr_size_in_bytes = instanceOopDesc::header_size() * HeapWordSize; initialize_header(obj, klass, noreg, t1, t2); #ifdef ASSERT { lwz(t1, in_bytes(Klass::layout_helper_offset()), klass); if (var_size_in_bytes != noreg) { cmpw(CCR0, t1, var_size_in_bytes); } else { cmpwi(CCR0, t1, con_size_in_bytes); } asm_assert_eq("bad size in initialize_object", 0x753); } #endif // Initialize body. if (var_size_in_bytes != noreg) { // Use a loop. addi(t1, obj, hdr_size_in_bytes); // Compute address of first element. addi(t2, var_size_in_bytes, -hdr_size_in_bytes); // Compute size of body. initialize_body(t1, t2); } else if (con_size_in_bytes > hdr_size_in_bytes) { // Use a loop. initialize_body(obj, t1, t2, con_size_in_bytes, hdr_size_in_bytes); } if (CURRENT_ENV->dtrace_alloc_probes()) { Unimplemented(); // assert(obj == O0, "must be"); // call(CAST_FROM_FN_PTR(address, Runtime1::entry_for(Runtime1::dtrace_object_alloc_id)), // relocInfo::runtime_call_type); } verify_oop(obj); }
void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register method, Register target, Register temp, bool for_compiler_entry) { Label L_no_such_method; assert(method == R19_method, "interpreter calling convention"); assert_different_registers(method, target, temp); if (!for_compiler_entry && JvmtiExport::can_post_interpreter_events()) { Label run_compiled_code; // JVMTI events, such as single-stepping, are implemented partly by avoiding running // compiled code in threads for which the event is enabled. Check here for // interp_only_mode if these events CAN be enabled. __ verify_thread(); __ lwz(temp, in_bytes(JavaThread::interp_only_mode_offset()), R16_thread); __ cmplwi(CCR0, temp, 0); __ beq(CCR0, run_compiled_code); // Null method test is replicated below in compiled case, // it might be able to address across the verify_thread() __ cmplwi(CCR0, R19_method, 0); __ beq(CCR0, L_no_such_method); __ ld(target, in_bytes(Method::interpreter_entry_offset()), R19_method); __ mtctr(target); __ bctr(); __ BIND(run_compiled_code); } // Compiled case, either static or fall-through from runtime conditional __ cmplwi(CCR0, R19_method, 0); __ beq(CCR0, L_no_such_method); const ByteSize entry_offset = for_compiler_entry ? Method::from_compiled_offset() : Method::from_interpreted_offset(); __ ld(target, in_bytes(entry_offset), R19_method); __ mtctr(target); __ bctr(); __ bind(L_no_such_method); assert(StubRoutines::throw_AbstractMethodError_entry() != NULL, "not yet generated!"); __ load_const_optimized(target, StubRoutines::throw_AbstractMethodError_entry()); __ mtctr(target); __ bctr(); }
void emit_trampoline(struct compilation_unit *cu, void *target_addr, struct jit_trampoline *t) { struct buffer *b = t->objcode; jit_text_lock(); b->buf = jit_text_ptr(); /* Allocate memory on the stack */ emit(b, stwu(1, -16, 1)); /* Save LR on stack */ emit(b, mflr(0)); emit(b, stw(0, 0, 1)); /* Pass pointer to 'struct compilation_unit' as first argument */ emit(b, lis(3, ptr_high(cu))); emit(b, ori(3, 3, ptr_low(cu))); /* Then call 'target_addr' */ emit(b, lis(0, ptr_high(target_addr))); emit(b, ori(0, 0, ptr_low(target_addr))); emit(b, mtctr(0)); emit(b, bctrl()); /* Restore LR from stack */ emit(b, lwz(0, 0, 1)); emit(b, mtlr(0)); /* Free memory on stack */ emit(b, addi(1, 1, 16)); /* Finally jump to the compiled method */ emit(b, mtctr(3)); emit(b, bctr()); jit_text_reserve(buffer_offset(b)); jit_text_unlock(); }
address InterpreterGenerator::generate_normal_entry(bool synchronized) { assert_different_registers(Rmethod, Rlocals, Rthread, Rstate, Rmonitor); Label re_dispatch; Label call_interpreter; Label call_method; Label call_non_interpreted_method; Label return_with_exception; Label return_from_method; Label resume_interpreter; Label return_to_initial_caller; Label more_monitors; Label throwing_exception; // We use the same code for synchronized and not if (normal_entry) return normal_entry; address start = __ pc(); // There are two ways in which we can arrive at this entry. // There is the special case where a normal interpreted method // calls another normal interpreted method, and there is the // general case of when we enter from somewhere else: from // call_stub, from C1 or C2, or from a fast accessor which // deferred. In the special case we're already in frame manager // code: we arrive at re_dispatch with Rstate containing the // previous interpreter state. In the general case we arrive // at start with no previous interpreter state so we set Rstate // to NULL to indicate this. __ bind (fast_accessor_slow_entry_path); __ load (Rstate, 0); __ bind (re_dispatch); // Adjust the caller's stack frame to accomodate any additional // local variables we have contiguously with our parameters. generate_adjust_callers_stack(); // Allocate and initialize our stack frame. generate_compute_interpreter_state(false); // Call the interpreter ============================================== __ bind (call_interpreter); // We can setup the frame anchor with everything we want at // this point as we are thread_in_Java and no safepoints can // occur until we go to vm mode. We do have to clear flags // on return from vm but that is it __ set_last_Java_frame (); // Call interpreter address interpreter = JvmtiExport::can_post_interpreter_events() ? CAST_FROM_FN_PTR(address, BytecodeInterpreter::runWithChecks) : CAST_FROM_FN_PTR(address, BytecodeInterpreter::run); __ mr (r3, Rstate); __ call (interpreter); __ fixup_after_potential_safepoint (); // Clear the frame anchor __ reset_last_Java_frame (); // Examine the message from the interpreter to decide what to do __ lwz (r4, STATE(_msg)); __ compare (r4, BytecodeInterpreter::call_method); __ beq (call_method); __ compare (r4, BytecodeInterpreter::return_from_method); __ beq (return_from_method); __ compare (r4, BytecodeInterpreter::more_monitors); __ beq (more_monitors); __ compare (r4, BytecodeInterpreter::throwing_exception); __ beq (throwing_exception); __ load (r3, (intptr_t) "error: bad message from interpreter: %d\n"); __ call (CAST_FROM_FN_PTR(address, printf)); __ should_not_reach_here (__FILE__, __LINE__); // Handle a call_method message ====================================== __ bind (call_method); __ load (Rmethod, STATE(_result._to_call._callee)); __ verify_oop(Rmethod); __ load (Rlocals, STATE(_stack)); __ lhz (r0, Address(Rmethod, methodOopDesc::size_of_parameters_offset())); __ shift_left (r0, r0, LogBytesPerWord); __ add (Rlocals, Rlocals, r0); __ load (r0, STATE(_result._to_call._callee_entry_point)); __ load (r3, (intptr_t) start); __ compare (r0, r3); __ bne (call_non_interpreted_method); // Interpreted methods are intercepted and re-dispatched ----------- __ load (r0, CAST_FROM_FN_PTR(intptr_t, RecursiveInterpreterActivation)); __ mtlr (r0); __ b (re_dispatch); // Non-interpreted methods are dispatched normally ----------------- __ bind (call_non_interpreted_method); __ mtctr (r0); __ bctrl (); // Restore Rstate __ load (Rstate, Address(r1, StackFrame::back_chain_offset * wordSize)); __ subi (Rstate, Rstate, sizeof(BytecodeInterpreter)); // Check for pending exceptions __ load (r0, Address(Rthread, Thread::pending_exception_offset())); __ compare (r0, 0); __ bne (return_with_exception); // Convert the result and resume generate_convert_result(CppInterpreter::_tosca_to_stack); __ b (resume_interpreter); // Handle a return_from_method message =============================== __ bind (return_from_method); __ load (r0, STATE(_prev_link)); __ compare (r0, 0); __ beq (return_to_initial_caller); // "Return" from a re-dispatch ------------------------------------- generate_convert_result(CppInterpreter::_stack_to_stack); generate_unwind_interpreter_state(); // Resume the interpreter __ bind (resume_interpreter); __ store (Rlocals, STATE(_stack)); __ load (Rlocals, STATE(_locals)); __ load (Rmethod, STATE(_method)); __ verify_oop(Rmethod); __ load (r0, BytecodeInterpreter::method_resume); __ stw (r0, STATE(_msg)); __ b (call_interpreter); // Return to the initial caller (call_stub etc) -------------------- __ bind (return_to_initial_caller); generate_convert_result(CppInterpreter::_stack_to_native_abi); generate_unwind_interpreter_state(); __ blr (); // Handle a more_monitors message ==================================== __ bind (more_monitors); generate_more_monitors(); __ load (r0, BytecodeInterpreter::got_monitors); __ stw (r0, STATE(_msg)); __ b (call_interpreter); // Handle a throwing_exception message =============================== __ bind (throwing_exception); // Check we actually have an exception #ifdef ASSERT { Label ok; __ load (r0, Address(Rthread, Thread::pending_exception_offset())); __ compare (r0, 0); __ bne (ok); __ should_not_reach_here (__FILE__, __LINE__); __ bind (ok); } #endif // Return to wherever generate_unwind_interpreter_state(); __ bind (return_with_exception); __ compare (Rstate, 0); __ bne (resume_interpreter); __ blr (); normal_entry = start; return start; }
address InterpreterGenerator::generate_native_entry(bool synchronized) { const Register handler = r14; const Register function = r15; assert_different_registers(Rmethod, Rlocals, Rthread, Rstate, Rmonitor, handler, function); // We use the same code for synchronized and not if (native_entry) return native_entry; address start = __ pc(); // Allocate and initialize our stack frame. __ load (Rstate, 0); generate_compute_interpreter_state(true); // Make sure method is native and not abstract #ifdef ASSERT { Label ok; __ lwz (r0, Address(Rmethod, methodOopDesc::access_flags_offset())); __ andi_ (r0, r0, JVM_ACC_NATIVE | JVM_ACC_ABSTRACT); __ compare (r0, JVM_ACC_NATIVE); __ beq (ok); __ should_not_reach_here (__FILE__, __LINE__); __ bind (ok); } #endif // Lock if necessary Label not_synchronized_1; __ bne (CRsync, not_synchronized_1); __ lock_object (Rmonitor); __ bind (not_synchronized_1); // Get signature handler const Address signature_handler_addr( Rmethod, methodOopDesc::signature_handler_offset()); Label return_to_caller, got_signature_handler; __ load (handler, signature_handler_addr); __ compare (handler, 0); __ bne (got_signature_handler); __ call_VM (noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::prepare_native_call), Rmethod, CALL_VM_NO_EXCEPTION_CHECKS); __ load (r0, Address(Rthread, Thread::pending_exception_offset())); __ compare (r0, 0); __ bne (return_to_caller); __ load (handler, signature_handler_addr); __ bind (got_signature_handler); // Get the native function entry point const Address native_function_addr( Rmethod, methodOopDesc::native_function_offset()); Label got_function; __ load (function, native_function_addr); #ifdef ASSERT { // InterpreterRuntime::prepare_native_call() sets the mirror // handle and native function address first and the signature // handler last, so function should always be set here. Label ok; __ compare (function, 0); __ bne (ok); __ should_not_reach_here (__FILE__, __LINE__); __ bind (ok); } #endif // Call signature handler __ mtctr (handler); __ bctrl (); __ mr (handler, r0); // Pass JNIEnv __ la (r3, Address(Rthread, JavaThread::jni_environment_offset())); // Pass mirror handle if static const Address oop_temp_addr = STATE(_oop_temp); Label not_static; __ bne (CRstatic, not_static); __ get_mirror_handle (r4); __ store (r4, oop_temp_addr); __ la (r4, oop_temp_addr); __ bind (not_static); // Set up the Java frame anchor __ set_last_Java_frame (); // Change the thread state to native const Address thread_state_addr(Rthread, JavaThread::thread_state_offset()); #ifdef ASSERT { Label ok; __ lwz (r0, thread_state_addr); __ compare (r0, _thread_in_Java); __ beq (ok); __ should_not_reach_here (__FILE__, __LINE__); __ bind (ok); } #endif __ load (r0, _thread_in_native); __ stw (r0, thread_state_addr); // Make the call __ call (function); __ fixup_after_potential_safepoint (); // The result will be in r3 (and maybe r4 on 32-bit) or f1. // Wherever it is, we need to store it before calling anything const Register r3_save = r16; #ifdef PPC32 const Register r4_save = r17; #endif const FloatRegister f1_save = f14; __ mr (r3_save, r3); #ifdef PPC32 __ mr (r4_save, r4); #endif __ fmr (f1_save, f1); // Switch thread to "native transition" state before reading the // synchronization state. This additional state is necessary // because reading and testing the synchronization state is not // atomic with respect to garbage collection. __ load (r0, _thread_in_native_trans); __ stw (r0, thread_state_addr); // Ensure the new state is visible to the VM thread. if(os::is_MP()) { if (UseMembar) __ sync (); else __ serialize_memory (r3, r4); } // Check for safepoint operation in progress and/or pending // suspend requests. We use a leaf call in order to leave // the last_Java_frame setup undisturbed. Label block, no_block; __ load (r3, (intptr_t) SafepointSynchronize::address_of_state()); __ lwz (r0, Address(r3, 0)); __ compare (r0, SafepointSynchronize::_not_synchronized); __ bne (block); __ lwz (r0, Address(Rthread, JavaThread::suspend_flags_offset())); __ compare (r0, 0); __ beq (no_block); __ bind (block); __ call_VM_leaf ( CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans)); __ fixup_after_potential_safepoint (); __ bind (no_block); // Change the thread state __ load (r0, _thread_in_Java); __ stw (r0, thread_state_addr); // Reset the frame anchor __ reset_last_Java_frame (); // If the result was an OOP then unbox it and store it in the frame // (where it will be safe from garbage collection) before we release // the handle it might be protected by Label non_oop, store_oop; __ load (r0, (intptr_t) AbstractInterpreter::result_handler(T_OBJECT)); __ compare (r0, handler); __ bne (non_oop); __ compare (r3_save, 0); __ beq (store_oop); __ load (r3_save, Address(r3_save, 0)); __ bind (store_oop); __ store (r3_save, STATE(_oop_temp)); __ bind (non_oop); // Reset handle block __ load (r3, Address(Rthread, JavaThread::active_handles_offset())); __ load (r0, 0); __ stw (r0, Address(r3, JNIHandleBlock::top_offset_in_bytes())); // If there is an exception we skip the result handler and return. // Note that this also skips unlocking which seems totally wrong, // but apparently this is what the asm interpreter does so we do // too. __ load (r0, Address(Rthread, Thread::pending_exception_offset())); __ compare (r0, 0); __ bne (return_to_caller); // Unlock if necessary Label not_synchronized_2; __ bne (CRsync, not_synchronized_2); __ unlock_object (Rmonitor); __ bind (not_synchronized_2); // Restore saved result and call the result handler __ mr (r3, r3_save); #ifdef PPC32 __ mr (r4, r4_save); #endif __ fmr (f1, f1_save); __ mtctr (handler); __ bctrl (); // Unwind the current activation and return __ bind (return_to_caller); generate_unwind_interpreter_state(); __ blr (); native_entry = start; return start; }
address InterpreterGenerator::generate_accessor_entry() { if (!UseFastAccessorMethods) return NULL; Label& slow_path = fast_accessor_slow_entry_path; address start = __ pc(); // Drop into the slow path if we need a safepoint check. __ load (r3, (intptr_t) SafepointSynchronize::address_of_state()); __ load (r0, Address(r3, 0)); __ compare (r0, SafepointSynchronize::_not_synchronized); __ bne (slow_path); // Load the object pointer and drop into the slow path // if we have a NullPointerException. const Register object = r4; __ load (object, Address(Rlocals, 0)); __ compare (object, 0); __ beq (slow_path); // Read the field index from the bytecode, which looks like this: // 0: 0x2a: aload_0 // 1: 0xb4: getfield // 2: index (high byte) // 3: index (low byte) // 4: 0xac/b0: ireturn/areturn const Register index = r5; __ load (index, Address(Rmethod, methodOopDesc::const_offset())); __ lwz (index, Address(index, constMethodOopDesc::codes_offset())); #ifdef ASSERT { Label ok; __ shift_right (r0, index, 16); __ compare (r0, (Bytecodes::_aload_0 << 8) | Bytecodes::_getfield); __ beq (ok); __ should_not_reach_here (__FILE__, __LINE__); __ bind (ok); } #endif __ andi_ (index, index, 0xffff); // Locate the entry in the constant pool cache const Register entry = r6; __ load (entry, Address(Rmethod, methodOopDesc::constants_offset())); __ load (entry, Address(entry,constantPoolOopDesc::cache_offset_in_bytes())); __ la (entry, Address(entry, constantPoolCacheOopDesc::base_offset())); __ shift_left(r0, index, exact_log2(in_words(ConstantPoolCacheEntry::size())) + LogBytesPerWord); __ add (entry, entry, r0); // Check the validity of the cache entry by testing whether the // _indices field contains Bytecode::_getfield in b1 byte. __ load (r0, Address(entry, ConstantPoolCacheEntry::indices_offset())); __ shift_right (r0, r0, 16); __ andi_ (r0, r0, 0xff); __ compare (r0, Bytecodes::_getfield); __ bne (slow_path); // Calculate the type and offset of the field const Register offset = r7; const Register type = r8; __ load (offset, Address(entry, ConstantPoolCacheEntry::f2_offset())); __ load (type, Address(entry, ConstantPoolCacheEntry::flags_offset())); ConstantPoolCacheEntry::verify_tosBits(); __ shift_right (type, type, ConstantPoolCacheEntry::tosBits); // Load the value Label is_object, is_int, is_byte, is_short, is_char; __ compare (type, atos); __ beq (is_object); __ compare (type, itos); __ beq (is_int); __ compare (type, btos); __ beq (is_byte); __ compare (type, stos); __ beq (is_short); __ compare (type, ctos); __ beq (is_char); __ load (r3, (intptr_t) "error: unknown type: %d\n"); __ mr (r4, type); __ call (CAST_FROM_FN_PTR(address, printf)); __ should_not_reach_here (__FILE__, __LINE__); __ bind (is_object); __ load_indexed (r3, object, offset); __ blr (); __ bind (is_int); __ lwax (r3, object, offset); __ blr (); __ bind (is_byte); __ lbax (r3, object, offset); __ blr (); __ bind (is_short); __ lhax (r3, object, offset); __ blr (); __ bind (is_char); __ lhzx (r3, object, offset); __ blr (); return start; }
void CppInterpreterGenerator::generate_compute_interpreter_state(bool native) { StackFrame frame; const Address stack_words_addr( Rmethod, methodOopDesc::max_stack_offset()); const Address access_flags_addr( Rmethod, methodOopDesc::access_flags_offset()); Label not_synchronized_1, not_synchronized_2, not_synchronized_3; Label not_static, init_monitor; const int monitor_size = frame::interpreter_frame_monitor_size() * wordSize; // Calculate the access flags conditions const Register access_flags = r3; __ lwz (access_flags, access_flags_addr); __ andi_ (r0, access_flags, JVM_ACC_SYNCHRONIZED); __ compare (CRsync, r0, JVM_ACC_SYNCHRONIZED); __ andi_ (r0, access_flags, JVM_ACC_STATIC); __ compare (CRstatic, r0, JVM_ACC_STATIC); const int basic_frame_size = frame.unaligned_size() + sizeof(BytecodeInterpreter) + slop_factor; // Calculate the frame size const Register stack_size = r3; const Register frame_size = r4; const Register padding = r5; if (native) { __ load (frame_size, basic_frame_size); } else { __ lhz (stack_size, stack_words_addr); __ shift_left (stack_size, stack_size, LogBytesPerWord); __ addi (frame_size, stack_size, basic_frame_size); } __ bne (CRsync, not_synchronized_1); __ addi (frame_size, frame_size, monitor_size); __ bind (not_synchronized_1); __ calc_padding_for_alignment (padding, frame_size, StackAlignmentInBytes); __ add (frame_size, frame_size, padding); // Save the link register and create the new frame __ mflr (r0); __ store (r0, Address(r1, StackFrame::lr_save_offset * wordSize)); __ neg (r0, frame_size); __ store_update_indexed (r1, r1, r0); // Calculate everything's addresses const Register stack_limit = r6; const Register stack = r7; const Register stack_base = Rmonitor; const Register monitor_base = r8; __ addi (stack_limit, r1, frame.start_of_locals() + slop_factor - wordSize); __ add (stack_limit, stack_limit, padding); if (native) __ mr (stack, stack_limit); else __ add (stack, stack_limit, stack_size); __ addi (stack_base, stack, wordSize); __ mr (monitor_base, stack_base); __ bne (CRsync, not_synchronized_2); __ addi (monitor_base, monitor_base, monitor_size); __ bind (not_synchronized_2); __ mr (r0, Rstate); __ mr (Rstate, monitor_base); // Initialise the interpreter state object __ store (Rlocals, STATE(_locals)); __ store (Rmethod, STATE(_method)); __ store (Rstate, STATE(_self_link)); __ store (r0, STATE(_prev_link)); __ store (stack_limit, STATE(_stack_limit)); __ store (stack, STATE(_stack)); __ store (stack_base, STATE(_stack_base)); __ store (monitor_base, STATE(_monitor_base)); __ store (Rthread, STATE(_thread)); #ifdef ASSERT { Label ok; __ load (r3, ThreadLocalStorage::thread_index()); __ call (CAST_FROM_FN_PTR(address, pthread_getspecific)); __ compare (Rthread, r3); __ beq (ok); __ should_not_reach_here (__FILE__, __LINE__); __ bind (ok); } #endif if (!native) { __ load (r3, Address(Rmethod, methodOopDesc::const_offset())); __ addi (r3, r3, in_bytes(constMethodOopDesc::codes_offset())); __ store (r3, STATE(_bcp)); } __ load (r3, Address(Rmethod, methodOopDesc::constants_offset())); __ load (r3, Address(r3, constantPoolOopDesc::cache_offset_in_bytes())); __ store (r3, STATE(_constants)); __ load (r3, BytecodeInterpreter::method_entry); __ stw (r3, STATE(_msg)); __ load (r3, 0); if (native) __ store (r3, STATE(_bcp)); __ store (r3, STATE(_oop_temp)); __ store (r3, STATE(_mdx)); __ store (r3, STATE(_result._to_call._callee)); // Initialise the monitor if synchronized __ bne (CRsync, not_synchronized_3); __ bne (CRstatic, not_static); __ get_mirror_handle (r3); __ b (init_monitor); __ bind (not_static); __ load (r3, Address(Rlocals, 0)); __ bind (init_monitor); __ store (r3, Address(Rmonitor, BasicObjectLock::obj_offset_in_bytes())); __ bind (not_synchronized_3); }
// Used by compiler only; may use only caller saved, non-argument // registers. VtableStub* VtableStubs::create_vtable_stub(int vtable_index) { // PPC port: use fixed size. const int code_length = VtableStub::pd_code_size_limit(true); VtableStub* s = new (code_length) VtableStub(true, vtable_index); // Can be NULL if there is no free space in the code cache. if (s == NULL) { return NULL; } ResourceMark rm; CodeBuffer cb(s->entry_point(), code_length); MacroAssembler* masm = new MacroAssembler(&cb); #ifndef PRODUCT if (CountCompiledCalls) { int offs = __ load_const_optimized(R11_scratch1, SharedRuntime::nof_megamorphic_calls_addr(), R12_scratch2, true); __ lwz(R12_scratch2, offs, R11_scratch1); __ addi(R12_scratch2, R12_scratch2, 1); __ stw(R12_scratch2, offs, R11_scratch1); } #endif assert(VtableStub::receiver_location() == R3_ARG1->as_VMReg(), "receiver expected in R3_ARG1"); // Get receiver klass. const Register rcvr_klass = R11_scratch1; // We might implicit NULL fault here. address npe_addr = __ pc(); // npe = null pointer exception __ load_klass_with_trap_null_check(rcvr_klass, R3); // Set method (in case of interpreted method), and destination address. int entry_offset = InstanceKlass::vtable_start_offset() + vtable_index*vtableEntry::size(); #ifndef PRODUCT if (DebugVtables) { Label L; // Check offset vs vtable length. const Register vtable_len = R12_scratch2; __ lwz(vtable_len, InstanceKlass::vtable_length_offset()*wordSize, rcvr_klass); __ cmpwi(CCR0, vtable_len, vtable_index*vtableEntry::size()); __ bge(CCR0, L); __ li(R12_scratch2, vtable_index); __ call_VM(noreg, CAST_FROM_FN_PTR(address, bad_compiled_vtable_index), R3_ARG1, R12_scratch2, false); __ bind(L); } #endif int v_off = entry_offset*wordSize + vtableEntry::method_offset_in_bytes(); __ ld(R19_method, v_off, rcvr_klass); #ifndef PRODUCT if (DebugVtables) { Label L; __ cmpdi(CCR0, R19_method, 0); __ bne(CCR0, L); __ stop("Vtable entry is ZERO", 102); __ bind(L); } #endif // If the vtable entry is null, the method is abstract. address ame_addr = __ pc(); // ame = abstract method error __ load_with_trap_null_check(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method); __ mtctr(R12_scratch2); __ bctr(); masm->flush(); guarantee(__ pc() <= s->code_end(), "overflowed buffer"); s->set_exception_points(npe_addr, ame_addr); return s; }
VtableStub* VtableStubs::create_itable_stub(int itable_index) { // PPC port: use fixed size. const int code_length = VtableStub::pd_code_size_limit(false); VtableStub* s = new (code_length) VtableStub(false, itable_index); // Can be NULL if there is no free space in the code cache. if (s == NULL) { return NULL; } ResourceMark rm; CodeBuffer cb(s->entry_point(), code_length); MacroAssembler* masm = new MacroAssembler(&cb); address start_pc; #ifndef PRODUCT if (CountCompiledCalls) { int offs = __ load_const_optimized(R11_scratch1, SharedRuntime::nof_megamorphic_calls_addr(), R12_scratch2, true); __ lwz(R12_scratch2, offs, R11_scratch1); __ addi(R12_scratch2, R12_scratch2, 1); __ stw(R12_scratch2, offs, R11_scratch1); } #endif assert(VtableStub::receiver_location() == R3_ARG1->as_VMReg(), "receiver expected in R3_ARG1"); // Entry arguments: // R19_method: Interface // R3_ARG1: Receiver Label L_no_such_interface; const Register rcvr_klass = R11_scratch1, interface = R12_scratch2, tmp1 = R21_tmp1, tmp2 = R22_tmp2; address npe_addr = __ pc(); // npe = null pointer exception __ load_klass_with_trap_null_check(rcvr_klass, R3_ARG1); // Receiver subtype check against REFC. __ ld(interface, CompiledICHolder::holder_klass_offset(), R19_method); __ lookup_interface_method(rcvr_klass, interface, noreg, R0, tmp1, tmp2, L_no_such_interface, /*return_method=*/ false); // Get Method* and entrypoint for compiler __ ld(interface, CompiledICHolder::holder_metadata_offset(), R19_method); __ lookup_interface_method(rcvr_klass, interface, itable_index, R19_method, tmp1, tmp2, L_no_such_interface, /*return_method=*/ true); #ifndef PRODUCT if (DebugVtables) { Label ok; __ cmpd(CCR0, R19_method, 0); __ bne(CCR0, ok); __ stop("method is null", 103); __ bind(ok); } #endif // If the vtable entry is null, the method is abstract. address ame_addr = __ pc(); // ame = abstract method error // Must do an explicit check if implicit checks are disabled. assert(!MacroAssembler::needs_explicit_null_check(in_bytes(Method::from_compiled_offset())), "sanity"); if (!ImplicitNullChecks || !os::zero_page_read_protected()) { if (TrapBasedNullChecks) { __ trap_null_check(R19_method); } else { __ cmpdi(CCR0, R19_method, 0); __ beq(CCR0, L_no_such_interface); } } __ ld(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method); __ mtctr(R12_scratch2); __ bctr(); // Handle IncompatibleClassChangeError in itable stubs. // More detailed error message. // We force resolving of the call site by jumping to the "handle // wrong method" stub, and so let the interpreter runtime do all the // dirty work. __ bind(L_no_such_interface); __ load_const_optimized(R11_scratch1, SharedRuntime::get_handle_wrong_method_stub(), R12_scratch2); __ mtctr(R11_scratch1); __ bctr(); masm->flush(); guarantee(__ pc() <= s->code_end(), "overflowed buffer"); s->set_exception_points(npe_addr, ame_addr); return s; }
// Call an accessor method (assuming it is resolved, otherwise drop into // vanilla (slow path) entry. address InterpreterGenerator::generate_accessor_entry(void) { if (!UseFastAccessorMethods && (!FLAG_IS_ERGO(UseFastAccessorMethods))) { return NULL; } Label Lslow_path, Lacquire; const Register Rclass_or_obj = R3_ARG1, Rconst_method = R4_ARG2, Rcodes = Rconst_method, Rcpool_cache = R5_ARG3, Rscratch = R11_scratch1, Rjvmti_mode = Rscratch, Roffset = R12_scratch2, Rflags = R6_ARG4, Rbtable = R7_ARG5; static address branch_table[number_of_states]; address entry = __ pc(); // Check for safepoint: // Ditch this, real man don't need safepoint checks. // Also check for JVMTI mode // Check for null obj, take slow path if so. __ ld(Rclass_or_obj, Interpreter::stackElementSize, CC_INTERP_ONLY(R17_tos) NOT_CC_INTERP(R15_esp)); __ lwz(Rjvmti_mode, thread_(interp_only_mode)); __ cmpdi(CCR1, Rclass_or_obj, 0); __ cmpwi(CCR0, Rjvmti_mode, 0); __ crorc(/*CCR0 eq*/2, /*CCR1 eq*/4+2, /*CCR0 eq*/2); __ beq(CCR0, Lslow_path); // this==null or jvmti_mode!=0 // Do 2 things in parallel: // 1. Load the index out of the first instruction word, which looks like this: // <0x2a><0xb4><index (2 byte, native endianess)>. // 2. Load constant pool cache base. __ ld(Rconst_method, in_bytes(Method::const_offset()), R19_method); __ ld(Rcpool_cache, in_bytes(ConstMethod::constants_offset()), Rconst_method); __ lhz(Rcodes, in_bytes(ConstMethod::codes_offset()) + 2, Rconst_method); // Lower half of 32 bit field. __ ld(Rcpool_cache, ConstantPool::cache_offset_in_bytes(), Rcpool_cache); // Get the const pool entry by means of <index>. const int codes_shift = exact_log2(in_words(ConstantPoolCacheEntry::size()) * BytesPerWord); __ slwi(Rscratch, Rcodes, codes_shift); // (codes&0xFFFF)<<codes_shift __ add(Rcpool_cache, Rscratch, Rcpool_cache); // Check if cpool cache entry is resolved. // We are resolved if the indices offset contains the current bytecode. ByteSize cp_base_offset = ConstantPoolCache::base_offset(); // Big Endian: __ lbz(Rscratch, in_bytes(cp_base_offset) + in_bytes(ConstantPoolCacheEntry::indices_offset()) + 7 - 2, Rcpool_cache); __ cmpwi(CCR0, Rscratch, Bytecodes::_getfield); __ bne(CCR0, Lslow_path); __ isync(); // Order succeeding loads wrt. load of _indices field from cpool_cache. // Finally, start loading the value: Get cp cache entry into regs. __ ld(Rflags, in_bytes(cp_base_offset) + in_bytes(ConstantPoolCacheEntry::flags_offset()), Rcpool_cache); __ ld(Roffset, in_bytes(cp_base_offset) + in_bytes(ConstantPoolCacheEntry::f2_offset()), Rcpool_cache); // Following code is from templateTable::getfield_or_static // Load pointer to branch table __ load_const_optimized(Rbtable, (address)branch_table, Rscratch); // Get volatile flag __ rldicl(Rscratch, Rflags, 64-ConstantPoolCacheEntry::is_volatile_shift, 63); // extract volatile bit // note: sync is needed before volatile load on PPC64 // Check field type __ rldicl(Rflags, Rflags, 64-ConstantPoolCacheEntry::tos_state_shift, 64-ConstantPoolCacheEntry::tos_state_bits); #ifdef ASSERT Label LFlagInvalid; __ cmpldi(CCR0, Rflags, number_of_states); __ bge(CCR0, LFlagInvalid); __ ld(R9_ARG7, 0, R1_SP); __ ld(R10_ARG8, 0, R21_sender_SP); __ cmpd(CCR0, R9_ARG7, R10_ARG8); __ asm_assert_eq("backlink", 0x543); #endif // ASSERT __ mr(R1_SP, R21_sender_SP); // Cut the stack back to where the caller started. // Load from branch table and dispatch (volatile case: one instruction ahead) __ sldi(Rflags, Rflags, LogBytesPerWord); __ cmpwi(CCR6, Rscratch, 1); // volatile? if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ sldi(Rscratch, Rscratch, exact_log2(BytesPerInstWord)); // volatile ? size of 1 instruction : 0 } __ ldx(Rbtable, Rbtable, Rflags); if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ subf(Rbtable, Rscratch, Rbtable); // point to volatile/non-volatile entry point } __ mtctr(Rbtable); __ bctr(); #ifdef ASSERT __ bind(LFlagInvalid); __ stop("got invalid flag", 0x6541); bool all_uninitialized = true, all_initialized = true; for (int i = 0; i<number_of_states; ++i) { all_uninitialized = all_uninitialized && (branch_table[i] == NULL); all_initialized = all_initialized && (branch_table[i] != NULL); } assert(all_uninitialized != all_initialized, "consistency"); // either or __ fence(); // volatile entry point (one instruction before non-volatile_entry point) if (branch_table[vtos] == 0) branch_table[vtos] = __ pc(); // non-volatile_entry point if (branch_table[dtos] == 0) branch_table[dtos] = __ pc(); // non-volatile_entry point if (branch_table[ftos] == 0) branch_table[ftos] = __ pc(); // non-volatile_entry point __ stop("unexpected type", 0x6551); #endif if (branch_table[itos] == 0) { // generate only once __ align(32, 28, 28); // align load __ fence(); // volatile entry point (one instruction before non-volatile_entry point) branch_table[itos] = __ pc(); // non-volatile_entry point __ lwax(R3_RET, Rclass_or_obj, Roffset); __ beq(CCR6, Lacquire); __ blr(); } if (branch_table[ltos] == 0) { // generate only once __ align(32, 28, 28); // align load __ fence(); // volatile entry point (one instruction before non-volatile_entry point) branch_table[ltos] = __ pc(); // non-volatile_entry point __ ldx(R3_RET, Rclass_or_obj, Roffset); __ beq(CCR6, Lacquire); __ blr(); } if (branch_table[btos] == 0) { // generate only once __ align(32, 28, 28); // align load __ fence(); // volatile entry point (one instruction before non-volatile_entry point) branch_table[btos] = __ pc(); // non-volatile_entry point __ lbzx(R3_RET, Rclass_or_obj, Roffset); __ extsb(R3_RET, R3_RET); __ beq(CCR6, Lacquire); __ blr(); } if (branch_table[ctos] == 0) { // generate only once __ align(32, 28, 28); // align load __ fence(); // volatile entry point (one instruction before non-volatile_entry point) branch_table[ctos] = __ pc(); // non-volatile_entry point __ lhzx(R3_RET, Rclass_or_obj, Roffset); __ beq(CCR6, Lacquire); __ blr(); } if (branch_table[stos] == 0) { // generate only once __ align(32, 28, 28); // align load __ fence(); // volatile entry point (one instruction before non-volatile_entry point) branch_table[stos] = __ pc(); // non-volatile_entry point __ lhax(R3_RET, Rclass_or_obj, Roffset); __ beq(CCR6, Lacquire); __ blr(); } if (branch_table[atos] == 0) { // generate only once __ align(32, 28, 28); // align load __ fence(); // volatile entry point (one instruction before non-volatile_entry point) branch_table[atos] = __ pc(); // non-volatile_entry point __ load_heap_oop(R3_RET, (RegisterOrConstant)Roffset, Rclass_or_obj); __ verify_oop(R3_RET); //__ dcbt(R3_RET); // prefetch __ beq(CCR6, Lacquire); __ blr(); } __ align(32, 12); __ bind(Lacquire); __ twi_0(R3_RET); __ isync(); // acquire __ blr(); #ifdef ASSERT for (int i = 0; i<number_of_states; ++i) { assert(branch_table[i], "accessor_entry initialization"); //tty->print_cr("accessor_entry: branch_table[%d] = 0x%llx (opcode 0x%llx)", i, branch_table[i], *((unsigned int*)branch_table[i])); } #endif __ bind(Lslow_path); __ branch_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals), Rscratch); __ flush(); return entry; }