[wasm-c-api] New call descriptor and stackframe kind

So far, calls to Wasm C/C++ API functions reused the call descriptors
of WasmImportWrappers, and the stack frame type of regular Wasm
functions. This CL cleans that up by introducing separate implementations
for both. No change in functionality or performance is expected.

Change-Id: I79301fa81da52283cc776ddf19d4712372f3a58b
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1632235
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Michael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61914}
This commit is contained in:
Jakob Kummerow 2019-05-29 12:42:21 +02:00 committed by Commit Bot
parent f6e3993825
commit 65f3861e3b
16 changed files with 112 additions and 81 deletions

View File

@ -2402,7 +2402,8 @@ void TurboAssembler::EnterFrame(StackFrame::Type type) {
// sp[1] : type
// sp[0] : for alignment
} else if (type == StackFrame::WASM_COMPILED ||
type == StackFrame::WASM_COMPILE_LAZY) {
type == StackFrame::WASM_COMPILE_LAZY ||
type == StackFrame::WASM_EXIT) {
Register type_reg = temps.AcquireX();
Mov(type_reg, StackFrame::TypeToMarker(type));
Push(lr, fp);

View File

@ -168,8 +168,9 @@ StackFrame::Type OptimizedCompilationInfo::GetOutputStackFrameType() const {
case Code::BUILTIN:
return StackFrame::STUB;
case Code::WASM_FUNCTION:
case Code::WASM_TO_CAPI_FUNCTION:
return StackFrame::WASM_COMPILED;
case Code::WASM_TO_CAPI_FUNCTION:
return StackFrame::WASM_EXIT;
case Code::JS_TO_WASM_FUNCTION:
return StackFrame::JS_TO_WASM;
case Code::WASM_TO_JS_FUNCTION:

View File

@ -833,12 +833,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
case kArchCallCFunction: {
int const num_parameters = MiscField::decode(instr->opcode());
// Put the return address in a stack slot.
if (linkage()->GetIncomingDescriptor()->kind() ==
CallDescriptor::kCallWasmImportWrapper) {
// WasmCapiFunctionWrappers, which are reusing the WasmImportWrapper
// call descriptor, also need access to the PC.
// TODO(jkummerow): Separate the call descriptors for clarity.
if (linkage()->GetIncomingDescriptor()->IsWasmCapiFunction()) {
// Put the return address in a stack slot.
__ str(pc, MemOperand(fp, WasmExitFrameConstants::kCallingPCOffset));
}
if (instr->InputAt(0)->IsImmediate()) {
@ -3008,7 +3004,8 @@ void CodeGenerator::AssembleConstructFrame() {
__ StubPrologue(info()->GetOutputStackFrameType());
if (call_descriptor->IsWasmFunctionCall()) {
__ Push(kWasmInstanceRegister);
} else if (call_descriptor->IsWasmImportWrapper()) {
} else if (call_descriptor->IsWasmImportWrapper() ||
call_descriptor->IsWasmCapiFunction()) {
// WASM import wrappers are passed a tuple in the place of the instance.
// Unpack the tuple into the instance and the target callable.
// This must be done here in the codegen because it cannot be expressed
@ -3018,9 +3015,10 @@ void CodeGenerator::AssembleConstructFrame() {
__ ldr(kWasmInstanceRegister,
FieldMemOperand(kWasmInstanceRegister, Tuple2::kValue1Offset));
__ Push(kWasmInstanceRegister);
// Reserve PC slot space for WasmCapiFunction wrappers.
// TODO(jkummerow): Separate the call descriptors for clarity.
__ AllocateStackSpace(kSystemPointerSize);
if (call_descriptor->IsWasmCapiFunction()) {
// Reserve space for saving the PC later.
__ AllocateStackSpace(kSystemPointerSize);
}
}
}

View File

@ -744,14 +744,10 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
break;
case kArchCallCFunction: {
int const num_parameters = MiscField::decode(instr->opcode());
// Put the return address in a stack slot.
Register scratch = x8;
Label return_location;
if (linkage()->GetIncomingDescriptor()->kind() ==
CallDescriptor::kCallWasmImportWrapper) {
// WasmCapiFunctionWrappers, which are reusing the WasmImportWrapper
// call descriptor, need access to the calling PC.
// TODO(jkummerow): Separate the call descriptors for clarity.
if (linkage()->GetIncomingDescriptor()->IsWasmCapiFunction()) {
// Put the return address in a stack slot.
Register scratch = x8;
__ Adr(scratch, &return_location);
__ Str(scratch,
MemOperand(fp, WasmExitFrameConstants::kCallingPCOffset));
@ -2559,7 +2555,8 @@ void CodeGenerator::AssembleConstructFrame() {
__ Str(kWasmInstanceRegister,
MemOperand(fp, WasmCompiledFrameConstants::kWasmInstanceOffset));
} break;
case CallDescriptor::kCallWasmImportWrapper: {
case CallDescriptor::kCallWasmImportWrapper:
case CallDescriptor::kCallWasmCapiFunction: {
UseScratchRegisterScope temps(tasm());
__ LoadTaggedPointerField(
kJSFunctionRegister,
@ -2567,8 +2564,11 @@ void CodeGenerator::AssembleConstructFrame() {
__ LoadTaggedPointerField(
kWasmInstanceRegister,
FieldMemOperand(kWasmInstanceRegister, Tuple2::kValue1Offset));
__ Claim(required_slots +
3); // Claim extra slots for marker + instance + pc.
int extra_slots =
call_descriptor->kind() == CallDescriptor::kCallWasmImportWrapper
? 2 // Import wrapper: marker + instance.
: 3; // C-API function: marker + instance + PC.
__ Claim(required_slots + extra_slots);
Register scratch = temps.AcquireX();
__ Mov(scratch,
StackFrame::TypeToMarker(info()->GetOutputStackFrameType()));

View File

@ -814,11 +814,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
case kArchCallCFunction: {
int const num_parameters = MiscField::decode(instr->opcode());
Label return_location;
if (linkage()->GetIncomingDescriptor()->kind() ==
CallDescriptor::kCallWasmImportWrapper) {
// WasmCapiFunctionWrappers, which are reusing the WasmImportWrapper
// call descriptor, also need access to the PC.
// TODO(jkummerow): Separate the call descriptors for clarity.
if (linkage()->GetIncomingDescriptor()->IsWasmCapiFunction()) {
// Put the return address in a stack slot.
Register scratch = eax;
__ push(scratch);
__ PushPC();
@ -4236,7 +4233,8 @@ void CodeGenerator::AssembleConstructFrame() {
__ StubPrologue(info()->GetOutputStackFrameType());
if (call_descriptor->IsWasmFunctionCall()) {
__ push(kWasmInstanceRegister);
} else if (call_descriptor->IsWasmImportWrapper()) {
} else if (call_descriptor->IsWasmImportWrapper() ||
call_descriptor->IsWasmCapiFunction()) {
// WASM import wrappers are passed a tuple in the place of the instance.
// Unpack the tuple into the instance and the target callable.
// This must be done here in the codegen because it cannot be expressed
@ -4248,9 +4246,10 @@ void CodeGenerator::AssembleConstructFrame() {
Operand(kWasmInstanceRegister,
Tuple2::kValue1Offset - kHeapObjectTag));
__ push(kWasmInstanceRegister);
// Reserve PC slot space for WasmCapiFunction wrappers.
// TODO(jkummerow): Separate the call descriptors for clarity.
__ AllocateStackSpace(kSystemPointerSize);
if (call_descriptor->IsWasmCapiFunction()) {
// Reserve space for saving the PC later.
__ AllocateStackSpace(kSystemPointerSize);
}
}
}
}

View File

@ -907,6 +907,7 @@ void InstructionSelector::InitializeCallBuffer(Node* call, CallBuffer* buffer,
? g.UseFixed(callee, kJavaScriptCallCodeStartRegister)
: g.UseRegister(callee));
break;
case CallDescriptor::kCallWasmCapiFunction:
case CallDescriptor::kCallWasmFunction:
case CallDescriptor::kCallWasmImportWrapper:
buffer->instruction_args.push_back(
@ -2631,6 +2632,7 @@ void InstructionSelector::VisitCall(Node* node, BasicBlock* handler) {
case CallDescriptor::kCallJSFunction:
opcode = kArchCallJSFunction | MiscField::encode(flags);
break;
case CallDescriptor::kCallWasmCapiFunction:
case CallDescriptor::kCallWasmFunction:
case CallDescriptor::kCallWasmImportWrapper:
opcode = kArchCallWasmFunction | MiscField::encode(flags);

View File

@ -902,11 +902,8 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
case kArchCallCFunction: {
int const num_parameters = MiscField::decode(instr->opcode());
Label return_location;
if (linkage()->GetIncomingDescriptor()->kind() ==
CallDescriptor::kCallWasmImportWrapper) {
// WasmCapiFunctionWrappers, which are reusing the WasmImportWrapper
// call descriptor, also need access to the PC.
// TODO(jkummerow): Separate the call descriptors for clarity.
if (linkage()->GetIncomingDescriptor()->IsWasmCapiFunction()) {
// Put the return address in a stack slot.
__ leaq(kScratchRegister, Operand(&return_location, 0));
__ movq(MemOperand(rbp, WasmExitFrameConstants::kCallingPCOffset),
kScratchRegister);
@ -3746,7 +3743,8 @@ void CodeGenerator::AssembleConstructFrame() {
__ StubPrologue(info()->GetOutputStackFrameType());
if (call_descriptor->IsWasmFunctionCall()) {
__ pushq(kWasmInstanceRegister);
} else if (call_descriptor->IsWasmImportWrapper()) {
} else if (call_descriptor->IsWasmImportWrapper() ||
call_descriptor->IsWasmCapiFunction()) {
// WASM import wrappers are passed a tuple in the place of the instance.
// Unpack the tuple into the instance and the target callable.
// This must be done here in the codegen because it cannot be expressed
@ -3758,9 +3756,10 @@ void CodeGenerator::AssembleConstructFrame() {
kWasmInstanceRegister,
FieldOperand(kWasmInstanceRegister, Tuple2::kValue1Offset));
__ pushq(kWasmInstanceRegister);
// Reserve PC slot space for WasmCapiFunction wrappers.
// TODO(jkummerow): Separate the call descriptors for clarity.
__ AllocateStackSpace(kSystemPointerSize);
if (call_descriptor->IsWasmCapiFunction()) {
// Reserve space for saving the PC later.
__ AllocateStackSpace(kSystemPointerSize);
}
}
}

View File

@ -37,6 +37,9 @@ std::ostream& operator<<(std::ostream& os, const CallDescriptor::Kind& k) {
case CallDescriptor::kCallAddress:
os << "Addr";
break;
case CallDescriptor::kCallWasmCapiFunction:
os << "WasmExit";
break;
case CallDescriptor::kCallWasmFunction:
os << "WasmFunction";
break;
@ -147,11 +150,9 @@ int CallDescriptor::CalculateFixedFrameSize() const {
case kCallBuiltinPointer:
return TypedFrameConstants::kFixedSlotCount;
case kCallWasmFunction:
return WasmCompiledFrameConstants::kFixedSlotCount;
case kCallWasmImportWrapper:
// TODO(jkummerow): Introduce a separate "wasm-to-capi" frame type,
// and let other CallWasmImportWrapper frames go back to having the
// same size as CallWasmFunction frames.
return WasmCompiledFrameConstants::kFixedSlotCount;
case kCallWasmCapiFunction:
return WasmExitFrameConstants::kFixedSlotCount;
}
UNREACHABLE();

View File

@ -175,6 +175,7 @@ class V8_EXPORT_PRIVATE CallDescriptor final
kCallCodeObject, // target is a Code object
kCallJSFunction, // target is a JSFunction object
kCallAddress, // target is a machine pointer
kCallWasmCapiFunction, // target is a Wasm C API function
kCallWasmFunction, // target is a wasm function
kCallWasmImportWrapper, // target is a wasm import wrapper
kCallBuiltinPointer, // target is a builtin pointer
@ -236,6 +237,9 @@ class V8_EXPORT_PRIVATE CallDescriptor final
// Returns {true} if this descriptor is a call to a WebAssembly function.
bool IsWasmImportWrapper() const { return kind_ == kCallWasmImportWrapper; }
// Returns {true} if this descriptor is a call to a Wasm C API function.
bool IsWasmCapiFunction() const { return kind_ == kCallWasmCapiFunction; }
bool RequiresFrameAsIncoming() const {
return IsCFunctionCall() || IsJSFunctionCall() || IsWasmFunctionCall();
}

View File

@ -6224,7 +6224,7 @@ wasm::WasmCode* CompileWasmImportCallWrapper(wasm::WasmEngine* wasm_engine,
// Schedule and compile to machine code.
CallDescriptor* incoming =
GetWasmCallDescriptor(&zone, sig, WasmGraphBuilder::kNoRetpoline,
WasmGraphBuilder::kExtraCallableParam);
WasmCallKind::kWasmImportWrapper);
if (machine.Is32()) {
incoming = GetI32WasmCallDescriptor(&zone, incoming);
}
@ -6279,7 +6279,7 @@ wasm::WasmCode* CompileWasmCapiCallWrapper(wasm::WasmEngine* wasm_engine,
// Run the compiler pipeline to generate machine code.
CallDescriptor* call_descriptor =
GetWasmCallDescriptor(&zone, sig, WasmGraphBuilder::kNoRetpoline,
WasmGraphBuilder::kExtraCallableParam);
WasmCallKind::kWasmCapiFunction);
if (mcgraph->machine()->Is32()) {
call_descriptor = GetI32WasmCallDescriptor(&zone, call_descriptor);
}
@ -6559,10 +6559,11 @@ class LinkageLocationAllocator {
// General code uses the above configuration data.
CallDescriptor* GetWasmCallDescriptor(
Zone* zone, wasm::FunctionSig* fsig,
WasmGraphBuilder::UseRetpoline use_retpoline,
WasmGraphBuilder::ExtraCallableParam extra_callable_param) {
WasmGraphBuilder::UseRetpoline use_retpoline, WasmCallKind call_kind) {
// The extra here is to accomodate the instance object as first parameter
// and, when specified, the additional callable.
bool extra_callable_param =
call_kind == kWasmImportWrapper || call_kind == kWasmCapiFunction;
int extra_params = extra_callable_param ? 2 : 1;
LocationSignature::Builder locations(zone, fsig->return_count(),
fsig->parameter_count() + extra_params);
@ -6627,14 +6628,20 @@ CallDescriptor* GetWasmCallDescriptor(
MachineType target_type = MachineType::Pointer();
LinkageLocation target_loc = LinkageLocation::ForAnyRegister(target_type);
CallDescriptor::Kind kind = extra_callable_param
? CallDescriptor::kCallWasmImportWrapper
: CallDescriptor::kCallWasmFunction;
CallDescriptor::Kind descriptor_kind;
if (call_kind == kWasmFunction) {
descriptor_kind = CallDescriptor::kCallWasmFunction;
} else if (call_kind == kWasmImportWrapper) {
descriptor_kind = CallDescriptor::kCallWasmImportWrapper;
} else {
DCHECK_EQ(call_kind, kWasmCapiFunction);
descriptor_kind = CallDescriptor::kCallWasmCapiFunction;
}
CallDescriptor::Flags flags =
use_retpoline ? CallDescriptor::kRetpoline : CallDescriptor::kNoFlags;
return new (zone) CallDescriptor( // --
kind, // kind
descriptor_kind, // kind
target_type, // target MachineType
target_loc, // target location
locations.Build(), // location_sig

View File

@ -164,10 +164,6 @@ class WasmGraphBuilder {
kRetpoline = true,
kNoRetpoline = false
};
enum ExtraCallableParam : bool { // --
kExtraCallableParam = true,
kNoExtraCallableParam = false
};
V8_EXPORT_PRIVATE WasmGraphBuilder(
wasm::CompilationEnv* env, Zone* zone, MachineGraph* mcgraph,
@ -610,12 +606,13 @@ class WasmGraphBuilder {
TrapId GetTrapIdForTrap(wasm::TrapReason reason);
};
enum WasmCallKind { kWasmFunction, kWasmImportWrapper, kWasmCapiFunction };
V8_EXPORT_PRIVATE CallDescriptor* GetWasmCallDescriptor(
Zone* zone, wasm::FunctionSig* signature,
WasmGraphBuilder::UseRetpoline use_retpoline =
WasmGraphBuilder::kNoRetpoline,
WasmGraphBuilder::ExtraCallableParam callable_param =
WasmGraphBuilder::kNoExtraCallableParam);
WasmCallKind kind = kWasmFunction);
V8_EXPORT_PRIVATE CallDescriptor* GetI32WasmCallDescriptor(
Zone* zone, CallDescriptor* call_descriptor);

View File

@ -210,13 +210,13 @@ class TypedFrameConstants : public CommonFrameConstants {
(TypedFrameConstants::kFirstPushedFrameValueOffset - (x)*kSystemPointerSize)
#define TYPED_FRAME_SIZE(count) \
(TypedFrameConstants::kFixedFrameSize + (count)*kSystemPointerSize)
#define TYPED_FRAME_SIZE_FROM_SP(count) \
#define TYPED_FRAME_SIZE_FROM_FP(count) \
(TypedFrameConstants::kFixedFrameSizeFromFp + (count)*kSystemPointerSize)
#define DEFINE_TYPED_FRAME_SIZES(count) \
static constexpr int kFixedFrameSize = TYPED_FRAME_SIZE(count); \
static constexpr int kFixedSlotCount = kFixedFrameSize / kSystemPointerSize; \
static constexpr int kFixedFrameSizeFromFp = \
TYPED_FRAME_SIZE_FROM_SP(count); \
TYPED_FRAME_SIZE_FROM_FP(count); \
static constexpr int kFixedSlotCountFromFp = \
kFixedFrameSizeFromFp / kSystemPointerSize

View File

@ -223,6 +223,9 @@ inline BuiltinFrame::BuiltinFrame(StackFrameIteratorBase* iterator)
inline WasmCompiledFrame::WasmCompiledFrame(StackFrameIteratorBase* iterator)
: StandardFrame(iterator) {}
inline WasmExitFrame::WasmExitFrame(StackFrameIteratorBase* iterator)
: WasmCompiledFrame(iterator) {}
inline WasmInterpreterEntryFrame::WasmInterpreterEntryFrame(
StackFrameIteratorBase* iterator)
: StandardFrame(iterator) {}

View File

@ -163,16 +163,7 @@ bool StackTraceFrameIterator::IsValidFrame(StackFrame* frame) const {
if (!js_frame->function().IsJSFunction()) return false;
return js_frame->function().shared().IsSubjectToDebugging();
}
// Apart from JavaScript frames, only Wasm frames are valid, with the
// exception of Wasm-to-Capi frames.
// TODO(jkummerow): Give Wasm-to-Capi frames their own marker.
if (frame->is_wasm_compiled()) {
wasm::WasmCodeRefScope scope;
if (static_cast<WasmCompiledFrame*>(frame)->wasm_code()->kind() ==
wasm::WasmCode::kWasmToCapiWrapper) {
return false;
}
}
// Apart from JavaScript frames, only Wasm frames are valid.
return frame->is_wasm();
}
@ -520,8 +511,9 @@ StackFrame::Type StackFrame::ComputeType(const StackFrameIteratorBase* iterator,
if (wasm_code != nullptr) {
switch (wasm_code->kind()) {
case wasm::WasmCode::kFunction:
case wasm::WasmCode::kWasmToCapiWrapper:
return WASM_COMPILED;
case wasm::WasmCode::kWasmToCapiWrapper:
return WASM_EXIT;
case wasm::WasmCode::kWasmToJsWrapper:
return WASM_TO_JS;
case wasm::WasmCode::kRuntimeStub:
@ -593,6 +585,7 @@ StackFrame::Type StackFrame::ComputeType(const StackFrameIteratorBase* iterator,
case WASM_TO_JS:
case WASM_COMPILED:
case WASM_COMPILE_LAZY:
case WASM_EXIT:
return candidate;
case JS_TO_WASM:
case OPTIMIZED:
@ -675,15 +668,9 @@ Address ExitFrame::GetCallerStackPointer() const {
StackFrame::Type ExitFrame::GetStateForFramePointer(Address fp, State* state) {
if (fp == 0) return NONE;
Address sp = ComputeStackPointer(fp);
StackFrame::Type type = ComputeFrameType(fp);
if (type == StackFrame::WASM_COMPILED) {
// {sp} is only needed for finding the PC slot, the rest is handled
// via safepoint.
sp = fp + WasmExitFrameConstants::kWasmInstanceOffset;
DCHECK_EQ(sp - 1 * kPCOnStackSize,
fp + WasmExitFrameConstants::kCallingPCOffset);
}
Address sp = (type == WASM_EXIT) ? WasmExitFrame::ComputeStackPointer(fp)
: ExitFrame::ComputeStackPointer(fp);
FillState(fp, sp, state);
DCHECK_NE(*state->pc_address, kNullAddress);
return type;
@ -703,7 +690,7 @@ StackFrame::Type ExitFrame::ComputeFrameType(Address fp) {
StackFrame::Type frame_type = static_cast<StackFrame::Type>(marker_int >> 1);
if (frame_type == EXIT || frame_type == BUILTIN_EXIT ||
frame_type == WASM_COMPILED) {
frame_type == WASM_EXIT) {
return frame_type;
}
@ -716,6 +703,15 @@ Address ExitFrame::ComputeStackPointer(Address fp) {
return Memory<Address>(fp + ExitFrameConstants::kSPOffset);
}
Address WasmExitFrame::ComputeStackPointer(Address fp) {
// For WASM_EXIT frames, {sp} is only needed for finding the PC slot,
// everything else is handled via safepoint information.
Address sp = fp + WasmExitFrameConstants::kWasmInstanceOffset;
DCHECK_EQ(sp - 1 * kPCOnStackSize,
fp + WasmExitFrameConstants::kCallingPCOffset);
return sp;
}
void ExitFrame::FillState(Address fp, Address sp, State* state) {
state->sp = sp;
state->fp = fp;
@ -938,6 +934,14 @@ void StandardFrame::IterateCompiledFrame(RootVisitor* v) const {
case WASM_COMPILE_LAZY:
frame_header_size = WasmCompiledFrameConstants::kFixedFrameSizeFromFp;
break;
case WASM_EXIT:
// The last value in the frame header is the calling PC, which should
// not be visited.
static_assert(WasmExitFrameConstants::kFixedSlotCountFromFp ==
WasmCompiledFrameConstants::kFixedSlotCountFromFp + 1,
"WasmExitFrame has one slot more than WasmCompiledFrame");
frame_header_size = WasmCompiledFrameConstants::kFixedFrameSizeFromFp;
break;
case OPTIMIZED:
case INTERPRETED:
case BUILTIN:

View File

@ -70,6 +70,7 @@ class StackHandler {
V(JS_TO_WASM, JsToWasmFrame) \
V(WASM_INTERPRETER_ENTRY, WasmInterpreterEntryFrame) \
V(C_WASM_ENTRY, CWasmEntryFrame) \
V(WASM_EXIT, WasmExitFrame) \
V(WASM_COMPILE_LAZY, WasmCompileLazyFrame) \
V(INTERPRETED, InterpretedFrame) \
V(STUB, StubFrame) \
@ -171,6 +172,7 @@ class StackFrame {
bool is_optimized() const { return type() == OPTIMIZED; }
bool is_interpreted() const { return type() == INTERPRETED; }
bool is_wasm_compiled() const { return type() == WASM_COMPILED; }
bool is_wasm_exit() const { return type() == WASM_EXIT; }
bool is_wasm_compile_lazy() const { return type() == WASM_COMPILE_LAZY; }
bool is_wasm_to_js() const { return type() == WASM_TO_JS; }
bool is_js_to_wasm() const { return type() == JS_TO_WASM; }
@ -925,7 +927,7 @@ class BuiltinFrame final : public JavaScriptFrame {
friend class StackFrameIteratorBase;
};
class WasmCompiledFrame final : public StandardFrame {
class WasmCompiledFrame : public StandardFrame {
public:
Type type() const override { return WASM_COMPILED; }
@ -968,6 +970,18 @@ class WasmCompiledFrame final : public StandardFrame {
WasmModuleObject module_object() const;
};
class WasmExitFrame : public WasmCompiledFrame {
public:
Type type() const override { return WASM_EXIT; }
static Address ComputeStackPointer(Address fp);
protected:
inline explicit WasmExitFrame(StackFrameIteratorBase* iterator);
private:
friend class StackFrameIteratorBase;
};
class WasmInterpreterEntryFrame final : public StandardFrame {
public:
Type type() const override { return WASM_INTERPRETER_ENTRY; }

View File

@ -425,6 +425,7 @@ FRAME_MARKERS = (
"JS_TO_WASM",
"WASM_INTERPRETER_ENTRY",
"C_WASM_ENTRY",
"WASM_EXIT",
"WASM_COMPILE_LAZY",
"INTERPRETED",
"STUB",