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, ...@@ -5375,31 +5375,38 @@ void TurboAssembler::CallCFunctionHelper(Register function_base,
// Save the frame pointer and PC so that the stack layout remains iterable, // 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. // 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.
// 't' registers are caller-saved so this is safe as a scratch register. Register pc_scratch = t4;
Register scratch1 = t4; Register scratch = t5;
Register scratch2 = t5; DCHECK(!AreAliased(pc_scratch, scratch, function_base));
DCHECK(!AreAliased(scratch1, scratch2, function_base));
mov(scratch, ra);
Label get_pc; nal();
mov(scratch1, ra); mov(pc_scratch, ra);
Call(&get_pc); mov(ra, scratch);
bind(&get_pc); // See x64 code for reasoning about how to address the isolate data fields.
mov(scratch2, ra); if (root_array_available()) {
mov(ra, scratch1); sw(pc_scratch, MemOperand(kRootRegister,
IsolateData::fast_c_call_caller_pc_offset()));
li(scratch1, ExternalReference::fast_c_call_caller_pc_address(isolate())); sw(fp, MemOperand(kRootRegister,
sw(scratch2, MemOperand(scratch1)); IsolateData::fast_c_call_caller_fp_offset()));
li(scratch1, ExternalReference::fast_c_call_caller_fp_address(isolate())); } else {
sw(fp, MemOperand(scratch1)); 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); Call(function_base, function_offset);
if (isolate() != nullptr) { // We don't unset the PC; the FP is the source of truth.
// We don't unset the PC; the FP is the source of truth. if (root_array_available()) {
Register scratch = t4; 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())); li(scratch, ExternalReference::fast_c_call_caller_fp_address(isolate()));
sw(zero_reg, MemOperand(scratch)); sw(zero_reg, MemOperand(scratch));
} }
......
...@@ -5699,31 +5699,38 @@ void TurboAssembler::CallCFunctionHelper(Register function, ...@@ -5699,31 +5699,38 @@ void TurboAssembler::CallCFunctionHelper(Register function,
// Save the frame pointer and PC so that the stack layout remains iterable, // 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. // 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.
// 't' registers are caller-saved so this is safe as a scratch register. Register pc_scratch = t1;
Register scratch1 = t1; Register scratch = t2;
Register scratch2 = t2; DCHECK(!AreAliased(pc_scratch, scratch, function));
DCHECK(!AreAliased(scratch1, scratch2, function));
mov(scratch, ra);
Label get_pc; nal();
mov(scratch1, ra); mov(pc_scratch, ra);
Call(&get_pc); mov(ra, scratch);
bind(&get_pc); // See x64 code for reasoning about how to address the isolate data fields.
mov(scratch2, ra); if (root_array_available()) {
mov(ra, scratch1); Sd(pc_scratch, MemOperand(kRootRegister,
IsolateData::fast_c_call_caller_pc_offset()));
li(scratch1, ExternalReference::fast_c_call_caller_pc_address(isolate())); Sd(fp, MemOperand(kRootRegister,
Sd(scratch2, MemOperand(scratch1)); IsolateData::fast_c_call_caller_fp_offset()));
li(scratch1, ExternalReference::fast_c_call_caller_fp_address(isolate())); } else {
Sd(fp, MemOperand(scratch1)); 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); Call(function);
if (isolate() != nullptr) { // We don't unset the PC; the FP is the source of truth.
// We don't unset the PC; the FP is the source of truth. if (root_array_available()) {
Register scratch = t1; 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())); li(scratch, ExternalReference::fast_c_call_caller_fp_address(isolate()));
Sd(zero_reg, MemOperand(scratch)); Sd(zero_reg, MemOperand(scratch));
} }
......
...@@ -787,7 +787,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( ...@@ -787,7 +787,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
bool isWasmCapiFunction = bool isWasmCapiFunction =
linkage()->GetIncomingDescriptor()->IsWasmCapiFunction(); linkage()->GetIncomingDescriptor()->IsWasmCapiFunction();
// from start_call to return address. // from start_call to return address.
int offset = 40; int offset = __ root_array_available() ? 68 : 80;
#if V8_HOST_ARCH_MIPS #if V8_HOST_ARCH_MIPS
if (__ emit_debug_code()) { if (__ emit_debug_code()) {
offset += 16; offset += 16;
......
...@@ -765,7 +765,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction( ...@@ -765,7 +765,7 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
bool isWasmCapiFunction = bool isWasmCapiFunction =
linkage()->GetIncomingDescriptor()->IsWasmCapiFunction(); linkage()->GetIncomingDescriptor()->IsWasmCapiFunction();
// from start_call to return address. // from start_call to return address.
int offset = 48; int offset = __ root_array_available() ? 76 : 88;
#if V8_HOST_ARCH_MIPS64 #if V8_HOST_ARCH_MIPS64
if (__ emit_debug_code()) { if (__ emit_debug_code()) {
offset += 16; offset += 16;
......
...@@ -106,6 +106,8 @@ RegExpMacroAssemblerMIPS::RegExpMacroAssemblerMIPS(Isolate* isolate, Zone* zone, ...@@ -106,6 +106,8 @@ RegExpMacroAssemblerMIPS::RegExpMacroAssemblerMIPS(Isolate* isolate, Zone* zone,
backtrack_label_(), backtrack_label_(),
exit_label_(), exit_label_(),
internal_failure_label_() { internal_failure_label_() {
masm_->set_root_array_available(false);
DCHECK_EQ(0, registers_to_save % 2); DCHECK_EQ(0, registers_to_save % 2);
__ jmp(&entry_label_); // We'll write the entry code later. __ jmp(&entry_label_); // We'll write the entry code later.
// If the code gets too big or corrupted, an internal exception will be // If the code gets too big or corrupted, an internal exception will be
......
...@@ -142,6 +142,8 @@ RegExpMacroAssemblerMIPS::RegExpMacroAssemblerMIPS(Isolate* isolate, Zone* zone, ...@@ -142,6 +142,8 @@ RegExpMacroAssemblerMIPS::RegExpMacroAssemblerMIPS(Isolate* isolate, Zone* zone,
backtrack_label_(), backtrack_label_(),
exit_label_(), exit_label_(),
internal_failure_label_() { internal_failure_label_() {
masm_->set_root_array_available(false);
DCHECK_EQ(0, registers_to_save % 2); DCHECK_EQ(0, registers_to_save % 2);
__ jmp(&entry_label_); // We'll write the entry code later. __ jmp(&entry_label_); // We'll write the entry code later.
// If the code gets too big or corrupted, an internal exception will be // If the code gets too big or corrupted, an internal exception will be
......
...@@ -22,14 +22,15 @@ class TurboAssemblerTest : public TestWithIsolate {}; ...@@ -22,14 +22,15 @@ class TurboAssemblerTest : public TestWithIsolate {};
TEST_F(TurboAssemblerTest, TestHardAbort) { TEST_F(TurboAssemblerTest, TestHardAbort) {
auto buffer = AllocateAssemblerBuffer(); auto buffer = AllocateAssemblerBuffer();
TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, TurboAssembler tasm(isolate(), AssemblerOptions{}, CodeObjectRequired::kNo,
buffer->CreateView()); buffer->CreateView());
__ set_root_array_available(false);
__ set_abort_hard(true); __ set_abort_hard(true);
__ Abort(AbortReason::kNoReason); __ Abort(AbortReason::kNoReason);
CodeDesc desc; CodeDesc desc;
tasm.GetCode(nullptr, &desc); tasm.GetCode(isolate(), &desc);
buffer->MakeExecutable(); buffer->MakeExecutable();
// We need an isolate here to execute in the simulator. // We need an isolate here to execute in the simulator.
auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer->start()); auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer->start());
...@@ -39,8 +40,9 @@ TEST_F(TurboAssemblerTest, TestHardAbort) { ...@@ -39,8 +40,9 @@ TEST_F(TurboAssemblerTest, TestHardAbort) {
TEST_F(TurboAssemblerTest, TestCheck) { TEST_F(TurboAssemblerTest, TestCheck) {
auto buffer = AllocateAssemblerBuffer(); auto buffer = AllocateAssemblerBuffer();
TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, TurboAssembler tasm(isolate(), AssemblerOptions{}, CodeObjectRequired::kNo,
buffer->CreateView()); buffer->CreateView());
__ set_root_array_available(false);
__ set_abort_hard(true); __ set_abort_hard(true);
// Fail if the first parameter (in {a0}) is 17. // Fail if the first parameter (in {a0}) is 17.
...@@ -48,7 +50,7 @@ TEST_F(TurboAssemblerTest, TestCheck) { ...@@ -48,7 +50,7 @@ TEST_F(TurboAssemblerTest, TestCheck) {
__ Ret(); __ Ret();
CodeDesc desc; CodeDesc desc;
tasm.GetCode(nullptr, &desc); tasm.GetCode(isolate(), &desc);
buffer->MakeExecutable(); buffer->MakeExecutable();
// We need an isolate here to execute in the simulator. // We need an isolate here to execute in the simulator.
auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer->start()); auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer->start());
......
...@@ -22,14 +22,15 @@ class TurboAssemblerTest : public TestWithIsolate {}; ...@@ -22,14 +22,15 @@ class TurboAssemblerTest : public TestWithIsolate {};
TEST_F(TurboAssemblerTest, TestHardAbort) { TEST_F(TurboAssemblerTest, TestHardAbort) {
auto buffer = AllocateAssemblerBuffer(); auto buffer = AllocateAssemblerBuffer();
TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, TurboAssembler tasm(isolate(), AssemblerOptions{}, CodeObjectRequired::kNo,
buffer->CreateView()); buffer->CreateView());
__ set_root_array_available(false);
__ set_abort_hard(true); __ set_abort_hard(true);
__ Abort(AbortReason::kNoReason); __ Abort(AbortReason::kNoReason);
CodeDesc desc; CodeDesc desc;
tasm.GetCode(nullptr, &desc); tasm.GetCode(isolate(), &desc);
buffer->MakeExecutable(); buffer->MakeExecutable();
// We need an isolate here to execute in the simulator. // We need an isolate here to execute in the simulator.
auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer->start()); auto f = GeneratedCode<void>::FromBuffer(isolate(), buffer->start());
...@@ -39,8 +40,9 @@ TEST_F(TurboAssemblerTest, TestHardAbort) { ...@@ -39,8 +40,9 @@ TEST_F(TurboAssemblerTest, TestHardAbort) {
TEST_F(TurboAssemblerTest, TestCheck) { TEST_F(TurboAssemblerTest, TestCheck) {
auto buffer = AllocateAssemblerBuffer(); auto buffer = AllocateAssemblerBuffer();
TurboAssembler tasm(nullptr, AssemblerOptions{}, CodeObjectRequired::kNo, TurboAssembler tasm(isolate(), AssemblerOptions{}, CodeObjectRequired::kNo,
buffer->CreateView()); buffer->CreateView());
__ set_root_array_available(false);
__ set_abort_hard(true); __ set_abort_hard(true);
// Fail if the first parameter (in {a0}) is 17. // Fail if the first parameter (in {a0}) is 17.
...@@ -48,7 +50,7 @@ TEST_F(TurboAssemblerTest, TestCheck) { ...@@ -48,7 +50,7 @@ TEST_F(TurboAssemblerTest, TestCheck) {
__ Ret(); __ Ret();
CodeDesc desc; CodeDesc desc;
tasm.GetCode(nullptr, &desc); tasm.GetCode(isolate(), &desc);
buffer->MakeExecutable(); buffer->MakeExecutable();
// We need an isolate here to execute in the simulator. // We need an isolate here to execute in the simulator.
auto f = GeneratedCode<void, int>::FromBuffer(isolate(), buffer->start()); 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