[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: Jakob Kummerow <jkummerow@chromium.org> Reviewed-by: Andreas Haas <ahaas@chromium.org> Cr-Commit-Position: refs/heads/main@{#77763}
This commit is contained in:
parent
13bcdc5b38
commit
0443eb2ef0
@ -2962,15 +2962,9 @@ void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
|
||||
// -------------------------------------------
|
||||
// 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.
|
||||
constexpr int kInParamCountOffset =
|
||||
kGCScanSlotCountOffset - kSystemPointerSize;
|
||||
BuiltinWasmWrapperConstants::kGCScanSlotCountOffset - kSystemPointerSize;
|
||||
// The number of parameters according to the signature.
|
||||
constexpr int kParamCountOffset = kInParamCountOffset - kSystemPointerSize;
|
||||
constexpr int kReturnCountOffset = kParamCountOffset - kSystemPointerSize;
|
||||
@ -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.
|
||||
constexpr int kWasmCallGCScanSlotCount = 0;
|
||||
__ Move(MemOperand(rbp, kGCScanSlotCountOffset), kWasmCallGCScanSlotCount);
|
||||
__ Move(MemOperand(rbp, BuiltinWasmWrapperConstants::kGCScanSlotCountOffset),
|
||||
kWasmCallGCScanSlotCount);
|
||||
|
||||
// -------------------------------------------
|
||||
// Call the Wasm function.
|
||||
@ -3470,10 +3465,12 @@ void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
|
||||
// The builtin expects the parameter to be in register param = rax.
|
||||
|
||||
constexpr int kBuiltinCallGCScanSlotCount = 2;
|
||||
PrepareForBuiltinCall(masm, MemOperand(rbp, kGCScanSlotCountOffset),
|
||||
kBuiltinCallGCScanSlotCount, current_param, param_limit,
|
||||
current_int_param_slot, current_float_param_slot,
|
||||
valuetypes_array_ptr, wasm_instance, function_data);
|
||||
PrepareForBuiltinCall(
|
||||
masm,
|
||||
MemOperand(rbp, BuiltinWasmWrapperConstants::kGCScanSlotCountOffset),
|
||||
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_kWasmI64;
|
||||
@ -3620,7 +3617,8 @@ void Builtins::Generate_GenericJSToWasmWrapper(MacroAssembler* masm) {
|
||||
// -------------------------------------------
|
||||
__ bind(&compile_wrapper);
|
||||
// Enable GC.
|
||||
MemOperand GCScanSlotPlace = MemOperand(rbp, kGCScanSlotCountOffset);
|
||||
MemOperand GCScanSlotPlace =
|
||||
MemOperand(rbp, BuiltinWasmWrapperConstants::kGCScanSlotCountOffset);
|
||||
__ Move(GCScanSlotPlace, 4);
|
||||
// Save registers to the stack.
|
||||
__ pushq(wasm_instance);
|
||||
@ -3651,7 +3649,7 @@ void LoadJumpBuffer(MacroAssembler* masm, Register jmpbuf) {
|
||||
|
||||
void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) {
|
||||
// Set up the stackframe.
|
||||
__ EnterFrame(StackFrame::JS_TO_WASM);
|
||||
__ EnterFrame(StackFrame::RETURN_PROMISE_ON_SUSPEND);
|
||||
|
||||
// Parameters.
|
||||
Register closure = kJSFunctionRegister; // rdi
|
||||
@ -3661,7 +3659,10 @@ void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
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.
|
||||
constexpr int kNumSpillSlots =
|
||||
-(kParamCountOffset - kFrameMarkerOffset) / kSystemPointerSize;
|
||||
@ -3723,11 +3724,13 @@ void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) {
|
||||
// -------------------------------------------
|
||||
// Allocate a new continuation.
|
||||
// -------------------------------------------
|
||||
MemOperand GCScanSlotPlace =
|
||||
MemOperand(rbp, BuiltinWasmWrapperConstants::kGCScanSlotCountOffset);
|
||||
__ Move(GCScanSlotPlace, 3);
|
||||
__ Push(wasm_instance);
|
||||
__ Push(function_data);
|
||||
__ Push(wasm_instance);
|
||||
__ Move(kContextRegister, Smi::zero());
|
||||
// TODO(thibaudm): Handle GC.
|
||||
__ CallRuntime(Runtime::kWasmAllocateContinuation);
|
||||
__ Pop(function_data);
|
||||
__ Pop(wasm_instance);
|
||||
@ -3750,6 +3753,14 @@ void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) {
|
||||
// Switch stack!
|
||||
LoadJumpBuffer(masm, target_jmpbuf);
|
||||
__ 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;
|
||||
target_jmpbuf = no_reg;
|
||||
// live: [rsi, rdi]
|
||||
@ -3827,6 +3838,7 @@ void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) {
|
||||
// Switch stack!
|
||||
LoadJumpBuffer(masm, jmpbuf);
|
||||
__ leaq(rbp, Operand(rsp, (kNumSpillSlots + 1) * kSystemPointerSize));
|
||||
__ Move(GCScanSlotPlace, 2);
|
||||
__ Push(wasm_instance); // Spill.
|
||||
__ Push(wasm_instance); // First arg.
|
||||
__ Move(kContextRegister, Smi::zero());
|
||||
@ -3841,7 +3853,7 @@ void Builtins::Generate_WasmReturnPromiseOnSuspend(MacroAssembler* masm) {
|
||||
// Epilogue.
|
||||
// -------------------------------------------
|
||||
__ movq(param_count, MemOperand(rbp, kParamCountOffset));
|
||||
__ LeaveFrame(StackFrame::JS_TO_WASM);
|
||||
__ LeaveFrame(StackFrame::RETURN_PROMISE_ON_SUSPEND);
|
||||
__ DropArguments(param_count, r8, TurboAssembler::kCountIsInteger,
|
||||
TurboAssembler::kCountExcludesReceiver);
|
||||
__ ret(0);
|
||||
|
@ -204,6 +204,14 @@ class BuiltinFrameConstants : public TypedFrameConstants {
|
||||
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 {
|
||||
public:
|
||||
// FP-relative.
|
||||
|
@ -239,6 +239,10 @@ inline WasmToJsFrame::WasmToJsFrame(StackFrameIteratorBase* iterator)
|
||||
inline JsToWasmFrame::JsToWasmFrame(StackFrameIteratorBase* iterator)
|
||||
: StubFrame(iterator) {}
|
||||
|
||||
inline ReturnPromiseOnSuspendFrame::ReturnPromiseOnSuspendFrame(
|
||||
StackFrameIteratorBase* iterator)
|
||||
: StubFrame(iterator) {}
|
||||
|
||||
inline CWasmEntryFrame::CWasmEntryFrame(StackFrameIteratorBase* iterator)
|
||||
: StubFrame(iterator) {}
|
||||
|
||||
|
@ -680,6 +680,7 @@ StackFrame::Type StackFrame::ComputeType(const StackFrameIteratorBase* iterator,
|
||||
case WASM_EXIT:
|
||||
case WASM_DEBUG_BREAK:
|
||||
case JS_TO_WASM:
|
||||
case RETURN_PROMISE_ON_SUSPEND:
|
||||
#endif // V8_ENABLE_WEBASSEMBLY
|
||||
return candidate;
|
||||
case OPTIMIZED:
|
||||
@ -1036,6 +1037,7 @@ void CommonFrame::IterateCompiledFrame(RootVisitor* v) const {
|
||||
case CONSTRUCT:
|
||||
#if V8_ENABLE_WEBASSEMBLY
|
||||
case JS_TO_WASM:
|
||||
case RETURN_PROMISE_ON_SUSPEND:
|
||||
case C_WASM_ENTRY:
|
||||
case WASM_DEBUG_BREAK:
|
||||
#endif // V8_ENABLE_WEBASSEMBLY
|
||||
@ -2084,10 +2086,29 @@ void JsToWasmFrame::Iterate(RootVisitor* v) const {
|
||||
IterateCompiledFrame(v);
|
||||
return;
|
||||
}
|
||||
// The [fp - 2*kSystemPointerSize] 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() - 2 * kSystemPointerSize);
|
||||
// The [fp + BuiltinFrameConstants::kGCScanSlotCount] 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_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_limit(
|
||||
|
@ -100,6 +100,7 @@ class StackHandler {
|
||||
IF_WASM(V, WASM, WasmFrame) \
|
||||
IF_WASM(V, WASM_TO_JS, WasmToJsFrame) \
|
||||
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, C_WASM_ENTRY, CWasmEntryFrame) \
|
||||
IF_WASM(V, WASM_EXIT, WasmExitFrame) \
|
||||
@ -1045,6 +1046,19 @@ class JsToWasmFrame : public StubFrame {
|
||||
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 {
|
||||
public:
|
||||
Type type() const override { return C_WASM_ENTRY; }
|
||||
|
@ -542,6 +542,7 @@ FRAME_MARKERS = (
|
||||
"WASM",
|
||||
"WASM_TO_JS",
|
||||
"JS_TO_WASM",
|
||||
"RETURN_PROMISE_ON_SUSPEND",
|
||||
"WASM_DEBUG_BREAK",
|
||||
"C_WASM_ENTRY",
|
||||
"WASM_EXIT",
|
||||
|
Loading…
Reference in New Issue
Block a user