Commit 38c3bd48 authored by Emanuel Ziegler's avatar Emanuel Ziegler Committed by Commit Bot

[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/+/2082566Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Commit-Queue: Emanuel Ziegler <ecmziegler@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66785}
parent e80ca24c
......@@ -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));
Label get_pc;
mov(scratch1, ra);
Call(&get_pc);
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));
// '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));
mov(scratch, ra);
nal();
mov(pc_scratch, ra);
mov(ra, scratch);
// 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));
Label get_pc;
mov(scratch1, ra);
Call(&get_pc);
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));
// '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));
mov(scratch, ra);
nal();
mov(pc_scratch, ra);
mov(ra, scratch);
// 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());
......
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