Commit 2bc979aa authored by Milad Fa's avatar Milad Fa Committed by Commit Bot

PPC/s390: [Turboprop] Move deoptimizations for dynamic map checks into builtin.

Port b6643320

Original Commit Message:

    In order to reduce the codegen size of dynamic map checks, add the
    ability to have an eager with resume deopt point, which can call
    a given builitin to perform a more detailed check than can be done
    in codegen, and then either deoptimizes itself (as if the calling
    code had performed an eager deopt) or resumes execution in the
    calling code after the check.

    In addition, support for adding extra arguments to a
    deoptimization continuation is added to enable us to pass the
    necessary arguments to the DynamicMapChecks builtin.

    Finally, a trampoline is added to the DynamicMapChecks which saves
    the registers that might be clobbered by that builtin, to avoid
    having to save them in the generated code. This trampoline also
    performs the deoptimization based on the result of the
    DynamicMapChecks builtin.

    In order to ensure both the trampoline and DynamicMapChecks
    builtin have the same call interface, and to limit the number
    of registers that need saving in the trampoline, the
    DynamicMapChecks builtin is moved to be a CSA builtin with a
    custom CallInterfaceDescriptor, that calls an exported Torque
    macro that implements the actual functionality.

    All told, this changes the codegen for a monomorphic dynamic
    map check from:
        movl rbx,<expected_map>
        cmpl [<object>-0x1],rbx
        jnz <deferred_call>
       resume_point:
        ...
       deferred_call:
        <spill registers>
        movl rax,<slot>
        movq rbx,<object>
        movq rcx,<handler>
        movq r10,<DynamicMapChecks>
        call r10
        cmpq rax,0x0
        jz <restore_regs>
        cmpq rax,0x1
        jz <deopt_point_1>
        cmpq rax,0x2
        jz <deopt_point_2>
        int3l
       restore_regs:
        <restore_regs>
        jmp <resume_point>
        ...
       deopt_point_1:
        call Deoptimization_Eager
       deopt_point_2:
        call Deoptimization_Bailout

        movl rcx,<expected_map>
        movq rdx,<handler>
        cmpl [<object>-0x1],rcx
        jnz <deopt_point>
       resume_point:
        ...
       deopt_point:
        call DynamicMapChecksTrampoline
        jmp <resume_point>

R=rmcilroy@chromium.org, joransiu@ca.ibm.com, junyan@redhat.com, midawson@redhat.com
BUG=v8:10582
LOG=N

Change-Id: I0739c1b40ed06bb22b73ebe1833ea648b540882a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2569359Reviewed-by: 's avatarJunliang Yan <junyan@redhat.com>
Commit-Queue: Milad Fa <mfarazma@redhat.com>
Cr-Commit-Position: refs/heads/master@{#71571}
parent 0f8fe4e5
......@@ -3559,6 +3559,52 @@ void Builtins::Generate_DeoptimizationEntry_Bailout(MacroAssembler* masm) {
void Builtins::Generate_DeoptimizationEntry_Lazy(MacroAssembler* masm) {
Generate_DeoptimizationEntry(masm, DeoptimizeKind::kLazy);
}
void Builtins::Generate_DynamicMapChecksTrampoline(MacroAssembler* masm) {
FrameScope scope(masm, StackFrame::MANUAL);
__ EnterFrame(StackFrame::INTERNAL);
// Only save the registers that the DynamicMapChecks builtin can clobber.
DynamicMapChecksDescriptor descriptor;
RegList registers = descriptor.allocatable_registers();
// FLAG_debug_code is enabled CSA checks will call C function and so we need
// to save all CallerSaved registers too.
if (FLAG_debug_code) registers |= kJSCallerSaved;
__ SaveRegisters(registers);
__ Call(BUILTIN_CODE(masm->isolate(), DynamicMapChecks),
RelocInfo::CODE_TARGET);
Label deopt, bailout;
__ cmpi(r3, Operand(static_cast<int>(DynamicMapChecksStatus::kSuccess)));
__ bne(&deopt);
__ RestoreRegisters(registers);
__ LeaveFrame(StackFrame::INTERNAL);
__ Ret();
__ bind(&deopt);
__ cmpi(r3, Operand(static_cast<int>(DynamicMapChecksStatus::kBailout)));
__ beq(&bailout);
if (FLAG_debug_code) {
__ cmpi(r3, Operand(static_cast<int>(DynamicMapChecksStatus::kDeopt)));
__ Assert(eq, AbortReason::kUnexpectedDynamicMapChecksStatus);
}
__ RestoreRegisters(registers);
__ LeaveFrame(StackFrame::INTERNAL);
Handle<Code> deopt_eager = masm->isolate()->builtins()->builtin_handle(
Deoptimizer::GetDeoptimizationEntry(DeoptimizeKind::kEager));
__ Jump(deopt_eager, RelocInfo::CODE_TARGET);
__ bind(&bailout);
__ RestoreRegisters(registers);
__ LeaveFrame(StackFrame::INTERNAL);
Handle<Code> deopt_bailout = masm->isolate()->builtins()->builtin_handle(
Deoptimizer::GetDeoptimizationEntry(DeoptimizeKind::kBailout));
__ Jump(deopt_bailout, RelocInfo::CODE_TARGET);
}
#undef __
} // namespace internal
} // namespace v8
......
......@@ -3579,6 +3579,51 @@ void Builtins::Generate_DeoptimizationEntry_Lazy(MacroAssembler* masm) {
Generate_DeoptimizationEntry(masm, DeoptimizeKind::kLazy);
}
void Builtins::Generate_DynamicMapChecksTrampoline(MacroAssembler* masm) {
FrameScope scope(masm, StackFrame::MANUAL);
__ EnterFrame(StackFrame::INTERNAL);
// Only save the registers that the DynamicMapChecks builtin can clobber.
DynamicMapChecksDescriptor descriptor;
RegList registers = descriptor.allocatable_registers();
// FLAG_debug_code is enabled CSA checks will call C function and so we need
// to save all CallerSaved registers too.
if (FLAG_debug_code) registers |= kJSCallerSaved;
__ SaveRegisters(registers);
__ Call(BUILTIN_CODE(masm->isolate(), DynamicMapChecks),
RelocInfo::CODE_TARGET);
Label deopt, bailout;
__ CmpP(r2, Operand(static_cast<int>(DynamicMapChecksStatus::kSuccess)));
__ bne(&deopt);
__ RestoreRegisters(registers);
__ LeaveFrame(StackFrame::INTERNAL);
__ Ret();
__ bind(&deopt);
__ CmpP(r2, Operand(static_cast<int>(DynamicMapChecksStatus::kBailout)));
__ beq(&bailout);
if (FLAG_debug_code) {
__ CmpP(r2, Operand(static_cast<int>(DynamicMapChecksStatus::kDeopt)));
__ Assert(eq, AbortReason::kUnexpectedDynamicMapChecksStatus);
}
__ RestoreRegisters(registers);
__ LeaveFrame(StackFrame::INTERNAL);
Handle<Code> deopt_eager = masm->isolate()->builtins()->builtin_handle(
Deoptimizer::GetDeoptimizationEntry(DeoptimizeKind::kEager));
__ Jump(deopt_eager, RelocInfo::CODE_TARGET);
__ bind(&bailout);
__ RestoreRegisters(registers);
__ LeaveFrame(StackFrame::INTERNAL);
Handle<Code> deopt_bailout = masm->isolate()->builtins()->builtin_handle(
Deoptimizer::GetDeoptimizationEntry(DeoptimizeKind::kBailout));
__ Jump(deopt_bailout, RelocInfo::CODE_TARGET);
}
#undef __
} // namespace internal
......
......@@ -34,6 +34,18 @@ void RecordWriteDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(kParameterCount, default_stub_registers);
}
void DynamicMapChecksDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register default_stub_registers[] = {r3, r4, r5, r6, cp};
data->RestrictAllocatableRegisters(default_stub_registers,
arraysize(default_stub_registers));
CHECK_LE(static_cast<size_t>(kParameterCount),
arraysize(default_stub_registers));
data->InitializePlatformSpecific(kParameterCount, default_stub_registers);
}
void EphemeronKeyBarrierDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
const Register default_stub_registers[] = {r3, r4, r5, r6, r7};
......
......@@ -3338,7 +3338,7 @@ void TurboAssembler::StoreReturnAddressAndCall(Register target) {
void TurboAssembler::CallForDeoptimization(Builtins::Name target, int,
Label* exit, DeoptimizeKind kind,
Label*) {
Label* ret, Label*) {
BlockTrampolinePoolScope block_trampoline_pool(this);
LoadP(ip, MemOperand(kRootRegister,
IsolateData::builtin_entry_slot_offset(target)));
......@@ -3347,7 +3347,11 @@ void TurboAssembler::CallForDeoptimization(Builtins::Name target, int,
(kind == DeoptimizeKind::kLazy)
? Deoptimizer::kLazyDeoptExitSize
: Deoptimizer::kNonLazyDeoptExitSize);
USE(exit, kind);
if (kind == DeoptimizeKind::kEagerWithResume) {
b(ret);
DCHECK_EQ(SizeOfCodeGeneratedSince(exit),
Deoptimizer::kEagerWithResumeDeoptExitSize);
}
}
void TurboAssembler::ZeroExtByte(Register dst, Register src) {
......
......@@ -444,7 +444,7 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
void CallBuiltinByIndex(Register builtin_index) override;
void CallForDeoptimization(Builtins::Name target, int deopt_id, Label* exit,
DeoptimizeKind kind,
DeoptimizeKind kind, Label* ret,
Label* jump_deoptimization_entry_label);
// Emit code to discard a non-negative number of pointer-sized elements
......
......@@ -34,6 +34,18 @@ void RecordWriteDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(kParameterCount, default_stub_registers);
}
void DynamicMapChecksDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register default_stub_registers[] = {r2, r3, r4, r5, cp};
data->RestrictAllocatableRegisters(default_stub_registers,
arraysize(default_stub_registers));
CHECK_LE(static_cast<size_t>(kParameterCount),
arraysize(default_stub_registers));
data->InitializePlatformSpecific(kParameterCount, default_stub_registers);
}
void EphemeronKeyBarrierDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
const Register default_stub_registers[] = {r2, r3, r4, r5, r6};
......
......@@ -4619,7 +4619,7 @@ void TurboAssembler::StoreReturnAddressAndCall(Register target) {
void TurboAssembler::CallForDeoptimization(Builtins::Name target, int,
Label* exit, DeoptimizeKind kind,
Label*) {
Label* ret, Label*) {
LoadP(ip, MemOperand(kRootRegister,
IsolateData::builtin_entry_slot_offset(target)));
Call(ip);
......@@ -4627,7 +4627,11 @@ void TurboAssembler::CallForDeoptimization(Builtins::Name target, int,
(kind == DeoptimizeKind::kLazy)
? Deoptimizer::kLazyDeoptExitSize
: Deoptimizer::kNonLazyDeoptExitSize);
USE(exit, kind);
if (kind == DeoptimizeKind::kEagerWithResume) {
b(ret);
DCHECK_EQ(SizeOfCodeGeneratedSince(exit),
Deoptimizer::kEagerWithResumeDeoptExitSize);
}
}
void TurboAssembler::Trap() { stop(); }
......
......@@ -156,7 +156,7 @@ class V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase {
void Ret(Condition cond) { b(cond, r14); }
void CallForDeoptimization(Builtins::Name target, int deopt_id, Label* exit,
DeoptimizeKind kind,
DeoptimizeKind kind, Label* ret,
Label* jump_deoptimization_entry_label);
// Emit code to discard a non-negative number of pointer-sized elements
......
......@@ -14,6 +14,7 @@ namespace internal {
const bool Deoptimizer::kSupportsFixedDeoptExitSizes = true;
const int Deoptimizer::kNonLazyDeoptExitSize = 3 * kInstrSize;
const int Deoptimizer::kLazyDeoptExitSize = 3 * kInstrSize;
const int Deoptimizer::kEagerWithResumeDeoptExitSize = 4 * kInstrSize;
Float32 RegisterValues::GetFloatRegister(unsigned n) const {
float float_val = static_cast<float>(double_registers_[n].get_scalar());
......
......@@ -10,6 +10,7 @@ namespace internal {
const bool Deoptimizer::kSupportsFixedDeoptExitSizes = true;
const int Deoptimizer::kNonLazyDeoptExitSize = 6 + 2;
const int Deoptimizer::kLazyDeoptExitSize = 6 + 2;
const int Deoptimizer::kEagerWithResumeDeoptExitSize = 6 + 2 + 6;
Float32 RegisterValues::GetFloatRegister(unsigned n) const {
return Float32::FromBits(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment