Skip to content

Commit 05803c1

Browse files
zjiazV8 LUCI CQ
authored andcommitted
[loong64][mips64][compiler] Handle deopt in the fast API
Port commit 6ec2694 Change-Id: I90e65615a2e3264dab9074a35eee62b728f8602b Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/6582247 Reviewed-by: Leszek Swirski <[email protected]> Commit-Queue: Leszek Swirski <[email protected]> Auto-Submit: Zhao Jiazhong <[email protected]> Cr-Commit-Position: refs/heads/main@{#100542}
1 parent c56ee56 commit 05803c1

File tree

13 files changed

+203
-55
lines changed

13 files changed

+203
-55
lines changed

src/builtins/loong64/builtins-loong64.cc

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4864,6 +4864,51 @@ void Builtins::Generate_DeoptimizationEntry_Lazy(MacroAssembler* masm) {
48644864
Generate_DeoptimizationEntry(masm, DeoptimizeKind::kLazy);
48654865
}
48664866

4867+
void Builtins::Generate_DeoptimizationEntry_LazyAfterFastCall(
4868+
MacroAssembler* masm) {
4869+
// The deoptimizer may have been triggered right after the return of a fast
4870+
// API call. In that case, exception handling and possible stack unwinding
4871+
// did not happen yet.
4872+
// We check here if a there is a pending exception by comparing the
4873+
// exception stored in the isolate with the no-exception sentinel
4874+
// (the_hole_value). If there is an exception, we call PropagateException to
4875+
// trigger stack unwinding.
4876+
Label no_exception;
4877+
Register scratch = a0;
4878+
__ Ld_d(scratch, __ ExternalReferenceAsOperand(
4879+
ExternalReference::Create(
4880+
IsolateAddressId::kExceptionAddress, __ isolate()),
4881+
scratch));
4882+
__ CompareRootAndBranch(scratch, RootIndex::kTheHoleValue, eq, &no_exception);
4883+
4884+
__ EnterFrame(StackFrame::INTERNAL);
4885+
const RegList kCalleeSaveRegisters = {C_CALL_CALLEE_SAVE_REGISTERS};
4886+
const DoubleRegList kCalleeSaveFPRegisters = {
4887+
C_CALL_CALLEE_SAVE_FP_REGISTERS};
4888+
// DeoptimizeEntry_Lazy uses the `ra` register to determine where the deopt
4889+
// came from. The runtime call below overwrites the `ra` register. We have to
4890+
// spill it on the stack here to preserve it.
4891+
__ MultiPushFPU(kCalleeSaveFPRegisters);
4892+
__ MultiPush(kCalleeSaveRegisters);
4893+
__ li(kContextRegister, Operand(Context::kNoContext));
4894+
// We have to reset IsolateData::fast_c_call_caller_fp(), because otherwise
4895+
// the stack unwinder thinks that we are still within the fast C call.
4896+
if (v8_flags.debug_code) {
4897+
__ Ld_d(scratch,
4898+
__ ExternalReferenceAsOperand(IsolateFieldId::kFastCCallCallerFP));
4899+
__ Assert(ne, AbortReason::kFastCallFallbackInvalid, scratch,
4900+
Operand(zero_reg));
4901+
}
4902+
__ St_d(zero_reg,
4903+
__ ExternalReferenceAsOperand(IsolateFieldId::kFastCCallCallerFP));
4904+
__ CallRuntime(Runtime::FunctionId::kPropagateException);
4905+
__ MultiPop(kCalleeSaveRegisters);
4906+
__ MultiPopFPU(kCalleeSaveFPRegisters);
4907+
__ LeaveFrame(StackFrame::INTERNAL);
4908+
__ bind(&no_exception);
4909+
__ TailCallBuiltin(Builtin::kDeoptimizationEntry_Lazy);
4910+
}
4911+
48674912
// If there is baseline code on the shared function info, converts an
48684913
// interpreter frame into a baseline frame and continues execution in baseline
48694914
// code. Otherwise execution continues with bytecode.

src/builtins/mips64/builtins-mips64.cc

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3915,6 +3915,51 @@ void Builtins::Generate_DeoptimizationEntry_Lazy(MacroAssembler* masm) {
39153915
Generate_DeoptimizationEntry(masm, DeoptimizeKind::kLazy);
39163916
}
39173917

3918+
void Builtins::Generate_DeoptimizationEntry_LazyAfterFastCall(
3919+
MacroAssembler* masm) {
3920+
// The deoptimizer may have been triggered right after the return of a fast
3921+
// API call. In that case, exception handling and possible stack unwinding
3922+
// did not happen yet.
3923+
// We check here if a there is a pending exception by comparing the
3924+
// exception stored in the isolate with the no-exception sentinel
3925+
// (the_hole_value). If there is an exception, we call PropagateException to
3926+
// trigger stack unwinding.
3927+
Label no_exception;
3928+
Register scratch = a0;
3929+
__ Ld(scratch, __ ExternalReferenceAsOperand(
3930+
ExternalReference::Create(
3931+
IsolateAddressId::kExceptionAddress, __ isolate()),
3932+
scratch));
3933+
__ Branch(&no_exception, eq, scratch, RootIndex::kTheHoleValue);
3934+
3935+
__ EnterFrame(StackFrame::INTERNAL);
3936+
const RegList kCalleeSaveRegisters = {C_CALL_CALLEE_SAVE_REGISTERS};
3937+
const DoubleRegList kCalleeSaveFPRegisters = {
3938+
C_CALL_CALLEE_SAVE_FP_REGISTERS};
3939+
// DeoptimizeEntry_Lazy uses the `ra` register to determine where the deopt
3940+
// came from. The runtime call below overwrites the `ra` register. We have to
3941+
// spill it on the stack here to preserve it.
3942+
__ MultiPushFPU(kCalleeSaveFPRegisters);
3943+
__ MultiPush(kCalleeSaveRegisters);
3944+
__ li(kContextRegister, Operand(Context::kNoContext));
3945+
// We have to reset IsolateData::fast_c_call_caller_fp(), because otherwise
3946+
// the stack unwinder thinks that we are still within the fast C call.
3947+
if (v8_flags.debug_code) {
3948+
__ Ld(scratch,
3949+
__ ExternalReferenceAsOperand(IsolateFieldId::kFastCCallCallerFP));
3950+
__ Assert(ne, AbortReason::kFastCallFallbackInvalid, scratch,
3951+
Operand(zero_reg));
3952+
}
3953+
__ Sd(zero_reg,
3954+
__ ExternalReferenceAsOperand(IsolateFieldId::kFastCCallCallerFP));
3955+
__ CallRuntime(Runtime::FunctionId::kPropagateException);
3956+
__ MultiPop(kCalleeSaveRegisters);
3957+
__ MultiPopFPU(kCalleeSaveFPRegisters);
3958+
__ LeaveFrame(StackFrame::INTERNAL);
3959+
__ bind(&no_exception);
3960+
__ TailCallBuiltin(Builtin::kDeoptimizationEntry_Lazy);
3961+
}
3962+
39183963
// If there is baseline code on the shared function info, converts an
39193964
// interpreter frame into a baseline frame and continues execution in baseline
39203965
// code. Otherwise execution continues with bytecode.

src/codegen/loong64/constants-loong64.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1296,6 +1296,10 @@ bool InstructionGetters<P>::IsTrap() const {
12961296
return false;
12971297
}
12981298

1299+
// The maximum size of the stack restore after a fast API call that pops the
1300+
// stack parameters of the call off the stack.
1301+
constexpr int kMaxSizeOfMoveAfterFastCall = 4;
1302+
12991303
} // namespace internal
13001304
} // namespace v8
13011305

src/codegen/loong64/macro-assembler-loong64.cc

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4741,26 +4741,40 @@ int MacroAssembler::CallCFunctionHelper(
47414741
St_d(fp, ExternalReferenceAsOperand(IsolateFieldId::kFastCCallCallerFP));
47424742
}
47434743

4744-
Call(function);
4745-
int call_pc_offset = pc_offset();
4746-
bind(&get_pc);
4747-
if (return_location) bind(return_location);
4744+
int call_pc_offset;
4745+
{
4746+
BlockTrampolinePoolScope block_trampoline_pool(this);
4747+
Call(function);
4748+
call_pc_offset = pc_offset();
4749+
bind(&get_pc);
4750+
if (return_location) bind(return_location);
4751+
4752+
int before_offset = pc_offset();
4753+
int stack_passed_arguments =
4754+
CalculateStackPassedWords(num_reg_arguments, num_double_arguments);
4755+
4756+
if (base::OS::ActivationFrameAlignment() > kSystemPointerSize) {
4757+
Ld_d(sp, MemOperand(sp, stack_passed_arguments * kSystemPointerSize));
4758+
} else {
4759+
Add_d(sp, sp, Operand(stack_passed_arguments * kSystemPointerSize));
4760+
}
4761+
4762+
if (kMaxSizeOfMoveAfterFastCall > pc_offset() - before_offset) {
4763+
nop();
4764+
}
4765+
// We assume that with the nop padding, the move instruction uses
4766+
// kMaxSizeOfMoveAfterFastCall bytes. When we patch in the deopt
4767+
// trampoline, we patch it in after the move instruction, so that the
4768+
// stack has been restored correctly.
4769+
CHECK_EQ(kMaxSizeOfMoveAfterFastCall, pc_offset() - before_offset);
4770+
}
47484771

47494772
if (set_isolate_data_slots == SetIsolateDataSlots::kYes) {
47504773
// We don't unset the PC; the FP is the source of truth.
47514774
St_d(zero_reg,
47524775
ExternalReferenceAsOperand(IsolateFieldId::kFastCCallCallerFP));
47534776
}
47544777

4755-
int stack_passed_arguments =
4756-
CalculateStackPassedWords(num_reg_arguments, num_double_arguments);
4757-
4758-
if (base::OS::ActivationFrameAlignment() > kSystemPointerSize) {
4759-
Ld_d(sp, MemOperand(sp, stack_passed_arguments * kSystemPointerSize));
4760-
} else {
4761-
Add_d(sp, sp, Operand(stack_passed_arguments * kSystemPointerSize));
4762-
}
4763-
47644778
set_pc_for_safepoint();
47654779

47664780
return call_pc_offset;

src/codegen/loong64/register-loong64.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ namespace internal {
5252
V(f8) V(f9) V(f10) V(f11) V(f12) V(f13) V(f14) V(f15) \
5353
V(f16) V(f17) V(f18) V(f19) V(f20) V(f21) V(f22) V(f23) \
5454
V(f24) V(f25) V(f26) V(f27) V(f28)
55+
56+
#define C_CALL_CALLEE_SAVE_REGISTERS fp, s0, s1, s2, s3, s4, s5, s6, s7, s8
57+
58+
#define C_CALL_CALLEE_SAVE_FP_REGISTERS f24, f25, f26, f27, f28, f29, f30, f31
59+
5560
// clang-format on
5661

5762
// Note that the bit values must match those used in actual instruction

src/codegen/loong64/reglist-loong64.h

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,11 @@ const RegList kJSCallerSaved = {a0, a1, a2, a3, a4, a5, a6, a7,
2323
const int kNumJSCallerSaved = 15;
2424

2525
// Callee-saved registers preserved when switching from C to JavaScript.
26-
const RegList kCalleeSaved = {fp, // fp
27-
s0, // s0
28-
s1, // s1
29-
s2, // s2
30-
s3, // s3
31-
s4, // s4
32-
s5, // s5
33-
s6, // s6 (roots in Javascript code)
34-
s7, // s7 (cp in Javascript code)
35-
s8}; // s8
26+
const RegList kCalleeSaved = {C_CALL_CALLEE_SAVE_REGISTERS};
3627

3728
const int kNumCalleeSaved = 10;
3829

39-
const DoubleRegList kCalleeSavedFPU = {f24, f25, f26, f27, f28, f29, f30, f31};
30+
const DoubleRegList kCalleeSavedFPU = {C_CALL_CALLEE_SAVE_FP_REGISTERS};
4031

4132
const int kNumCalleeSavedFPU = 8;
4233

src/codegen/mips64/constants-mips64.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2024,6 +2024,11 @@ bool InstructionGetters<T>::IsForbiddenAfterBranchInstr(Instr instr) {
20242024
return false;
20252025
}
20262026
}
2027+
2028+
// The maximum size of the stack restore after a fast API call that pops the
2029+
// stack parameters of the call off the stack.
2030+
constexpr int kMaxSizeOfMoveAfterFastCall = 4;
2031+
20272032
} // namespace internal
20282033
} // namespace v8
20292034

src/codegen/mips64/macro-assembler-mips64.cc

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4728,8 +4728,9 @@ void MacroAssembler::LoadAddressPCRelative(Register dst, Label* target) {
47284728
// daddiu could handle 16-bit pc offset.
47294729
int32_t offset = branch_offset_helper(target, OffsetSize::kOffset16);
47304730
DCHECK(is_int16(offset));
4731-
mov(t8, ra);
4732-
daddiu(dst, ra, offset);
4731+
mov(t8, ra); // Delay slot and pc base address
4732+
daddiu(dst, ra, offset); // Address that ra really points to
4733+
daddiu(dst, dst, -kInstrSize); // Fix offset computed based on ra
47334734
mov(ra, t8);
47344735
}
47354736

@@ -6265,27 +6266,40 @@ int MacroAssembler::CallCFunctionHelper(
62656266
Sd(fp, ExternalReferenceAsOperand(IsolateFieldId::kFastCCallCallerFP));
62666267
}
62676268

6268-
Call(function);
6269-
int call_pc_offset = pc_offset();
6270-
bind(&get_pc);
6269+
int call_pc_offset;
6270+
{
6271+
BlockTrampolinePoolScope block_trampoline_pool(this);
6272+
Call(function);
6273+
call_pc_offset = pc_offset();
6274+
bind(&get_pc);
6275+
if (return_location) bind(return_location);
6276+
6277+
int before_offset = pc_offset();
6278+
int stack_passed_arguments =
6279+
CalculateStackPassedWords(num_reg_arguments, num_double_arguments);
6280+
6281+
if (base::OS::ActivationFrameAlignment() > kSystemPointerSize) {
6282+
Ld(sp, MemOperand(sp, stack_passed_arguments * kSystemPointerSize));
6283+
} else {
6284+
Daddu(sp, sp, Operand(stack_passed_arguments * kSystemPointerSize));
6285+
}
62716286

6272-
if (return_location) bind(return_location);
6287+
if (kMaxSizeOfMoveAfterFastCall > pc_offset() - before_offset) {
6288+
nop();
6289+
}
6290+
// We assume that with the nop padding, the move instruction uses
6291+
// kMaxSizeOfMoveAfterFastCall bytes. When we patch in the deopt
6292+
// trampoline, we patch it in after the move instruction, so that the
6293+
// stack has been restored correctly.
6294+
CHECK_EQ(kMaxSizeOfMoveAfterFastCall, pc_offset() - before_offset);
6295+
}
62736296

62746297
if (set_isolate_data_slots == SetIsolateDataSlots::kYes) {
62756298
// We don't unset the PC; the FP is the source of truth.
62766299
Sd(zero_reg,
62776300
ExternalReferenceAsOperand(IsolateFieldId::kFastCCallCallerFP));
62786301
}
62796302

6280-
int stack_passed_arguments =
6281-
CalculateStackPassedWords(num_reg_arguments, num_double_arguments);
6282-
6283-
if (base::OS::ActivationFrameAlignment() > kPointerSize) {
6284-
Ld(sp, MemOperand(sp, stack_passed_arguments * kPointerSize));
6285-
} else {
6286-
Daddu(sp, sp, Operand(stack_passed_arguments * kPointerSize));
6287-
}
6288-
62896303
set_pc_for_safepoint();
62906304

62916305
return call_pc_offset;

src/codegen/mips64/register-mips64.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ namespace internal {
4646
#define ALLOCATABLE_DOUBLE_REGISTERS(V) \
4747
V(f0) V(f2) V(f4) V(f6) V(f8) V(f10) V(f12) V(f14) \
4848
V(f16) V(f18) V(f20) V(f22) V(f24) V(f26)
49+
50+
#define C_CALL_CALLEE_SAVE_REGISTERS s0, s1, s2, s3, s4, s5, s6, s7, fp
51+
52+
#define C_CALL_CALLEE_SAVE_FP_REGISTERS f20, f22, f24, f26, f28, f30
53+
4954
// clang-format on
5055

5156
// Note that the bit values must match those used in actual instruction

src/codegen/mips64/reglist-mips64.h

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,11 @@ const RegList kJSCallerSaved = {v0, v1, a0, a1, a2, a3, a4,
2323
const int kNumJSCallerSaved = 14;
2424

2525
// Callee-saved registers preserved when switching from C to JavaScript.
26-
const RegList kCalleeSaved = {s0, // s0
27-
s1, // s1
28-
s2, // s2
29-
s3, // s3
30-
s4, // s4
31-
s5, // s5
32-
s6, // s6 (roots in Javascript code)
33-
s7, // s7 (cp in Javascript code)
34-
fp}; // fp/s8
26+
const RegList kCalleeSaved = {C_CALL_CALLEE_SAVE_REGISTERS};
3527

3628
const int kNumCalleeSaved = 9;
3729

38-
const DoubleRegList kCalleeSavedFPU = {f20, f22, f24, f26, f28, f30};
30+
const DoubleRegList kCalleeSavedFPU = {C_CALL_CALLEE_SAVE_FP_REGISTERS};
3931

4032
const int kNumCalleeSavedFPU = 6;
4133

0 commit comments

Comments
 (0)