[wasm][mips] Save FP & PC when calling C functions
Ported changes from the following CLs to mips/mips64: - https://chromium-review.googlesource.com/c/v8/v8/+/2066964 - https://chromium-review.googlesource.com/c/v8/v8/+/2071866 - https://chromium-review.googlesource.com/c/v8/v8/+/2080242 This change is needed for profiling of Wasm code that calls C-function to ignore the C-stack above the Wasm stack that otherwise couldn't be parsed otherwise. Bug: chromium:1045860 Change-Id: Ifdce5be6c5373714a67b3ce8d8c4f0a18f63b6fa Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2082566 Reviewed-by: Jakob Gruber <jgruber@chromium.org> Commit-Queue: Emanuel Ziegler <ecmziegler@chromium.org> Cr-Commit-Position: refs/heads/master@{#66785}
This commit is contained in:
parent
e80ca24c80
commit
38c3bd4866
@ -5375,31 +5375,38 @@ void TurboAssembler::CallCFunctionHelper(Register function_base,
|
||||
|
||||
// Save the frame pointer and PC so that the stack layout remains iterable,
|
||||
// even without an ExitFrame which normally exists between JS and C frames.
|
||||
if (isolate() != nullptr) {
|
||||
// 't' registers are caller-saved so this is safe as a scratch register.
|
||||
Register scratch1 = t4;
|
||||
Register scratch2 = t5;
|
||||
DCHECK(!AreAliased(scratch1, scratch2, function_base));
|
||||
// 't' registers are caller-saved so this is safe as a scratch register.
|
||||
Register pc_scratch = t4;
|
||||
Register scratch = t5;
|
||||
DCHECK(!AreAliased(pc_scratch, scratch, function_base));
|
||||
|
||||
Label get_pc;
|
||||
mov(scratch1, ra);
|
||||
Call(&get_pc);
|
||||
mov(scratch, ra);
|
||||
nal();
|
||||
mov(pc_scratch, ra);
|
||||
mov(ra, scratch);
|
||||
|
||||
bind(&get_pc);
|
||||
mov(scratch2, ra);
|
||||
mov(ra, scratch1);
|
||||
|
||||
li(scratch1, ExternalReference::fast_c_call_caller_pc_address(isolate()));
|
||||
sw(scratch2, MemOperand(scratch1));
|
||||
li(scratch1, ExternalReference::fast_c_call_caller_fp_address(isolate()));
|
||||
sw(fp, MemOperand(scratch1));
|
||||
// See x64 code for reasoning about how to address the isolate data fields.
|
||||
if (root_array_available()) {
|
||||
sw(pc_scratch, MemOperand(kRootRegister,
|
||||
IsolateData::fast_c_call_caller_pc_offset()));
|
||||
sw(fp, MemOperand(kRootRegister,
|
||||
IsolateData::fast_c_call_caller_fp_offset()));
|
||||
} else {
|
||||
DCHECK_NOT_NULL(isolate());
|
||||
li(scratch, ExternalReference::fast_c_call_caller_pc_address(isolate()));
|
||||
sw(pc_scratch, MemOperand(scratch));
|
||||
li(scratch, ExternalReference::fast_c_call_caller_fp_address(isolate()));
|
||||
sw(fp, MemOperand(scratch));
|
||||
}
|
||||
|
||||
Call(function_base, function_offset);
|
||||
|
||||
if (isolate() != nullptr) {
|
||||
// We don't unset the PC; the FP is the source of truth.
|
||||
Register scratch = t4;
|
||||
// We don't unset the PC; the FP is the source of truth.
|
||||
if (root_array_available()) {
|
||||
sw(zero_reg, MemOperand(kRootRegister,
|
||||
IsolateData::fast_c_call_caller_fp_offset()));
|
||||
} else {
|
||||
DCHECK_NOT_NULL(isolate());
|
||||
li(scratch, ExternalReference::fast_c_call_caller_fp_address(isolate()));
|
||||
sw(zero_reg, MemOperand(scratch));
|
||||
}
|
||||
|
@ -5699,31 +5699,38 @@ void TurboAssembler::CallCFunctionHelper(Register function,
|
||||
|
||||
// Save the frame pointer and PC so that the stack layout remains iterable,
|
||||
// even without an ExitFrame which normally exists between JS and C frames.
|
||||
if (isolate() != nullptr) {
|
||||
// 't' registers are caller-saved so this is safe as a scratch register.
|
||||
Register scratch1 = t1;
|
||||
Register scratch2 = t2;
|
||||
DCHECK(!AreAliased(scratch1, scratch2, function));
|
||||
// 't' registers are caller-saved so this is safe as a scratch register.
|
||||
Register pc_scratch = t1;
|
||||
Register scratch = t2;
|
||||
DCHECK(!AreAliased(pc_scratch, scratch, function));
|
||||
|
||||
Label get_pc;
|
||||
mov(scratch1, ra);
|
||||
Call(&get_pc);
|
||||
mov(scratch, ra);
|
||||
nal();
|
||||
mov(pc_scratch, ra);
|
||||
mov(ra, scratch);
|
||||
|
||||
bind(&get_pc);
|
||||
mov(scratch2, ra);
|
||||
mov(ra, scratch1);
|
||||
|
||||
li(scratch1, ExternalReference::fast_c_call_caller_pc_address(isolate()));
|
||||
Sd(scratch2, MemOperand(scratch1));
|
||||
li(scratch1, ExternalReference::fast_c_call_caller_fp_address(isolate()));
|
||||
Sd(fp, MemOperand(scratch1));
|
||||
// See x64 code for reasoning about how to address the isolate data fields.
|
||||
if (root_array_available()) {
|
||||
Sd(pc_scratch, MemOperand(kRootRegister,
|
||||
IsolateData::fast_c_call_caller_pc_offset()));
|
||||
Sd(fp, MemOperand(kRootRegister,
|
||||
IsolateData::fast_c_call_caller_fp_offset()));
|
||||
} else {
|
||||
DCHECK_NOT_NULL(isolate());
|
||||
li(scratch, ExternalReference::fast_c_call_caller_pc_address(isolate()));
|
||||
Sd(pc_scratch, MemOperand(scratch));
|
||||
li(scratch, ExternalReference::fast_c_call_caller_fp_address(isolate()));
|
||||
Sd(fp, MemOperand(scratch));
|
||||
}
|
||||
|
||||
Call(function);
|
||||
|
||||
if (isolate() != nullptr) {
|
||||
// We don't unset the PC; the FP is the source of truth.
|
||||
Register scratch = t1;
|
||||
// We don't unset the PC; the FP is the source of truth.
|
||||
if (root_array_available()) {
|
||||
Sd(zero_reg, MemOperand(kRootRegister,
|
||||
IsolateData::fast_c_call_caller_fp_offset()));
|
||||
} else {
|
||||
DCHECK_NOT_NULL(isolate());
|
||||
li(scratch, ExternalReference::fast_c_call_caller_fp_address(isolate()));
|
||||
Sd(zero_reg, MemOperand(scratch));
|
||||
}
|
||||
|
@ -787,7 +787,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
bool isWasmCapiFunction =
|
||||
linkage()->GetIncomingDescriptor()->IsWasmCapiFunction();
|
||||
// from start_call to return address.
|
||||
int offset = 40;
|
||||
int offset = __ root_array_available() ? 68 : 80;
|
||||
#if V8_HOST_ARCH_MIPS
|
||||
if (__ emit_debug_code()) {
|
||||
offset += 16;
|
||||
|
@ -765,7 +765,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
bool isWasmCapiFunction =
|
||||
linkage()->GetIncomingDescriptor()->IsWasmCapiFunction();
|
||||
// from start_call to return address.
|
||||
int offset = 48;
|
||||
int offset = __ root_array_available() ? 76 : 88;
|
||||
#if V8_HOST_ARCH_MIPS64
|
||||
if (__ emit_debug_code()) {
|
||||
offset += 16;
|
||||
|
@ -106,6 +106,8 @@ RegExpMacroAssemblerMIPS::RegExpMacroAssemblerMIPS(Isolate* isolate, Zone* zone,
|
||||
backtrack_label_(),
|
||||
exit_label_(),
|
||||
internal_failure_label_() {
|
||||
masm_->set_root_array_available(false);
|
||||
|
||||
DCHECK_EQ(0, registers_to_save % 2);
|
||||
__ jmp(&entry_label_); // We'll write the entry code later.
|
||||
// If the code gets too big or corrupted, an internal exception will be
|
||||
|
@ -142,6 +142,8 @@ RegExpMacroAssemblerMIPS::RegExpMacroAssemblerMIPS(Isolate* isolate, Zone* zone,
|
||||
backtrack_label_(),
|
||||
exit_label_(),
|
||||
internal_failure_label_() {
|
||||
masm_->set_root_array_available(false);
|
||||
|
||||
DCHECK_EQ(0, registers_to_save % 2);
|
||||
__ jmp(&entry_label_); // We'll write the entry code later.
|
||||
// If the code gets too big or corrupted, an internal exception will be
|
||||
|
@ -22,14 +22,15 @@ class TurboAssemblerTest : public TestWithIsolate {};
|
||||
|
||||
TEST_F(TurboAssemblerTest, TestHardAbort) {
|
||||
auto buffer = AllocateAssemblerBuffer();
|
||||
TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
|
||||
TurboAssembler tasm(isolate(), AssemblerOptions{}, CodeObjectRequired::kNo,
|
||||
buffer->CreateView());
|
||||
__ set_root_array_available(false);
|
||||
__ set_abort_hard(true);
|
||||
|
||||
__ Abort(AbortReason::kNoReason);
|
||||
|
||||
CodeDesc desc;
|
||||
tasm.GetCode(nullptr, &desc);
|
||||
tasm.GetCode(isolate(), &desc);
|
||||
buffer->MakeExecutable();
|
||||
// We need an isolate here to execute in the simulator.
|
||||
auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer->start());
|
||||
@ -39,8 +40,9 @@ TEST_F(TurboAssemblerTest, TestHardAbort) {
|
||||
|
||||
TEST_F(TurboAssemblerTest, TestCheck) {
|
||||
auto buffer = AllocateAssemblerBuffer();
|
||||
TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
|
||||
TurboAssembler tasm(isolate(), AssemblerOptions{}, CodeObjectRequired::kNo,
|
||||
buffer->CreateView());
|
||||
__ set_root_array_available(false);
|
||||
__ set_abort_hard(true);
|
||||
|
||||
// Fail if the first parameter (in {a0}) is 17.
|
||||
@ -48,7 +50,7 @@ TEST_F(TurboAssemblerTest, TestCheck) {
|
||||
__ Ret();
|
||||
|
||||
CodeDesc desc;
|
||||
tasm.GetCode(nullptr, &desc);
|
||||
tasm.GetCode(isolate(), &desc);
|
||||
buffer->MakeExecutable();
|
||||
// We need an isolate here to execute in the simulator.
|
||||
auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer->start());
|
||||
|
@ -22,14 +22,15 @@ class TurboAssemblerTest : public TestWithIsolate {};
|
||||
|
||||
TEST_F(TurboAssemblerTest, TestHardAbort) {
|
||||
auto buffer = AllocateAssemblerBuffer();
|
||||
TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
|
||||
TurboAssembler tasm(isolate(), AssemblerOptions{}, CodeObjectRequired::kNo,
|
||||
buffer->CreateView());
|
||||
__ set_root_array_available(false);
|
||||
__ set_abort_hard(true);
|
||||
|
||||
__ Abort(AbortReason::kNoReason);
|
||||
|
||||
CodeDesc desc;
|
||||
tasm.GetCode(nullptr, &desc);
|
||||
tasm.GetCode(isolate(), &desc);
|
||||
buffer->MakeExecutable();
|
||||
// We need an isolate here to execute in the simulator.
|
||||
auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer->start());
|
||||
@ -39,8 +40,9 @@ TEST_F(TurboAssemblerTest, TestHardAbort) {
|
||||
|
||||
TEST_F(TurboAssemblerTest, TestCheck) {
|
||||
auto buffer = AllocateAssemblerBuffer();
|
||||
TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo,
|
||||
TurboAssembler tasm(isolate(), AssemblerOptions{}, CodeObjectRequired::kNo,
|
||||
buffer->CreateView());
|
||||
__ set_root_array_available(false);
|
||||
__ set_abort_hard(true);
|
||||
|
||||
// Fail if the first parameter (in {a0}) is 17.
|
||||
@ -48,7 +50,7 @@ TEST_F(TurboAssemblerTest, TestCheck) {
|
||||
__ Ret();
|
||||
|
||||
CodeDesc desc;
|
||||
tasm.GetCode(nullptr, &desc);
|
||||
tasm.GetCode(isolate(), &desc);
|
||||
buffer->MakeExecutable();
|
||||
// We need an isolate here to execute in the simulator.
|
||||
auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer->start());
|
||||
|
Loading…
Reference in New Issue
Block a user