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; }
//------------------------------------------------------------------------------------------------------------------------ // Call stubs are used to call Java from C // // GR_I0 - call wrapper address : address // GR_I1 - result : intptr_t* // GR_I2 - result type : BasicType // GR_I3 - method : methodOop // GR_I4 - interpreter entry point : address // GR_I5 - parameter block : intptr_t* // GR_I6 - parameter count in words : int // GR_I7 - thread : Thread* // address generate_call_stub(address& return_address) { StubCodeMark mark(this, "StubRoutines", "call_stub"); const Register result = GR_I1; const Register type = GR_I2; const Register method = GR_I3; const Register entry_ptr = GR_I4; const Register parms = GR_I5; const Register parm_count = GR_I6; const Register thread = GR_I7; const Register parm_size = GR31_SCRATCH; const Register entry = GR30_SCRATCH; const Register arg = GR29_SCRATCH; const Register out_tos = GR49; // Equivalent of GR_Otos const Register out_parms = GR50; // Equivalent of GR_Olocals (unused) const BranchRegister entry_br = BR6_SCRATCH; const PredicateRegister no_args = PR6_SCRATCH; address start = __ emit_fd(); // Must allocate 8 output registers in case we go thru an i2c // and the callee needs 8 input registers __ alloc(GR_Lsave_PFS, 8, 9, 8, 0); // save AR_PFS __ sxt4(parm_count, parm_count); // # of parms __ mov(GR_Lsave_SP, SP); // save caller's SP __ mov(GR_entry_frame_GR5, GR5_poll_page_addr); __ mov(GR_entry_frame_GR6, GR6_caller_BSP); __ mov(GR_entry_frame_GR7, GR7_reg_stack_limit); // We can not tolerate an eager RSE cpu. Itanium-1 & 2 do not support // this feature but we turn it off anyway const Register RSC = GR2_SCRATCH; __ mov(RSC, AR_RSC); __ and3(RSC, -4, RSC); // Turn off two low bits __ mov(AR_RSC, RSC); // enforced lazy mode __ shladd(parm_size, parm_count, Interpreter::logStackElementSize(), GR0); // size of stack space for the parms __ mov(GR_Lsave_RP, RP); // save return address __ add(parm_size, parm_size, 15); // round up to multiple of 16 bytes. we use // caller's 16-byte scratch area for params, // so no need to add 16 to the current frame size. __ mov(GR_Lsave_LC, AR_LC); // save AR_LC __ add(out_parms, SP, Interpreter::stackElementSize()); // caller's SP+8 is 1st parm addr == target method locals addr __ and3(parm_size, parm_size, -16); __ cmp4(PR0, no_args, 0, parm_count, Assembler::less); // any parms? __ mov(GR_entry_frame_GR4, GR4_thread); // save GR4_thread: it's a preserved register __ sub(SP, SP, parm_size); // allocate the space for args + scratch __ mov(entry_br, entry_ptr); __ mov(GR27_method, method); // load method __ mov(GR4_thread, thread); // load thread if (TaggedStackInterpreter) __ shl(parm_count, parm_count, 1); // 2x tags __ sub(parm_count, parm_count, 1); // cloop counts down to zero // Initialize the register and memory stack limits for stack checking in compiled code __ add(GR7_reg_stack_limit, thread_(register_stack_limit)); __ mov(GR6_caller_BSP, AR_BSP); // load register SP __ movl(GR5_poll_page_addr, (intptr_t) os::get_polling_page() ); __ ld8(GR7_reg_stack_limit, GR7_reg_stack_limit); // load register stack limit Label exit; __ mov(AR_LC, parm_count); __ mov(out_tos, out_parms); // out_tos = &out_parms[0] __ br(no_args, exit, Assembler::dpnt); // Reverse argument list and set up sender tos Label copy_word; __ bind(copy_word); __ ld8(arg, parms, BytesPerWord); // load *parms++ __ st8(out_tos, arg, -BytesPerWord); // store *out_tos-- __ cloop(copy_word, Assembler::sptk, Assembler::few); // Bias stack for tags. if (TaggedStackInterpreter) __ st8(out_tos, GR0, -BytesPerWord); __ bind(exit); __ mov(GR_entry_frame_TOS, out_tos); // so entry_frame_argument_at can find TOS // call interpreter frame manager // Remember the senderSP so we interpreter can pop c2i arguments off of the stack // when called via a c2i. __ mov(GR28_sender_SP, SP); __ call(entry_br); return_address = __ pc(); // Store result depending on type. Everything that is not // T_OBJECT, T_LONG, T_FLOAT, or T_DOUBLE is treated as T_INT. const PredicateRegister is_obj = PR6_SCRATCH; const PredicateRegister is_flt = PR7_SCRATCH; const PredicateRegister is_dbl = PR8_SCRATCH; const PredicateRegister is_lng = PR9_SCRATCH; __ cmp4(is_obj, PR0, T_OBJECT, type, Assembler::equal); __ cmp4(is_flt, PR0, T_FLOAT, type, Assembler::equal); __ st4( result, GR_RET); __ st8( is_obj, result, GR_RET); __ stfs(is_flt, result, FR_RET); __ cmp4(is_dbl, PR0, T_DOUBLE, type, Assembler::equal); __ stfd(is_dbl, result, FR_RET); __ cmp4(is_lng, PR0, T_LONG, type, Assembler::equal); __ mov(RP, GR_Lsave_RP); __ st8( is_lng, result, GR_RET); __ mov(GR4_thread, GR_entry_frame_GR4); __ mov(GR6_caller_BSP, GR_entry_frame_GR6); __ mov(GR7_reg_stack_limit, GR_entry_frame_GR7); __ mov(GR5_poll_page_addr, GR_entry_frame_GR5); __ mov(AR_PFS, GR_Lsave_PFS); __ mov(AR_LC, GR_Lsave_LC); __ mov(SP, GR_Lsave_SP); __ ret(); return start; }
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; }