< prev index next >

src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp

Print this page
*** 625,15 ***
  
  // Note: the INPUTS in sig_bt are in units of Java argument words, which are
  // either 32-bit or 64-bit depending on the build. The OUTPUTS are in 32-bit
  // units regardless of build. Of course for i486 there is no 64 bit build
  
! // The Java calling convention is a "shifted" version of the C ABI.
! // By skipping the first C ABI register we can call non-static jni methods
- // with small numbers of arguments without having to shuffle the arguments
- // at all. Since we control the java ABI we ought to at least get some
- // advantage out of it.
  
  const VMReg java_iarg_reg[8] = {
    R3->as_VMReg(),
    R4->as_VMReg(),
    R5->as_VMReg(),
--- 625,12 ---
  
  // Note: the INPUTS in sig_bt are in units of Java argument words, which are
  // either 32-bit or 64-bit depending on the build. The OUTPUTS are in 32-bit
  // units regardless of build. Of course for i486 there is no 64 bit build
  
! // In contrast to other platforms the Java calling convention is *NOT* a
! // "shifted" version of the C ABI.
  
  const VMReg java_iarg_reg[8] = {
    R3->as_VMReg(),
    R4->as_VMReg(),
    R5->as_VMReg(),

*** 769,10 ***
--- 766,91 ---
      }
    }
    return stk;
  }
  
+ // Similar to java_calling_convention() but for multiple return
+ // values. There's no way to store them on the stack so if we don't
+ // have enough registers, multiple values can't be returned.
+ const uint SharedRuntime::java_return_convention_max_int = Argument::n_int_register_parameters_j;
+ const uint SharedRuntime::java_return_convention_max_float = Argument::n_float_register_parameters_j;
+ int SharedRuntime::java_return_convention(const BasicType *sig_bt,
+                                           VMRegPair *regs,
+                                           int total_args_passed) {
+   // Create the mapping between argument positions and
+   // registers.
+   static const Register INT_ArgReg[java_return_convention_max_int] = {
+     R3_RET, R10_ARG8, R9_ARG7, R8_ARG6, R7_ARG5, R6_ARG4, R5_ARG3, R4_ARG2
+   };
+   static const FloatRegister FP_ArgReg[java_return_convention_max_float] = {
+     F1_RET, F2_ARG2, F3_ARG3, F4_ARG4, F5_ARG5, F6_ARG6, F7_ARG7, F8_ARG8,
+     F9_ARG9, F10_ARG10, F11_ARG11, F12_ARG12, F13_ARG13
+   };
+ 
+ 
+   uint int_args = 0;
+   uint fp_args = 0;
+ 
+   for (int i = 0; i < total_args_passed; i++) {
+     switch (sig_bt[i]) {
+     case T_BOOLEAN:
+     case T_CHAR:
+     case T_BYTE:
+     case T_SHORT:
+     case T_INT:
+       if (int_args < java_return_convention_max_int) {
+         regs[i].set1(INT_ArgReg[int_args]->as_VMReg());
+         int_args++;
+       } else {
+         return -1;
+       }
+       break;
+     case T_VOID:
+       // halves of T_LONG or T_DOUBLE
+       assert(i != 0 && (sig_bt[i - 1] == T_LONG || sig_bt[i - 1] == T_DOUBLE), "expecting half");
+       regs[i].set_bad();
+       break;
+     case T_LONG:
+       assert(sig_bt[i + 1] == T_VOID, "expecting half");
+       // fall through
+     case T_OBJECT:
+     case T_ARRAY:
+     case T_ADDRESS:
+     case T_METADATA:
+       if (int_args < java_return_convention_max_int) {
+         regs[i].set2(INT_ArgReg[int_args]->as_VMReg());
+         int_args++;
+       } else {
+         return -1;
+       }
+       break;
+     case T_FLOAT:
+       if (fp_args < java_return_convention_max_float) {
+         regs[i].set1(FP_ArgReg[fp_args]->as_VMReg());
+         fp_args++;
+       } else {
+         return -1;
+       }
+       break;
+     case T_DOUBLE:
+       assert(sig_bt[i + 1] == T_VOID, "expecting half");
+       if (fp_args < java_return_convention_max_float) {
+         regs[i].set2(FP_ArgReg[fp_args]->as_VMReg());
+         fp_args++;
+       } else {
+         return -1;
+       }
+       break;
+     default:
+       ShouldNotReachHere();
+       break;
+     }
+   }
+ 
+   return int_args + fp_args;
+ }
+ 
  // Calling convention for calling C code.
  int SharedRuntime::c_calling_convention(const BasicType *sig_bt,
                                          VMRegPair *regs,
                                          int total_args_passed) {
    // Calling conventions for C runtime calls and calls to JNI native methods.

*** 914,74 ***
                                               uint total_args_passed) {
    Unimplemented();
    return 0;
  }
  
! static address gen_c2i_adapter(MacroAssembler *masm,
!                             int total_args_passed,
!                             int comp_args_on_stack,
!                             const BasicType *sig_bt,
!                             const VMRegPair *regs,
!                             Label& call_interpreter,
-                             const Register& ientry) {
- 
-   address c2i_entrypoint;
- 
-   const Register sender_SP = R21_sender_SP; // == R21_tmp1
-   const Register code      = R22_tmp2;
-   //const Register ientry  = R23_tmp3;
-   const Register value_regs[] = { R24_tmp4, R25_tmp5, R26_tmp6 };
-   const int num_value_regs = sizeof(value_regs) / sizeof(Register);
-   int value_regs_index = 0;
- 
-   const Register return_pc = R27_tmp7;
-   const Register tmp       = R28_tmp8;
- 
-   assert_different_registers(sender_SP, code, ientry, return_pc, tmp);
- 
-   // Adapter needs TOP_IJAVA_FRAME_ABI.
-   const int adapter_size = frame::top_ijava_frame_abi_size +
-                            align_up(total_args_passed * wordSize, frame::alignment_in_bytes);
- 
-   // regular (verified) c2i entry point
-   c2i_entrypoint = __ pc();
- 
-   // Does compiled code exists? If yes, patch the caller's callsite.
-   __ ld(code, method_(code));
-   __ cmpdi(CR0, code, 0);
-   __ ld(ientry, method_(interpreter_entry)); // preloaded
-   __ beq(CR0, call_interpreter);
- 
  
    // Patch caller's callsite, method_(code) was not null which means that
    // compiled code exists.
    __ mflr(return_pc);
    __ std(return_pc, _abi0(lr), R1_SP);
    RegisterSaver::push_frame_and_save_argument_registers(masm, tmp, adapter_size, total_args_passed, regs);
  
    __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::fixup_callers_callsite), R19_method, return_pc);
  
    RegisterSaver::restore_argument_registers_and_pop_frame(masm, adapter_size, total_args_passed, regs);
    __ ld(return_pc, _abi0(lr), R1_SP);
-   __ ld(ientry, method_(interpreter_entry)); // preloaded
    __ mtlr(return_pc);
  
  
    // Call the interpreter.
!   __ BIND(call_interpreter);
    __ mtctr(ientry);
  
    // Get a copy of the current SP for loading caller's arguments.
!   __ mr(sender_SP, R1_SP);
  
    // Add space for the adapter.
    __ resize_frame(-adapter_size, R12_scratch2);
  
    int st_off = adapter_size - wordSize;
  
    // Write the args into the outgoing interpreter space.
    for (int i = 0; i < total_args_passed; i++) {
      VMReg r_1 = regs[i].first();
      VMReg r_2 = regs[i].second();
      if (!r_1->is_valid()) {
        assert(!r_2->is_valid(), "");
        continue;
--- 992,165 ---
                                               uint total_args_passed) {
    Unimplemented();
    return 0;
  }
  
! // Patch the callers callsite with entry to compiled code if it exists.
! static void patch_callers_callsite(MacroAssembler *masm, int adapter_size, int total_args_passed, const VMRegPair *regs) {
!   Label L;
!   __ ld(R0, in_bytes(Method::code_offset()), R19_method);
!   __ cmpdi(CR0, R0, 0);
!   __ beq(CR0, L);
  
    // Patch caller's callsite, method_(code) was not null which means that
    // compiled code exists.
+   const Register return_pc = R11_scratch1;
+   const Register tmp       = R12_scratch2;
    __ mflr(return_pc);
    __ std(return_pc, _abi0(lr), R1_SP);
    RegisterSaver::push_frame_and_save_argument_registers(masm, tmp, adapter_size, total_args_passed, regs);
  
    __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::fixup_callers_callsite), R19_method, return_pc);
  
    RegisterSaver::restore_argument_registers_and_pop_frame(masm, adapter_size, total_args_passed, regs);
    __ ld(return_pc, _abi0(lr), R1_SP);
    __ mtlr(return_pc);
  
+   // callsite->set_to_clean() uses icache flush including isync
+ 
+   __ bind(L);
+ }
+ 
+ // For each inline type argument, sig includes the list of fields of
+ // the inline type. This utility function computes the number of
+ // arguments for the call if inline types are passed by reference (the
+ // calling convention the interpreter expects).
+ static int compute_total_args_passed_int(const GrowableArray<SigEntry>* sig_extended) {
+   int total_args_passed = 0;
+   if (InlineTypePassFieldsAsArgs) {
+     for (int i = 0; i < sig_extended->length(); i++) {
+       BasicType bt = sig_extended->at(i)._bt;
+       if (bt == T_METADATA) {
+         // In sig_extended, an inline type argument starts with:
+         // T_METADATA, followed by the types of the fields of the
+         // inline type and T_VOID to mark the end of the value
+         // type. Inline types are flattened so, for instance, in the
+         // case of an inline type with an int field and an inline type
+         // field that itself has 2 fields, an int and a long:
+         // T_METADATA T_INT T_METADATA T_INT T_LONG T_VOID (second
+         // slot for the T_LONG) T_VOID (inner inline type) T_VOID
+         // (outer inline type)
+         total_args_passed++;
+         int vt = 1;
+         do {
+           i++;
+           BasicType bt = sig_extended->at(i)._bt;
+           BasicType prev_bt = sig_extended->at(i-1)._bt;
+           if (bt == T_METADATA) {
+             vt++;
+           } else if (bt == T_VOID &&
+                      prev_bt != T_LONG &&
+                      prev_bt != T_DOUBLE) {
+             vt--;
+           }
+         } while (vt != 0);
+       } else {
+         total_args_passed++;
+       }
+     }
+   } else {
+     total_args_passed = sig_extended->length();
+   }
+   return total_args_passed;
+ }
+ 
+ static void gen_c2i_adapter(MacroAssembler *masm,
+                             const GrowableArray<SigEntry>* sig_extended,
+                             const VMRegPair *regs,
+                             bool requires_clinit_barrier,
+                             address& c2i_no_clinit_check_entry,
+                             Label& skip_fixup,
+                             address start,
+                             OopMapSet* oop_maps,
+                             int& frame_complete,
+                             int& frame_size_in_words,
+                             bool alloc_inline_receiver) {
+   if (requires_clinit_barrier) {
+     assert(VM_Version::supports_fast_class_init_checks(), "sanity");
+     Label L_skip_barrier;
+ 
+     // Bypass the barrier for non-static methods
+     __ lhz(R0, in_bytes(Method::access_flags_offset()), R19_method);
+     __ andi_(R0, R0, JVM_ACC_STATIC);
+     __ beq(CR0, L_skip_barrier); // non-static
+ 
+     Register klass = R11_scratch1;
+     __ load_method_holder(klass, R19_method);
+     __ clinit_barrier(klass, R16_thread, &L_skip_barrier /*L_fast_path*/);
+ 
+     __ load_const_optimized(klass, SharedRuntime::get_handle_wrong_method_stub(), R0);
+     __ mtctr(klass);
+     __ bctr();
+ 
+     __ bind(L_skip_barrier);
+     c2i_no_clinit_check_entry = __ pc();
+   }
+ 
+   BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
+   bs->c2i_entry_barrier(masm, R11_scratch1, R12_scratch2, R21_tmp1);
+ 
+   // Since all args are passed on the stack, total_args_passed *
+   // Interpreter::stackElementSize is the space we need.
+   int total_args_passed = compute_total_args_passed_int(sig_extended);
+   assert(total_args_passed >= 0, "total_args_passed is %d", total_args_passed);
+ 
+     // Adapter needs TOP_IJAVA_FRAME_ABI.
+   const int adapter_size = frame::top_ijava_frame_abi_size +
+                            align_up(total_args_passed * wordSize, frame::alignment_in_bytes);
+ 
+   // Before we get into the guts of the C2I adapter, see if we should be here
+   // at all.  We've come from compiled code and are attempting to jump to the
+   // interpreter, which means the caller made a static call to get here
+   // (vcalls always get a compiled target if there is one).  Check for a
+   // compiled target.  If there is one, we need to patch the caller's call.
+   patch_callers_callsite(masm, adapter_size, total_args_passed, regs);
+ 
+   __ bind(skip_fixup);
+ 
+   if (InlineTypePassFieldsAsArgs) {
+     // Is there an inline type argument?
+     bool has_inline_argument = false;
+     for (int i = 0; i < sig_extended->length() && !has_inline_argument; i++) {
+       has_inline_argument = (sig_extended->at(i)._bt == T_METADATA);
+     }
+     if (has_inline_argument) {
+       __ unimplemented("c2i has_inline_argument");
+     }
+   }
  
    // Call the interpreter.
!   const Register tmp = R22_tmp2, ientry = R23_tmp3;
+   const Register value_regs[] = { R24_tmp4, R25_tmp5, R26_tmp6 };
+   const int num_value_regs = sizeof(value_regs) / sizeof(Register);
+   int value_regs_index = 0;
+ 
+   __ ld(ientry, method_(interpreter_entry)); // preloaded
    __ mtctr(ientry);
  
    // Get a copy of the current SP for loading caller's arguments.
!   __ mr(R21_sender_SP, R1_SP);
  
    // Add space for the adapter.
    __ resize_frame(-adapter_size, R12_scratch2);
  
    int st_off = adapter_size - wordSize;
  
    // Write the args into the outgoing interpreter space.
+   // TODO: support for InlineTypePassFieldsAsArgs
    for (int i = 0; i < total_args_passed; i++) {
+     BasicType bt = sig_extended->at(i)._bt;
+ 
      VMReg r_1 = regs[i].first();
      VMReg r_2 = regs[i].second();
      if (!r_1->is_valid()) {
        assert(!r_2->is_valid(), "");
        continue;

*** 991,13 ***
        value_regs_index = (value_regs_index + 1) % num_value_regs;
        // The calling convention produces OptoRegs that ignore the out
        // preserve area (JIT's ABI). We must account for it here.
        int ld_off = (r_1->reg2stack() + SharedRuntime::out_preserve_stack_slots()) * VMRegImpl::stack_slot_size;
        if (!r_2->is_valid()) {
!         __ lwz(tmp_reg, ld_off, sender_SP);
        } else {
!         __ ld(tmp_reg, ld_off, sender_SP);
        }
        // Pretend stack targets were loaded into tmp_reg.
        r_1 = tmp_reg->as_VMReg();
      }
  
--- 1160,13 ---
        value_regs_index = (value_regs_index + 1) % num_value_regs;
        // The calling convention produces OptoRegs that ignore the out
        // preserve area (JIT's ABI). We must account for it here.
        int ld_off = (r_1->reg2stack() + SharedRuntime::out_preserve_stack_slots()) * VMRegImpl::stack_slot_size;
        if (!r_2->is_valid()) {
!         __ lwz(tmp_reg, ld_off, R21_sender_SP);
        } else {
!         __ ld(tmp_reg, ld_off, R21_sender_SP);
        }
        // Pretend stack targets were loaded into tmp_reg.
        r_1 = tmp_reg->as_VMReg();
      }
  

*** 1007,11 ***
          __ stw(r, st_off, R1_SP);
          st_off-=wordSize;
        } else {
          // Longs are given 2 64-bit slots in the interpreter, but the
          // data is passed in only 1 slot.
!         if (sig_bt[i] == T_LONG || sig_bt[i] == T_DOUBLE) {
            DEBUG_ONLY( __ li(tmp, 0); __ std(tmp, st_off, R1_SP); )
            st_off-=wordSize;
          }
          __ std(r, st_off, R1_SP);
          st_off-=wordSize;
--- 1176,11 ---
          __ stw(r, st_off, R1_SP);
          st_off-=wordSize;
        } else {
          // Longs are given 2 64-bit slots in the interpreter, but the
          // data is passed in only 1 slot.
!         if (bt == T_LONG || bt == T_DOUBLE) {
            DEBUG_ONLY( __ li(tmp, 0); __ std(tmp, st_off, R1_SP); )
            st_off-=wordSize;
          }
          __ std(r, st_off, R1_SP);
          st_off-=wordSize;

*** 1039,21 ***
    __ load_const_optimized(R25_templateTableBase, (address)Interpreter::dispatch_table((TosState)0), R11_scratch1);
  
    // load TOS
    __ addi(R15_esp, R1_SP, st_off);
  
-   // Frame_manager expects initial_caller_sp (= SP without resize by c2i) in R21_tmp1.
-   assert(sender_SP == R21_sender_SP, "passing initial caller's SP in wrong register");
    __ bctr();
- 
-   return c2i_entrypoint;
  }
  
  void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm,
-                                     int total_args_passed,
                                      int comp_args_on_stack,
!                                     const BasicType *sig_bt,
                                      const VMRegPair *regs) {
  
    // Load method's entry-point from method.
    __ ld(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method);
    __ mtctr(R12_scratch2);
--- 1208,16 ---
    __ load_const_optimized(R25_templateTableBase, (address)Interpreter::dispatch_table((TosState)0), R11_scratch1);
  
    // load TOS
    __ addi(R15_esp, R1_SP, st_off);
  
    __ bctr();
  }
  
  void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm,
                                      int comp_args_on_stack,
!                                     const GrowableArray<SigEntry>* sig,
                                      const VMRegPair *regs) {
  
    // Load method's entry-point from method.
    __ ld(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method);
    __ mtctr(R12_scratch2);

*** 1076,10 ***
--- 1240,11 ---
    const Register ld_ptr = R15_esp;
    const Register value_regs[] = { R22_tmp2, R23_tmp3, R24_tmp4, R25_tmp5, R26_tmp6 };
    const int num_value_regs = sizeof(value_regs) / sizeof(Register);
    int value_regs_index = 0;
  
+   int total_args_passed = sig->length();
    int ld_offset = total_args_passed*wordSize;
  
    // Cut-out for having no stack args. Since up to 2 int/oop args are passed
    // in registers, we will occasionally have no stack args.
    int comp_words_on_stack = 0;

*** 1096,13 ***
    }
  
    // Now generate the shuffle code.  Pick up all register args and move the
    // rest through register value=Z_R12.
    BLOCK_COMMENT("Shuffle arguments");
    for (int i = 0; i < total_args_passed; i++) {
!     if (sig_bt[i] == T_VOID) {
!       assert(i > 0 && (sig_bt[i-1] == T_LONG || sig_bt[i-1] == T_DOUBLE), "missing half");
        continue;
      }
  
      // Pick up 0, 1 or 2 words from ld_ptr.
      assert(!regs[i].second()->is_valid() || regs[i].first()->next() == regs[i].second(),
--- 1261,15 ---
    }
  
    // Now generate the shuffle code.  Pick up all register args and move the
    // rest through register value=Z_R12.
    BLOCK_COMMENT("Shuffle arguments");
+ 
    for (int i = 0; i < total_args_passed; i++) {
!     BasicType bt = sig->at(i)._bt;
!     if (bt == T_VOID) {
+       assert(i > 0 && (sig->at(i - 1)._bt == T_LONG || sig->at(i - 1)._bt == T_DOUBLE), "missing half");
        continue;
      }
  
      // Pick up 0, 1 or 2 words from ld_ptr.
      assert(!regs[i].second()->is_valid() || regs[i].first()->next() == regs[i].second(),

*** 1131,33 ***
        } else {
          r = r_1->as_Register();
        }
        if (!r_2->is_valid()) {
          // Not sure we need to do this but it shouldn't hurt.
!         if (is_reference_type(sig_bt[i]) || sig_bt[i] == T_ADDRESS) {
            __ ld(r, ld_offset, ld_ptr);
            ld_offset-=wordSize;
          } else {
            __ lwz(r, ld_offset, ld_ptr);
            ld_offset-=wordSize;
          }
        } else {
          // In 64bit, longs are given 2 64-bit slots in the interpreter, but the
          // data is passed in only 1 slot.
!         if (sig_bt[i] == T_LONG || sig_bt[i] == T_DOUBLE) {
            ld_offset-=wordSize;
          }
          __ ld(r, ld_offset, ld_ptr);
          ld_offset-=wordSize;
        }
  
        if (r_1->is_stack()) {
          // Now store value where the compiler expects it
          int st_off = (r_1->reg2stack() + SharedRuntime::out_preserve_stack_slots())*VMRegImpl::stack_slot_size;
  
!         if (sig_bt[i] == T_INT   || sig_bt[i] == T_FLOAT ||sig_bt[i] == T_BOOLEAN ||
!             sig_bt[i] == T_SHORT || sig_bt[i] == T_CHAR  || sig_bt[i] == T_BYTE) {
            __ stw(r, st_off, R1_SP);
          } else {
            __ std(r, st_off, R1_SP);
          }
        }
--- 1298,33 ---
        } else {
          r = r_1->as_Register();
        }
        if (!r_2->is_valid()) {
          // Not sure we need to do this but it shouldn't hurt.
!         if (is_reference_type(bt) || bt == T_ADDRESS) {
            __ ld(r, ld_offset, ld_ptr);
            ld_offset-=wordSize;
          } else {
            __ lwz(r, ld_offset, ld_ptr);
            ld_offset-=wordSize;
          }
        } else {
          // In 64bit, longs are given 2 64-bit slots in the interpreter, but the
          // data is passed in only 1 slot.
!         if (bt == T_LONG || bt == T_DOUBLE) {
            ld_offset-=wordSize;
          }
          __ ld(r, ld_offset, ld_ptr);
          ld_offset-=wordSize;
        }
  
        if (r_1->is_stack()) {
          // Now store value where the compiler expects it
          int st_off = (r_1->reg2stack() + SharedRuntime::out_preserve_stack_slots())*VMRegImpl::stack_slot_size;
  
!         if (bt == T_INT   || bt == T_FLOAT || bt == T_BOOLEAN ||
!             bt == T_SHORT || bt == T_CHAR  || bt == T_BYTE) {
            __ stw(r, st_off, R1_SP);
          } else {
            __ std(r, st_off, R1_SP);
          }
        }

*** 1180,83 ***
  
    // Jump to the compiled code just as if compiled code was doing it.
    __ bctr();
  }
  
! void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
!                                             int total_args_passed,
!                                             int comp_args_on_stack,
-                                             const BasicType *sig_bt,
-                                             const VMRegPair *regs,
-                                             address entry_address[AdapterBlob::ENTRY_COUNT]) {
-   // entry: i2c
  
!   __ align(CodeEntryAlignment);
!   entry_address[AdapterBlob::I2C] = __ pc();
!   gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs);
! 
! 
!   // entry: c2i unverified
- 
-   __ align(CodeEntryAlignment);
-   BLOCK_COMMENT("c2i unverified entry");
-   entry_address[AdapterBlob::C2I_Unverified] = __ pc();
- 
-   // inline_cache contains a CompiledICData
-   const Register ic             = R19_inline_cache_reg;
-   const Register ic_klass       = R11_scratch1;
-   const Register receiver_klass = R12_scratch2;
-   const Register code           = R21_tmp1;
-   const Register ientry         = R23_tmp3;
- 
-   assert_different_registers(ic, ic_klass, receiver_klass, R3_ARG1, code, ientry);
-   assert(R11_scratch1 == R11, "need prologue scratch register");
- 
-   Label call_interpreter;
- 
-   __ ic_check(4 /* end_alignment */);
-   __ ld(R19_method, CompiledICData::speculated_method_offset(), ic);
-   // Argument is valid and klass is as expected, continue.
- 
-   __ ld(code, method_(code));
-   __ cmpdi(CR0, code, 0);
-   __ ld(ientry, method_(interpreter_entry)); // preloaded
-   __ beq_predict_taken(CR0, call_interpreter);
  
    // Branch to ic_miss_stub.
    __ b64_patchable((address)SharedRuntime::get_ic_miss_stub(), relocInfo::runtime_call_type);
  
!   // entry: c2i
  
!   entry_address[AdapterBlob::C2I] = __ pc();
  
!   // Class initialization barrier for static methods
!   entry_address[AdapterBlob::C2I_No_Clinit_Check] = nullptr;
!   assert(VM_Version::supports_fast_class_init_checks(), "sanity");
!   Label L_skip_barrier;
  
!   // Bypass the barrier for non-static methods
!   __ lhz(R0, in_bytes(Method::access_flags_offset()), R19_method);
!   __ andi_(R0, R0, JVM_ACC_STATIC);
-   __ beq(CR0, L_skip_barrier); // non-static
  
!   Register klass = R11_scratch1;
-   __ load_method_holder(klass, R19_method);
-   __ clinit_barrier(klass, R16_thread, &L_skip_barrier /*L_fast_path*/);
  
!   __ load_const_optimized(klass, SharedRuntime::get_handle_wrong_method_stub(), R0);
!   __ mtctr(klass);
!   __ bctr();
  
!   __ bind(L_skip_barrier);
!   entry_address[AdapterBlob::C2I_No_Clinit_Check] = __ pc();
  
!   BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
!   bs->c2i_entry_barrier(masm, /* tmp register*/ ic_klass, /* tmp register*/ receiver_klass, /* tmp register*/ code);
  
!   gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, call_interpreter, ientry);
!   return;
  }
  
  // An oop arg. Must pass a handle not the oop itself.
  static void object_move(MacroAssembler* masm,
                          int frame_size_in_slots,
--- 1347,103 ---
  
    // Jump to the compiled code just as if compiled code was doing it.
    __ bctr();
  }
  
! static void gen_inline_cache_check(MacroAssembler *masm, Label& skip_fixup) {
!   __ ic_check(BytesPerInstWord /* end_alignment */);
!   __ ld(R19_method, CompiledICData::speculated_method_offset(), R19_inline_cache_reg);
  
!   // Method might have been compiled since the call site was patched to
!   // interpreted; if that is the case treat it as a miss so we can get
!   // the call site corrected.
!   __ ld(R0, method_(code));
!   __ cmpdi(CR0, R0, 0);
!   __ beq_predict_taken(CR0, skip_fixup);
  
    // Branch to ic_miss_stub.
    __ b64_patchable((address)SharedRuntime::get_ic_miss_stub(), relocInfo::runtime_call_type);
+ }
  
! void SharedRuntime::generate_i2c2i_adapters(MacroAssembler* masm,
+                                             int comp_args_on_stack,
+                                             const GrowableArray<SigEntry>* sig,
+                                             const VMRegPair* regs,
+                                             const GrowableArray<SigEntry>* sig_cc,
+                                             const VMRegPair* regs_cc,
+                                             const GrowableArray<SigEntry>* sig_cc_ro,
+                                             const VMRegPair* regs_cc_ro,
+                                             address entry_address[AdapterBlob::ENTRY_COUNT],
+                                             AdapterBlob*& new_adapter,
+                                             bool allocate_code_blob) {
  
!   entry_address[AdapterBlob::I2C] = __ pc();
+   gen_i2c_adapter(masm, comp_args_on_stack, sig, regs);
  
!   // -------------------------------------------------------------------------
!   // Generate a C2I adapter.  On entry we know rmethod holds the Method* during calls
!   // to the interpreter.  The args start out packed in the compiled layout.  They
!   // need to be unpacked into the interpreter layout.  This will almost always
+   // require some stack space.  We grow the current (compiled) stack, then repack
+   // the args.  We  finally end in a jump to the generic interpreter entry point.
+   // On exit from the interpreter, the interpreter will restore our SP (lest the
+   // compiled code, which relies solely on SP and not FP, get sick).
  
!   entry_address[AdapterBlob::C2I_Unverified] = __ pc();
!   entry_address[AdapterBlob::C2I_Unverified_Inline] = __ pc();
!   Label skip_fixup;
  
!   gen_inline_cache_check(masm, skip_fixup);
  
!   OopMapSet* oop_maps = new OopMapSet();
!   int frame_complete = CodeOffsets::frame_never_safe;
!   int frame_size_in_words = 0;
  
!   // Scalarized c2i adapter with non-scalarized receiver (i.e., don't pack receiver)
!   entry_address[AdapterBlob::C2I_No_Clinit_Check] = nullptr;
+   entry_address[AdapterBlob::C2I_Inline_RO] = __ pc();
+   if (regs_cc != regs_cc_ro) {
+     // No class init barrier needed because method is guaranteed to be non-static
+     __ unimplemented("C2I_Inline_RO");
+ #if 0
+     gen_c2i_adapter(masm, sig_cc_ro, regs_cc_ro, /* requires_clinit_barrier = */ false, entry_address[AdapterBlob::C2I_No_Clinit_Check],
+                     skip_fixup, entry_address[AdapterBlob::I2C], oop_maps, frame_complete, frame_size_in_words, /* alloc_inline_receiver = */ false);
+ #endif
+     skip_fixup.reset();
+   }
  
!   // Scalarized c2i adapter
!   entry_address[AdapterBlob::C2I]        = __ pc();
+   entry_address[AdapterBlob::C2I_Inline] = __ pc();
+   gen_c2i_adapter(masm, sig_cc, regs_cc, /* requires_clinit_barrier = */ true, entry_address[AdapterBlob::C2I_No_Clinit_Check],
+                   skip_fixup, entry_address[AdapterBlob::I2C], oop_maps, frame_complete, frame_size_in_words, /* alloc_inline_receiver = */ true);
+ 
+   // Non-scalarized c2i adapter
+   if (regs != regs_cc) {
+     entry_address[AdapterBlob::C2I_Unverified_Inline] = __ pc();
+     Label inline_entry_skip_fixup;
+     __ unimplemented("C2I_Unverified_Inline");
+ #if 0
+     gen_inline_cache_check(masm, inline_entry_skip_fixup);
+ #endif
  
!     entry_address[AdapterBlob::C2I_Inline] = __ pc();
!     __ unimplemented("C2I_Inline2");
+ #if 0
+     gen_c2i_adapter(masm, sig, regs, /* requires_clinit_barrier = */ true, entry_address[AdapterBlob::C2I_No_Clinit_Check],
+                     inline_entry_skip_fixup, entry_address[AdapterBlob::I2C], oop_maps, frame_complete, frame_size_in_words, /* alloc_inline_receiver = */ false);
+ #endif
+   }
+   // The c2i adapters might safepoint and trigger a GC. The caller must make sure that
+   // the GC knows about the location of oop argument locations passed to the c2i adapter.
+   if (allocate_code_blob) {
+     bool caller_must_gc_arguments = (regs != regs_cc);
+     int entry_offset[AdapterHandlerEntry::ENTRIES_COUNT];
+     assert(AdapterHandlerEntry::ENTRIES_COUNT == 7, "sanity");
+     AdapterHandlerLibrary::address_to_offset(entry_address, entry_offset);
+     new_adapter = AdapterBlob::create(masm->code(), entry_offset, frame_complete, frame_size_in_words, oop_maps, caller_must_gc_arguments);
+   }
  }
  
  // An oop arg. Must pass a handle not the oop itself.
  static void object_move(MacroAssembler* masm,
                          int frame_size_in_slots,

*** 3707,10 ***
--- 3894,15 ---
    }
  
    reverse_words(m, (unsigned long *)m_ints, longwords);
  }
  
+ BufferedInlineTypeBlob* SharedRuntime::generate_buffered_inline_type_adapter(const InlineKlass* vk) {
+   Unimplemented();
+   return nullptr;
+ }
+ 
  #if INCLUDE_JFR
  
  // For c2: c_rarg0 is junk, call to runtime to write a checkpoint.
  // It returns a jobject handle to the event writer.
  // The handle is dereferenced and the return value is the event writer oop.

*** 3782,7 ***
      RuntimeStub::new_runtime_stub(name, &code, frame_complete,
                                    (framesize >> (LogBytesPerWord - LogBytesPerInt)),
                                    oop_maps, false);
    return stub;
  }
- 
  #endif // INCLUDE_JFR
--- 3974,6 ---
< prev index next >