src/cpu/x86/vm/sharedRuntime_x86_32.cpp

changeset 3969
1d7922586cf6
parent 3500
0382d2b469b2
child 4037
da91efe96a93
     1.1 --- a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp	Mon Jul 23 13:04:59 2012 -0700
     1.2 +++ b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp	Tue Jul 24 10:51:00 2012 -0700
     1.3 @@ -643,6 +643,19 @@
     1.4    __ movdbl(r, Address(saved_sp, next_val_off));
     1.5  }
     1.6  
     1.7 +static void range_check(MacroAssembler* masm, Register pc_reg, Register temp_reg,
     1.8 +                        address code_start, address code_end,
     1.9 +                        Label& L_ok) {
    1.10 +  Label L_fail;
    1.11 +  __ lea(temp_reg, ExternalAddress(code_start));
    1.12 +  __ cmpptr(pc_reg, temp_reg);
    1.13 +  __ jcc(Assembler::belowEqual, L_fail);
    1.14 +  __ lea(temp_reg, ExternalAddress(code_end));
    1.15 +  __ cmpptr(pc_reg, temp_reg);
    1.16 +  __ jcc(Assembler::below, L_ok);
    1.17 +  __ bind(L_fail);
    1.18 +}
    1.19 +
    1.20  static void gen_i2c_adapter(MacroAssembler *masm,
    1.21                              int total_args_passed,
    1.22                              int comp_args_on_stack,
    1.23 @@ -653,9 +666,53 @@
    1.24    // we may do a i2c -> c2i transition if we lose a race where compiled
    1.25    // code goes non-entrant while we get args ready.
    1.26  
    1.27 +  // Adapters can be frameless because they do not require the caller
    1.28 +  // to perform additional cleanup work, such as correcting the stack pointer.
    1.29 +  // An i2c adapter is frameless because the *caller* frame, which is interpreted,
    1.30 +  // routinely repairs its own stack pointer (from interpreter_frame_last_sp),
    1.31 +  // even if a callee has modified the stack pointer.
    1.32 +  // A c2i adapter is frameless because the *callee* frame, which is interpreted,
    1.33 +  // routinely repairs its caller's stack pointer (from sender_sp, which is set
    1.34 +  // up via the senderSP register).
    1.35 +  // In other words, if *either* the caller or callee is interpreted, we can
    1.36 +  // get the stack pointer repaired after a call.
    1.37 +  // This is why c2i and i2c adapters cannot be indefinitely composed.
    1.38 +  // In particular, if a c2i adapter were to somehow call an i2c adapter,
    1.39 +  // both caller and callee would be compiled methods, and neither would
    1.40 +  // clean up the stack pointer changes performed by the two adapters.
    1.41 +  // If this happens, control eventually transfers back to the compiled
    1.42 +  // caller, but with an uncorrected stack, causing delayed havoc.
    1.43 +
    1.44    // Pick up the return address
    1.45    __ movptr(rax, Address(rsp, 0));
    1.46  
    1.47 +  if (VerifyAdapterCalls &&
    1.48 +      (Interpreter::code() != NULL || StubRoutines::code1() != NULL)) {
    1.49 +    // So, let's test for cascading c2i/i2c adapters right now.
    1.50 +    //  assert(Interpreter::contains($return_addr) ||
    1.51 +    //         StubRoutines::contains($return_addr),
    1.52 +    //         "i2c adapter must return to an interpreter frame");
    1.53 +    __ block_comment("verify_i2c { ");
    1.54 +    Label L_ok;
    1.55 +    if (Interpreter::code() != NULL)
    1.56 +      range_check(masm, rax, rdi,
    1.57 +                  Interpreter::code()->code_start(), Interpreter::code()->code_end(),
    1.58 +                  L_ok);
    1.59 +    if (StubRoutines::code1() != NULL)
    1.60 +      range_check(masm, rax, rdi,
    1.61 +                  StubRoutines::code1()->code_begin(), StubRoutines::code1()->code_end(),
    1.62 +                  L_ok);
    1.63 +    if (StubRoutines::code2() != NULL)
    1.64 +      range_check(masm, rax, rdi,
    1.65 +                  StubRoutines::code2()->code_begin(), StubRoutines::code2()->code_end(),
    1.66 +                  L_ok);
    1.67 +    const char* msg = "i2c adapter must return to an interpreter frame";
    1.68 +    __ block_comment(msg);
    1.69 +    __ stop(msg);
    1.70 +    __ bind(L_ok);
    1.71 +    __ block_comment("} verify_i2ce ");
    1.72 +  }
    1.73 +
    1.74    // Must preserve original SP for loading incoming arguments because
    1.75    // we need to align the outgoing SP for compiled code.
    1.76    __ movptr(rdi, rsp);
    1.77 @@ -1293,6 +1350,89 @@
    1.78    __ bind(done);
    1.79  }
    1.80  
    1.81 +static void verify_oop_args(MacroAssembler* masm,
    1.82 +                            int total_args_passed,
    1.83 +                            const BasicType* sig_bt,
    1.84 +                            const VMRegPair* regs) {
    1.85 +  Register temp_reg = rbx;  // not part of any compiled calling seq
    1.86 +  if (VerifyOops) {
    1.87 +    for (int i = 0; i < total_args_passed; i++) {
    1.88 +      if (sig_bt[i] == T_OBJECT ||
    1.89 +          sig_bt[i] == T_ARRAY) {
    1.90 +        VMReg r = regs[i].first();
    1.91 +        assert(r->is_valid(), "bad oop arg");
    1.92 +        if (r->is_stack()) {
    1.93 +          __ movptr(temp_reg, Address(rsp, r->reg2stack() * VMRegImpl::stack_slot_size + wordSize));
    1.94 +          __ verify_oop(temp_reg);
    1.95 +        } else {
    1.96 +          __ verify_oop(r->as_Register());
    1.97 +        }
    1.98 +      }
    1.99 +    }
   1.100 +  }
   1.101 +}
   1.102 +
   1.103 +static void gen_special_dispatch(MacroAssembler* masm,
   1.104 +                                 int total_args_passed,
   1.105 +                                 int comp_args_on_stack,
   1.106 +                                 vmIntrinsics::ID special_dispatch,
   1.107 +                                 const BasicType* sig_bt,
   1.108 +                                 const VMRegPair* regs) {
   1.109 +  verify_oop_args(masm, total_args_passed, sig_bt, regs);
   1.110 +
   1.111 +  // Now write the args into the outgoing interpreter space
   1.112 +  bool     has_receiver   = false;
   1.113 +  Register receiver_reg   = noreg;
   1.114 +  int      member_arg_pos = -1;
   1.115 +  Register member_reg     = noreg;
   1.116 +  int      ref_kind       = MethodHandles::signature_polymorphic_intrinsic_ref_kind(special_dispatch);
   1.117 +  if (ref_kind != 0) {
   1.118 +    member_arg_pos = total_args_passed - 1;  // trailing MemberName argument
   1.119 +    member_reg = rbx;  // known to be free at this point
   1.120 +    has_receiver = MethodHandles::ref_kind_has_receiver(ref_kind);
   1.121 +  } else if (special_dispatch == vmIntrinsics::_invokeBasic) {
   1.122 +    has_receiver = true;
   1.123 +  } else {
   1.124 +    guarantee(false, err_msg("special_dispatch=%d", special_dispatch));
   1.125 +  }
   1.126 +
   1.127 +  if (member_reg != noreg) {
   1.128 +    // Load the member_arg into register, if necessary.
   1.129 +    assert(member_arg_pos >= 0 && member_arg_pos < total_args_passed, "oob");
   1.130 +    assert(sig_bt[member_arg_pos] == T_OBJECT, "dispatch argument must be an object");
   1.131 +    VMReg r = regs[member_arg_pos].first();
   1.132 +    assert(r->is_valid(), "bad member arg");
   1.133 +    if (r->is_stack()) {
   1.134 +      __ movptr(member_reg, Address(rsp, r->reg2stack() * VMRegImpl::stack_slot_size + wordSize));
   1.135 +    } else {
   1.136 +      // no data motion is needed
   1.137 +      member_reg = r->as_Register();
   1.138 +    }
   1.139 +  }
   1.140 +
   1.141 +  if (has_receiver) {
   1.142 +    // Make sure the receiver is loaded into a register.
   1.143 +    assert(total_args_passed > 0, "oob");
   1.144 +    assert(sig_bt[0] == T_OBJECT, "receiver argument must be an object");
   1.145 +    VMReg r = regs[0].first();
   1.146 +    assert(r->is_valid(), "bad receiver arg");
   1.147 +    if (r->is_stack()) {
   1.148 +      // Porting note:  This assumes that compiled calling conventions always
   1.149 +      // pass the receiver oop in a register.  If this is not true on some
   1.150 +      // platform, pick a temp and load the receiver from stack.
   1.151 +      assert(false, "receiver always in a register");
   1.152 +      receiver_reg = rcx;  // known to be free at this point
   1.153 +      __ movptr(receiver_reg, Address(rsp, r->reg2stack() * VMRegImpl::stack_slot_size + wordSize));
   1.154 +    } else {
   1.155 +      // no data motion is needed
   1.156 +      receiver_reg = r->as_Register();
   1.157 +    }
   1.158 +  }
   1.159 +
   1.160 +  // Figure out which address we are really jumping to:
   1.161 +  MethodHandles::generate_method_handle_dispatch(masm, special_dispatch,
   1.162 +                                                 receiver_reg, member_reg, /*for_compiler_entry:*/ true);
   1.163 +}
   1.164  
   1.165  // ---------------------------------------------------------------------------
   1.166  // Generate a native wrapper for a given method.  The method takes arguments
   1.167 @@ -1323,14 +1463,37 @@
   1.168  //    transition back to thread_in_Java
   1.169  //    return to caller
   1.170  //
   1.171 -nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
   1.172 +nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
   1.173                                                  methodHandle method,
   1.174                                                  int compile_id,
   1.175                                                  int total_in_args,
   1.176                                                  int comp_args_on_stack,
   1.177 -                                                BasicType *in_sig_bt,
   1.178 -                                                VMRegPair *in_regs,
   1.179 +                                                BasicType* in_sig_bt,
   1.180 +                                                VMRegPair* in_regs,
   1.181                                                  BasicType ret_type) {
   1.182 +  if (method->is_method_handle_intrinsic()) {
   1.183 +    vmIntrinsics::ID iid = method->intrinsic_id();
   1.184 +    intptr_t start = (intptr_t)__ pc();
   1.185 +    int vep_offset = ((intptr_t)__ pc()) - start;
   1.186 +    gen_special_dispatch(masm,
   1.187 +                         total_in_args,
   1.188 +                         comp_args_on_stack,
   1.189 +                         method->intrinsic_id(),
   1.190 +                         in_sig_bt,
   1.191 +                         in_regs);
   1.192 +    int frame_complete = ((intptr_t)__ pc()) - start;  // not complete, period
   1.193 +    __ flush();
   1.194 +    int stack_slots = SharedRuntime::out_preserve_stack_slots();  // no out slots at all, actually
   1.195 +    return nmethod::new_native_nmethod(method,
   1.196 +                                       compile_id,
   1.197 +                                       masm->code(),
   1.198 +                                       vep_offset,
   1.199 +                                       frame_complete,
   1.200 +                                       stack_slots / VMRegImpl::slots_per_word,
   1.201 +                                       in_ByteSize(-1),
   1.202 +                                       in_ByteSize(-1),
   1.203 +                                       (OopMapSet*)NULL);
   1.204 +  }
   1.205    bool is_critical_native = true;
   1.206    address native_func = method->critical_native_function();
   1.207    if (native_func == NULL) {
   1.208 @@ -1436,7 +1599,7 @@
   1.209        if (in_regs[i].first()->is_Register()) {
   1.210          const Register reg = in_regs[i].first()->as_Register();
   1.211          switch (in_sig_bt[i]) {
   1.212 -          case T_ARRAY:
   1.213 +          case T_ARRAY:  // critical array (uses 2 slots on LP64)
   1.214            case T_BOOLEAN:
   1.215            case T_BYTE:
   1.216            case T_SHORT:

mercurial