< prev index next >

src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp

Print this page
*** 1244,10 ***
--- 1244,12 ---
  
  void LIR_Assembler::return_op(LIR_Opr result, C1SafepointPollStub* code_stub) {
    const Register return_pc = R31;  // Must survive C-call to enable_stack_reserved_zone().
    const Register temp      = R12;
  
+   assert(!InlineTypeReturnedAsFields, "unimplemented");
+ 
    // Pop the stack before the safepoint code.
    int frame_size = initial_frame_size_in_bytes();
    if (Assembler::is_simm(frame_size, 16)) {
      __ addi(R1_SP, R1_SP, frame_size);
    } else {

*** 1773,10 ***
--- 1775,24 ---
    assert(exceptionOop->as_register() == R3, "should match");
    __ b(_unwind_handler_entry);
  }
  
  
+ void LIR_Assembler::arraycopy_inlinetype_check(Register obj, Register tmp, CodeStub* slow_path, bool is_dest, bool null_check) {
+   if (null_check) {
+     __ cmpdi(CR0, obj, 0);
+     __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CR0, Assembler::equal), *slow_path->entry());
+   }
+   if (is_dest) {
+     __ test_null_free_array_oop(obj, tmp, *slow_path->entry(), true);
+     __ test_flat_array_oop(obj, tmp, *slow_path->entry(), true);
+   } else {
+     __ test_flat_array_oop(obj, tmp, *slow_path->entry(), true);
+   }
+ }
+ 
+ 
  void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) {
    Register src = op->src()->as_register();
    Register dst = op->dst()->as_register();
    Register src_pos = op->src_pos()->as_register();
    Register dst_pos = op->dst_pos()->as_register();

*** 1790,10 ***
--- 1806,16 ---
    if (basic_type == T_ARRAY) basic_type = T_OBJECT;
  
    // Set up the arraycopy stub information.
    ArrayCopyStub* stub = op->stub();
  
+   if (flags & LIR_OpArrayCopy::always_slow_path) {
+     __ b(*stub->entry());
+     __ bind(*stub->continuation());
+     return;
+   }
+ 
    // Always do stub if no type information is available. It's ok if
    // the known type isn't loaded since the code sanity checks
    // in debug mode and the type isn't required when we know the exact type
    // also check that the type is an array type.
    if (default_type == nullptr) {

*** 1829,10 ***
--- 1851,18 ---
      __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CR0, Assembler::less), *stub->entry());
      __ bind(*stub->continuation());
      return;
    }
  
+   // Handle inline type arrays
+   if (flags & LIR_OpArrayCopy::src_inlinetype_check) {
+     arraycopy_inlinetype_check(src, tmp, stub, false, (flags & LIR_OpArrayCopy::src_null_check));
+   }
+   if (flags & LIR_OpArrayCopy::dst_inlinetype_check) {
+     arraycopy_inlinetype_check(dst, tmp, stub, true, (flags & LIR_OpArrayCopy::dst_null_check));
+   }
+ 
    assert(default_type != nullptr && default_type->is_array_klass() && default_type->is_loaded(), "must be true at this point");
    Label cont, slow, copyfunc;
  
    bool simple_check_flag_set = flags & (LIR_OpArrayCopy::src_null_check |
                                          LIR_OpArrayCopy::dst_null_check |

*** 2323,10 ***
--- 2353,11 ---
    } else {
      klass2reg_with_patching(k_RInfo, op->info_for_patch());
    }
  
    if (op->fast_check()) {
+     assert(!k->is_loaded() || !k->is_obj_array_klass(), "Use refined array for a direct pointer comparison");
      assert_different_registers(klass_RInfo, k_RInfo);
      __ cmpd(CR0, k_RInfo, klass_RInfo);
      __ beq(CR0, *success);
      // Fall through to failure case.
    } else {

*** 2392,30 ***
        setup_md_access(method, op->profiled_bci(), md, data, mdo_offset_bias);
      }
  
      Label done;
  
!     if (should_profile) {
!       Label not_null;
!       Register mdo      = k_RInfo;
!       Register data_val = Rtmp1;
!       metadata2reg(md->constant_encoding(), mdo);
!       __ add_const_optimized(mdo, mdo, mdo_offset_bias, R0);
!       __ cmpdi(CR0, value, 0);
!       __ bne(CR0, not_null);
!       __ lbz(data_val, md->byte_offset_of_slot(data, DataLayout::flags_offset()) - mdo_offset_bias, mdo);
!       __ ori(data_val, data_val, BitData::null_seen_byte_constant());
!       __ stb(data_val, md->byte_offset_of_slot(data, DataLayout::flags_offset()) - mdo_offset_bias, mdo);
!       __ b(done);
!       __ bind(not_null);
! 
!       Register recv = klass_RInfo;
!       __ load_klass(recv, value);
!       type_profile_helper(mdo, mdo_offset_bias, md, data, recv, Rtmp1); // kills recv
!     } else {
!       __ cmpdi(CR0, value, 0);
!       __ beq(CR0, done);
      }
      if (!os::zero_page_read_protected() || !ImplicitNullChecks) {
        explicit_null_check(array, op->info_for_exception());
      } else {
        add_debug_info_for_null_check_here(op->info_for_exception());
--- 2423,32 ---
        setup_md_access(method, op->profiled_bci(), md, data, mdo_offset_bias);
      }
  
      Label done;
  
!     if (op->need_null_check()) {
!       if (should_profile) {
!         Label not_null;
!         Register mdo      = k_RInfo;
!         Register data_val = Rtmp1;
!         metadata2reg(md->constant_encoding(), mdo);
!         __ add_const_optimized(mdo, mdo, mdo_offset_bias, R0);
!         __ cmpdi(CR0, value, 0);
!         __ bne(CR0, not_null);
!         __ lbz(data_val, md->byte_offset_of_slot(data, DataLayout::flags_offset()) - mdo_offset_bias, mdo);
!         __ ori(data_val, data_val, BitData::null_seen_byte_constant());
!         __ stb(data_val, md->byte_offset_of_slot(data, DataLayout::flags_offset()) - mdo_offset_bias, mdo);
!         __ b(done);
!         __ bind(not_null);
! 
!         Register recv = klass_RInfo;
!         __ load_klass(recv, value);
!         type_profile_helper(mdo, mdo_offset_bias, md, data, recv, Rtmp1); // kills recv
!       } else {
!         __ cmpdi(CR0, value, 0);
+         __ beq(CR0, done);
+       }
      }
      if (!os::zero_page_read_protected() || !ImplicitNullChecks) {
        explicit_null_check(array, op->info_for_exception());
      } else {
        add_debug_info_for_null_check_here(op->info_for_exception());

*** 3035,10 ***
--- 3068,29 ---
      if (klass_reg_used) { __ load_const_optimized(R29_TOC, MacroAssembler::global_toc(), R0); } // reinit
    }
    __ bind(Ldone);
  }
  
+ void LIR_Assembler::emit_profile_inline_type(LIR_OpProfileInlineType* op) {
+   Register obj = op->obj()->as_register();
+   //Register tmp = op->tmp()->as_pointer_register(); not needed!
+   LIR_Address* mdo_addr = op->mdp()->as_address_ptr();
+   assert(!mdo_addr->index()->is_valid(), "index unsupported");
+   Register mdo_base = mdo_addr->base()->as_pointer_register();
+   int mdo_offs = mdo_addr->disp();
+   bool not_null = op->not_null();
+   int flag = op->flag();
+ 
+   Label not_inline_type;
+   __ test_oop_is_not_inline_type(obj, not_inline_type, !not_null);
+ 
+   __ lbz(R0, mdo_offs, mdo_base);
+   __ ori(R0, R0, flag);
+   __ stb(R0, mdo_offs, mdo_base);
+ 
+   __ bind(not_inline_type);
+ }
  
  void LIR_Assembler::emit_updatecrc32(LIR_OpUpdateCRC32* op) {
    assert(op->crc()->is_single_cpu(), "crc must be register");
    assert(op->val()->is_single_cpu(), "byte value must be register");
    assert(op->result_opr()->is_single_cpu(), "result must be register");

*** 3051,6 ***
--- 3103,107 ---
    __ load_const_optimized(res, StubRoutines::crc_table_addr(), R0);
    __ kernel_crc32_singleByteReg(crc, val, res, true);
    __ mr(res, crc);
  }
  
+ // Valhalla support
+ 
+ void LIR_Assembler::check_orig_pc() {
+   Address address_for_orig_pc_addr = frame_map()->address_for_orig_pc_addr();
+   __ ld(R0, address_for_orig_pc_addr);
+   __ cmpdi(BOOL_RESULT, R0, (u1)NULL_WORD);
+ }
+ 
+ int LIR_Assembler::store_inline_type_fields_to_buf(ciInlineKlass* vk) {
+   return (__ store_inline_type_fields_to_buf(vk, false));
+ }
+ 
+ void LIR_Assembler::emit_opFlattenedArrayCheck(LIR_OpFlattenedArrayCheck* op) {
+   // We are loading/storing from/to an array that *may* be a flat array (the
+   // declared type is Object[], abstract[], interface[] or VT.ref[]).
+   // If this array is a flat array, take the slow path.
+   __ test_flat_array_oop(op->array()->as_register(), op->tmp()->as_register(), *op->stub()->entry(), true);
+ }
+ 
+ void LIR_Assembler::emit_opNullFreeArrayCheck(LIR_OpNullFreeArrayCheck* op) {
+   // We are storing into an array that *may* be null-free (the declared type is
+   // Object[], abstract[], interface[] or VT.ref[]).
+   Label test_mark_word;
+   Register tmp = op->tmp()->as_register();
+   __ ld(tmp, oopDesc::mark_offset_in_bytes(), op->array()->as_register());
+   __ andi_(R0, tmp, markWord::unlocked_value);
+   __ bne(CR0, test_mark_word);
+   __ load_prototype_header(tmp, op->array()->as_register());
+   __ bind(test_mark_word);
+   __ andi(R0, tmp, markWord::null_free_array_bit_in_place);
+   __ cmpwi(BOOL_RESULT, R0, 0);
+ }
+ 
+ void LIR_Assembler::emit_opSubstitutabilityCheck(LIR_OpSubstitutabilityCheck* op) {
+   Label L_oops_equal;
+   Label L_oops_not_equal;
+   Label L_end;
+ 
+   Register left  = op->left()->as_register();
+   Register right = op->right()->as_register();
+ 
+   __ cmpd(CR0, left, right);
+   __ beq(CR0, L_oops_equal);
+ 
+   // (1) Null check -- if one of the operands is null, the other must not be null (because
+   //     the two references are not equal), so they are not substitutable,
+   __ cmpdi(CR0, left, 0);
+   __ cmpdi(CR1, right, 0);
+   __ cror(CR0, Assembler::equal, CR1, Assembler::equal);
+   __ beq(CR0, L_oops_not_equal);
+ 
+   ciKlass* left_klass = op->left_klass();
+   ciKlass* right_klass = op->right_klass();
+ 
+   // (2) Inline type check -- if either of the operands is not an inline type,
+   //     they are not substitutable. We do this only if we are not sure that the
+   //     operands are inline type
+   if ((left_klass == nullptr || right_klass == nullptr) ||// The klass is still unloaded, or came from a Phi node.
+       !left_klass->is_inlinetype() || !right_klass->is_inlinetype()) {
+     Register tmp = op->tmp1()->as_register();
+     __ ld(tmp, oopDesc::mark_offset_in_bytes(), left);
+     __ ld(R0, oopDesc::mark_offset_in_bytes(), right);
+     __ andi(tmp, tmp, (intptr_t)markWord::inline_type_pattern);
+     __ andr(tmp, tmp, R0);
+     __ cmpdi(CR0, tmp, (intptr_t)markWord::inline_type_pattern);
+     __ bne(CR0, L_oops_not_equal);
+   }
+ 
+   // (3) Same klass check: if the operands are of different klasses, they are not substitutable.
+   if (left_klass != nullptr && left_klass->is_inlinetype() && left_klass == right_klass) {
+     // No need to load klass -- the operands are statically known to be the same inline klass.
+     __ b(*op->stub()->entry());
+   } else {
+     Register tmp1 = op->tmp1()->as_register();
+     Register tmp2 = op->tmp2()->as_register();
+     if (left == right) { // same operand, so clearly the same klasses, let's save the check
+       __ b(*op->stub()->entry());  //  -> do slow check
+     } else {
+       __ cmp_klasses_from_objects(CR0, left, right, tmp1, tmp2);
+       __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CR0, Assembler::equal),
+                           *op->stub()->entry()); // same klass -> do slow check
+     }
+     // fall through to L_oops_not_equal
+   }
+ 
+   __ bind(L_oops_not_equal);
+   load_to_reg(this, op->not_equal_result(), op->result_opr());
+   __ b(L_end);
+ 
+   // We've returned from the stub. R3_RET (stub's _scratch_reg) contains 0x0 IFF the two
+   // operands are not substitutable. (Don't compare against 0x1 in case the
+   // C compiler is naughty)
+   __ bind(*op->stub()->continuation());
+   __ cmpdi(CR0, R3_RET, 0);
+   __ beq(CR0, L_oops_not_equal);
+ 
+   __ bind(L_oops_equal);
+   load_to_reg(this, op->equal_result(), op->result_opr()); // (call_stub() != 0x0) -> equal
+   // fall-through
+   __ bind(L_end);
+ }
  #undef __
< prev index next >