From 65f3861e3b7d0e24059ea3f37a0c50561faeec1d Mon Sep 17 00:00:00 2001 From: Jakob Kummerow Date: Wed, 29 May 2019 12:42:21 +0200 Subject: [PATCH] [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 Reviewed-by: Michael Starzinger Cr-Commit-Position: refs/heads/master@{#61914} --- src/codegen/arm64/macro-assembler-arm64.cc | 3 +- src/codegen/optimized-compilation-info.cc | 3 +- .../backend/arm/code-generator-arm.cc | 18 ++++---- .../backend/arm64/code-generator-arm64.cc | 20 ++++----- .../backend/ia32/code-generator-ia32.cc | 17 ++++--- src/compiler/backend/instruction-selector.cc | 2 + .../backend/x64/code-generator-x64.cc | 17 ++++--- src/compiler/linkage.cc | 9 ++-- src/compiler/linkage.h | 4 ++ src/compiler/wasm-compiler.cc | 23 ++++++---- src/compiler/wasm-compiler.h | 9 ++-- src/execution/frame-constants.h | 4 +- src/execution/frames-inl.h | 3 ++ src/execution/frames.cc | 44 ++++++++++--------- src/execution/frames.h | 16 ++++++- tools/v8heapconst.py | 1 + 16 files changed, 112 insertions(+), 81 deletions(-) diff --git a/src/codegen/arm64/macro-assembler-arm64.cc b/src/codegen/arm64/macro-assembler-arm64.cc index d16db372b6..aab9fc79a2 100644 --- a/src/codegen/arm64/macro-assembler-arm64.cc +++ b/src/codegen/arm64/macro-assembler-arm64.cc @@ -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); diff --git a/src/codegen/optimized-compilation-info.cc b/src/codegen/optimized-compilation-info.cc index fad5a26538..596d5c261e 100644 --- a/src/codegen/optimized-compilation-info.cc +++ b/src/codegen/optimized-compilation-info.cc @@ -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: diff --git a/src/compiler/backend/arm/code-generator-arm.cc b/src/compiler/backend/arm/code-generator-arm.cc index 0f6bb7ae65..d93053c64b 100644 --- a/src/compiler/backend/arm/code-generator-arm.cc +++ b/src/compiler/backend/arm/code-generator-arm.cc @@ -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); + } } } diff --git a/src/compiler/backend/arm64/code-generator-arm64.cc b/src/compiler/backend/arm64/code-generator-arm64.cc index f020d68fab..53864ad2e9 100644 --- a/src/compiler/backend/arm64/code-generator-arm64.cc +++ b/src/compiler/backend/arm64/code-generator-arm64.cc @@ -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())); diff --git a/src/compiler/backend/ia32/code-generator-ia32.cc b/src/compiler/backend/ia32/code-generator-ia32.cc index bbb988d2b4..0e61c22cbb 100644 --- a/src/compiler/backend/ia32/code-generator-ia32.cc +++ b/src/compiler/backend/ia32/code-generator-ia32.cc @@ -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); + } } } } diff --git a/src/compiler/backend/instruction-selector.cc b/src/compiler/backend/instruction-selector.cc index 8ff9c070d6..2b748a188b 100644 --- a/src/compiler/backend/instruction-selector.cc +++ b/src/compiler/backend/instruction-selector.cc @@ -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); diff --git a/src/compiler/backend/x64/code-generator-x64.cc b/src/compiler/backend/x64/code-generator-x64.cc index 8664557b06..c6667292fc 100644 --- a/src/compiler/backend/x64/code-generator-x64.cc +++ b/src/compiler/backend/x64/code-generator-x64.cc @@ -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); + } } } diff --git a/src/compiler/linkage.cc b/src/compiler/linkage.cc index 2afc639cf2..8bb47b43e9 100644 --- a/src/compiler/linkage.cc +++ b/src/compiler/linkage.cc @@ -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(); diff --git a/src/compiler/linkage.h b/src/compiler/linkage.h index d6febdc99d..e4fa6f9f20 100644 --- a/src/compiler/linkage.h +++ b/src/compiler/linkage.h @@ -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(); } diff --git a/src/compiler/wasm-compiler.cc b/src/compiler/wasm-compiler.cc index 1da23ec0b5..3396214e58 100644 --- a/src/compiler/wasm-compiler.cc +++ b/src/compiler/wasm-compiler.cc @@ -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 diff --git a/src/compiler/wasm-compiler.h b/src/compiler/wasm-compiler.h index fbc06c1f2f..460d0d2f1b 100644 --- a/src/compiler/wasm-compiler.h +++ b/src/compiler/wasm-compiler.h @@ -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); diff --git a/src/execution/frame-constants.h b/src/execution/frame-constants.h index a01e49b8e5..7ddee5689e 100644 --- a/src/execution/frame-constants.h +++ b/src/execution/frame-constants.h @@ -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 diff --git a/src/execution/frames-inl.h b/src/execution/frames-inl.h index 1edfe9c468..aeb43fe0a6 100644 --- a/src/execution/frames-inl.h +++ b/src/execution/frames-inl.h @@ -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) {} diff --git a/src/execution/frames.cc b/src/execution/frames.cc index d2e0da0402..af660a338e 100644 --- a/src/execution/frames.cc +++ b/src/execution/frames.cc @@ -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(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(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
(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: diff --git a/src/execution/frames.h b/src/execution/frames.h index d37439512a..982716db93 100644 --- a/src/execution/frames.h +++ b/src/execution/frames.h @@ -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; } diff --git a/tools/v8heapconst.py b/tools/v8heapconst.py index 44167a48a1..0165e0f1dd 100644 --- a/tools/v8heapconst.py +++ b/tools/v8heapconst.py @@ -425,6 +425,7 @@ FRAME_MARKERS = ( "JS_TO_WASM", "WASM_INTERPRETER_ENTRY", "C_WASM_ENTRY", + "WASM_EXIT", "WASM_COMPILE_LAZY", "INTERPRETED", "STUB",