[wasm] Update stack limits on stack switch
This is done in a separate runtime function call for now, so that we can update the limit under the ExecutionAcess lock. Also set the thread-in-wasm flag before calling the wasm function. R=ahaas@chromium.org CC=fgm@chromium.org Bug: v8:12191 Change-Id: I914856bc261fa0f75e93620bc6597bd28bec0695 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3250902 Reviewed-by: Andreas Haas <ahaas@chromium.org> Commit-Queue: Thibaud Michaud <thibaudm@chromium.org> Cr-Commit-Position: refs/heads/main@{#77613}
This commit is contained in:
parent
c249bf6f16
commit
f4b4bfdcd3
@ -3642,11 +3642,9 @@ void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// Helper function for WasmReturnPromiseOnSuspend.
|
// Helper function for WasmReturnPromiseOnSuspend.
|
||||||
void LoadJumpBuffer(MacroAssembler* masm, Register jmpbuf,
|
void LoadJumpBuffer(MacroAssembler* masm, Register jmpbuf) {
|
||||||
Register stack_limit_address, Register stack_limit_tmp) {
|
|
||||||
__ movq(rsp, MemOperand(jmpbuf, wasm::kJmpBufSpOffset));
|
__ movq(rsp, MemOperand(jmpbuf, wasm::kJmpBufSpOffset));
|
||||||
__ movq(stack_limit_tmp, MemOperand(jmpbuf, wasm::kJmpBufStackLimitOffset));
|
// The stack limit is set separately under the ExecutionAccess lock.
|
||||||
__ movq(MemOperand(stack_limit_address, 0), stack_limit_tmp);
|
|
||||||
// TODO(thibaudm): Reload live registers.
|
// TODO(thibaudm): Reload live registers.
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
@ -3712,7 +3710,7 @@ void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) {
|
|||||||
Register stack_limit_address = rcx;
|
Register stack_limit_address = rcx;
|
||||||
__ movq(stack_limit_address,
|
__ movq(stack_limit_address,
|
||||||
FieldOperand(wasm_instance,
|
FieldOperand(wasm_instance,
|
||||||
WasmInstanceObject::kStackLimitAddressOffset));
|
WasmInstanceObject::kRealStackLimitAddressOffset));
|
||||||
Register stack_limit = rdx;
|
Register stack_limit = rdx;
|
||||||
__ movq(stack_limit, MemOperand(stack_limit_address, 0));
|
__ movq(stack_limit, MemOperand(stack_limit_address, 0));
|
||||||
__ movq(MemOperand(jmpbuf, wasm::kJmpBufStackLimitOffset), stack_limit);
|
__ movq(MemOperand(jmpbuf, wasm::kJmpBufStackLimitOffset), stack_limit);
|
||||||
@ -3720,7 +3718,7 @@ void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) {
|
|||||||
foreign_jmpbuf = no_reg;
|
foreign_jmpbuf = no_reg;
|
||||||
stack_limit = no_reg;
|
stack_limit = no_reg;
|
||||||
stack_limit_address = no_reg;
|
stack_limit_address = no_reg;
|
||||||
// live: [rsi, rdi, rax, rcx]
|
// live: [rsi, rdi, rax]
|
||||||
|
|
||||||
// -------------------------------------------
|
// -------------------------------------------
|
||||||
// Allocate a new continuation.
|
// Allocate a new continuation.
|
||||||
@ -3749,16 +3747,11 @@ void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) {
|
|||||||
target_jmpbuf,
|
target_jmpbuf,
|
||||||
FieldOperand(foreign_jmpbuf, Foreign::kForeignAddressOffset),
|
FieldOperand(foreign_jmpbuf, Foreign::kForeignAddressOffset),
|
||||||
kForeignForeignAddressTag, r8);
|
kForeignForeignAddressTag, r8);
|
||||||
stack_limit_address = rcx;
|
|
||||||
__ movq(stack_limit_address,
|
|
||||||
FieldOperand(wasm_instance,
|
|
||||||
WasmInstanceObject::kStackLimitAddressOffset));
|
|
||||||
// Switch stack!
|
// Switch stack!
|
||||||
LoadJumpBuffer(masm, target_jmpbuf, stack_limit_address, rdx);
|
LoadJumpBuffer(masm, target_jmpbuf);
|
||||||
__ movq(rbp, rsp); // New stack, there is no frame yet.
|
__ movq(rbp, rsp); // New stack, there is no frame yet.
|
||||||
foreign_jmpbuf = no_reg;
|
foreign_jmpbuf = no_reg;
|
||||||
target_jmpbuf = no_reg;
|
target_jmpbuf = no_reg;
|
||||||
stack_limit_address = no_reg;
|
|
||||||
// live: [rsi, rdi]
|
// live: [rsi, rdi]
|
||||||
|
|
||||||
// -------------------------------------------
|
// -------------------------------------------
|
||||||
@ -3766,6 +3759,12 @@ void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) {
|
|||||||
// -------------------------------------------
|
// -------------------------------------------
|
||||||
// TODO(thibaudm): Handle arguments.
|
// TODO(thibaudm): Handle arguments.
|
||||||
// TODO(thibaudm): Handle GC.
|
// TODO(thibaudm): Handle GC.
|
||||||
|
// Set thread_in_wasm_flag.
|
||||||
|
Register thread_in_wasm_flag_addr = rax;
|
||||||
|
__ movq(
|
||||||
|
thread_in_wasm_flag_addr,
|
||||||
|
MemOperand(kRootRegister, Isolate::thread_in_wasm_flag_address_offset()));
|
||||||
|
__ movl(MemOperand(thread_in_wasm_flag_addr, 0), Immediate(1));
|
||||||
Register function_entry = function_data;
|
Register function_entry = function_data;
|
||||||
__ LoadExternalPointerField(
|
__ LoadExternalPointerField(
|
||||||
function_entry,
|
function_entry,
|
||||||
@ -3775,6 +3774,12 @@ void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) {
|
|||||||
__ Push(wasm_instance);
|
__ Push(wasm_instance);
|
||||||
__ call(function_entry);
|
__ call(function_entry);
|
||||||
__ Pop(wasm_instance);
|
__ Pop(wasm_instance);
|
||||||
|
// Unset thread_in_wasm_flag.
|
||||||
|
__ movq(
|
||||||
|
thread_in_wasm_flag_addr,
|
||||||
|
MemOperand(kRootRegister, Isolate::thread_in_wasm_flag_address_offset()));
|
||||||
|
__ movl(MemOperand(thread_in_wasm_flag_addr, 0), Immediate(0));
|
||||||
|
thread_in_wasm_flag_addr = no_reg;
|
||||||
function_entry = no_reg;
|
function_entry = no_reg;
|
||||||
function_data = no_reg;
|
function_data = no_reg;
|
||||||
// live: [rsi]
|
// live: [rsi]
|
||||||
@ -3819,16 +3824,16 @@ void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) {
|
|||||||
__ LoadExternalPointerField(
|
__ LoadExternalPointerField(
|
||||||
jmpbuf, FieldOperand(foreign_jmpbuf, Foreign::kForeignAddressOffset),
|
jmpbuf, FieldOperand(foreign_jmpbuf, Foreign::kForeignAddressOffset),
|
||||||
kForeignForeignAddressTag, r8);
|
kForeignForeignAddressTag, r8);
|
||||||
stack_limit_address = rcx;
|
|
||||||
__ movq(stack_limit_address,
|
|
||||||
FieldOperand(wasm_instance,
|
|
||||||
WasmInstanceObject::kStackLimitAddressOffset));
|
|
||||||
// Switch stack!
|
// Switch stack!
|
||||||
LoadJumpBuffer(masm, jmpbuf, stack_limit_address, rdx);
|
LoadJumpBuffer(masm, jmpbuf);
|
||||||
__ leaq(rbp, Operand(rsp, (kNumSpillSlots + 1) * kSystemPointerSize));
|
__ leaq(rbp, Operand(rsp, (kNumSpillSlots + 1) * kSystemPointerSize));
|
||||||
|
__ Push(wasm_instance); // Spill.
|
||||||
|
__ Push(wasm_instance); // First arg.
|
||||||
|
__ Move(kContextRegister, Smi::zero());
|
||||||
|
__ CallRuntime(Runtime::kWasmSyncStackLimit);
|
||||||
|
__ Pop(wasm_instance);
|
||||||
parent = no_reg;
|
parent = no_reg;
|
||||||
active_continuation = no_reg;
|
active_continuation = no_reg;
|
||||||
stack_limit_address = no_reg;
|
|
||||||
foreign_jmpbuf = no_reg;
|
foreign_jmpbuf = no_reg;
|
||||||
wasm_instance = no_reg;
|
wasm_instance = no_reg;
|
||||||
|
|
||||||
|
@ -681,6 +681,25 @@ RUNTIME_FUNCTION(Runtime_WasmArrayCopy) {
|
|||||||
return ReadOnlyRoots(isolate).undefined_value();
|
return ReadOnlyRoots(isolate).undefined_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// Synchronize the stack limit with the active continuation for stack-switching.
|
||||||
|
// This can be done before or after changing the stack pointer itself, as long
|
||||||
|
// as we update both before the next stack check.
|
||||||
|
// {StackGuard::SetStackLimit} doesn't update the value of the jslimit if it
|
||||||
|
// contains a sentinel value, and it is also thread-safe. So if an interrupt is
|
||||||
|
// requested before, during or after this call, it will be preserved and handled
|
||||||
|
// at the next stack check.
|
||||||
|
void SyncStackLimit(Isolate* isolate, Handle<WasmInstanceObject> instance) {
|
||||||
|
auto jmpbuf = Managed<wasm::JumpBuffer>::cast(
|
||||||
|
instance->active_continuation().managed_jmpbuf())
|
||||||
|
.get();
|
||||||
|
uintptr_t limit = reinterpret_cast<uintptr_t>(jmpbuf->stack_limit);
|
||||||
|
isolate->stack_guard()->SetStackLimit(limit);
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
// Allocate a new continuation, and prepare for stack switching by updating the
|
||||||
|
// active continuation and setting the stack limit.
|
||||||
RUNTIME_FUNCTION(Runtime_WasmAllocateContinuation) {
|
RUNTIME_FUNCTION(Runtime_WasmAllocateContinuation) {
|
||||||
CHECK(FLAG_experimental_wasm_stack_switching);
|
CHECK(FLAG_experimental_wasm_stack_switching);
|
||||||
DCHECK_EQ(1, args.length());
|
DCHECK_EQ(1, args.length());
|
||||||
@ -689,8 +708,18 @@ RUNTIME_FUNCTION(Runtime_WasmAllocateContinuation) {
|
|||||||
auto parent = instance->active_continuation();
|
auto parent = instance->active_continuation();
|
||||||
auto target = WasmContinuationObject::New(isolate, parent);
|
auto target = WasmContinuationObject::New(isolate, parent);
|
||||||
instance->set_active_continuation(*target);
|
instance->set_active_continuation(*target);
|
||||||
|
SyncStackLimit(isolate, instance);
|
||||||
return *target;
|
return *target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update the stack limit after a stack switch, and preserve pending interrupts.
|
||||||
|
RUNTIME_FUNCTION(Runtime_WasmSyncStackLimit) {
|
||||||
|
CHECK(FLAG_experimental_wasm_stack_switching);
|
||||||
|
HandleScope scope(isolate);
|
||||||
|
CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
|
||||||
|
SyncStackLimit(isolate, instance);
|
||||||
|
return ReadOnlyRoots(isolate).undefined_value();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace v8
|
} // namespace v8
|
||||||
|
@ -596,7 +596,8 @@ namespace internal {
|
|||||||
F(WasmAllocateRtt, 3, 1) \
|
F(WasmAllocateRtt, 3, 1) \
|
||||||
F(WasmArrayCopy, 5, 1) \
|
F(WasmArrayCopy, 5, 1) \
|
||||||
F(WasmAllocateContinuation, 1, 1) \
|
F(WasmAllocateContinuation, 1, 1) \
|
||||||
F(WasmReturnPromiseOnSuspend, 1, 1)
|
F(WasmReturnPromiseOnSuspend, 1, 1) \
|
||||||
|
F(WasmSyncStackLimit, 1, 1)
|
||||||
|
|
||||||
#define FOR_EACH_INTRINSIC_WASM_TEST(F, I) \
|
#define FOR_EACH_INTRINSIC_WASM_TEST(F, I) \
|
||||||
F(DeserializeWasmModule, 2, 1) \
|
F(DeserializeWasmModule, 2, 1) \
|
||||||
|
Loading…
Reference in New Issue
Block a user