Commit 0443eb2e authored by Thibaud Michaud's avatar Thibaud Michaud Committed by V8 LUCI CQ

[wasm] Introduce stack-switching frame type

And make the GC visit spilled references in the frame.

R=ahaas@chromium.org
CC=​fgm@chromium.org

Bug: v8:12191
Change-Id: Ida430f12a6de7658972e7890542fb02f7f7ddbb1
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3226784
Commit-Queue: Thibaud Michaud <thibaudm@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/main@{#77763}
parent 13bcdc5b
...@@ -2962,15 +2962,9 @@ void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) { ...@@ -2962,15 +2962,9 @@ void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
// ------------------------------------------- // -------------------------------------------
// Compute offsets and prepare for GC. // Compute offsets and prepare for GC.
// ------------------------------------------- // -------------------------------------------
// We will have to save a value indicating the GC the number
// of values on the top of the stack that have to be scanned before calling
// the Wasm function.
constexpr int kFrameMarkerOffset = -kSystemPointerSize;
constexpr int kGCScanSlotCountOffset =
kFrameMarkerOffset - kSystemPointerSize;
// The number of parameters passed to this function. // The number of parameters passed to this function.
constexpr int kInParamCountOffset = constexpr int kInParamCountOffset =
kGCScanSlotCountOffset - kSystemPointerSize; BuiltinWasmWrapperConstants::kGCScanSlotCountOffset - kSystemPointerSize;
// The number of parameters according to the signature. // The number of parameters according to the signature.
constexpr int kParamCountOffset = kInParamCountOffset - kSystemPointerSize; constexpr int kParamCountOffset = kInParamCountOffset - kSystemPointerSize;
constexpr int kReturnCountOffset = kParamCountOffset - kSystemPointerSize; constexpr int kReturnCountOffset = kParamCountOffset - kSystemPointerSize;
...@@ -3387,7 +3381,8 @@ void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) { ...@@ -3387,7 +3381,8 @@ void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
// We set the indicating value for the GC to the proper one for Wasm call. // We set the indicating value for the GC to the proper one for Wasm call.
constexpr int kWasmCallGCScanSlotCount = 0; constexpr int kWasmCallGCScanSlotCount = 0;
__ Move(MemOperand(rbp, kGCScanSlotCountOffset), kWasmCallGCScanSlotCount); __ Move(MemOperand(rbp, BuiltinWasmWrapperConstants::kGCScanSlotCountOffset),
kWasmCallGCScanSlotCount);
// ------------------------------------------- // -------------------------------------------
// Call the Wasm function. // Call the Wasm function.
...@@ -3470,10 +3465,12 @@ void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) { ...@@ -3470,10 +3465,12 @@ void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
// The builtin expects the parameter to be in register param = rax. // The builtin expects the parameter to be in register param = rax.
constexpr int kBuiltinCallGCScanSlotCount = 2; constexpr int kBuiltinCallGCScanSlotCount = 2;
PrepareForBuiltinCall(masm, MemOperand(rbp, kGCScanSlotCountOffset), PrepareForBuiltinCall(
kBuiltinCallGCScanSlotCount, current_param, param_limit, masm,
current_int_param_slot, current_float_param_slot, MemOperand(rbp, BuiltinWasmWrapperConstants::kGCScanSlotCountOffset),
valuetypes_array_ptr, wasm_instance, function_data); kBuiltinCallGCScanSlotCount, current_param, param_limit,
current_int_param_slot, current_float_param_slot, valuetypes_array_ptr,
wasm_instance, function_data);
Label param_kWasmI32_not_smi; Label param_kWasmI32_not_smi;
Label param_kWasmI64; Label param_kWasmI64;
...@@ -3620,7 +3617,8 @@ void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) { ...@@ -3620,7 +3617,8 @@ void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
// ------------------------------------------- // -------------------------------------------
__ bind(&compile_wrapper); __ bind(&compile_wrapper);
// Enable GC. // Enable GC.
MemOperand GCScanSlotPlace = MemOperand(rbp, kGCScanSlotCountOffset); MemOperand GCScanSlotPlace =
MemOperand(rbp, BuiltinWasmWrapperConstants::kGCScanSlotCountOffset);
__ Move(GCScanSlotPlace, 4); __ Move(GCScanSlotPlace, 4);
// Save registers to the stack. // Save registers to the stack.
__ pushq(wasm_instance); __ pushq(wasm_instance);
...@@ -3651,7 +3649,7 @@ void LoadJumpBuffer(MacroAssembler* masm, Register jmpbuf) { ...@@ -3651,7 +3649,7 @@ void LoadJumpBuffer(MacroAssembler* masm, Register jmpbuf) {
void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) { void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) {
// Set up the stackframe. // Set up the stackframe.
__ EnterFrame(StackFrame::JS_TO_WASM); __ EnterFrame(StackFrame::RETURN_PROMISE_ON_SUSPEND);
// Parameters. // Parameters.
Register closure = kJSFunctionRegister; // rdi Register closure = kJSFunctionRegister; // rdi
...@@ -3661,7 +3659,10 @@ void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) { ...@@ -3661,7 +3659,10 @@ void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) {
} }
constexpr int kFrameMarkerOffset = -kSystemPointerSize; constexpr int kFrameMarkerOffset = -kSystemPointerSize;
constexpr int kParamCountOffset = kFrameMarkerOffset - kSystemPointerSize; // This slot contains the number of slots at the top of the frame that need to
// be scanned by the GC.
constexpr int kParamCountOffset =
BuiltinWasmWrapperConstants::kGCScanSlotCountOffset - kSystemPointerSize;
// The frame marker is not included in the slot count. // The frame marker is not included in the slot count.
constexpr int kNumSpillSlots = constexpr int kNumSpillSlots =
-(kParamCountOffset - kFrameMarkerOffset) / kSystemPointerSize; -(kParamCountOffset - kFrameMarkerOffset) / kSystemPointerSize;
...@@ -3723,11 +3724,13 @@ void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) { ...@@ -3723,11 +3724,13 @@ void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) {
// ------------------------------------------- // -------------------------------------------
// Allocate a new continuation. // Allocate a new continuation.
// ------------------------------------------- // -------------------------------------------
MemOperand GCScanSlotPlace =
MemOperand(rbp, BuiltinWasmWrapperConstants::kGCScanSlotCountOffset);
__ Move(GCScanSlotPlace, 3);
__ Push(wasm_instance); __ Push(wasm_instance);
__ Push(function_data); __ Push(function_data);
__ Push(wasm_instance); __ Push(wasm_instance);
__ Move(kContextRegister, Smi::zero()); __ Move(kContextRegister, Smi::zero());
// TODO(thibaudm): Handle GC.
__ CallRuntime(Runtime::kWasmAllocateContinuation); __ CallRuntime(Runtime::kWasmAllocateContinuation);
__ Pop(function_data); __ Pop(function_data);
__ Pop(wasm_instance); __ Pop(wasm_instance);
...@@ -3750,6 +3753,14 @@ void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) { ...@@ -3750,6 +3753,14 @@ void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) {
// Switch stack! // Switch stack!
LoadJumpBuffer(masm, target_jmpbuf); LoadJumpBuffer(masm, target_jmpbuf);
__ movq(rbp, rsp); // New stack, there is no frame yet. __ movq(rbp, rsp); // New stack, there is no frame yet.
__ Move(GCScanSlotPlace, 3);
__ Push(wasm_instance);
__ Push(function_data);
__ Push(wasm_instance);
__ Move(kContextRegister, Smi::zero());
__ CallRuntime(Runtime::kWasmSyncStackLimit);
__ Pop(function_data);
__ Pop(wasm_instance);
foreign_jmpbuf = no_reg; foreign_jmpbuf = no_reg;
target_jmpbuf = no_reg; target_jmpbuf = no_reg;
// live: [rsi, rdi] // live: [rsi, rdi]
...@@ -3827,6 +3838,7 @@ void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) { ...@@ -3827,6 +3838,7 @@ void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) {
// Switch stack! // Switch stack!
LoadJumpBuffer(masm, jmpbuf); LoadJumpBuffer(masm, jmpbuf);
__ leaq(rbp, Operand(rsp, (kNumSpillSlots + 1) * kSystemPointerSize)); __ leaq(rbp, Operand(rsp, (kNumSpillSlots + 1) * kSystemPointerSize));
__ Move(GCScanSlotPlace, 2);
__ Push(wasm_instance); // Spill. __ Push(wasm_instance); // Spill.
__ Push(wasm_instance); // First arg. __ Push(wasm_instance); // First arg.
__ Move(kContextRegister, Smi::zero()); __ Move(kContextRegister, Smi::zero());
...@@ -3841,7 +3853,7 @@ void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) { ...@@ -3841,7 +3853,7 @@ void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) {
// Epilogue. // Epilogue.
// ------------------------------------------- // -------------------------------------------
__ movq(param_count, MemOperand(rbp, kParamCountOffset)); __ movq(param_count, MemOperand(rbp, kParamCountOffset));
__ LeaveFrame(StackFrame::JS_TO_WASM); __ LeaveFrame(StackFrame::RETURN_PROMISE_ON_SUSPEND);
__ DropArguments(param_count, r8, TurboAssembler::kCountIsInteger, __ DropArguments(param_count, r8, TurboAssembler::kCountIsInteger,
TurboAssembler::kCountExcludesReceiver); TurboAssembler::kCountExcludesReceiver);
__ ret(0); __ ret(0);
......
...@@ -204,6 +204,14 @@ class BuiltinFrameConstants : public TypedFrameConstants { ...@@ -204,6 +204,14 @@ class BuiltinFrameConstants : public TypedFrameConstants {
DEFINE_TYPED_FRAME_SIZES(2); DEFINE_TYPED_FRAME_SIZES(2);
}; };
class BuiltinWasmWrapperConstants : public TypedFrameConstants {
public:
// This slot contains the number of slots at the top of the frame that need to
// be scanned by the GC.
static constexpr int kGCScanSlotCountOffset =
kFrameTypeOffset - kSystemPointerSize;
};
class ConstructFrameConstants : public TypedFrameConstants { class ConstructFrameConstants : public TypedFrameConstants {
public: public:
// FP-relative. // FP-relative.
......
...@@ -239,6 +239,10 @@ inline WasmToJsFrame::WasmToJsFrame(StackFrameIteratorBase* iterator) ...@@ -239,6 +239,10 @@ inline WasmToJsFrame::WasmToJsFrame(StackFrameIteratorBase* iterator)
inline JsToWasmFrame::JsToWasmFrame(StackFrameIteratorBase* iterator) inline JsToWasmFrame::JsToWasmFrame(StackFrameIteratorBase* iterator)
: StubFrame(iterator) {} : StubFrame(iterator) {}
inline ReturnPromiseOnSuspendFrame::ReturnPromiseOnSuspendFrame(
StackFrameIteratorBase* iterator)
: StubFrame(iterator) {}
inline CWasmEntryFrame::CWasmEntryFrame(StackFrameIteratorBase* iterator) inline CWasmEntryFrame::CWasmEntryFrame(StackFrameIteratorBase* iterator)
: StubFrame(iterator) {} : StubFrame(iterator) {}
......
...@@ -680,6 +680,7 @@ StackFrame::Type StackFrame::ComputeType(const StackFrameIteratorBase* iterator, ...@@ -680,6 +680,7 @@ StackFrame::Type StackFrame::ComputeType(const StackFrameIteratorBase* iterator,
case WASM_EXIT: case WASM_EXIT:
case WASM_DEBUG_BREAK: case WASM_DEBUG_BREAK:
case JS_TO_WASM: case JS_TO_WASM:
case RETURN_PROMISE_ON_SUSPEND:
#endif // V8_ENABLE_WEBASSEMBLY #endif // V8_ENABLE_WEBASSEMBLY
return candidate; return candidate;
case OPTIMIZED: case OPTIMIZED:
...@@ -1036,6 +1037,7 @@ void CommonFrame::IterateCompiledFrame(RootVisitor* v) const { ...@@ -1036,6 +1037,7 @@ void CommonFrame::IterateCompiledFrame(RootVisitor* v) const {
case CONSTRUCT: case CONSTRUCT:
#if V8_ENABLE_WEBASSEMBLY #if V8_ENABLE_WEBASSEMBLY
case JS_TO_WASM: case JS_TO_WASM:
case RETURN_PROMISE_ON_SUSPEND:
case C_WASM_ENTRY: case C_WASM_ENTRY:
case WASM_DEBUG_BREAK: case WASM_DEBUG_BREAK:
#endif // V8_ENABLE_WEBASSEMBLY #endif // V8_ENABLE_WEBASSEMBLY
...@@ -2084,10 +2086,29 @@ void JsToWasmFrame::Iterate(RootVisitor* v) const { ...@@ -2084,10 +2086,29 @@ void JsToWasmFrame::Iterate(RootVisitor* v) const {
IterateCompiledFrame(v); IterateCompiledFrame(v);
return; return;
} }
// The [fp - 2*kSystemPointerSize] on the stack is a value indicating how // The [fp + BuiltinFrameConstants::kGCScanSlotCount] on the stack is a value
// many values should be scanned from the top. // indicating how many values should be scanned from the top.
intptr_t scan_count = intptr_t scan_count = *reinterpret_cast<intptr_t*>(
*reinterpret_cast<intptr_t*>(fp() - 2 * kSystemPointerSize); fp() + BuiltinWasmWrapperConstants::kGCScanSlotCountOffset);
FullObjectSlot spill_slot_base(&Memory<Address>(sp()));
FullObjectSlot spill_slot_limit(
&Memory<Address>(sp() + scan_count * kSystemPointerSize));
v->VisitRootPointers(Root::kStackRoots, nullptr, spill_slot_base,
spill_slot_limit);
}
void ReturnPromiseOnSuspendFrame::Iterate(RootVisitor* v) const {
// See JsToWasmFrame layout.
#ifdef DEBUG
Code code = GetContainingCode(isolate(), pc());
DCHECK(code.is_builtin() &&
code.builtin_id() == Builtin::kWasmReturnPromiseOnSuspend);
#endif
// The [fp + BuiltinFrameConstants::kGCScanSlotCountOffset] on the stack is a
// value indicating how many values should be scanned from the top.
intptr_t scan_count = *reinterpret_cast<intptr_t*>(
fp() + BuiltinWasmWrapperConstants::kGCScanSlotCountOffset);
FullObjectSlot spill_slot_base(&Memory<Address>(sp())); FullObjectSlot spill_slot_base(&Memory<Address>(sp()));
FullObjectSlot spill_slot_limit( FullObjectSlot spill_slot_limit(
......
...@@ -100,6 +100,7 @@ class StackHandler { ...@@ -100,6 +100,7 @@ class StackHandler {
IF_WASM(V, WASM, WasmFrame) \ IF_WASM(V, WASM, WasmFrame) \
IF_WASM(V, WASM_TO_JS, WasmToJsFrame) \ IF_WASM(V, WASM_TO_JS, WasmToJsFrame) \
IF_WASM(V, JS_TO_WASM, JsToWasmFrame) \ IF_WASM(V, JS_TO_WASM, JsToWasmFrame) \
IF_WASM(V, RETURN_PROMISE_ON_SUSPEND, ReturnPromiseOnSuspendFrame) \
IF_WASM(V, WASM_DEBUG_BREAK, WasmDebugBreakFrame) \ IF_WASM(V, WASM_DEBUG_BREAK, WasmDebugBreakFrame) \
IF_WASM(V, C_WASM_ENTRY, CWasmEntryFrame) \ IF_WASM(V, C_WASM_ENTRY, CWasmEntryFrame) \
IF_WASM(V, WASM_EXIT, WasmExitFrame) \ IF_WASM(V, WASM_EXIT, WasmExitFrame) \
...@@ -1045,6 +1046,19 @@ class JsToWasmFrame : public StubFrame { ...@@ -1045,6 +1046,19 @@ class JsToWasmFrame : public StubFrame {
friend class StackFrameIteratorBase; friend class StackFrameIteratorBase;
}; };
class ReturnPromiseOnSuspendFrame : public StubFrame {
public:
Type type() const override { return RETURN_PROMISE_ON_SUSPEND; }
void Iterate(RootVisitor* v) const override;
protected:
inline explicit ReturnPromiseOnSuspendFrame(StackFrameIteratorBase* iterator);
private:
friend class StackFrameIteratorBase;
};
class CWasmEntryFrame : public StubFrame { class CWasmEntryFrame : public StubFrame {
public: public:
Type type() const override { return C_WASM_ENTRY; } Type type() const override { return C_WASM_ENTRY; }
......
...@@ -542,6 +542,7 @@ FRAME_MARKERS = ( ...@@ -542,6 +542,7 @@ FRAME_MARKERS = (
"WASM", "WASM",
"WASM_TO_JS", "WASM_TO_JS",
"JS_TO_WASM", "JS_TO_WASM",
"RETURN_PROMISE_ON_SUSPEND",
"WASM_DEBUG_BREAK", "WASM_DEBUG_BREAK",
"C_WASM_ENTRY", "C_WASM_ENTRY",
"WASM_EXIT", "WASM_EXIT",
......
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