[loong64][mips] Fix safepoint record of CallCFunction

Currently, the safepoint is last call instruction's return address on
mips and loongarch64 platform. But in `CallCFunction`, there are some
other instructions after calling, which leading to a wrong safepoint
record on mips and loongarch64.

So I record the pc for safepoint at the end of `CallCFunction`
function, and change `last_call_pc_` to `pc_for_safepoint_`.

Besides, commit 48b2b89176 introduced
a typo on loong64 platform, I also fixed it in this CL.

Change-Id: Ia3ea77ae2f6f1c8c604e35f420a7632a78c9725a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3258875
Commit-Queue: Zhao Jiazhong <zhaojiazhong-hf@loongson.cn>
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: Victor Gomes <victorgomes@chromium.org>
Cr-Commit-Position: refs/heads/main@{#77694}
This commit is contained in:
Zhao Jiazhong 2021-11-03 18:32:45 +08:00 committed by V8 LUCI CQ
parent 92eae6d126
commit f385232a87
12 changed files with 60 additions and 91 deletions

View File

@ -2137,7 +2137,7 @@ void Assembler::GrowBuffer() {
buffer_ = std::move(new_buffer);
buffer_start_ = new_start;
pc_ += pc_delta;
last_call_pc_ += pc_delta;
pc_for_safepoint_ += pc_delta;
reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
reloc_info_writer.last_pc() + pc_delta);

View File

@ -142,14 +142,13 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
void MaybeEmitOutOfLineConstantPool() {}
// Loong64 uses BlockTrampolinePool to prevent generating trampoline inside a
// continuous instruction block. In the destructor of
// BlockTrampolinePool, it must check if it needs to generate trampoline
// immediately, if it does not do this, the branch range will go beyond the
// max branch offset, that means the pc_offset after call CheckTrampolinePool
// may be not the Call instruction's location. So we use last_call_pc here for
// safepoint record.
// continuous instruction block. In the destructor of BlockTrampolinePool, it
// must check if it needs to generate trampoline immediately, if it does not
// do this, the branch range will go beyond the max branch offset, that means
// the pc_offset after call CheckTrampolinePool may have changed. So we use
// pc_for_safepoint_ here for safepoint record.
int pc_offset_for_safepoint() {
return static_cast<int>(last_call_pc_ - buffer_start_);
return static_cast<int>(pc_for_safepoint_ - buffer_start_);
}
// TODO(LOONG_dev): LOONG64 Check this comment
@ -890,7 +889,7 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
}
}
void set_last_call_pc_(byte* pc) { last_call_pc_ = pc; }
void set_pc_for_safepoint() { pc_for_safepoint_ = pc_; }
private:
// Avoid overflows for displacements etc.
@ -1062,7 +1061,7 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
// Keep track of the last Call's position to ensure that safepoint can get the
// correct information even if there is a trampoline immediately after the
// Call.
byte* last_call_pc_;
byte* pc_for_safepoint_;
RegList scratch_register_list_;

View File

@ -2653,7 +2653,7 @@ void TurboAssembler::Call(Register target, Condition cond, Register rj,
jirl(ra, target, 0);
bind(&skip);
}
set_last_call_pc_(pc_);
set_pc_for_safepoint();
}
void MacroAssembler::JumpIfIsInRange(Register value, unsigned lower_limit,
@ -2708,7 +2708,7 @@ void TurboAssembler::Call(Handle<Code> code, RelocInfo::Mode rmode,
RecordCommentForOffHeapTrampoline(builtin);
RecordRelocInfo(RelocInfo::RELATIVE_CODE_TARGET);
bl(code_target_index);
set_last_call_pc_(pc_);
set_pc_for_safepoint();
bind(&skip);
RecordComment("]");
return;
@ -4010,15 +4010,17 @@ void TurboAssembler::CallCFunctionHelper(Register function,
li(scratch, ExternalReference::fast_c_call_caller_fp_address(isolate()));
St_d(zero_reg, MemOperand(scratch, 0));
}
}
int stack_passed_arguments =
CalculateStackPassedWords(num_reg_arguments, num_double_arguments);
int stack_passed_arguments =
CalculateStackPassedWords(num_reg_arguments, num_double_arguments);
if (base::OS::ActivationFrameAlignment() > kPointerSize) {
Ld_d(sp, MemOperand(sp, stack_passed_arguments * kPointerSize));
} else {
Add_d(sp, sp, Operand(stack_passed_arguments * kPointerSize));
if (base::OS::ActivationFrameAlignment() > kPointerSize) {
Ld_d(sp, MemOperand(sp, stack_passed_arguments * kPointerSize));
} else {
Add_d(sp, sp, Operand(stack_passed_arguments * kPointerSize));
}
set_pc_for_safepoint();
}
}

View File

@ -3564,7 +3564,7 @@ void Assembler::GrowBuffer() {
buffer_ = std::move(new_buffer);
buffer_start_ = new_start;
pc_ += pc_delta;
last_call_pc_ += pc_delta;
pc_for_safepoint_ += pc_delta;
reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
reloc_info_writer.last_pc() + pc_delta);
@ -3828,7 +3828,7 @@ void Assembler::GenPCRelativeJumpAndLink(Register t, int32_t imm32,
addu(t, ra, t);
jalr(t);
if (bdslot == PROTECT) nop();
set_last_call_pc_(pc_);
set_pc_for_safepoint();
}
UseScratchRegisterScope::UseScratchRegisterScope(Assembler* assembler)

View File

@ -176,27 +176,9 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
// BlockTrampolinePool, it must check if it needs to generate trampoline
// immediately, if it does not do this, the branch range will go beyond the
// max branch offset, that means the pc_offset after call CheckTrampolinePool
// may be not the Call instruction's location. So we use last_call_pc here for
// safepoint record.
// may have changed. So we use pc_for_safepoint_ here for safepoint record.
int pc_offset_for_safepoint() {
#ifdef DEBUG
Instr instr1 =
instr_at(static_cast<int>(last_call_pc_ - buffer_start_ - kInstrSize));
Instr instr2 = instr_at(
static_cast<int>(last_call_pc_ - buffer_start_ - kInstrSize * 2));
if (GetOpcodeField(instr1) != SPECIAL) { // instr1 == jialc.
DCHECK(IsMipsArchVariant(kMips32r6) && GetOpcodeField(instr1) == POP76 &&
GetRs(instr1) == 0);
} else {
if (GetFunctionField(instr1) == SLL) { // instr1 == nop, instr2 == jalr.
DCHECK(GetOpcodeField(instr2) == SPECIAL &&
GetFunctionField(instr2) == JALR);
} else { // instr1 == jalr.
DCHECK(GetFunctionField(instr1) == JALR);
}
}
#endif
return static_cast<int>(last_call_pc_ - buffer_start_);
return static_cast<int>(pc_for_safepoint_ - buffer_start_);
}
// Label operations & relative jumps (PPUM Appendix D).
@ -1625,7 +1607,7 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
void GenPCRelativeJumpAndLink(Register t, int32_t imm32,
RelocInfo::Mode rmode, BranchDelaySlot bdslot);
void set_last_call_pc_(byte* pc) { last_call_pc_ = pc; }
void set_pc_for_safepoint() { pc_for_safepoint_ = pc_; }
private:
// Avoid overflows for displacements etc.
@ -1893,7 +1875,7 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
// Keep track of the last Call's position to ensure that safepoint can get the
// correct information even if there is a trampoline immediately after the
// Call.
byte* last_call_pc_;
byte* pc_for_safepoint_;
private:
void AllocateAndInstallRequestedHeapObjects(Isolate* isolate);

View File

@ -3851,7 +3851,7 @@ void TurboAssembler::Call(Register target, int16_t offset, Condition cond,
// Emit a nop in the branch delay slot if required.
if (bd == PROTECT) nop();
}
set_last_call_pc_(pc_);
set_pc_for_safepoint();
}
// Note: To call gcc-compiled C code on mips, you must call through t9.
@ -3884,7 +3884,7 @@ void TurboAssembler::Call(Register target, Register base, int16_t offset,
// Emit a nop in the branch delay slot if required.
if (bd == PROTECT) nop();
}
set_last_call_pc_(pc_);
set_pc_for_safepoint();
}
void TurboAssembler::Call(Address target, RelocInfo::Mode rmode, Condition cond,
@ -5489,15 +5489,17 @@ void TurboAssembler::CallCFunctionHelper(Register function_base,
li(scratch, ExternalReference::fast_c_call_caller_fp_address(isolate()));
sw(zero_reg, MemOperand(scratch));
}
}
int stack_passed_arguments =
CalculateStackPassedWords(num_reg_arguments, num_double_arguments);
int stack_passed_arguments =
CalculateStackPassedWords(num_reg_arguments, num_double_arguments);
if (base::OS::ActivationFrameAlignment() > kPointerSize) {
lw(sp, MemOperand(sp, stack_passed_arguments * kPointerSize));
} else {
Addu(sp, sp, Operand(stack_passed_arguments * kPointerSize));
if (base::OS::ActivationFrameAlignment() > kPointerSize) {
lw(sp, MemOperand(sp, stack_passed_arguments * kPointerSize));
} else {
Addu(sp, sp, Operand(stack_passed_arguments * kPointerSize));
}
set_pc_for_safepoint();
}
}

View File

@ -3764,7 +3764,7 @@ void Assembler::GrowBuffer() {
buffer_ = std::move(new_buffer);
buffer_start_ = new_start;
pc_ += pc_delta;
last_call_pc_ += pc_delta;
pc_for_safepoint_ += pc_delta;
reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
reloc_info_writer.last_pc() + pc_delta);

View File

@ -176,27 +176,9 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
// BlockTrampolinePool, it must check if it needs to generate trampoline
// immediately, if it does not do this, the branch range will go beyond the
// max branch offset, that means the pc_offset after call CheckTrampolinePool
// may be not the Call instruction's location. So we use last_call_pc here for
// safepoint record.
// may have changed. So we use pc_for_safepoint_ here for safepoint record.
int pc_offset_for_safepoint() {
#ifdef DEBUG
Instr instr1 =
instr_at(static_cast<int>(last_call_pc_ - buffer_start_ - kInstrSize));
Instr instr2 = instr_at(
static_cast<int>(last_call_pc_ - buffer_start_ - kInstrSize * 2));
if (GetOpcodeField(instr1) != SPECIAL) { // instr1 == jialc.
DCHECK((kArchVariant == kMips64r6) && GetOpcodeField(instr1) == POP76 &&
GetRs(instr1) == 0);
} else {
if (GetFunctionField(instr1) == SLL) { // instr1 == nop, instr2 == jalr.
DCHECK(GetOpcodeField(instr2) == SPECIAL &&
GetFunctionField(instr2) == JALR);
} else { // instr1 == jalr.
DCHECK(GetFunctionField(instr1) == JALR);
}
}
#endif
return static_cast<int>(last_call_pc_ - buffer_start_);
return static_cast<int>(pc_for_safepoint_ - buffer_start_);
}
// Label operations & relative jumps (PPUM Appendix D).
@ -1663,7 +1645,7 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
}
}
void set_last_call_pc_(byte* pc) { last_call_pc_ = pc; }
void set_pc_for_safepoint() { pc_for_safepoint_ = pc_; }
private:
// Avoid overflows for displacements etc.
@ -1921,7 +1903,7 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
// Keep track of the last Call's position to ensure that safepoint can get the
// correct information even if there is a trampoline immediately after the
// Call.
byte* last_call_pc_;
byte* pc_for_safepoint_;
RegList scratch_register_list_;

View File

@ -4384,7 +4384,7 @@ void TurboAssembler::Call(Register target, Condition cond, Register rs,
// Emit a nop in the branch delay slot if required.
if (bd == PROTECT) nop();
}
set_last_call_pc_(pc_);
set_pc_for_safepoint();
}
void MacroAssembler::JumpIfIsInRange(Register value, unsigned lower_limit,
@ -6030,15 +6030,17 @@ void TurboAssembler::CallCFunctionHelper(Register function,
li(scratch, ExternalReference::fast_c_call_caller_fp_address(isolate()));
Sd(zero_reg, MemOperand(scratch));
}
}
int stack_passed_arguments =
CalculateStackPassedWords(num_reg_arguments, num_double_arguments);
int stack_passed_arguments =
CalculateStackPassedWords(num_reg_arguments, num_double_arguments);
if (base::OS::ActivationFrameAlignment() > kPointerSize) {
Ld(sp, MemOperand(sp, stack_passed_arguments * kPointerSize));
} else {
Daddu(sp, sp, Operand(stack_passed_arguments * kPointerSize));
if (base::OS::ActivationFrameAlignment() > kPointerSize) {
Ld(sp, MemOperand(sp, stack_passed_arguments * kPointerSize));
} else {
Daddu(sp, sp, Operand(stack_passed_arguments * kPointerSize));
}
set_pc_for_safepoint();
}
}

View File

@ -703,7 +703,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
#if V8_ENABLE_WEBASSEMBLY
if (isWasmCapiFunction) {
__ bind(&start_call);
__ pcaddi(t7, -4);
__ pcaddi(t7, offset >> kInstrSizeLog2);
__ St_d(t7, MemOperand(fp, WasmExitFrameConstants::kCallingPCOffset));
}
#endif // V8_ENABLE_WEBASSEMBLY
@ -2216,7 +2216,7 @@ void CodeGenerator::AssembleConstructFrame() {
} else {
__ StubPrologue(info()->GetOutputStackFrameType());
#if V8_ENABLE_WEBASSEMBLY
if (call_descriptor->IsWasmImportWrapper() ||
if (call_descriptor->IsWasmFunctionCall() ||
call_descriptor->IsWasmImportWrapper() ||
call_descriptor->IsWasmCapiFunction()) {
__ Push(kWasmInstanceRegister);

View File

@ -5545,15 +5545,15 @@ TEST(Call_with_trampoline) {
__ Call(FUNCTION_ADDR(DummyFunction), RelocInfo::RUNTIME_ENTRY);
}
int pc_offset_after = __ pc_offset();
int last_call_pc = __ pc_offset_for_safepoint();
int safepoint_pc_offset = __ pc_offset_for_safepoint();
// Without trampoline, the Call emits no more than 6 instructions, otherwise
// more than 6 instructions will be generated.
int num_instrs = 6;
// pc_offset_after records the offset after trampoline.
CHECK_GT(pc_offset_after - pc_offset_before, num_instrs * kInstrSize);
// last_call_pc records the offset before trampoline.
CHECK_LE(last_call_pc - pc_offset_before, num_instrs * kInstrSize);
// safepoint_pc_offset records the offset before trampoline.
CHECK_LE(safepoint_pc_offset - pc_offset_before, num_instrs * kInstrSize);
__ bind(&done);
}

View File

@ -6236,15 +6236,15 @@ TEST(Call_with_trampoline) {
__ Call(FUNCTION_ADDR(DummyFunction), RelocInfo::RUNTIME_ENTRY);
}
int pc_offset_after = __ pc_offset();
int last_call_pc = __ pc_offset_for_safepoint();
int safepoint_pc_offset = __ pc_offset_for_safepoint();
// Without trampoline, the Call emits no more than 8 instructions, otherwise
// more than 8 instructions will be generated.
int num_instrs = 8;
// pc_offset_after records the offset after trampoline.
CHECK_GT(pc_offset_after - pc_offset_before, num_instrs * kInstrSize);
// last_call_pc records the offset before trampoline.
CHECK_LE(last_call_pc - pc_offset_before, num_instrs * kInstrSize);
// safepoint_pc_offset records the offset before trampoline.
CHECK_LE(safepoint_pc_offset - pc_offset_before, num_instrs * kInstrSize);
__ bind(&done);
}