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;
}
Beispiel #2
0
  //------------------------------------------------------------------------------------------------------------------------
  // 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;
  }
Beispiel #3
0
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;
}