Cube::Cube(const position_type &where, std::shared_ptr<Texture> texture ) : Object3D(where) { // 8 points, 6 surfaces position_type blf(-1.0, -1.0, 1.0) // front rectangle , brf(1.0, -1.0, 1.0) , trf(1.0, 1.0, 1.0) , tlf(-1.0, 1.0, 1.0) , blr(-1.0, -1.0, -1.0) // rear rectangle , brr(1.0, -1.0, -1.0) , trr(1.0, 1.0, -1.0) , tlr(-1.0, 1.0, -1.0); position_type negZ(0.0, 0.0, -1.0) , posZ(0.0, 0.0, 1.0) , negY(0.0, -1.0, 0.0) , posY(0.0, 1.0, 0.0) , negX(-1.0, 0.0, 0.0) , posX(1.0, 0.0, 0.0); // if changing the order, make sure to change accessors so they grab the correct object this->add_child(new Rectangle(POSITION_INHERIT, { blf, blr, brr, brf }, { negY, negY, negY, negY }, texture)); // bottom negY this->add_child(new Rectangle(POSITION_INHERIT, { trr, brr, blr, tlr }, { negZ, negZ, negZ, negZ }, texture)); // rear negZ this->add_child(new Rectangle(POSITION_INHERIT, { trf, brf, brr, trr }, { posX, posX, posX, posX }, texture)); // right posX this->add_child(new Rectangle(POSITION_INHERIT, { tlr, blr, blf, tlf }, { negX, negX, negX, negX }, texture)); // left negX this->add_child(new Rectangle(POSITION_INHERIT, { tlf, blf, brf, trf }, { posZ, posZ, posZ, posZ }, texture)); // front posZ this->add_child(new Rectangle(POSITION_INHERIT, { tlr, tlf, trf, trr }, { posY, posY, posY, posY }, texture)); // top posY } // Cube
address AbstractInterpreterGenerator::generate_result_handler_for(BasicType type) { // // Registers alive // R3_RET // LR // // Registers updated // R3_RET // Label done; address entry = __ pc(); switch (type) { case T_BOOLEAN: // convert !=0 to 1 __ neg(R0, R3_RET); __ orr(R0, R3_RET, R0); __ srwi(R3_RET, R0, 31); break; case T_BYTE: // sign extend 8 bits __ extsb(R3_RET, R3_RET); break; case T_CHAR: // zero extend 16 bits __ clrldi(R3_RET, R3_RET, 48); break; case T_SHORT: // sign extend 16 bits __ extsh(R3_RET, R3_RET); break; case T_INT: // sign extend 32 bits __ extsw(R3_RET, R3_RET); break; case T_LONG: break; case T_OBJECT: // unbox result if not null __ cmpdi(CCR0, R3_RET, 0); __ beq(CCR0, done); __ ld(R3_RET, 0, R3_RET); __ verify_oop(R3_RET); break; case T_FLOAT: break; case T_DOUBLE: break; case T_VOID: break; default: ShouldNotReachHere(); } __ BIND(done); __ blr(); return entry; }
// Abstract method entry. // address InterpreterGenerator::generate_abstract_entry(void) { address entry = __ pc(); // // Registers alive // R16_thread - JavaThread* // R19_method - callee's method (method to be invoked) // R1_SP - SP prepared such that caller's outgoing args are near top // LR - return address to caller // // Stack layout at this point: // // 0 [TOP_IJAVA_FRAME_ABI] <-- R1_SP // alignment (optional) // [outgoing Java arguments] // ... // PARENT [PARENT_IJAVA_FRAME_ABI] // ... // // Can't use call_VM here because we have not set up a new // interpreter state. Make the call to the vm and make it look like // our caller set up the JavaFrameAnchor. __ set_top_ijava_frame_at_SP_as_last_Java_frame(R1_SP, R12_scratch2/*tmp*/); // Push a new C frame and save LR. __ save_LR_CR(R0); __ push_frame_reg_args(0, R11_scratch1); // This is not a leaf but we have a JavaFrameAnchor now and we will // check (create) exceptions afterward so this is ok. __ call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError), R16_thread); // Pop the C frame and restore LR. __ pop_frame(); __ restore_LR_CR(R0); // Reset JavaFrameAnchor from call_VM_leaf above. __ reset_last_Java_frame(); #ifdef CC_INTERP // Return to frame manager, it will handle the pending exception. __ blr(); #else // We don't know our caller, so jump to the general forward exception stub, // which will also pop our full frame off. Satisfy the interface of // SharedRuntime::generate_forward_exception() __ load_const_optimized(R11_scratch1, StubRoutines::forward_exception_entry(), R0); __ mtctr(R11_scratch1); __ bctr(); #endif return entry; }
address CppInterpreterGenerator::generate_result_handler_for(BasicType type) { address start = __ pc(); switch (type) { case T_VOID: break; case T_BOOLEAN: { Label zero; __ compare (r3, 0); __ beq (zero); __ load (r3, 1); __ bind (zero); } break; case T_CHAR: __ andi_ (r3, r3, 0xffff); break; case T_BYTE: __ extsb (r3, r3); break; case T_SHORT: __ extsh (r3, r3); break; case T_INT: #ifdef PPC64 __ extsw (r3, r3); #endif break; case T_LONG: case T_FLOAT: case T_DOUBLE: break; case T_OBJECT: __ load (r3, STATE(_oop_temp)); __ verify_oop (r3); break; default: ShouldNotReachHere(); } __ blr (); return start; }
address CppInterpreterGenerator::generate_stack_to_native_abi_converter( BasicType type) { const Register stack = r5; address start = __ pc(); switch (type) { case T_VOID: break; case T_BOOLEAN: case T_CHAR: case T_BYTE: case T_SHORT: case T_INT: __ load (stack, STATE(_stack)); __ lwa (r3, Address(stack, wordSize)); break; case T_LONG: __ load (stack, STATE(_stack)); __ load (r3, Address(stack, wordSize)); #ifdef PPC32 __ load (r4, Address(stack, wordSize * 2)); #endif break; case T_FLOAT: __ load (stack, STATE(_stack)); __ lfs (f1, Address(stack, wordSize)); break; case T_DOUBLE: __ load (stack, STATE(_stack)); __ lfd (f1, Address(stack, wordSize)); break; case T_OBJECT: __ load (stack, STATE(_stack)); __ load (r3, Address(stack, wordSize)); __ verify_oop (r3); break; default: ShouldNotReachHere(); } __ blr (); return start; }
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; }
address CppInterpreterGenerator::generate_tosca_to_stack_converter( BasicType type) { address start = __ pc(); switch (type) { case T_VOID: break; case T_BOOLEAN: case T_CHAR: case T_BYTE: case T_SHORT: case T_INT: __ stw (r3, Address(Rlocals, 0)); __ subi (Rlocals, Rlocals, wordSize); break; case T_LONG: __ store (r3, Address(Rlocals, -wordSize)); #ifdef PPC32 __ store (r4, Address(Rlocals, 0)); #endif __ subi (Rlocals, Rlocals, wordSize * 2); break; case T_FLOAT: __ stfs (f1, Address(Rlocals, 0)); __ subi (Rlocals, Rlocals, wordSize); break; case T_DOUBLE: __ stfd (f1, Address(Rlocals, -wordSize)); __ subi (Rlocals, Rlocals, wordSize * 2); break; case T_OBJECT: __ verify_oop (r3); __ store (r3, Address(Rlocals, 0)); __ subi (Rlocals, Rlocals, wordSize); break; default: ShouldNotReachHere(); } __ blr (); return start; }
address InterpreterGenerator::generate_empty_entry() { if (!UseFastEmptyMethods) 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); // Ok, we're done :) __ blr (); return start; }
// These stubs get called from some dumb test routine. // I'll write them properly when they're called from // something that's actually doing something. address generate_arraycopy_stub(const char *name, int line) { #ifdef PPC StubCodeMark mark(this, "StubRoutines", name); address start = __ enter(); const Register from = r3; // source array address const Register to = r4; // destination array address const Register count = r5; // element count __ compare (count, 0); __ beqlr (); __ unimplemented (__FILE__, line); __ blr (); return start; #else return UnimplementedStub(); #endif // PPC }
Cube::Cube( const position_type &where, Texture::pointer_type texture ) : Object( where, texture ) { glm::vec3 blf( -1.0, -1.0, 1.0 ) // front rectangle , brf( 1.0, -1.0, 1.0 ) , trf( 1.0, 1.0, 1.0 ) , tlf( -1.0, 1.0, 1.0 ) , blr( -1.0, -1.0, -1.0 ) // rear rectangle , brr( 1.0, -1.0, -1.0 ) , trr( 1.0, 1.0, -1.0 ) , tlr( -1.0, 1.0, -1.0 ) ; glm::vec3 negZ( 0.0, 0.0, -1.0 ) , posZ( 0.0, 0.0, 1.0 ) , negY( 0.0, -1.0, 0.0 ) , posY( 0.0, 1.0, 0.0 ) , negX( -1.0, 0.0, 0.0 ) , posX( 1.0, 0.0, 0.0 ) ; // gl_triangle strip // for ccw winding: top left, bottom left, top right, bottom right auto add_components = [ &]( const std::vector<Component::pointer_type>& vec ) { for ( auto& v : vec ) this->components.emplace_back( v ); }; add_components( Triangle::from_quad( std::vector<glm::vec3>( { blf, blr, brf, brr } ), negY, texture ) ); // bottom add_components( Triangle::from_quad( std::vector<glm::vec3>( { trr, brr, tlr, blr } ), negZ, texture ) ); // rear add_components( Triangle::from_quad( std::vector<glm::vec3>( { trf, brf, trr, brr } ), posX, texture ) ); // right posX add_components( Triangle::from_quad( std::vector<glm::vec3>( { tlr, blr, tlf, blf } ), negX, texture ) ); // left negX add_components( Triangle::from_quad( std::vector<glm::vec3>( { tlf, blf, trf, brf } ), posZ, texture ) ); // front posZ add_components( Triangle::from_quad( std::vector<glm::vec3>( { tlr, tlf, trr, trf } ), posY, texture ) ); // top posY }
address generate_call_stub(address& return_address) { assert (!TaggedStackInterpreter, "not supported"); StubCodeMark mark(this, "StubRoutines", "call_stub"); address start = __ enter(); const Register call_wrapper = r3; const Register result = r4; const Register result_type = r5; const Register method = r6; const Register entry_point = r7; const Register parameters = r8; const Register parameter_words = r9; const Register thread = r10; #ifdef ASSERT // Make sure we have no pending exceptions { StackFrame frame; Label label; __ load (r0, Address(thread, Thread::pending_exception_offset())); __ compare (r0, 0); __ beq (label); __ prolog (frame); __ should_not_reach_here (__FILE__, __LINE__); __ epilog (frame); __ blr (); __ bind (label); } #endif // ASSERT // Calculate the frame size StackFrame frame; for (int i = 0; i < StackFrame::max_crfs; i++) frame.get_cr_field(); for (int i = 0; i < StackFrame::max_gprs; i++) frame.get_register(); StubRoutines::set_call_stub_base_size(frame.unaligned_size() + 3*wordSize); // the 3 extra words are for call_wrapper, result and result_type const Register parameter_bytes = parameter_words; __ shift_left (parameter_bytes, parameter_words, LogBytesPerWord); const Register frame_size = r11; const Register padding = r12; __ addi (frame_size, parameter_bytes, StubRoutines::call_stub_base_size()); __ 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); #ifdef PPC64 __ mfcr (r0); __ store (r0, Address(r1, StackFrame::cr_save_offset * wordSize)); #endif // PPC64 // Calculate the address of the interpreter's local variables const Register locals = frame_size; __ addi (locals, r1, frame.start_of_locals() - wordSize); __ add (locals, locals, padding); __ add (locals, locals, parameter_bytes); // Store the call wrapper address and the result stuff const int initial_offset = 1; int offset = initial_offset; __ store (call_wrapper, Address(locals, offset++ * wordSize)); __ store (result, Address(locals, offset++ * wordSize)); __ store (result_type, Address(locals, offset++ * wordSize)); // Store the registers #ifdef PPC32 __ mfcr (r0); __ store (r0, Address(locals, offset++ * wordSize)); #endif // PPC32 for (int i = 14; i < 32; i++) { __ store (as_Register(i), Address(locals, offset++ * wordSize)); } const int final_offset = offset; // Store the location of call_wrapper frame::set_call_wrapper_offset((final_offset - initial_offset) * wordSize); #ifdef ASSERT // Check that we wrote all the way to the end of the frame. // The frame may have been resized when we return from the // interpreter, so the start of the frame may have moved // but the end will be where we left it and we rely on this // to find our stuff. { StackFrame frame; Label label; __ load (r3, Address(r1, 0)); __ subi (r3, r3, final_offset * wordSize); __ compare (r3, locals); __ beq (label); __ prolog (frame); __ should_not_reach_here (__FILE__, __LINE__); __ epilog (frame); __ blr (); __ bind (label); } #endif // ASSERT // Pass parameters if any { Label loop, done; __ compare (parameter_bytes, 0); __ ble (done); const Register src = parameters; const Register dst = padding; __ mr (dst, locals); __ shift_right (r0, parameter_bytes, LogBytesPerWord); __ mtctr (r0); __ bind (loop); __ load (r0, Address(src, 0)); __ store (r0, Address(dst, 0)); __ addi (src, src, wordSize); __ subi (dst, dst, wordSize); __ bdnz (loop); __ bind (done); } // Make the call __ mr (Rmethod, method); __ mr (Rlocals, locals); __ mr (Rthread, thread); __ mtctr (entry_point); __ bctrl(); // This is used to identify call_stub stack frames return_address = __ pc(); // Figure out where our stuff is stored __ load (locals, Address(r1, 0)); __ subi (locals, locals, final_offset * wordSize); #ifdef ASSERT // Rlocals should contain the address we just calculated. { StackFrame frame; Label label; __ compare (Rlocals, locals); __ beq (label); __ prolog (frame); __ should_not_reach_here (__FILE__, __LINE__); __ epilog (frame); __ blr (); __ bind (label); } #endif // ASSERT // Is an exception being thrown? Label exit; __ load (r0, Address(Rthread, Thread::pending_exception_offset())); __ compare (r0, 0); __ bne (exit); // Store result depending on type const Register result_addr = r6; Label is_int, is_long, is_object; offset = initial_offset + 1; // skip call_wrapper __ load (result_addr, Address(locals, offset++ * wordSize)); __ load (result_type, Address(locals, offset++ * wordSize)); __ compare (result_type, T_INT); __ beq (is_int); __ compare (result_type, T_LONG); __ beq (is_long); __ compare (result_type, T_OBJECT); __ beq (is_object); __ should_not_reach_here (__FILE__, __LINE__); __ bind (is_int); __ stw (r3, Address(result_addr, 0)); __ b (exit); __ bind (is_long); #ifdef PPC32 __ store (r4, Address(result_addr, wordSize)); #endif __ store (r3, Address(result_addr, 0)); __ b (exit); __ bind (is_object); __ store (r3, Address(result_addr, 0)); //__ b (exit); // Restore the registers __ bind (exit); #ifdef PPC32 __ load (r0, Address(locals, offset++ * wordSize)); __ mtcr (r0); #endif // PPC32 for (int i = 14; i < 32; i++) { __ load (as_Register(i), Address(locals, offset++ * wordSize)); } #ifdef PPC64 __ load (r0, Address(r1, StackFrame::cr_save_offset * wordSize)); __ mtcr (r0); #endif // PPC64 assert (offset == final_offset, "save and restore must match"); // Unwind and return __ load (r1, Address(r1, StackFrame::back_chain_offset * wordSize)); __ load (r0, Address(r1, StackFrame::lr_save_offset * wordSize)); __ mtlr (r0); __ blr (); return start; }
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; }
// 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; }
// Interpreter intrinsic for WeakReference.get(). // 1. Don't push a full blown frame and go on dispatching, but fetch the value // into R8 and return quickly // 2. If G1 is active we *must* execute this intrinsic for corrrectness: // It contains a GC barrier which puts the reference into the satb buffer // to indicate that someone holds a strong reference to the object the // weak ref points to! address InterpreterGenerator::generate_Reference_get_entry(void) { // Code: _aload_0, _getfield, _areturn // parameter size = 1 // // The code that gets generated by this routine is split into 2 parts: // 1. the "intrinsified" code for G1 (or any SATB based GC), // 2. the slow path - which is an expansion of the regular method entry. // // Notes: // * In the G1 code we do not check whether we need to block for // a safepoint. If G1 is enabled then we must execute the specialized // code for Reference.get (except when the Reference object is null) // so that we can log the value in the referent field with an SATB // update buffer. // If the code for the getfield template is modified so that the // G1 pre-barrier code is executed when the current method is // Reference.get() then going through the normal method entry // will be fine. // * The G1 code can, however, check the receiver object (the instance // of java.lang.Reference) and jump to the slow path if null. If the // Reference object is null then we obviously cannot fetch the referent // and so we don't need to call the G1 pre-barrier. Thus we can use the // regular method entry code to generate the NPE. // // This code is based on generate_accessor_enty. address entry = __ pc(); const int referent_offset = java_lang_ref_Reference::referent_offset; guarantee(referent_offset > 0, "referent offset not initialized"); if (UseG1GC) { Label slow_path; // Debugging not possible, so can't use __ skip_if_jvmti_mode(slow_path, GR31_SCRATCH); // In the G1 code we don't check if we need to reach a safepoint. We // continue and the thread will safepoint at the next bytecode dispatch. // If the receiver is null then it is OK to jump to the slow path. __ ld(R3_RET, Interpreter::stackElementSize, CC_INTERP_ONLY(R17_tos) NOT_CC_INTERP(R15_esp)); // get receiver // Check if receiver == NULL and go the slow path. __ cmpdi(CCR0, R3_RET, 0); __ beq(CCR0, slow_path); // Load the value of the referent field. __ load_heap_oop(R3_RET, referent_offset, R3_RET); // Generate the G1 pre-barrier code to log the value of // the referent field in an SATB buffer. Note with // these parameters the pre-barrier does not generate // the load of the previous value. // Restore caller sp for c2i case. #ifdef ASSERT __ ld(R9_ARG7, 0, R1_SP); __ ld(R10_ARG8, 0, R21_sender_SP); __ cmpd(CCR0, R9_ARG7, R10_ARG8); __ asm_assert_eq("backlink", 0x544); #endif // ASSERT __ mr(R1_SP, R21_sender_SP); // Cut the stack back to where the caller started. __ g1_write_barrier_pre(noreg, // obj noreg, // offset R3_RET, // pre_val R11_scratch1, // tmp R12_scratch2, // tmp true); // needs_frame __ blr(); // Generate regular method entry. __ bind(slow_path); __ branch_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals), R11_scratch1); __ flush(); return entry; } else { return generate_accessor_entry(); } }
address AbstractInterpreterGenerator::generate_slow_signature_handler() { // Slow_signature handler that respects the PPC C calling conventions. // // We get called by the native entry code with our output register // area == 8. First we call InterpreterRuntime::get_result_handler // to copy the pointer to the signature string temporarily to the // first C-argument and to return the result_handler in // R3_RET. Since native_entry will copy the jni-pointer to the // first C-argument slot later on, it is OK to occupy this slot // temporarilly. Then we copy the argument list on the java // expression stack into native varargs format on the native stack // and load arguments into argument registers. Integer arguments in // the varargs vector will be sign-extended to 8 bytes. // // On entry: // R3_ARG1 - intptr_t* Address of java argument list in memory. // R15_prev_state - BytecodeInterpreter* Address of interpreter state for // this method // R19_method // // On exit (just before return instruction): // R3_RET - contains the address of the result_handler. // R4_ARG2 - is not updated for static methods and contains "this" otherwise. // R5_ARG3-R10_ARG8: - When the (i-2)th Java argument is not of type float or double, // ARGi contains this argument. Otherwise, ARGi is not updated. // F1_ARG1-F13_ARG13 - contain the first 13 arguments of type float or double. const int LogSizeOfTwoInstructions = 3; // FIXME: use Argument:: GL: Argument names different numbers! const int max_fp_register_arguments = 13; const int max_int_register_arguments = 6; // first 2 are reserved const Register arg_java = R21_tmp1; const Register arg_c = R22_tmp2; const Register signature = R23_tmp3; // is string const Register sig_byte = R24_tmp4; const Register fpcnt = R25_tmp5; const Register argcnt = R26_tmp6; const Register intSlot = R27_tmp7; const Register target_sp = R28_tmp8; const FloatRegister floatSlot = F0; address entry = __ function_entry(); __ save_LR_CR(R0); __ save_nonvolatile_gprs(R1_SP, _spill_nonvolatiles_neg(r14)); // We use target_sp for storing arguments in the C frame. __ mr(target_sp, R1_SP); __ push_frame_reg_args_nonvolatiles(0, R11_scratch1); __ mr(arg_java, R3_ARG1); __ call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::get_signature), R16_thread, R19_method); // Signature is in R3_RET. Signature is callee saved. __ mr(signature, R3_RET); // Get the result handler. __ call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::get_result_handler), R16_thread, R19_method); { Label L; // test if static // _access_flags._flags must be at offset 0. // TODO PPC port: requires change in shared code. //assert(in_bytes(AccessFlags::flags_offset()) == 0, // "MethodDesc._access_flags == MethodDesc._access_flags._flags"); // _access_flags must be a 32 bit value. assert(sizeof(AccessFlags) == 4, "wrong size"); __ lwa(R11_scratch1/*access_flags*/, method_(access_flags)); // testbit with condition register. __ testbitdi(CCR0, R0, R11_scratch1/*access_flags*/, JVM_ACC_STATIC_BIT); __ btrue(CCR0, L); // For non-static functions, pass "this" in R4_ARG2 and copy it // to 2nd C-arg slot. // We need to box the Java object here, so we use arg_java // (address of current Java stack slot) as argument and don't // dereference it as in case of ints, floats, etc. __ mr(R4_ARG2, arg_java); __ addi(arg_java, arg_java, -BytesPerWord); __ std(R4_ARG2, _abi(carg_2), target_sp); __ bind(L); } // Will be incremented directly after loop_start. argcnt=0 // corresponds to 3rd C argument. __ li(argcnt, -1); // arg_c points to 3rd C argument __ addi(arg_c, target_sp, _abi(carg_3)); // no floating-point args parsed so far __ li(fpcnt, 0); Label move_intSlot_to_ARG, move_floatSlot_to_FARG; Label loop_start, loop_end; Label do_int, do_long, do_float, do_double, do_dontreachhere, do_object, do_array, do_boxed; // signature points to '(' at entry #ifdef ASSERT __ lbz(sig_byte, 0, signature); __ cmplwi(CCR0, sig_byte, '('); __ bne(CCR0, do_dontreachhere); #endif __ bind(loop_start); __ addi(argcnt, argcnt, 1); __ lbzu(sig_byte, 1, signature); __ cmplwi(CCR0, sig_byte, ')'); // end of signature __ beq(CCR0, loop_end); __ cmplwi(CCR0, sig_byte, 'B'); // byte __ beq(CCR0, do_int); __ cmplwi(CCR0, sig_byte, 'C'); // char __ beq(CCR0, do_int); __ cmplwi(CCR0, sig_byte, 'D'); // double __ beq(CCR0, do_double); __ cmplwi(CCR0, sig_byte, 'F'); // float __ beq(CCR0, do_float); __ cmplwi(CCR0, sig_byte, 'I'); // int __ beq(CCR0, do_int); __ cmplwi(CCR0, sig_byte, 'J'); // long __ beq(CCR0, do_long); __ cmplwi(CCR0, sig_byte, 'S'); // short __ beq(CCR0, do_int); __ cmplwi(CCR0, sig_byte, 'Z'); // boolean __ beq(CCR0, do_int); __ cmplwi(CCR0, sig_byte, 'L'); // object __ beq(CCR0, do_object); __ cmplwi(CCR0, sig_byte, '['); // array __ beq(CCR0, do_array); // __ cmplwi(CCR0, sig_byte, 'V'); // void cannot appear since we do not parse the return type // __ beq(CCR0, do_void); __ bind(do_dontreachhere); __ unimplemented("ShouldNotReachHere in slow_signature_handler", 120); __ bind(do_array); { Label start_skip, end_skip; __ bind(start_skip); __ lbzu(sig_byte, 1, signature); __ cmplwi(CCR0, sig_byte, '['); __ beq(CCR0, start_skip); // skip further brackets __ cmplwi(CCR0, sig_byte, '9'); __ bgt(CCR0, end_skip); // no optional size __ cmplwi(CCR0, sig_byte, '0'); __ bge(CCR0, start_skip); // skip optional size __ bind(end_skip); __ cmplwi(CCR0, sig_byte, 'L'); __ beq(CCR0, do_object); // for arrays of objects, the name of the object must be skipped __ b(do_boxed); // otherwise, go directly to do_boxed } __ bind(do_object); { Label L; __ bind(L); __ lbzu(sig_byte, 1, signature); __ cmplwi(CCR0, sig_byte, ';'); __ bne(CCR0, L); } // Need to box the Java object here, so we use arg_java (address of // current Java stack slot) as argument and don't dereference it as // in case of ints, floats, etc. Label do_null; __ bind(do_boxed); __ ld(R0,0, arg_java); __ cmpdi(CCR0, R0, 0); __ li(intSlot,0); __ beq(CCR0, do_null); __ mr(intSlot, arg_java); __ bind(do_null); __ std(intSlot, 0, arg_c); __ addi(arg_java, arg_java, -BytesPerWord); __ addi(arg_c, arg_c, BytesPerWord); __ cmplwi(CCR0, argcnt, max_int_register_arguments); __ blt(CCR0, move_intSlot_to_ARG); __ b(loop_start); __ bind(do_int); __ lwa(intSlot, 0, arg_java); __ std(intSlot, 0, arg_c); __ addi(arg_java, arg_java, -BytesPerWord); __ addi(arg_c, arg_c, BytesPerWord); __ cmplwi(CCR0, argcnt, max_int_register_arguments); __ blt(CCR0, move_intSlot_to_ARG); __ b(loop_start); __ bind(do_long); __ ld(intSlot, -BytesPerWord, arg_java); __ std(intSlot, 0, arg_c); __ addi(arg_java, arg_java, - 2 * BytesPerWord); __ addi(arg_c, arg_c, BytesPerWord); __ cmplwi(CCR0, argcnt, max_int_register_arguments); __ blt(CCR0, move_intSlot_to_ARG); __ b(loop_start); __ bind(do_float); __ lfs(floatSlot, 0, arg_java); #if defined(LINUX) // Linux uses ELF ABI. Both original ELF and ELFv2 ABIs have float // in the least significant word of an argument slot. #if defined(VM_LITTLE_ENDIAN) __ stfs(floatSlot, 0, arg_c); #else __ stfs(floatSlot, 4, arg_c); #endif #elif defined(AIX) // Although AIX runs on big endian CPU, float is in most significant // word of an argument slot. __ stfs(floatSlot, 0, arg_c); #else #error "unknown OS" #endif __ addi(arg_java, arg_java, -BytesPerWord); __ addi(arg_c, arg_c, BytesPerWord); __ cmplwi(CCR0, fpcnt, max_fp_register_arguments); __ blt(CCR0, move_floatSlot_to_FARG); __ b(loop_start); __ bind(do_double); __ lfd(floatSlot, - BytesPerWord, arg_java); __ stfd(floatSlot, 0, arg_c); __ addi(arg_java, arg_java, - 2 * BytesPerWord); __ addi(arg_c, arg_c, BytesPerWord); __ cmplwi(CCR0, fpcnt, max_fp_register_arguments); __ blt(CCR0, move_floatSlot_to_FARG); __ b(loop_start); __ bind(loop_end); __ pop_frame(); __ restore_nonvolatile_gprs(R1_SP, _spill_nonvolatiles_neg(r14)); __ restore_LR_CR(R0); __ blr(); Label move_int_arg, move_float_arg; __ bind(move_int_arg); // each case must consist of 2 instructions (otherwise adapt LogSizeOfTwoInstructions) __ mr(R5_ARG3, intSlot); __ b(loop_start); __ mr(R6_ARG4, intSlot); __ b(loop_start); __ mr(R7_ARG5, intSlot); __ b(loop_start); __ mr(R8_ARG6, intSlot); __ b(loop_start); __ mr(R9_ARG7, intSlot); __ b(loop_start); __ mr(R10_ARG8, intSlot); __ b(loop_start); __ bind(move_float_arg); // each case must consist of 2 instructions (otherwise adapt LogSizeOfTwoInstructions) __ fmr(F1_ARG1, floatSlot); __ b(loop_start); __ fmr(F2_ARG2, floatSlot); __ b(loop_start); __ fmr(F3_ARG3, floatSlot); __ b(loop_start); __ fmr(F4_ARG4, floatSlot); __ b(loop_start); __ fmr(F5_ARG5, floatSlot); __ b(loop_start); __ fmr(F6_ARG6, floatSlot); __ b(loop_start); __ fmr(F7_ARG7, floatSlot); __ b(loop_start); __ fmr(F8_ARG8, floatSlot); __ b(loop_start); __ fmr(F9_ARG9, floatSlot); __ b(loop_start); __ fmr(F10_ARG10, floatSlot); __ b(loop_start); __ fmr(F11_ARG11, floatSlot); __ b(loop_start); __ fmr(F12_ARG12, floatSlot); __ b(loop_start); __ fmr(F13_ARG13, floatSlot); __ b(loop_start); __ bind(move_intSlot_to_ARG); __ sldi(R0, argcnt, LogSizeOfTwoInstructions); __ load_const(R11_scratch1, move_int_arg); // Label must be bound here. __ add(R11_scratch1, R0, R11_scratch1); __ mtctr(R11_scratch1/*branch_target*/); __ bctr(); __ bind(move_floatSlot_to_FARG); __ sldi(R0, fpcnt, LogSizeOfTwoInstructions); __ addi(fpcnt, fpcnt, 1); __ load_const(R11_scratch1, move_float_arg); // Label must be bound here. __ add(R11_scratch1, R0, R11_scratch1); __ mtctr(R11_scratch1/*branch_target*/); __ bctr(); return entry; }
address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { const char *name; switch (type) { case T_BOOLEAN: name = "jni_fast_GetBooleanField"; break; case T_BYTE: name = "jni_fast_GetByteField"; break; case T_CHAR: name = "jni_fast_GetCharField"; break; case T_SHORT: name = "jni_fast_GetShortField"; break; case T_INT: name = "jni_fast_GetIntField"; break; case T_LONG: name = "jni_fast_GetLongField"; break; case T_FLOAT: name = "jni_fast_GetFloatField"; break; case T_DOUBLE: name = "jni_fast_GetDoubleField"; break; default: ShouldNotReachHere(); } ResourceMark rm; BufferBlob* blob = BufferBlob::create(name, BUFFER_SIZE); CodeBuffer cbuf(blob); MacroAssembler* masm = new MacroAssembler(&cbuf); address fast_entry = __ pc(); Label slow; unsigned long offset; __ adrp(rcounter_addr, SafepointSynchronize::safepoint_counter_addr(), offset); Address safepoint_counter_addr(rcounter_addr, offset); __ ldrw(rcounter, safepoint_counter_addr); __ andw(rscratch1, rcounter, 1); __ cbnzw(rscratch1, slow); __ eor(robj, c_rarg1, rcounter); __ eor(robj, robj, rcounter); // obj, since // robj ^ rcounter ^ rcounter == robj // robj is address dependent on rcounter. __ ldr(robj, Address(robj, 0)); // *obj __ lsr(roffset, c_rarg2, 2); // offset assert(count < LIST_CAPACITY, "LIST_CAPACITY too small"); speculative_load_pclist[count] = __ pc(); // Used by the segfault handler switch (type) { case T_BOOLEAN: __ ldrb (result, Address(robj, roffset)); break; case T_BYTE: __ ldrsb (result, Address(robj, roffset)); break; case T_CHAR: __ ldrh (result, Address(robj, roffset)); break; case T_SHORT: __ ldrsh (result, Address(robj, roffset)); break; case T_FLOAT: __ ldrw (result, Address(robj, roffset)); break; case T_INT: __ ldrsw (result, Address(robj, roffset)); break; case T_DOUBLE: case T_LONG: __ ldr (result, Address(robj, roffset)); break; default: ShouldNotReachHere(); } // counter_addr is address dependent on result. __ eor(rcounter_addr, rcounter_addr, result); __ eor(rcounter_addr, rcounter_addr, result); __ ldrw(rscratch1, safepoint_counter_addr); __ cmpw(rcounter, rscratch1); __ br (Assembler::NE, slow); switch (type) { case T_FLOAT: __ fmovs(v0, result); break; case T_DOUBLE: __ fmovd(v0, result); break; default: __ mov(r0, result); break; } __ ret(lr); slowcase_entry_pclist[count++] = __ pc(); __ bind(slow); address slow_case_addr; switch (type) { case T_BOOLEAN: slow_case_addr = jni_GetBooleanField_addr(); break; case T_BYTE: slow_case_addr = jni_GetByteField_addr(); break; case T_CHAR: slow_case_addr = jni_GetCharField_addr(); break; case T_SHORT: slow_case_addr = jni_GetShortField_addr(); break; case T_INT: slow_case_addr = jni_GetIntField_addr(); break; case T_LONG: slow_case_addr = jni_GetLongField_addr(); break; case T_FLOAT: slow_case_addr = jni_GetFloatField_addr(); break; case T_DOUBLE: slow_case_addr = jni_GetDoubleField_addr(); break; default: ShouldNotReachHere(); } { __ enter(); __ lea(rscratch1, ExternalAddress(slow_case_addr)); __ blr(rscratch1); __ maybe_isb(); __ leave(); __ ret(lr); } __ flush (); return fast_entry; }