< prev index next > src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp
Print this page
#include "c1/c1_LIRAssembler.hpp"
#include "c1/c1_MacroAssembler.hpp"
#include "c1/c1_Runtime1.hpp"
#include "c1/c1_ValueStack.hpp"
#include "ci/ciArrayKlass.hpp"
+ #include "ci/ciInlineKlass.hpp"
#include "ci/ciInstance.hpp"
+ #include "ci/ciObjArrayKlass.hpp"
#include "code/compiledIC.hpp"
#include "gc/shared/collectedHeap.hpp"
#include "nativeInst_riscv.hpp"
#include "oops/objArrayKlass.hpp"
+ #include "oops/oop.inline.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/sharedRuntime.hpp"
#include "utilities/powerOfTwo.hpp"
#include "vmreg_riscv.inline.hpp"
__ mv(x10, x9); // Restore the exception
}
// remove the activation and dispatch to the unwind handler
__ block_comment("remove_frame and dispatch to the unwind handler");
- __ remove_frame(initial_frame_size_in_bytes());
+ __ remove_frame(initial_frame_size_in_bytes(), needs_stack_repair());
__ far_jump(RuntimeAddress(Runtime1::entry_for(StubId::c1_unwind_exception_id)));
// Emit the slow path assembly
if (stub != nullptr) {
stub->emit_code(this);
}
void LIR_Assembler::return_op(LIR_Opr result, C1SafepointPollStub* code_stub) {
assert(result->is_illegal() || !result->is_single_cpu() || result->as_register() == x10, "word returns are in x10");
+ assert(!InlineTypeReturnedAsFields, "unimplemented");
+
// Pop the stack before the safepoint code
- __ remove_frame(initial_frame_size_in_bytes());
+ __ remove_frame(initial_frame_size_in_bytes(), needs_stack_repair());
if (StackReservedPages > 0 && compilation()->has_reserved_stack_access()) {
__ reserved_stack_check();
}
__ relocate(relocInfo::poll_return_type);
__ safepoint_poll(*code_stub->entry(), true /* at_return */, true /* in_nmethod */);
__ ret();
}
+ int LIR_Assembler::store_inline_type_fields_to_buf(ciInlineKlass* vk) {
+ Unimplemented();
+ return 0;
+ }
+
int LIR_Assembler::safepoint_poll(LIR_Opr tmp, CodeEmitInfo* info) {
guarantee(info != nullptr, "Shouldn't be null");
__ get_polling_page(t0, relocInfo::poll_type);
add_debug_info_for_branch(info); // This isn't just debug info:
// it's the oop map
__ mv(dest->as_register_lo(), (intptr_t)c->as_jlong());
break;
case T_OBJECT:
case T_ARRAY:
- if (patch_code == lir_patch_none) {
- jobject2reg(c->as_jobject(), dest->as_register());
- } else {
+ if (patch_code != lir_patch_none) {
jobject2reg_with_patching(dest->as_register(), info);
+ } else {
+ jobject2reg(c->as_jobject(), dest->as_register());
}
break;
case T_METADATA:
if (patch_code != lir_patch_none) {
__ verify_oop(dest->as_register());
}
}
+ void LIR_Assembler::move(LIR_Opr src, LIR_Opr dst) {
+ assert(dst->is_cpu_register(), "must be");
+ assert(dst->type() == src->type(), "must be");
+
+ if (src->is_cpu_register()) {
+ reg2reg(src, dst);
+ } else if (src->is_stack()) {
+ stack2reg(src, dst, dst->type());
+ } else if (src->is_constant()) {
+ const2reg(src, dst, lir_patch_none, nullptr);
+ } else {
+ ShouldNotReachHere();
+ }
+ }
+
void LIR_Assembler::emit_op3(LIR_Op3* op) {
switch (op->code()) {
case lir_idiv: // fall through
case lir_irem:
arithmetic_idiv(op->code(),
}
void LIR_Assembler::emit_alloc_array(LIR_OpAllocArray* op) {
Register len = op->len()->as_register();
- if (UseSlowPath ||
+ if (UseSlowPath || op->always_slow_path() ||
(!UseFastNewObjectArray && is_reference_type(op->type())) ||
(!UseFastNewTypeArray && !is_reference_type(op->type()))) {
__ j(*op->stub()->entry());
} else {
Register tmp1 = op->tmp1()->as_register();
// successful cast, fall through to profile or jump
} else {
// See if we get an immediate positive hit
__ beq(k_RInfo, t0, *success_target);
// check for self
- __ beq(klass_RInfo, k_RInfo, *success_target);
-
+ if (k->is_loaded() && k->is_obj_array_klass()) {
+ // For a direct pointer comparison, we need the refined array klass pointer
+ ciKlass* k_refined = ciObjArrayKlass::make(k->as_obj_array_klass()->element_klass());
+ if (!k_refined->is_loaded()) {
+ bailout("encountered unloaded_ciobjarrayklass due to out of memory error");
+ return;
+ }
+ __ mov_metadata(t0, k_refined->constant_encoding());
+ __ beq(klass_RInfo, t0, *success_target);
+ } else {
+ __ beq(klass_RInfo, k_RInfo, *success_target);
+ }
__ subi(sp, sp, 2 * wordSize); // 2: store k_RInfo and klass_RInfo
__ sd(k_RInfo, Address(sp, 0)); // sub klass
__ sd(klass_RInfo, Address(sp, wordSize)); // super klass
__ far_call(RuntimeAddress(Runtime1::entry_for(StubId::c1_slow_subtype_check_id)));
// load result to k_RInfo
Rtmp1 = op->tmp3()->as_register();
select_different_registers(obj, dst, k_RInfo, klass_RInfo, Rtmp1);
assert_different_registers(obj, k_RInfo, klass_RInfo);
- if (should_profile) {
- profile_object(md, data, obj, k_RInfo, klass_RInfo, obj_is_null);
- } else {
- __ beqz(obj, *obj_is_null);
+ if (op->need_null_check()) {
+ if (should_profile) {
+ profile_object(md, data, obj, k_RInfo, klass_RInfo, obj_is_null);
+ } else {
+ __ beqz(obj, *obj_is_null);
+ }
}
typecheck_loaded(op, k, k_RInfo);
__ verify_oop(obj);
if (op->fast_check()) {
+ assert(!k->is_loaded() || !k->is_obj_array_klass(), "Use refined array for a direct pointer comparison");
// get object class
// not a safepoint as obj null check happens earlier
__ load_klass(t0, obj, t1);
__ bne(t0, k_RInfo, *failure_target, /* is_far */ true);
// successful cast, fall through to profile or jump
} else {
ShouldNotReachHere();
}
}
+ 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());
+ }
+
+ 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, Address(op->array()->as_register(), oopDesc::mark_offset_in_bytes()));
+ __ test_bit(t0, tmp, exact_log2(markWord::unlocked_value));
+ __ bnez(t0, test_mark_word);
+ __ load_prototype_header(tmp, op->array()->as_register());
+ __ bind(test_mark_word);
+ __ test_bit(tmp, tmp, exact_log2(markWord::null_free_array_bit_in_place));
+ }
+
+ 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();
+
+ __ beq(left, right, 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,
+ __ beqz(left, L_oops_not_equal);
+ __ beqz(right, 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 a 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 tmp1 = op->tmp1()->as_register();
+ Register tmp2 = op->tmp2()->as_register();
+ __ mv(tmp1, markWord::inline_type_pattern);
+ __ ld(tmp2, Address(left, oopDesc::mark_offset_in_bytes()));
+ __ andr(tmp1, tmp1, tmp2);
+ __ ld(tmp2, Address(right, oopDesc::mark_offset_in_bytes()));
+ __ andr(tmp1, tmp1, tmp2);
+ __ mv(tmp2, (u1)markWord::inline_type_pattern);
+ __ bne(tmp1, tmp2, 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.
+ __ j(*op->stub()->entry());
+ } else {
+ Register left_klass_op = op->tmp1()->as_register();
+ Register right_klass_op = op->tmp2()->as_register();
+ if (UseCompactObjectHeaders) {
+ __ load_narrow_klass_compact(left_klass_op, left);
+ __ load_narrow_klass_compact(right_klass_op, right);
+ } else {
+ __ lwu(left_klass_op, Address(left, oopDesc::klass_offset_in_bytes()));
+ __ lwu(right_klass_op, Address(right, oopDesc::klass_offset_in_bytes()));
+ }
+ __ beq(left_klass_op, right_klass_op, *op->stub()->entry(), /* is_far */ true); // same klass -> do slow check
+ // fall through to L_oops_not_equal
+ }
+
+ __ bind(L_oops_not_equal);
+ move(op->not_equal_result(), op->result_opr());
+ __ j(L_end);
+
+ // We've returned from the stub. X10 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());
+ __ beqz(x10, L_oops_not_equal); // (call_stub() == 0x0) -> not_equal
+
+ __ bind(L_oops_equal);
+ move(op->equal_result(), op->result_opr()); // (call_stub() != 0x0) -> equal
+ // fall-through
+ __ bind(L_end);
+ }
+
+ void LIR_Assembler::emit_profile_inline_type(LIR_OpProfileInlineType* op) {
+ Register obj = op->obj()->as_register();
+ Register tmp = op->tmp()->as_pointer_register();
+ bool not_null = op->not_null();
+ int flag = op->flag();
+
+ assert_different_registers(tmp, t0, t1);
+
+ Label not_inline_type;
+ if (!not_null) {
+ __ beqz(obj, not_inline_type);
+ }
+
+ __ test_oop_is_not_inline_type(obj, tmp, not_inline_type);
+
+ Address mdo_addr = as_Address(op->mdp()->as_address_ptr(), t1);
+ __ lbu(tmp, mdo_addr);
+ __ mv(t0, flag);
+ __ orr(tmp, tmp, t0);
+ __ sb(tmp, mdo_addr);
+
+ __ bind(not_inline_type);
+ }
+
+ void LIR_Assembler::check_orig_pc() {
+ Unimplemented();
+ }
+
void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) {
Register addr;
if (op->addr()->is_register()) {
addr = as_reg(op->addr());
} else {
address call = __ reloc_call(Address(op->addr(), rtype));
if (call == nullptr) {
bailout("reloc call address stub overflow");
return;
}
- add_call_info(code_offset(), op->info());
+ add_call_info(code_offset(), op->info(), op->maybe_return_as_fields());
__ post_call_nop();
}
void LIR_Assembler::ic_call(LIR_OpJavaCall* op) {
Assembler::IncompressibleScope scope(_masm);
address call = __ ic_call(op->addr());
if (call == nullptr) {
bailout("reloc call address stub overflow");
return;
}
- add_call_info(code_offset(), op->info());
+ add_call_info(code_offset(), op->info(), op->maybe_return_as_fields());
__ post_call_nop();
}
void LIR_Assembler::emit_static_call_stub() {
address call_pc = __ pc();
< prev index next >