Revert "Reland^3 "[wasm][x64] Run JS imports on the central stack""

This reverts commit be830f359c.

Reason for revert: This broke on the chromium roll, see e.g.
https://ci.chromium.org/ui/p/chromium/builders/try/linux-asan-v8-arm-rel/22/overview
The bisection is off by one because of an unrelated build failure

Original change's description:
> Reland^3 "[wasm][x64] Run JS imports on the central stack"
>
> This is a reland of commit 2d6e2bd529
> The stack-switching test uses %SimulateNewspaceFull, which is
> incompatible with the single-generation flag, so just skip the test
> in this case.
>
> Original change's description:
> > Reland "Reland "[wasm][x64] Run JS imports on the central stack""
> >
> > This is a reland of commit 4be9ff946b
> >
> > Builtins should have the same IR shape on all platforms for PGO. The
> > wasm-to-js torque wrapper was different on x64 because of a compile-time
> > guard, which is fixed by turning it into an IR check. The check will
> > eventually be removed when this is ported to other archs.
> >
> > Original change's description:
> > > Reland "[wasm][x64] Run JS imports on the central stack"
> > >
> > > This is a reland of commit 9d9f49d201
> > >
> > > The reland includes:
> > >
> > > - Ignore secondary stacks for conservative scanning. Now that we always
> > >   switch to the central stack, all "interesting" frames are on the
> > >   central stack.  Without this change, the marker is not in sync with
> > >   the stack start because of the switch to the central stack.
> > > - Merging 8bbc90166d into this change,
> > >   because landing them separately also breaks the CSS bot. I think this
> > >   was already broken before but reproduces more easily with this change.
> > >   The problem is that because of the switch to the central stack, the
> > >   marker is not in sync with the registered secondary stack start.
> > > - Also switch in the generic (torque) wrapper.
> > >
> > > Original change's description:
> > > > [wasm][x64] Run JS imports on the central stack
> > > >
> > > > Switch to the central stack before running a JS import, and switch
> > > > back after the call. Only on x64 for now, will be ported to other archs
> > > > in a separate CL.
> > > >
> > > > Design doc: https://docs.google.com/document/d/1DBVwKthBdejx9Qy1W8indme5pJ6mq_fSdhQ3N-K2XP4/edit?usp=sharing
> > > >
> > > > R=ahaas@chromium.org
> > > > CC=irezvov@chromium.org
> > > >
> > > > Bug: v8:13983
> > > > Change-Id: I217ef988f46bb9a747cc65a37688817a4abf9618
> > > > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4846976
> > > > Reviewed-by: Jakob Linke <jgruber@chromium.org>
> > > > Commit-Queue: Thibaud Michaud <thibaudm@chromium.org>
> > > > Reviewed-by: Andreas Haas <ahaas@chromium.org>
> > > > Cr-Commit-Position: refs/heads/main@{#90041}
> > >
> > > Bug: v8:13983
> > > Change-Id: I75492e0b26955c66ba59d4f19ef19764c516fcac
> > > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4875537
> > > Reviewed-by: Igor Sheludko <ishell@chromium.org>
> > > Reviewed-by: Andreas Haas <ahaas@chromium.org>
> > > Commit-Queue: Thibaud Michaud <thibaudm@chromium.org>
> > > Cr-Commit-Position: refs/heads/main@{#90864}
> >
> > Bug: v8:13983
> > Change-Id: I4808e17bcaafc309bd0c40c0705bee3fa52528c0
> > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5022950
> > Reviewed-by: Igor Sheludko <ishell@chromium.org>
> > Commit-Queue: Thibaud Michaud <thibaudm@chromium.org>
> > Cr-Commit-Position: refs/heads/main@{#90879}
>
> Bug: v8:13983
> Change-Id: I5e19a1759ffb56b8d38231cb1b3b5c9742ffc90c
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5024199
> Reviewed-by: Igor Sheludko <ishell@chromium.org>
> Commit-Queue: Thibaud Michaud <thibaudm@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#90889}

Bug: v8:13983
Change-Id: I77787d7409ce3331609056650a27b63cfaee5f35
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5028407
Commit-Queue: Matthias Liedtke <mliedtke@chromium.org>
Reviewed-by: Michael Achenbach <machenbach@chromium.org>
Owners-Override: Matthias Liedtke <mliedtke@chromium.org>
Cr-Commit-Position: refs/heads/main@{#90936}
This commit is contained in:
Matthias Liedtke authored and V8 LUCI CQ committed 2023-11-14 19:46:38 +00:00
1 parent e1f7254f7a
commit 083b24225f
58 files changed
+281 -994

No files matched your search

+2 -8
View File
@@ -2952,14 +2952,8 @@ void Builtins::Generate_WasmToJsWrapperAsm(MacroAssembler* masm) {
// arbitrarily.
__ Push(r6, wasm::kGpParamRegisters[3], wasm::kGpParamRegisters[2],
wasm::kGpParamRegisters[1]);
// Reserve fixed slots for the CSA wrapper.
// Two slots for stack-switching (central stack pointer and secondary stack
// limit):
Register scratch = r1;
__ mov(scratch, Operand::Zero());
__ Push(scratch);
__ Push(scratch);
// One slot for the signature:
// Push an arbitrary register to reserve stack space for the signature which
// will be spilled on the stack in Torque.
__ Push(r0);
__ TailCallBuiltin(Builtin::kWasmToJsWrapperCSA);
}
+4 -5
View File
@@ -3749,11 +3749,10 @@ void Builtins::Generate_WasmToJsWrapperAsm(MacroAssembler* masm) {
__ Push(wasm::kGpParamRegisters[6], wasm::kGpParamRegisters[5],
wasm::kGpParamRegisters[4], wasm::kGpParamRegisters[3]);
__ Push(wasm::kGpParamRegisters[2], wasm::kGpParamRegisters[1]);
// Push four more slots that will be used as fixed spill slots in the torque
// wrapper. Two slots for stack-switching (central stack pointer and secondary
// stack limit), one for the signature, and one for stack alignment.
__ Push(xzr, xzr, xzr, xzr);
__ Push(wasm::kGpParamRegisters[2], wasm::kGpParamRegisters[1],
// Spill two more slots, one to allocate space for the signature,
// which will get spilled in Torque, and one for stack alignment.
xzr, xzr);
__ TailCallBuiltin(Builtin::kWasmToJsWrapperCSA);
}
-2
View File
@@ -260,8 +260,6 @@ namespace internal {
/* Adapters for Turbofan into runtime */ \
TFC(AllocateInYoungGeneration, Allocate) \
TFC(AllocateInOldGeneration, Allocate) \
IF_WASM(TFC, WasmAllocateInYoungGeneration, Allocate) \
IF_WASM(TFC, WasmAllocateInOldGeneration, Allocate) \
\
TFC(NewHeapNumber, NewHeapNumber) \
\
-22
View File
@@ -1320,28 +1320,6 @@ TF_BUILTIN(AllocateInOldGeneration, CodeStubAssembler) {
SmiFromIntPtr(requested_size), runtime_flags);
}
#if V8_ENABLE_WEBASSEMBLY
TF_BUILTIN(WasmAllocateInYoungGeneration, CodeStubAssembler) {
auto requested_size = UncheckedParameter<IntPtrT>(Descriptor::kRequestedSize);
CSA_CHECK(this, IsValidPositiveSmi(requested_size));
TNode<Smi> allocation_flags =
SmiConstant(Smi::FromInt(AllocateDoubleAlignFlag::encode(false)));
TailCallRuntime(Runtime::kAllocateInYoungGeneration, NoContextConstant(),
SmiFromIntPtr(requested_size), allocation_flags);
}
TF_BUILTIN(WasmAllocateInOldGeneration, CodeStubAssembler) {
auto requested_size = UncheckedParameter<IntPtrT>(Descriptor::kRequestedSize);
CSA_CHECK(this, IsValidPositiveSmi(requested_size));
TNode<Smi> runtime_flags =
SmiConstant(Smi::FromInt(AllocateDoubleAlignFlag::encode(false)));
TailCallRuntime(Runtime::kAllocateInOldGeneration, NoContextConstant(),
SmiFromIntPtr(requested_size), runtime_flags);
}
#endif
TF_BUILTIN(Abort, CodeStubAssembler) {
auto message_id = Parameter<Smi>(Descriptor::kMessageOrMessageId);
TailCallRuntime(Runtime::kAbort, NoContextConstant(), message_id);
+2 -6
View File
@@ -3839,12 +3839,8 @@ void Builtins::Generate_WasmToJsWrapperAsm(MacroAssembler* masm) {
for (size_t i = arraysize(wasm::kGpParamRegisters) - 1; i > 0; --i) {
__ push(wasm::kGpParamRegisters[i]);
}
// Reserve fixed slots for the CSA wrapper.
// Two slots for stack-switching (central stack pointer and secondary stack
// limit):
__ push(Immediate(0));
__ push(Immediate(0));
// One slot for the signature:
// Decrement the stack to allocate a stack slot. The signature gets written
// into the slot in Torque.
__ push(eax);
// Push the return address again.
__ push(scratch);
-12
View File
@@ -23,10 +23,6 @@
#include "src/objects/shared-function-info.h"
#include "src/objects/smi.h"
#if V8_ENABLE_WEBASSEMBLY
#include "src/wasm/wasm-builtin-list.h"
#endif
namespace v8 {
namespace internal {
@@ -45,14 +41,6 @@ AssemblerOptions BuiltinAssemblerOptions(Isolate* isolate, Builtin builtin) {
CHECK(!options.isolate_independent_code);
CHECK(!options.collect_win64_unwind_info);
#if V8_ENABLE_WEBASSEMBLY
if (wasm::BuiltinLookup::IsWasmBuiltinId(builtin) ||
builtin == Builtin::kJSToWasmWrapper ||
builtin == Builtin::kJSToWasmHandleReturns ||
builtin == Builtin::kWasmToJsWrapperCSA) {
options.is_wasm = true;
}
#endif
if (!isolate->IsGeneratingEmbeddedBuiltins()) {
return options;
}
+9 -11
View File
@@ -16,9 +16,10 @@ struct WasmToJSResult {
result3: float64;
}
extern macro CallOnCentralStack(
extern builtin CallVarargs(
Context,
JSAny, // target
int32, // number of arguments already on the stack
int32, // number of arguments in the FixedArray
FixedArray // arguments list
): JSAny;
@@ -60,10 +61,7 @@ transitioning macro WasmToJSWrapper(ref: WasmApiFunctionRef): WasmToJSResult {
// Caller FP + return address.
const sigSlot = LoadFramePointer() + kSignatureOffset;
*GetRefAt<intptr>(sigSlot, 0) = BitcastTaggedToWord(ref.sig);
const alignment: intptr =
StackAlignmentInBytes() / torque_internal::SizeOf<intptr>();
// 3 fixed slots, rounded up to stack alignment.
const numFixedSlots = ((2 + alignment) / alignment) * alignment;
const sizeOfSig = StackAlignmentInBytes() / torque_internal::SizeOf<intptr>();
ModifyWasmToJSCounter(1);
ModifyThreadInWasmFlag(0);
@@ -97,9 +95,9 @@ transitioning macro WasmToJSWrapper(ref: WasmApiFunctionRef): WasmToJSResult {
// builtin takes care of it automatically
outParams.objects[nextIndex++] = Undefined;
// Caller FP + return address + fixed slots.
const stackParamStart = LoadFramePointer() +
(2 + numFixedSlots) * torque_internal::SizeOf<intptr>();
// Caller FP + return address + signature.
const stackParamStart =
LoadFramePointer() + (2 + sizeOfSig) * torque_internal::SizeOf<intptr>();
const inParams = torque_internal::unsafe::NewOffHeapReference(
%RawDownCast<RawPtr<intptr>>(stackParamStart));
@@ -186,8 +184,8 @@ transitioning macro WasmToJSWrapper(ref: WasmApiFunctionRef): WasmToJSResult {
// scanned anymore.
*GetRefAt<intptr>(sigSlot, 0) = 0;
const result = CallOnCentralStack(
context, target, Convert<int32>(numStackParams), outParams);
const result = CallVarargs(
context, target, 0, Convert<int32>(numStackParams), outParams);
// Put a marker on the stack to indicate to the frame iterator that the call
// to JavaScript is finished. For asm.js source positions it is important to
@@ -307,7 +305,7 @@ transitioning macro WasmToJSWrapper(ref: WasmApiFunctionRef): WasmToJSResult {
const popCount =
(Convert<intptr>(stackSlots) - Convert<intptr>(stackParamStart)) /
torque_internal::SizeOf<intptr>() +
numFixedSlots;
sizeOfSig;
ModifyThreadInWasmFlag(1);
ModifyWasmToJSCounter(-1);
+2 -12
View File
@@ -3695,18 +3695,8 @@ void Builtins::Generate_WasmToJsWrapperAsm(MacroAssembler* masm) {
for (size_t i = arraysize(wasm::kGpParamRegisters) - 1; i > 0; --i) {
__ pushq(wasm::kGpParamRegisters[i]);
}
// Reserve fixed slots for the CSA wrapper.
// Two slots for stack-switching (central stack pointer and secondary stack
// limit):
static_assert(WasmImportWrapperFrameConstants::kCentralStackSPOffset ==
WasmImportWrapperFrameConstants::kWasmInstanceOffset -
kSystemPointerSize);
__ pushq(Immediate(kNullAddress));
static_assert(WasmImportWrapperFrameConstants::kSecondaryStackLimitOffset ==
WasmImportWrapperFrameConstants::kCentralStackSPOffset -
kSystemPointerSize);
__ pushq(Immediate(kNullAddress));
// One slot for the signature:
// Decrement the stack to allocate a stack slot. The signature gets written
// into the slot in Torque.
__ pushq(rax);
// Push the return address again.
__ pushq(kScratchRegister);
+2 -1
View File
@@ -2009,7 +2009,8 @@ void MacroAssembler::CallRuntime(const Runtime::Function* f,
Mov(x0, num_arguments);
Mov(x1, ExternalReference::Create(f));
bool switch_to_central = this->options().is_wasm;
bool switch_to_central =
Runtime::SwitchToTheCentralStackForTarget(f->function_id);
Handle<Code> code = CodeFactory::CEntry(
isolate(), f->result_size, ArgvMode::kStack, false, switch_to_central);
Call(code, RelocInfo::CODE_TARGET);
-2
View File
@@ -250,8 +250,6 @@ struct V8_EXPORT_PRIVATE AssemblerOptions {
// Whether to emit code comments.
bool emit_code_comments = v8_flags.code_comments;
bool is_wasm = false;
static AssemblerOptions Default(Isolate* isolate);
};
-82
View File
@@ -13,7 +13,6 @@
#include "src/codegen/code-factory.h"
#include "src/codegen/tnode.h"
#include "src/common/globals.h"
#include "src/execution/frame-constants.h"
#include "src/execution/frames-inl.h"
#include "src/execution/frames.h"
#include "src/execution/protectors.h"
@@ -17731,86 +17730,5 @@ TNode<FixedArray> CodeStubAssembler::ArrayListElements(TNode<ArrayList> array) {
return elements;
}
#if V8_ENABLE_WEBASSEMBLY
TNode<RawPtrT> CodeStubAssembler::SwitchToTheCentralStackForJS(
TNode<Object> callable) {
TNode<WordT> stack_limit_slot = IntPtrAdd(
LoadFramePointer(),
IntPtrConstant(WasmToJSWrapperConstants::kSecondaryStackLimitOffset));
TNode<ExternalReference> do_switch = ExternalConstant(
ExternalReference::wasm_switch_to_the_central_stack_for_js());
TNode<RawPtrT> central_stack_sp = TNode<RawPtrT>::UncheckedCast(
CallCFunction(do_switch, MachineType::Pointer(),
std::make_pair(MachineType::TaggedPointer(), callable),
std::make_pair(MachineType::Pointer(), stack_limit_slot)));
TNode<RawPtrT> old_sp = LoadStackPointer();
SetStackPointer(central_stack_sp);
StoreNoWriteBarrier(
MachineType::PointerRepresentation(), LoadFramePointer(),
IntPtrConstant(WasmToJSWrapperConstants::kCentralStackSPOffset),
central_stack_sp);
return old_sp;
}
void CodeStubAssembler::SwitchFromTheCentralStackForJS(TNode<RawPtrT> old_sp,
TNode<Object> callable) {
TNode<WordT> stack_limit = Load<RawPtrT>(
LoadFramePointer(),
IntPtrConstant(WasmToJSWrapperConstants::kSecondaryStackLimitOffset));
TNode<ExternalReference> do_switch = ExternalConstant(
ExternalReference::wasm_switch_from_the_central_stack_for_js());
CallCFunction(do_switch, MachineType::Pointer(),
std::make_pair(MachineType::TaggedPointer(), callable),
std::make_pair(MachineType::Pointer(), stack_limit));
StoreNoWriteBarrier(
MachineType::PointerRepresentation(), LoadFramePointer(),
IntPtrConstant(WasmToJSWrapperConstants::kCentralStackSPOffset),
IntPtrConstant(0));
SetStackPointer(old_sp);
}
TNode<Object> CodeStubAssembler::CallOnCentralStack(TNode<Context> context,
TNode<Object> target,
TNode<Int32T> num_args,
TNode<FixedArray> args) {
// If the current stack is a secondary stack, switch, perform the call and
// switch back. Otherwise, just do the call.
// Use UniqueInt32Constant instead of BoolConstant here in order to ensure
// that the graph structure does not depend on the value of the predicate
// (BoolConstant uses cached nodes).
#if V8_TARGET_ARCH_X64
auto is_supported_arch = UniqueInt32Constant(1);
#else
auto is_supported_arch = UniqueInt32Constant(0);
#endif
Label no_switch(this);
GotoIfNot(is_supported_arch, &no_switch);
TVARIABLE(Object, result);
Label end(this); // -> return value of the call (kTaggedPointer)
TNode<Uint8T> is_on_central_stack_flag = LoadUint8FromRootRegister(
IntPtrConstant(IsolateData::is_on_central_stack_flag_offset()));
GotoIf(is_on_central_stack_flag, &no_switch);
TNode<RawPtrT> old_sp = SwitchToTheCentralStackForJS(target);
result = CallBuiltin(Builtin::kCallVarargs, context, target, Int32Constant(0),
num_args, args);
SwitchFromTheCentralStackForJS(old_sp, target);
Goto(&end);
Bind(&no_switch);
result = CallBuiltin(Builtin::kCallVarargs, context, target, Int32Constant(0),
num_args, args);
Goto(&end);
Bind(&end);
return result.value();
}
#endif
} // namespace internal
} // namespace v8
-8
View File
@@ -4602,10 +4602,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<Uint8T> property_details,
Label* needs_resize);
TNode<Object> CallOnCentralStack(TNode<Context> context, TNode<Object> target,
TNode<Int32T> num_args,
TNode<FixedArray> args);
private:
friend class CodeStubArguments;
@@ -4757,10 +4753,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
void EmitElementStoreTypedArrayUpdateValue(
TNode<Object> value, ElementsKind elements_kind,
TNode<TValue> converted_value, TVariable<Object>* maybe_converted_value);
TNode<RawPtrT> SwitchToTheCentralStackForJS(TNode<Object> callable_node);
void SwitchFromTheCentralStackForJS(TNode<RawPtrT> old_sp,
TNode<Object> callable);
};
class V8_EXPORT_PRIVATE CodeStubArguments {
-4
View File
@@ -470,10 +470,6 @@ FUNCTION_REFERENCE(wasm_switch_to_the_central_stack,
wasm::switch_to_the_central_stack)
FUNCTION_REFERENCE(wasm_switch_from_the_central_stack,
wasm::switch_from_the_central_stack)
FUNCTION_REFERENCE(wasm_switch_to_the_central_stack_for_js,
wasm::switch_to_the_central_stack_for_js)
FUNCTION_REFERENCE(wasm_switch_from_the_central_stack_for_js,
wasm::switch_from_the_central_stack_for_js)
FUNCTION_REFERENCE(wasm_f32_trunc, wasm::f32_trunc_wrapper)
FUNCTION_REFERENCE(wasm_f32_floor, wasm::f32_floor_wrapper)
FUNCTION_REFERENCE(wasm_f32_ceil, wasm::f32_ceil_wrapper)
-4
View File
@@ -260,10 +260,6 @@ class StatsCounter;
"wasm::switch_to_the_central_stack") \
IF_WASM(V, wasm_switch_from_the_central_stack, \
"wasm::switch_from_the_central_stack") \
IF_WASM(V, wasm_switch_to_the_central_stack_for_js, \
"wasm::switch_to_the_central_stack_for_js") \
IF_WASM(V, wasm_switch_from_the_central_stack_for_js, \
"wasm::switch_from_the_central_stack_for_js") \
IF_WASM(V, wasm_f32_ceil, "wasm::f32_ceil_wrapper") \
IF_WASM(V, wasm_f32_floor, "wasm::f32_floor_wrapper") \
IF_WASM(V, wasm_f32_nearest_int, "wasm::f32_nearest_int_wrapper") \
-13
View File
@@ -21,10 +21,6 @@
#include "src/utils/identity-map.h"
#include "src/utils/utils.h"
#if V8_ENABLE_WEBASSEMBLY
#include "src/wasm/wasm-builtin-list.h"
#endif
namespace v8 {
namespace tracing {
@@ -159,15 +155,6 @@ class V8_EXPORT_PRIVATE OptimizedCompilationInfo final {
}
#if V8_ENABLE_WEBASSEMBLY
bool IsWasm() const { return code_kind() == CodeKind::WASM_FUNCTION; }
bool IsWasmBuiltin() const {
return code_kind() == CodeKind::WASM_TO_JS_FUNCTION ||
code_kind() == CodeKind::JS_TO_WASM_FUNCTION ||
(code_kind() == CodeKind::BUILTIN &&
(builtin() == Builtin::kJSToWasmWrapper ||
builtin() == Builtin::kJSToWasmHandleReturns ||
builtin() == Builtin::kWasmToJsWrapperCSA ||
wasm::BuiltinLookup::IsWasmBuiltinId(builtin())));
}
#endif // V8_ENABLE_WEBASSEMBLY
void set_persistent_handles(
+2 -1
View File
@@ -942,7 +942,8 @@ void MacroAssembler::CallRuntime(const Runtime::Function* f,
// smarter.
Move(rax, num_arguments);
LoadAddress(rbx, ExternalReference::Create(f));
bool switch_to_central = this->options().is_wasm;
bool switch_to_central =
Runtime::SwitchToTheCentralStackForTarget(f->function_id);
Handle<Code> code = CodeFactory::CEntry(
isolate(), f->result_size, ArgvMode::kStack, false, switch_to_central);
Call(code, RelocInfo::CODE_TARGET);
+1 -12
View File
@@ -6925,18 +6925,7 @@ void CodeGenerator::AssembleConstructFrame() {
// accessors.
__ pushq(kWasmInstanceRegister);
}
if (call_descriptor->IsWasmImportWrapper()) {
// If the wrapper is running on a secondary stack, it will switch to the
// central stack and fill these slots with the central stack pointer and
// secondary stack limit. Otherwise the slots remain empty.
static_assert(WasmImportWrapperFrameConstants::kCentralStackSPOffset ==
-24);
static_assert(
WasmImportWrapperFrameConstants::kSecondaryStackLimitOffset == -32);
__ pushq(Immediate(kNullAddress));
__ pushq(Immediate(kNullAddress));
} else if (call_descriptor->IsWasmCapiFunction()) {
if (call_descriptor->IsWasmCapiFunction()) {
// Reserve space for saving the PC later.
__ AllocateStackSpace(kSystemPointerSize);
}
+2 -36
View File
@@ -6,7 +6,6 @@
#include <ostream>
#include "src/builtins/builtins.h"
#include "src/codegen/code-factory.h"
#include "src/codegen/interface-descriptors-inl.h"
#include "src/codegen/machine-type.h"
@@ -579,25 +578,12 @@ TNode<RawPtrT> CodeAssembler::LoadParentFramePointer() {
return UncheckedCast<RawPtrT>(raw_assembler()->LoadParentFramePointer());
}
TNode<RawPtrT> CodeAssembler::LoadStackPointer() {
return UncheckedCast<RawPtrT>(raw_assembler()->LoadStackPointer());
}
void CodeAssembler::SetStackPointer(TNode<RawPtrT> ptr) {
raw_assembler()->SetStackPointer(ptr);
}
TNode<RawPtrT> CodeAssembler::LoadPointerFromRootRegister(
TNode<IntPtrT> offset) {
return UncheckedCast<RawPtrT>(
Load(MachineType::IntPtr(), raw_assembler()->LoadRootRegister(), offset));
}
TNode<Uint8T> CodeAssembler::LoadUint8FromRootRegister(TNode<IntPtrT> offset) {
return UncheckedCast<Uint8T>(
Load(MachineType::Uint8(), raw_assembler()->LoadRootRegister(), offset));
}
TNode<RawPtrT> CodeAssembler::StackSlotPtr(int size, int alignment) {
return UncheckedCast<RawPtrT>(raw_assembler()->StackSlot(size, alignment));
}
@@ -1074,18 +1060,8 @@ Node* CodeAssembler::CallRuntimeImpl(
Runtime::FunctionId function, TNode<Object> context,
std::initializer_list<TNode<Object>> args) {
int result_size = Runtime::FunctionForId(function)->result_size;
#if V8_ENABLE_WEBASSEMBLY
bool switch_to_the_central_stack =
state_->kind_ == CodeKind::WASM_FUNCTION ||
state_->kind_ == CodeKind::WASM_TO_JS_FUNCTION ||
state_->kind_ == CodeKind::JS_TO_WASM_FUNCTION ||
state_->builtin_ == Builtin::kJSToWasmWrapper ||
state_->builtin_ == Builtin::kJSToWasmHandleReturns ||
state_->builtin_ == Builtin::kWasmToJsWrapperCSA ||
wasm::BuiltinLookup::IsWasmBuiltinId(state_->builtin_);
#else
bool switch_to_the_central_stack = false;
#endif
Runtime::SwitchToTheCentralStackForTarget(function);
TNode<Code> centry = HeapConstantNoHole(CodeFactory::RuntimeCEntry(
isolate(), result_size, switch_to_the_central_stack));
constexpr size_t kMaxNumArgs = 6;
@@ -1119,18 +1095,8 @@ void CodeAssembler::TailCallRuntimeImpl(
Runtime::FunctionId function, TNode<Int32T> arity, TNode<Object> context,
std::initializer_list<TNode<Object>> args) {
int result_size = Runtime::FunctionForId(function)->result_size;
#if V8_ENABLE_WEBASSEMBLY
bool switch_to_the_central_stack =
state_->kind_ == CodeKind::WASM_FUNCTION ||
state_->kind_ == CodeKind::WASM_TO_JS_FUNCTION ||
state_->kind_ == CodeKind::JS_TO_WASM_FUNCTION ||
state_->builtin_ == Builtin::kJSToWasmWrapper ||
state_->builtin_ == Builtin::kJSToWasmHandleReturns ||
state_->builtin_ == Builtin::kWasmToJsWrapperCSA ||
wasm::BuiltinLookup::IsWasmBuiltinId(state_->builtin_);
#else
bool switch_to_the_central_stack = false;
#endif
Runtime::SwitchToTheCentralStackForTarget(function);
TNode<Code> centry = HeapConstantNoHole(CodeFactory::RuntimeCEntry(
isolate(), result_size, switch_to_the_central_stack));
constexpr size_t kMaxNumArgs = 6;
+1 -6
View File
@@ -748,17 +748,12 @@ class V8_EXPORT_PRIVATE CodeAssembler {
void Switch(Node* index, Label* default_label, const int32_t* case_values,
Label** case_labels, size_t case_count);
// Access to the frame pointer.
// Access to the frame pointer
TNode<RawPtrT> LoadFramePointer();
TNode<RawPtrT> LoadParentFramePointer();
TNode<RawPtrT> StackSlotPtr(int size, int alignment);
// Access to the stack pointer.
TNode<RawPtrT> LoadStackPointer();
void SetStackPointer(TNode<RawPtrT> ptr);
TNode<RawPtrT> LoadPointerFromRootRegister(TNode<IntPtrT> offset);
TNode<Uint8T> LoadUint8FromRootRegister(TNode<IntPtrT> offset);
// Load raw memory location.
Node* Load(MachineType type, Node* base);
+2 -2
View File
@@ -137,8 +137,8 @@ Node* GraphAssembler::LoadStackPointer() {
}
Node* GraphAssembler::SetStackPointer(Node* node) {
return AddNode(
graph()->NewNode(machine()->SetStackPointer(), node, effect()));
return AddNode(graph()->NewNode(machine()->SetStackPointer(), node, effect(),
control()));
}
Node* GraphAssembler::LoadHeapNumberValue(Node* heap_number) {
+22 -24
View File
@@ -129,30 +129,28 @@ class Reducer;
V(Uint64Div) \
V(Uint64Mod)
#define JSGRAPH_SINGLETON_CONSTANT_LIST(V) \
V(AllocateInOldGenerationStub, InstructionStream) \
V(AllocateInYoungGenerationStub, InstructionStream) \
IF_WASM(V, WasmAllocateInYoungGenerationStub, InstructionStream) \
IF_WASM(V, WasmAllocateInOldGenerationStub, InstructionStream) \
V(BigIntMap, Map) \
V(BooleanMap, Map) \
V(EmptyString, String) \
V(ExternalObjectMap, Map) \
V(False, Boolean) \
V(FixedArrayMap, Map) \
V(FixedDoubleArrayMap, Map) \
V(WeakFixedArrayMap, Map) \
V(HeapNumberMap, Map) \
V(MinusOne, Number) \
V(NaN, Number) \
V(NoContext, Object) \
V(Null, Null) \
V(One, Number) \
V(TheHole, Hole) \
V(ToNumberBuiltin, InstructionStream) \
V(PlainPrimitiveToNumberBuiltin, InstructionStream) \
V(True, Boolean) \
V(Undefined, Undefined) \
#define JSGRAPH_SINGLETON_CONSTANT_LIST(V) \
V(AllocateInOldGenerationStub, InstructionStream) \
V(AllocateInYoungGenerationStub, InstructionStream) \
V(BigIntMap, Map) \
V(BooleanMap, Map) \
V(EmptyString, String) \
V(ExternalObjectMap, Map) \
V(False, Boolean) \
V(FixedArrayMap, Map) \
V(FixedDoubleArrayMap, Map) \
V(WeakFixedArrayMap, Map) \
V(HeapNumberMap, Map) \
V(MinusOne, Number) \
V(NaN, Number) \
V(NoContext, Object) \
V(Null, Null) \
V(One, Number) \
V(TheHole, Hole) \
V(ToNumberBuiltin, InstructionStream) \
V(PlainPrimitiveToNumberBuiltin, InstructionStream) \
V(True, Boolean) \
V(Undefined, Undefined) \
V(Zero, Number)
class GraphAssembler;
-10
View File
@@ -176,16 +176,6 @@ DEFINE_GETTER(AllocateInOldGenerationStubConstant, Code,
HeapConstantNoHole(BUILTIN_CODE(isolate(),
AllocateInOldGeneration)))
#if V8_ENABLE_WEBASSEMBLY
DEFINE_GETTER(WasmAllocateInYoungGenerationStubConstant, Code,
HeapConstantNoHole(BUILTIN_CODE(isolate(),
WasmAllocateInYoungGeneration)))
DEFINE_GETTER(WasmAllocateInOldGenerationStubConstant, Code,
HeapConstantNoHole(BUILTIN_CODE(isolate(),
WasmAllocateInOldGeneration)))
#endif
DEFINE_GETTER(ArrayConstructorStubConstant, Code,
HeapConstantNoHole(BUILTIN_CODE(isolate(), ArrayConstructorImpl)))
+33 -35
View File
@@ -98,41 +98,39 @@ class V8_EXPORT_PRIVATE JSGraph : public MachineGraph {
void GetCachedNodes(NodeVector* nodes);
// Cached global nodes.
#define CACHED_GLOBAL_LIST(V) \
V(AllocateInYoungGenerationStubConstant, Code) \
V(AllocateInOldGenerationStubConstant, Code) \
IF_WASM(V, WasmAllocateInYoungGenerationStubConstant, Code) \
IF_WASM(V, WasmAllocateInOldGenerationStubConstant, Code) \
V(ArrayConstructorStubConstant, Code) \
V(BigIntMapConstant, Map) \
V(BooleanMapConstant, Map) \
V(ToNumberBuiltinConstant, Code) \
V(PlainPrimitiveToNumberBuiltinConstant, Code) \
V(EmptyFixedArrayConstant, FixedArray) \
V(EmptyStringConstant, String) \
V(FixedArrayMapConstant, Map) \
V(PropertyArrayMapConstant, Map) \
V(FixedDoubleArrayMapConstant, Map) \
V(WeakFixedArrayMapConstant, Map) \
V(HeapNumberMapConstant, Map) \
V(UndefinedConstant, Undefined) \
V(TheHoleConstant, Hole) \
V(PropertyCellHoleConstant, Hole) \
V(HashTableHoleConstant, Hole) \
V(PromiseHoleConstant, Hole) \
V(UninitializedConstant, Hole) \
V(OptimizedOutConstant, Hole) \
V(StaleRegisterConstant, Hole) \
V(TrueConstant, True) \
V(FalseConstant, False) \
V(NullConstant, Null) \
V(ZeroConstant, Number) \
V(MinusZeroConstant, Number) \
V(OneConstant, Number) \
V(MinusOneConstant, Number) \
V(NaNConstant, Number) \
V(EmptyStateValues, UntaggedT) \
V(SingleDeadTypedStateValues, UntaggedT) \
#define CACHED_GLOBAL_LIST(V) \
V(AllocateInYoungGenerationStubConstant, Code) \
V(AllocateInOldGenerationStubConstant, Code) \
V(ArrayConstructorStubConstant, Code) \
V(BigIntMapConstant, Map) \
V(BooleanMapConstant, Map) \
V(ToNumberBuiltinConstant, Code) \
V(PlainPrimitiveToNumberBuiltinConstant, Code) \
V(EmptyFixedArrayConstant, FixedArray) \
V(EmptyStringConstant, String) \
V(FixedArrayMapConstant, Map) \
V(PropertyArrayMapConstant, Map) \
V(FixedDoubleArrayMapConstant, Map) \
V(WeakFixedArrayMapConstant, Map) \
V(HeapNumberMapConstant, Map) \
V(UndefinedConstant, Undefined) \
V(TheHoleConstant, Hole) \
V(PropertyCellHoleConstant, Hole) \
V(HashTableHoleConstant, Hole) \
V(PromiseHoleConstant, Hole) \
V(UninitializedConstant, Hole) \
V(OptimizedOutConstant, Hole) \
V(StaleRegisterConstant, Hole) \
V(TrueConstant, True) \
V(FalseConstant, False) \
V(NullConstant, Null) \
V(ZeroConstant, Number) \
V(MinusZeroConstant, Number) \
V(OneConstant, Number) \
V(MinusOneConstant, Number) \
V(NaNConstant, Number) \
V(EmptyStateValues, UntaggedT) \
V(SingleDeadTypedStateValues, UntaggedT) \
V(ExternalObjectMapConstant, Map)
// Cached global node accessor methods.
+1 -2
View File
@@ -200,9 +200,8 @@ int CallDescriptor::CalculateFixedFrameSize(CodeKind code_kind) const {
return TypedFrameConstants::kFixedSlotCount;
#if V8_ENABLE_WEBASSEMBLY
case kCallWasmFunction:
return WasmFrameConstants::kFixedSlotCount;
case kCallWasmImportWrapper:
return WasmImportWrapperFrameConstants::kFixedSlotCount;
return WasmFrameConstants::kFixedSlotCount;
case kCallWasmCapiFunction:
return WasmExitFrameConstants::kFixedSlotCount;
#endif // V8_ENABLE_WEBASSEMBLY
-5
View File
@@ -103,7 +103,6 @@ class MachineRepresentationInferrer {
case IrOpcode::kLoadParentFramePointer:
case IrOpcode::kStackSlot:
case IrOpcode::kLoadRootRegister:
case IrOpcode::kLoadStackPointer:
representation_vector_[node->id()] =
MachineType::PointerRepresentation();
break;
@@ -682,10 +681,6 @@ class MachineRepresentationChecker {
CheckValueInputRepresentationIs(
node, 0, MachineType::PointerRepresentation());
break;
case IrOpcode::kSetStackPointer:
CheckValueInputRepresentationIs(
node, 0, MachineType::PointerRepresentation());
break;
case IrOpcode::kThrow:
case IrOpcode::kTypedStateValues:
case IrOpcode::kFrameState:
+10 -19
View File
@@ -59,7 +59,7 @@ class MemoryLowering::AllocationGroup final : public ZoneObject {
};
MemoryLowering::MemoryLowering(JSGraph* jsgraph, Zone* zone,
JSGraphAssembler* graph_assembler, bool is_wasm,
JSGraphAssembler* graph_assembler,
AllocationFolding allocation_folding,
WriteBarrierAssertFailedCallback callback,
const char* function_debug_name)
@@ -69,7 +69,6 @@ MemoryLowering::MemoryLowering(JSGraph* jsgraph, Zone* zone,
common_(jsgraph->common()),
machine_(jsgraph->machine()),
graph_assembler_(graph_assembler),
is_wasm_(is_wasm),
allocation_folding_(allocation_folding),
write_barrier_assert_failed_(callback),
function_debug_name_(function_debug_name) {}
@@ -181,34 +180,26 @@ Reduction MemoryLowering::ReduceAllocateRaw(Node* node,
gasm()->InitializeEffectControl(effect, control);
Node* allocate_builtin;
if (!is_wasm_) {
if (isolate_ != nullptr) {
if (allocation_type == AllocationType::kYoung) {
allocate_builtin = __ AllocateInYoungGenerationStubConstant();
} else {
allocate_builtin = __ AllocateInOldGenerationStubConstant();
}
} else {
#if V8_ENABLE_WEBASSEMBLY
// This lowering is used by Wasm, where we compile isolate-independent
// code. Builtin calls simply encode the target builtin ID, which will
// be patched to the builtin's address later.
if (isolate_ == nullptr) {
Builtin builtin;
if (allocation_type == AllocationType::kYoung) {
builtin = Builtin::kWasmAllocateInYoungGeneration;
} else {
builtin = Builtin::kWasmAllocateInOldGeneration;
}
static_assert(std::is_same<Smi, BuiltinPtr>(), "BuiltinPtr must be Smi");
allocate_builtin =
graph()->NewNode(common()->NumberConstant(static_cast<int>(builtin)));
#if V8_ENABLE_WEBASSEMBLY
Builtin builtin;
if (allocation_type == AllocationType::kYoung) {
builtin = Builtin::kAllocateInYoungGeneration;
} else {
if (allocation_type == AllocationType::kYoung) {
allocate_builtin = __ WasmAllocateInYoungGenerationStubConstant();
} else {
allocate_builtin = __ WasmAllocateInOldGenerationStubConstant();
}
builtin = Builtin::kAllocateInOldGeneration;
}
static_assert(std::is_same<Smi, BuiltinPtr>(), "BuiltinPtr must be Smi");
allocate_builtin =
graph()->NewNode(common()->NumberConstant(static_cast<int>(builtin)));
#else
UNREACHABLE();
#endif
-2
View File
@@ -75,7 +75,6 @@ class MemoryLowering final : public Reducer {
MemoryLowering(
JSGraph* jsgraph, Zone* zone, JSGraphAssembler* graph_assembler,
bool is_wasm,
AllocationFolding allocation_folding =
AllocationFolding::kDontAllocationFolding,
WriteBarrierAssertFailedCallback callback = [](Node*, Node*, const char*,
@@ -135,7 +134,6 @@ class MemoryLowering final : public Reducer {
CommonOperatorBuilder* common_;
MachineOperatorBuilder* machine_;
JSGraphAssembler* graph_assembler_;
bool is_wasm_;
AllocationFolding allocation_folding_;
WriteBarrierAssertFailedCallback write_barrier_assert_failed_;
const char* function_debug_name_;
+3 -4
View File
@@ -188,11 +188,10 @@ void WriteBarrierAssertFailed(Node* node, Node* object, const char* name,
MemoryOptimizer::MemoryOptimizer(
JSHeapBroker* broker, JSGraph* jsgraph, Zone* zone,
MemoryLowering::AllocationFolding allocation_folding,
const char* function_debug_name, TickCounter* tick_counter, bool is_wasm)
const char* function_debug_name, TickCounter* tick_counter)
: graph_assembler_(broker, jsgraph, zone, BranchSemantics::kMachine),
memory_lowering_(jsgraph, zone, &graph_assembler_, is_wasm,
allocation_folding, WriteBarrierAssertFailed,
function_debug_name),
memory_lowering_(jsgraph, zone, &graph_assembler_, allocation_folding,
WriteBarrierAssertFailed, function_debug_name),
wasm_address_reassociation_(jsgraph, zone),
jsgraph_(jsgraph),
empty_state_(AllocationState::Empty(zone)),
+1 -2
View File
@@ -50,8 +50,7 @@ class MemoryOptimizer final {
public:
MemoryOptimizer(JSHeapBroker* broker, JSGraph* jsgraph, Zone* zone,
MemoryLowering::AllocationFolding allocation_folding,
const char* function_debug_name, TickCounter* tick_counter,
bool is_wasm);
const char* function_debug_name, TickCounter* tick_counter);
~MemoryOptimizer() = default;
void Optimize();
+1 -13
View File
@@ -10,7 +10,6 @@
#include <sstream>
#include "src/base/optional.h"
#include "src/builtins/builtins.h"
#include "src/builtins/profile-data-reader.h"
#include "src/codegen/assembler-inl.h"
#include "src/codegen/bailout-reason.h"
@@ -113,7 +112,6 @@
#include "src/logging/counters.h"
#include "src/logging/runtime-call-stats-scope.h"
#include "src/logging/runtime-call-stats.h"
#include "src/objects/code-kind.h"
#include "src/objects/shared-function-info.h"
#include "src/objects/string-inl.h"
#include "src/tracing/trace-event.h"
@@ -139,7 +137,6 @@
#include "src/wasm/function-body-decoder.h"
#include "src/wasm/function-compiler.h"
#include "src/wasm/turboshaft-graph-interface.h"
#include "src/wasm/wasm-builtin-list.h"
#include "src/wasm/wasm-engine.h"
#endif // V8_ENABLE_WEBASSEMBLY
@@ -596,10 +593,6 @@ class PipelineData {
void InitializeCodeGenerator(Linkage* linkage) {
DCHECK_NULL(code_generator_);
#if V8_ENABLE_WEBASSEMBLY
assembler_options_.is_wasm =
this->info()->IsWasm() || this->info()->IsWasmBuiltin();
#endif
code_generator_ = new CodeGenerator(
codegen_zone(), frame(), linkage, sequence(), info(), isolate(),
osr_helper_, start_source_position_, jump_optimization_info_,
@@ -2033,17 +2026,12 @@ struct MemoryOptimizationPhase {
}
// Optimize allocations and load/store operations.
#if V8_ENABLE_WEBASSEMBLY
bool is_wasm = data->info()->IsWasm() || data->info()->IsWasmBuiltin();
#else
bool is_wasm = false;
#endif
MemoryOptimizer optimizer(
data->broker(), data->jsgraph(), temp_zone,
data->info()->allocation_folding()
? MemoryLowering::AllocationFolding::kDoAllocationFolding
: MemoryLowering::AllocationFolding::kDontAllocationFolding,
data->debug_name(), &data->info()->tick_counter(), is_wasm);
data->debug_name(), &data->info()->tick_counter());
optimizer.Optimize();
}
};
-4
View File
@@ -963,10 +963,6 @@ class V8_EXPORT_PRIVATE RawMachineAssembler {
// Stack operations.
Node* LoadFramePointer() { return AddNode(machine()->LoadFramePointer()); }
Node* LoadStackPointer() { return AddNode(machine()->LoadStackPointer()); }
void SetStackPointer(Node* ptr) {
AddNode(machine()->SetStackPointer(), ptr);
}
Node* LoadParentFramePointer() {
return AddNode(machine()->LoadParentFramePointer());
}
@@ -39,13 +39,11 @@ struct MemoryAnalyzer {
const Graph& input_graph;
Isolate* isolate_ = PipelineData::Get().isolate();
AllocationFolding allocation_folding;
bool is_wasm;
MemoryAnalyzer(Zone* phase_zone, const Graph& input_graph,
AllocationFolding allocation_folding, bool is_wasm)
AllocationFolding allocation_folding)
: phase_zone(phase_zone),
input_graph(input_graph),
allocation_folding(allocation_folding),
is_wasm(is_wasm) {}
allocation_folding(allocation_folding) {}
struct BlockState {
const AllocateOp* last_allocation = nullptr;
@@ -139,18 +137,11 @@ class MemoryOptimizationReducer : public Next {
TURBOSHAFT_REDUCER_BOILERPLATE()
void Analyze() {
auto* info = PipelineData::Get().info();
#if V8_ENABLE_WEBASSEMBLY
bool is_wasm = info->IsWasm() || info->IsWasmBuiltin();
#else
bool is_wasm = false;
#endif
analyzer_.emplace(
__ phase_zone(), __ input_graph(),
info->allocation_folding()
PipelineData::Get().info()->allocation_folding()
? MemoryAnalyzer::AllocationFolding::kDoAllocationFolding
: MemoryAnalyzer::AllocationFolding::kDontAllocationFolding,
is_wasm);
: MemoryAnalyzer::AllocationFolding::kDontAllocationFolding);
analyzer_->Run();
Next::Analyze();
}
@@ -221,7 +212,7 @@ class MemoryOptimizationReducer : public Next {
__ LoadOffHeap(top_address, MemoryRepresentation::PointerSized()));
OpIndex allocate_builtin;
if (!analyzer_->is_wasm) {
if (isolate_ != nullptr) {
if (type == AllocationType::kYoung) {
allocate_builtin =
__ BuiltinCode(Builtin::kAllocateInYoungGeneration, isolate_);
@@ -230,29 +221,18 @@ class MemoryOptimizationReducer : public Next {
__ BuiltinCode(Builtin::kAllocateInOldGeneration, isolate_);
}
} else {
#if V8_ENABLE_WEBASSEMBLY
// This lowering is used by Wasm, where we compile isolate-independent
// code. Builtin calls simply encode the target builtin ID, which will
// be patched to the builtin's address later.
if (isolate_ == nullptr) {
Builtin builtin;
if (type == AllocationType::kYoung) {
builtin = Builtin::kWasmAllocateInYoungGeneration;
} else {
builtin = Builtin::kWasmAllocateInOldGeneration;
}
static_assert(std::is_same<Smi, BuiltinPtr>(),
"BuiltinPtr must be Smi");
allocate_builtin = __ NumberConstant(static_cast<int>(builtin));
#if V8_ENABLE_WEBASSEMBLY
Builtin builtin;
if (type == AllocationType::kYoung) {
builtin = Builtin::kAllocateInYoungGeneration;
} else {
if (type == AllocationType::kYoung) {
allocate_builtin =
__ BuiltinCode(Builtin::kWasmAllocateInYoungGeneration, isolate_);
} else {
allocate_builtin =
__ BuiltinCode(Builtin::kWasmAllocateInOldGeneration, isolate_);
}
builtin = Builtin::kAllocateInOldGeneration;
}
static_assert(std::is_same<Smi, BuiltinPtr>(), "BuiltinPtr must be Smi");
allocate_builtin = __ NumberConstant(static_cast<int>(builtin));
#else
UNREACHABLE();
#endif
+13 -92
View File
@@ -35,7 +35,6 @@
#include "src/compiler/wasm-compiler-definitions.h"
#include "src/compiler/wasm-graph-assembler.h"
#include "src/compiler/wasm-inlining-into-js.h"
#include "src/compiler/write-barrier-kind.h"
#include "src/execution/simulator-base.h"
#include "src/heap/factory.h"
#include "src/logging/counters.h"
@@ -7759,91 +7758,6 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
return resume.PhiAt(0);
}
#if V8_TARGET_ARCH_X64
Node* BuildSwitchToTheCentralStack(Node* callable_node) {
Node* stack_limit_slot = gasm_->IntPtrAdd(
gasm_->LoadFramePointer(),
gasm_->IntPtrConstant(
WasmImportWrapperFrameConstants::kSecondaryStackLimitOffset));
Node* do_switch = gasm_->ExternalConstant(
ExternalReference::wasm_switch_to_the_central_stack_for_js());
MachineType reps[] = {MachineType::Pointer(), MachineType::Pointer(),
MachineType::Pointer()};
MachineSignature sig(1, 2, reps);
Node* central_stack_sp =
BuildCCall(&sig, do_switch, callable_node, stack_limit_slot);
Node* old_sp = gasm_->LoadStackPointer();
gasm_->SetStackPointer(central_stack_sp);
gasm_->Store(StoreRepresentation(MachineType::PointerRepresentation(),
kNoWriteBarrier),
gasm_->LoadFramePointer(),
WasmImportWrapperFrameConstants::kCentralStackSPOffset,
central_stack_sp);
return old_sp;
}
void BuildSwitchBackFromCentralStack(Node* old_sp, Node* callable_node) {
Node* stack_limit = gasm_->Load(
MachineType::Pointer(), gasm_->LoadFramePointer(),
WasmImportWrapperFrameConstants::kSecondaryStackLimitOffset);
Node* do_switch = gasm_->ExternalConstant(
ExternalReference::wasm_switch_from_the_central_stack_for_js());
MachineType reps[] = {MachineType::Pointer(), MachineType::Pointer()};
MachineSignature sig(0, 2, reps);
BuildCCall(&sig, do_switch, callable_node, stack_limit);
gasm_->Store(StoreRepresentation(MachineType::PointerRepresentation(),
kNoWriteBarrier),
gasm_->LoadFramePointer(),
WasmImportWrapperFrameConstants::kCentralStackSPOffset,
gasm_->IntPtrConstant(0));
gasm_->SetStackPointer(old_sp);
}
#endif
Node* BuildCallOnCentralStack(base::SmallVector<Node*, 16>& args, int& pos,
CallDescriptor* call_descriptor,
Node* callable_node) {
#if V8_TARGET_ARCH_X64
// If the current stack is a secondary stack, switch, perform the call and
// switch back. Otherwise, just do the call.
// Return the Phi of the calls in the two branches.
auto no_switch = gasm_->MakeLabel();
auto end = gasm_->MakeLabel(MachineRepresentation::kTaggedPointer);
Node* isolate_root = BuildLoadIsolateRoot();
Node* is_on_central_stack_flag =
gasm_->Load(MachineType::Uint8(), isolate_root,
IsolateData::is_on_central_stack_flag_offset());
gasm_->GotoIf(is_on_central_stack_flag, &no_switch);
Node* old_sp = BuildSwitchToTheCentralStack(callable_node);
args[pos++] = effect();
args[pos++] = control();
DCHECK_EQ(pos, args.size());
Node* call = gasm_->Call(call_descriptor, pos, args.begin());
BuildSwitchBackFromCentralStack(old_sp, callable_node);
gasm_->Goto(&end, call);
gasm_->Bind(&no_switch);
args[pos - 2] = effect();
args[pos - 1] = control();
call = gasm_->Call(call_descriptor, pos, args.begin());
gasm_->Goto(&end, call);
gasm_->Bind(&end);
return end.PhiAt(0);
#else
// TODO(thibaudm): Port to other archs.
args[pos++] = effect();
args[pos++] = control();
DCHECK_EQ(pos, args.size());
return gasm_->Call(call_descriptor, pos, args.begin());
#endif
}
// For wasm-to-js wrappers, parameter 0 is a WasmApiFunctionRef.
bool BuildWasmToJSWrapper(wasm::ImportCallKind kind, int expected_arity,
wasm::Suspend suspend,
@@ -7931,9 +7845,11 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
args[pos++] = Int32Constant(
JSParameterCount(wasm_count - suspend)); // argument count
args[pos++] = function_context;
args[pos++] = effect();
args[pos++] = control();
call =
BuildCallOnCentralStack(args, pos, call_descriptor, callable_node);
DCHECK_EQ(pos, args.size());
call = gasm_->Call(call_descriptor, pos, args.begin());
break;
}
// =======================================================================
@@ -7962,11 +7878,13 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
Node* function_context =
gasm_->LoadContextFromJSFunction(callable_node);
args[pos++] = function_context;
args[pos++] = effect();
args[pos++] = control();
DCHECK_EQ(pos, args.size());
auto call_descriptor = Linkage::GetJSCallDescriptor(
graph()->zone(), false, pushed_count + 1, CallDescriptor::kNoFlags);
call =
BuildCallOnCentralStack(args, pos, call_descriptor, callable_node);
call = gasm_->Call(call_descriptor, pos, args.begin());
break;
}
// =======================================================================
@@ -7997,8 +7915,11 @@ class WasmWrapperGraphBuilder : public WasmGraphBuilder {
// TypeError, if the target is a native function, or if the target is a
// callable JSObject, which can only be constructed by the runtime.
args[pos++] = native_context;
call =
BuildCallOnCentralStack(args, pos, call_descriptor, callable_node);
args[pos++] = effect();
args[pos++] = control();
DCHECK_EQ(pos, args.size());
call = gasm_->Call(call_descriptor, pos, args.begin());
break;
}
default:
-16
View File
@@ -261,20 +261,6 @@ class WasmFrameConstants : public TypedFrameConstants {
static constexpr int kProtectedInstructionReturnAddressOffset = 1;
};
class WasmImportWrapperFrameConstants : public WasmFrameConstants {
public:
#if V8_TARGET_ARCH_X64
// FP-relative.
static constexpr int kCentralStackSPOffset =
TYPED_FRAME_PUSHED_VALUE_OFFSET(1);
static constexpr int kSecondaryStackLimitOffset =
TYPED_FRAME_PUSHED_VALUE_OFFSET(2);
DEFINE_TYPED_FRAME_SIZES(3);
#else
DEFINE_TYPED_FRAME_SIZES(1);
#endif
};
class WasmExitFrameConstants : public WasmFrameConstants {
public:
// FP-relative.
@@ -358,8 +344,6 @@ class WasmToJSWrapperConstants {
public:
// FP-relative.
static constexpr size_t kSignatureOffset = 2 * kSystemPointerSize;
static constexpr size_t kCentralStackSPOffset = 3 * kSystemPointerSize;
static constexpr size_t kSecondaryStackLimitOffset = 4 * kSystemPointerSize;
};
#endif // V8_ENABLE_WEBASSEMBLY
+13 -51
View File
@@ -355,12 +355,7 @@ StackFrameIteratorForProfiler::StackFrameIteratorForProfiler(
high_bound_(js_entry_sp),
top_frame_type_(StackFrame::NO_FRAME_TYPE),
external_callback_scope_(isolate->external_callback_scope()),
top_link_register_(lr)
#if V8_ENABLE_WEBASSEMBLY
,
wasm_stacks_(isolate->wasm_stacks())
#endif
{
top_link_register_(lr) {
if (!isolate->isolate_data()->stack_is_iterable()) {
// The stack is not iterable in a short time interval during deoptimization.
// See also: ExternalReference::stack_is_iterable_address.
@@ -1467,11 +1462,13 @@ void WasmFrame::Iterate(RootVisitor* v) const {
pc() - WasmFrameConstants::kProtectedInstructionReturnAddressOffset));
}
#ifdef DEBUG
intptr_t marker =
Memory<intptr_t>(fp() + CommonFrameConstants::kContextOrFrameTypeOffset);
DCHECK(StackFrame::IsTypeMarker(marker));
StackFrame::Type type = StackFrame::MarkerToType(marker);
DCHECK(type == WASM_TO_JS || type == WASM || type == WASM_EXIT);
#endif
// Determine the fixed header and spill slot area size.
// The last value in the frame header is the calling PC, which should
@@ -1488,29 +1485,15 @@ void WasmFrame::Iterate(RootVisitor* v) const {
int spill_slot_space =
wasm_code->stack_slots() * kSystemPointerSize -
(frame_header_size + StandardFrameConstants::kFixedFrameSizeAboveFp);
// Fixed frame slots.
FullObjectSlot frame_header_base(&Memory<Address>(fp() - frame_header_size));
FullObjectSlot frame_header_limit(
&Memory<Address>(fp() - StandardFrameConstants::kCPSlotSize));
// Parameters passed to the callee.
FullObjectSlot parameters_base(&Memory<Address>(sp()));
#if V8_TARGET_ARCH_X64
Address central_stack_sp = Memory<Address>(
fp() + WasmImportWrapperFrameConstants::kCentralStackSPOffset);
FullObjectSlot parameters_limit(
v8_flags.experimental_wasm_stack_switching && type == WASM_TO_JS &&
central_stack_sp != kNullAddress
? central_stack_sp
: frame_header_base.address() - spill_slot_space);
#else
// TODO(thibaudm): Support switching to the central stack on other archs.
FullObjectSlot parameters_limit(frame_header_base.address() -
spill_slot_space);
USE(type);
#endif
FullObjectSlot spill_space_end =
FullObjectSlot(frame_header_base.address() - spill_slot_space);
// Visit the rest of the parameters if they are tagged.
bool has_tagged_outgoing_params =
@@ -1525,7 +1508,7 @@ void WasmFrame::Iterate(RootVisitor* v) const {
if (safepoint_entry.is_initialized()) {
DCHECK_GE((wasm_code->stack_slots() + kBitsPerByte) / kBitsPerByte,
safepoint_entry.tagged_slots().size());
VisitSpillSlots(isolate(), v, spill_space_end,
VisitSpillSlots(isolate(), v, parameters_limit,
safepoint_entry.tagged_slots());
}
@@ -1695,9 +1678,8 @@ void TypedFrame::Iterate(RootVisitor* v) const {
CHECK(entry->code.has_value());
Tagged<GcSafeCode> code = entry->code.value();
#if V8_ENABLE_WEBASSEMBLY
bool is_wasm_to_js =
code->is_builtin() && code->builtin_id() == Builtin::kWasmToJsWrapperCSA;
if (is_wasm_to_js) {
if (code->is_builtin() &&
code->builtin_id() == Builtin::kWasmToJsWrapperCSA) {
IterateParamsOfWasmToJSWrapper(v);
}
#endif // V8_ENABLE_WEBASSEMBLY
@@ -1722,29 +1704,9 @@ void TypedFrame::Iterate(RootVisitor* v) const {
FullObjectSlot frame_header_limit(
&Memory<Address>(fp() - StandardFrameConstants::kCPSlotSize));
// Parameters passed to the callee.
#if V8_ENABLE_WEBASSEMBLY
// Load the central stack SP value from the fixed slot.
// If it is null, the import wrapper didn't switch and the layout is the same
// as regular typed frames: the outgoing stack parameters end where the spill
// area begins.
// Otherwise, it holds the address in the central stack where the import
// wrapper switched to before pushing the outgoing stack parameters and
// calling the target. It marks the limit of the stack param area, and is
// distinct from the beginning of the spill area.
Address central_stack_sp =
Memory<Address>(fp() + WasmToJSWrapperConstants::kCentralStackSPOffset);
FullObjectSlot parameters_limit(
v8_flags.experimental_wasm_stack_switching && is_wasm_to_js &&
central_stack_sp != kNullAddress
? central_stack_sp
: frame_header_base.address() - spill_slots_size);
#else
FullObjectSlot parameters_base(&Memory<Address>(sp()));
FullObjectSlot parameters_limit(frame_header_base.address() -
spill_slots_size);
#endif
FullObjectSlot parameters_base(&Memory<Address>(sp()));
FullObjectSlot spill_slots_end(frame_header_base.address() -
spill_slots_size);
// Visit the rest of the parameters.
if (HasTaggedOutgoingParams(code)) {
@@ -1755,7 +1717,7 @@ void TypedFrame::Iterate(RootVisitor* v) const {
// Visit pointer spill slots and locals.
DCHECK_GE((code->stack_slots() + kBitsPerByte) / kBitsPerByte,
safepoint_entry.tagged_slots().size());
VisitSpillSlots(isolate(), v, spill_slots_end,
VisitSpillSlots(isolate(), v, parameters_limit,
safepoint_entry.tagged_slots());
// Visit fixed header region.
@@ -3149,7 +3111,8 @@ bool WasmFrame::at_to_number_conversion() const {
isolate()->inner_pointer_to_code_cache()->GetCacheEntry(callee_pc());
CHECK(entry->code.has_value());
Tagged<GcSafeCode> code = entry->code.value();
if (code->builtin_id() != Builtin::kWasmToJsWrapperCSA) {
if (!code->is_builtin() ||
code->builtin_id() != Builtin::kWasmToJsWrapperCSA) {
return false;
}
@@ -3223,7 +3186,7 @@ void StackSwitchFrame::Iterate(RootVisitor* v) const {
// because the return address is on a different stack.
// The [fp + BuiltinFrameConstants::kGCScanSlotCountOffset] on the stack is a
// value indicating how many values should be scanned from the top.
intptr_t scan_count = Memory<intptr_t>(
intptr_t scan_count = *reinterpret_cast<intptr_t*>(
fp() + StackSwitchFrameConstants::kGCScanSlotCountOffset);
FullObjectSlot spill_slot_base(&Memory<Address>(sp()));
@@ -3246,7 +3209,6 @@ void StackSwitchFrame::GetStateForJumpBuffer(wasm::JumpBuffer* jmpbuf,
DCHECK_NE(jmpbuf->fp, kNullAddress);
DCHECK_EQ(ComputeFrameType(jmpbuf->fp), STACK_SWITCH);
FillState(jmpbuf->fp, jmpbuf->sp, state);
state->pc_address = &jmpbuf->pc;
DCHECK_NE(*state->pc_address, kNullAddress);
}
@@ -3257,7 +3219,7 @@ int WasmLiftoffSetupFrame::GetDeclaredFunctionIndex() const {
}
wasm::NativeModule* WasmLiftoffSetupFrame::GetNativeModule() const {
return Memory<wasm::NativeModule*>(
return *reinterpret_cast<wasm::NativeModule**>(
sp() + WasmLiftoffSetupFrameConstants::kNativeModuleOffset);
}
-14
View File
@@ -16,7 +16,6 @@
#include "src/objects/objects.h"
#if V8_ENABLE_WEBASSEMBLY
#include "src/wasm/stacks.h"
#include "src/wasm/wasm-code-manager.h"
#endif // V8_ENABLE_WEBASSEMBLY
@@ -1599,16 +1598,6 @@ class StackFrameIteratorForProfiler : public StackFrameIteratorBase {
void AdvanceOneFrame();
bool IsValidStackAddress(Address addr) const {
#if V8_ENABLE_WEBASSEMBLY
if (V8_UNLIKELY(v8_flags.experimental_wasm_stack_switching)) {
wasm::StackMemory* head = wasm_stacks_;
if (head->Contains(addr)) return true;
for (wasm::StackMemory* current = head->next(); current != head;
current = current->next()) {
if (current->Contains(addr)) return true;
}
}
#endif
return low_bound_ <= addr && addr <= high_bound_;
}
bool IsValidFrame(StackFrame* frame) const;
@@ -1630,9 +1619,6 @@ class StackFrameIteratorForProfiler : public StackFrameIteratorBase {
StackFrame::Type top_frame_type_;
ExternalCallbackScope* external_callback_scope_;
Address top_link_register_;
#if V8_ENABLE_WEBASSEMBLY
wasm::StackMemory* wasm_stacks_;
#endif
};
// We cannot export 'StackFrameIteratorForProfiler' for cctests since the
-10
View File
@@ -172,16 +172,6 @@ class IsolateData final {
return (address - start) < sizeof(*this);
}
// Offset of a ThreadLocalTop member from {isolate_root()}.
#define THREAD_LOCAL_TOP_MEMBER_OFFSET(Name) \
static uint32_t Name##_offset() { \
return static_cast<uint32_t>(IsolateData::thread_local_top_offset() + \
OFFSET_OF(ThreadLocalTop, Name##_)); \
}
THREAD_LOCAL_TOP_MEMBER_OFFSET(is_on_central_stack_flag)
#undef THREAD_LOCAL_TOP_MEMBER_OFFSET
private:
// Static layout definition.
//
+27 -79
View File
@@ -2150,7 +2150,7 @@ Tagged<Object> Isolate::UnwindAndFindHandler() {
}
case StackFrame::WASM_TO_JS:
if (v8_flags.experimental_wasm_stack_switching) {
// Decrement the Wasm-to-JS counter and reset the central-stack info.
// Decrement the Wasm-to-JS counter.
Tagged<Object> suspender_obj = root(RootIndex::kActiveSuspender);
if (!IsUndefined(suspender_obj)) {
Tagged<WasmSuspenderObject> suspender =
@@ -2158,23 +2158,6 @@ Tagged<Object> Isolate::UnwindAndFindHandler() {
int wasm_to_js_counter = suspender->wasm_to_js_counter();
DCHECK_LT(0, wasm_to_js_counter);
suspender->set_wasm_to_js_counter(wasm_to_js_counter - 1);
#if V8_TARGET_ARCH_X64
// If the wasm-to-js wrapper was on a secondary stack and switched
// to the central stack, handle the implicit switch back.
Address central_stack_sp = *reinterpret_cast<Address*>(
frame->fp() +
WasmImportWrapperFrameConstants::kCentralStackSPOffset);
bool switched_stacks = central_stack_sp != kNullAddress;
if (switched_stacks) {
thread_local_top()->is_on_central_stack_flag_ = false;
Address secondary_stack_limit = Memory<Address>(
frame->fp() +
WasmImportWrapperFrameConstants::kSecondaryStackLimitOffset);
stack_guard()->SetStackLimitForStackSwitching(
secondary_stack_limit);
}
#endif
}
}
break;
@@ -2215,34 +2198,10 @@ Tagged<Object> Isolate::UnwindAndFindHandler() {
// Some stubs are able to handle exceptions.
if (!catchable_by_js) break;
StubFrame* stub_frame = static_cast<StubFrame*>(frame);
#if V8_ENABLE_WEBASSEMBLY
#if defined(DEBUG)
{
wasm::WasmCodeRefScope code_ref_scope;
DCHECK_NULL(wasm::GetWasmCodeManager()->LookupCode(frame->pc()));
}
#endif
#if V8_TARGET_ARCH_X64
if (v8_flags.experimental_wasm_stack_switching) {
Tagged<Code> code = stub_frame->LookupCode();
if (code->builtin_id() == Builtin::kWasmToJsWrapperCSA) {
// If the wasm-to-js wrapper was on a secondary stack and switched
// to the central stack, handle the implicit switch back.
Address central_stack_sp = *reinterpret_cast<Address*>(
frame->fp() + WasmToJSWrapperConstants::kCentralStackSPOffset);
bool switched_stacks = central_stack_sp != kNullAddress;
if (switched_stacks) {
thread_local_top()->is_on_central_stack_flag_ = false;
Address secondary_stack_limit = Memory<Address>(
frame->fp() +
WasmToJSWrapperConstants::kSecondaryStackLimitOffset);
stack_guard()->SetStackLimitForStackSwitching(
secondary_stack_limit);
}
}
}
#endif // V8_TARGET_ARCH_X64
#endif // V8_ENABLE_WEBASSEMBLY
#if defined(DEBUG) && V8_ENABLE_WEBASSEMBLY
wasm::WasmCodeRefScope code_ref_scope;
DCHECK_NULL(wasm::GetWasmCodeManager()->LookupCode(frame->pc()));
#endif // defined(DEBUG) && V8_ENABLE_WEBASSEMBLY
// The code might be a dynamically generated stub or a turbofanned
// embedded builtin.
@@ -3300,20 +3259,6 @@ void Isolate::UnregisterManagedPtrDestructor(ManagedPtrDestructor* destructor) {
}
#if V8_ENABLE_WEBASSEMBLY
bool Isolate::IsOnCentralStack(Address addr) {
#ifdef USE_SIMULATOR
auto simulator_stack = Simulator::current(this)->GetCurrentStackView();
uint8_t* addr_ptr = reinterpret_cast<uint8_t*>(addr);
return simulator_stack.begin() < addr_ptr &&
addr_ptr <= simulator_stack.end();
#else
uintptr_t upper_bound = base::Stack::GetStackStart();
uintptr_t lower_bound = upper_bound - v8_flags.stack_size * KB -
wasm::StackMemory::kJSLimitOffsetKB * KB;
return lower_bound < addr && addr <= upper_bound;
#endif
}
void Isolate::AddSharedWasmMemory(Handle<WasmMemoryObject> memory_object) {
Handle<WeakArrayList> shared_wasm_memories =
factory()->shared_wasm_memories();
@@ -3341,29 +3286,36 @@ void Isolate::SyncStackLimit() {
}
uintptr_t limit = reinterpret_cast<uintptr_t>(stack->jmpbuf()->stack_limit);
stack_guard()->SetStackLimitForStackSwitching(limit);
UpdateCentralStackInfo();
RecordStackSwitchForScanning();
}
void Isolate::UpdateCentralStackInfo() {
namespace {
bool IsOnCentralStack(Isolate* isolate, Address addr) {
#ifdef USE_SIMULATOR
auto simulator_stack = Simulator::current(isolate)->GetCurrentStackView();
uint8_t* addr_ptr = reinterpret_cast<uint8_t*>(addr);
return simulator_stack.begin() < addr_ptr &&
addr_ptr <= simulator_stack.end();
#else
uintptr_t upper_bound = base::Stack::GetStackStart();
uintptr_t lower_bound = upper_bound - v8_flags.stack_size * KB;
return lower_bound < addr && addr <= upper_bound;
#endif
}
} // namespace
void Isolate::RecordStackSwitchForScanning() {
Tagged<Object> current = root(RootIndex::kActiveContinuation);
DCHECK(!IsUndefined(current));
stack().ClearStackSegments();
wasm::StackMemory* wasm_stack =
Managed<wasm::StackMemory>::cast(
WasmContinuationObject::cast(current)->stack())
->get()
.get();
// On platforms where we switch to the central stack for foreign calls
// (runtime/JS), we don't need to scan secondary stacks conservatively. They
// only contain frames that use precise scanning.
// Otherwise register the active secondary stack start and the bounds of the
// inactive stacks in the Stack object.
#if !V8_TARGET_ARCH_X64
stack().ClearStackSegments();
heap()->SetStackStart(reinterpret_cast<void*>(wasm_stack->base()));
#endif
current = WasmContinuationObject::cast(current)->parent();
thread_local_top()->is_on_central_stack_flag_ =
IsOnCentralStack(wasm_stack->base());
heap()->SetStackStart(reinterpret_cast<void*>(wasm_stack->base()));
thread_local_top()->is_on_central_stack_flag_ = IsUndefined(current);
// Update the central stack info on switch. Only consider the innermost stack
bool updated_central_stack = false;
// We don't need to add all inactive stacks. Only the ones in the active chain
@@ -3372,16 +3324,12 @@ void Isolate::UpdateCentralStackInfo() {
auto cont = WasmContinuationObject::cast(current);
auto* wasm_stack =
Managed<wasm::StackMemory>::cast(cont->stack())->get().get();
#if !V8_TARGET_ARCH_X64
stack().AddStackSegment(
reinterpret_cast<const void*>(wasm_stack->base()),
reinterpret_cast<const void*>(wasm_stack->jmpbuf()->sp));
#endif
// On x64 we don't need to record the stack segments for conservative stack
// scanning. We switch to the central stack for foreign calls, so secondary
// stacks only contain wasm frames which use the precise GC.
current = cont->parent();
if (!updated_central_stack && IsOnCentralStack(wasm_stack->jmpbuf()->sp)) {
if (!updated_central_stack &&
IsOnCentralStack(this, wasm_stack->jmpbuf()->sp)) {
// This is the most recent use of the central stack in the call chain.
// Switch to this SP if we need to switch to the central stack in the
// future.
+6 -9
View File
@@ -52,10 +52,6 @@
#include "src/runtime/runtime-utils.h"
#endif
#if V8_ENABLE_WEBASSEMBLY
#include "src/wasm/stacks.h"
#endif
#ifdef V8_INTL_SUPPORT
#include "unicode/uversion.h" // Define U_ICU_NAMESPACE.
namespace U_ICU_NAMESPACE {
@@ -182,6 +178,10 @@ namespace metrics {
class Recorder;
} // namespace metrics
namespace wasm {
class StackMemory;
}
#define RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate) \
do { \
Isolate* __isolate__ = (isolate); \
@@ -1317,7 +1317,7 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
THREAD_LOCAL_TOP_ADDRESS(Address, thread_in_wasm_flag_address)
THREAD_LOCAL_TOP_ADDRESS(uint8_t, is_on_central_stack_flag)
THREAD_LOCAL_TOP_ADDRESS(bool, is_on_central_stack_flag)
MaterializedObjectStore* materialized_object_store() const {
return materialized_object_store_;
@@ -2106,15 +2106,12 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
::heap::base::Stack& stack() { return stack_; }
#ifdef V8_ENABLE_WEBASSEMBLY
bool IsOnCentralStack(Address addr);
wasm::StackMemory*& wasm_stacks() { return wasm_stacks_; }
// Update the thread local's Stack object so that it is aware of the new stack
// start and the inactive stacks.
void UpdateCentralStackInfo();
void RecordStackSwitchForScanning();
void SyncStackLimit();
#else
bool IsOnCentralStack(Address addr) { return true; }
#endif
// Access to the global "locals block list cache". Caches outer-stack
+2 -1
View File
@@ -39,8 +39,9 @@ void ThreadLocalTop::Clear() {
current_embedder_state_ = nullptr;
failed_access_check_callback_ = nullptr;
thread_in_wasm_flag_address_ = kNullAddress;
central_stack_limit_ = kNullAddress;
is_on_central_stack_flag_ = true;
central_stack_sp_ = kNullAddress;
central_stack_limit_ = kNullAddress;
secondary_stack_sp_ = kNullAddress;
secondary_stack_limit_ = kNullAddress;
}
+1 -1
View File
@@ -149,7 +149,7 @@ class ThreadLocalTop {
// Wasm Stack Switching: The central stack.
// If set, then we are currently executing code on the central stack.
uint8_t is_on_central_stack_flag_;
bool is_on_central_stack_flag_;
// On switching from the central stack these fields are set
// to the central stack's SP and stack limit accordingly,
// to use for switching from secondary stacks.
-3
View File
@@ -483,9 +483,6 @@ class SaveAndClearThreadInWasmFlag {};
RUNTIME_FUNCTION(Runtime_AllocateInYoungGeneration) {
HandleScope scope(isolate);
#ifdef V8_TARGET_ARCH_X64
DCHECK(isolate->IsOnCentralStack(GetCurrentStackPosition()));
#endif
DCHECK_EQ(2, args.length());
// TODO(v8:13070): Align allocations in the builtins that call this.
int size = ALIGN_TO_ALLOCATION_ALIGNMENT(args.smi_value_at(0));
-10
View File
@@ -636,15 +636,5 @@ RUNTIME_FUNCTION(Runtime_WasmSwitchToTheCentralStackCount) {
return Smi::FromInt(count);
}
RUNTIME_FUNCTION(Runtime_CheckIsOnCentralStack) {
// This function verifies that itself, and therefore the JS function that
// called it, is running on the central stack. This is used to check that wasm
// switches to the central stack to run JS imports.
#if V8_TARGET_ARCH_X64
CHECK(isolate->IsOnCentralStack(GetCurrentStackPosition()));
#endif
return ReadOnlyRoots(isolate).undefined_value();
}
} // namespace internal
} // namespace v8
-3
View File
@@ -832,9 +832,6 @@ RUNTIME_FUNCTION(Runtime_WasmTableCopy) {
RUNTIME_FUNCTION(Runtime_WasmTableGrow) {
ClearThreadInWasmScope flag_scope(isolate);
#if V8_TARGET_ARCH_X64
DCHECK(isolate->IsOnCentralStack(GetCurrentStackPosition()));
#endif
HandleScope scope(isolate);
DCHECK_EQ(4, args.length());
Tagged<WasmInstanceObject> instance = WasmInstanceObject::cast(args[0]);
+15
View File
@@ -238,6 +238,21 @@ bool Runtime::IsAllowListedForFuzzing(FunctionId id) {
}
}
bool Runtime::SwitchToTheCentralStackForTarget(FunctionId id) {
// Runtime functions called from Wasm directly or
// from Wasm runtime stubs should execute on the central stack.
switch (id) {
#if V8_ENABLE_WEBASSEMBLY
#define WASM_CASE(Name, ...) case Runtime::k##Name:
FOR_EACH_INTRINSIC_WASM(WASM_CASE, WASM_CASE)
#undef WASM_CASE
return true;
#endif // V8_ENABLE_WEBASSEMBLY
default:
return false;
}
}
const Runtime::Function* Runtime::FunctionForName(const unsigned char* name,
int length) {
base::CallOnce(&initialize_function_name_map_once,
+5 -2
View File
@@ -709,8 +709,7 @@ namespace internal {
F(WasmTierUpFunction, 1, 1) \
F(WasmTraceEnter, 0, 1) \
F(WasmTraceExit, 1, 1) \
F(WasmTraceMemory, 1, 1) \
F(CheckIsOnCentralStack, 0, 1)
F(WasmTraceMemory, 1, 1)
#define FOR_EACH_INTRINSIC_WEAKREF(F, I) \
F(JSFinalizationRegistryRegisterWeakCellWithUnregisterToken, 4, 1) \
@@ -873,6 +872,10 @@ class Runtime : public AllStatic {
// using it with fuzzers.
static bool IsAllowListedForFuzzing(FunctionId id);
// Check if a switch to the central stack should be performed
// for a runtime function.
static bool SwitchToTheCentralStackForTarget(FunctionId id);
// Get the intrinsic function with the given name.
static const Function* FunctionForName(const unsigned char* name, int length);
+1 -5
View File
@@ -347,11 +347,7 @@ int LiftoffAssembler::GetTotalFrameSlotCountForGC() const {
namespace {
AssemblerOptions DefaultLiftoffOptions() {
AssemblerOptions options = AssemblerOptions{};
options.is_wasm = true;
return options;
}
AssemblerOptions DefaultLiftoffOptions() { return AssemblerOptions{}; }
} // namespace
+2 -8
View File
@@ -10,12 +10,9 @@
#endif // !V8_ENABLE_WEBASSEMBLY
#include "src/common/globals.h"
#include "src/execution/isolate.h"
#include "src/utils/allocation.h"
namespace v8 {
class Isolate;
}
namespace v8::internal::wasm {
struct JumpBuffer {
@@ -45,9 +42,6 @@ class StackMemory {
void* jslimit() const { return limit_ + kJSLimitOffsetKB * KB; }
Address base() const { return reinterpret_cast<Address>(limit_ + size_); }
JumpBuffer* jmpbuf() { return &jmpbuf_; }
bool Contains(Address addr) {
return reinterpret_cast<Address>(jslimit()) <= addr && addr < base();
}
int id() { return id_; }
// Insert a stack in the linked list after this stack.
@@ -59,13 +53,13 @@ class StackMemory {
size_t owned_size() { return sizeof(StackMemory) + (owned_ ? size_ : 0); }
bool IsActive() { return jmpbuf_.state == JumpBuffer::Active; }
private:
#ifdef DEBUG
static constexpr int kJSLimitOffsetKB = 80;
#else
static constexpr int kJSLimitOffsetKB = 40;
#endif
private:
// This constructor allocates a new stack segment.
explicit StackMemory(Isolate* isolate);
+1 -19
View File
@@ -192,11 +192,7 @@ namespace v8::internal::wasm {
V(WasmStringFromDataSegment) \
V(StringAdd_CheckNone) \
V(DebugPrintFloat64) \
V(DebugPrintWordPtr) \
V(WasmAllocateInYoungGeneration) \
V(WasmAllocateInOldGeneration) \
V(IterableToFixedArrayForWasm) \
V(WasmAllocateZeroedFixedArray)
V(DebugPrintWordPtr)
namespace detail {
constexpr std::array<uint8_t, static_cast<int>(Builtin::kFirstBytecodeHandler)>
@@ -229,20 +225,6 @@ class BuiltinLookup {
static constexpr int BuiltinCount() { return kBuiltinCount; }
static bool IsWasmBuiltinId(Builtin id) {
switch (id) {
#define BUILTIN_ID(Name) \
case Builtin::k##Name: \
return true;
#define BUILTIN_ID_TRAP(Name) \
case Builtin::kThrowWasm##Name: \
return true;
WASM_BUILTIN_LIST(BUILTIN_ID, BUILTIN_ID_TRAP)
default:
return false;
}
}
private:
#define BUILTIN_COUNTER(NAME) +1
static constexpr int kBuiltinCount =
+3 -22
View File
@@ -695,6 +695,9 @@ intptr_t switch_to_the_central_stack(Isolate* isolate, uintptr_t current_sp) {
ThreadLocalTop* thread_local_top = isolate->thread_local_top();
StackGuard* stack_guard = isolate->stack_guard();
CHECK_EQ(thread_local_top->secondary_stack_sp_, 0);
CHECK_EQ(thread_local_top->secondary_stack_limit_, 0);
auto secondary_stack_limit = stack_guard->real_jslimit();
stack_guard->SetStackLimitForStackSwitching(
@@ -726,28 +729,6 @@ void switch_from_the_central_stack(Isolate* isolate) {
stack_guard->SetStackLimitForStackSwitching(secondary_stack_limit);
}
intptr_t switch_to_the_central_stack_for_js(Address raw_callable,
uintptr_t* stack_limit_slot) {
Tagged<JSReceiver> callable = JSReceiver::cast(Tagged<Object>(raw_callable));
Isolate* isolate = callable->GetIsolate();
ThreadLocalTop* thread_local_top = isolate->thread_local_top();
StackGuard* stack_guard = isolate->stack_guard();
*stack_limit_slot = stack_guard->real_jslimit();
stack_guard->SetStackLimit(thread_local_top->central_stack_limit_);
thread_local_top->is_on_central_stack_flag_ = true;
return thread_local_top->central_stack_sp_;
}
void switch_from_the_central_stack_for_js(Address raw_callable,
uintptr_t stack_limit) {
Tagged<JSReceiver> callable = JSReceiver::cast(Tagged<Object>(raw_callable));
Isolate* isolate = callable->GetIsolate();
ThreadLocalTop* thread_local_top = isolate->thread_local_top();
thread_local_top->is_on_central_stack_flag_ = false;
StackGuard* stack_guard = isolate->stack_guard();
stack_guard->SetStackLimit(stack_limit);
}
} // namespace v8::internal::wasm
#undef V8_WITH_SANITIZER
-4
View File
@@ -135,10 +135,6 @@ void sync_stack_limit(Isolate* isolate);
intptr_t switch_to_the_central_stack(Isolate* isolate, uintptr_t sp);
void switch_from_the_central_stack(Isolate* isolate);
intptr_t switch_to_the_central_stack_for_js(Address callable,
uintptr_t* stack_limit_slot);
void switch_from_the_central_stack_for_js(Address callable,
uintptr_t stack_limit);
} // namespace wasm
} // namespace internal
+3 -9
View File
@@ -2341,15 +2341,9 @@ Handle<WasmJSFunction> WasmJSFunction::New(Isolate* isolate,
}
// TODO(wasm): Think about caching and sharing the wasm-to-JS wrappers per
// signature instead of compiling a new one for every instantiation.
if (UseGenericWasmToJSWrapper(kind, sig, suspend)) {
wasm_to_js_wrapper_code = handle(
isolate->builtins()->code(Builtin::kWasmToJsWrapperAsm), isolate);
} else {
wasm_to_js_wrapper_code =
compiler::CompileWasmToJSWrapper(isolate, sig, kind, expected_arity,
suspend)
.ToHandleChecked();
}
wasm_to_js_wrapper_code = compiler::CompileWasmToJSWrapper(
isolate, sig, kind, expected_arity, suspend)
.ToHandleChecked();
}
function_data->internal()->set_code(*wasm_to_js_wrapper_code);
}
-2
View File
@@ -13,8 +13,6 @@
#include "src/base/bit-field.h"
#include "src/debug/interface-types.h"
#include "src/heap/heap.h"
#include "src/objects/backing-store.h"
#include "src/objects/foreign.h"
#include "src/objects/js-function.h"
#include "src/objects/js-objects.h"
-2
View File
@@ -1748,7 +1748,6 @@
# These tests use %SimulateNewspaceFull, which only works in the young generation
'regress/regress-1424415': [SKIP],
'wasm/stack-switching': [SKIP],
'wasm/stack-switching-generic-wrapper': [SKIP],
}], # single_generation
################################################################################
@@ -1902,7 +1901,6 @@
# Stack switching is only supported on x64/arm64.
'wasm/stack-switching': [SKIP],
'wasm/stack-switching-export': [SKIP],
'wasm/stack-switching-generic-wrapper': [SKIP]
}], # (arch != x64 and arch != arm64 and arch != ia32)
##############################################################################
+58 -49
View File
@@ -11,9 +11,18 @@
d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
function GC() {
%CheckIsOnCentralStack();
gc();
function ToPromising(wasm_export) {
let sig = wasm_export.type();
assertTrue(sig.parameters.length > 0);
assertEquals('externref', sig.parameters[0]);
assertEquals(1, sig.results.length);
let wrapper_sig = {
parameters: sig.parameters.slice(1),
results: ['externref']
};
return new WebAssembly.Function(
wrapper_sig, wasm_export, {promising: 'first'});
}
(function testGenericWrapper0Param() {
@@ -29,7 +38,7 @@ function GC() {
let x = 12;
function import_func() {
GC();
gc();
x = 20;
}
@@ -86,7 +95,7 @@ function GC() {
let x = 12;
function import_func(suspender, param) {
GC();
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
x += param;
}
@@ -113,12 +122,12 @@ function GC() {
let x = 12;
function import_func(suspender, param) {
GC();
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
x += param;
}
let y = { valueOf: () => { print("Hello!"); GC(); return 24; } };
let y = { valueOf: () => { print("Hello!"); gc(); return 24; } };
let instance = builder.instantiate({ mod: { func: import_func } });
let main = ToPromising(instance.exports.main);
assertPromiseResult(main(y), v => { assertEquals(undefined, v); });
@@ -145,13 +154,13 @@ function GC() {
let x = 12;
function import_func(suspender, param1, param2, param3, param4) {
GC();
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
x += 2 * param1 + 3 * param2 + 4 * param3 + 5 * param4;
}
let param2 = { valueOf: () => { GC(); return 6; } };
let param3 = { valueOf: () => { GC(); return 3; } };
let param2 = { valueOf: () => { gc(); return 6; } };
let param3 = { valueOf: () => { gc(); return 3; } };
let instance = builder.instantiate({ mod: { func: import_func } });
let main = ToPromising(instance.exports.main);
assertPromiseResult(
@@ -198,16 +207,16 @@ let kSig_r_riiiiiiii = makeSig([kWasmExternRef, kWasmI32, kWasmI32, kWasmI32,
let x = 12;
function import_func(suspender, param1, param2, param3, param4, param5,
param6, param7, param8) {
GC();
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
x += param1 + 2 * param2 + 3 * param3 + 4 * param4 + 5 * param5
+ 6 * param6 + 7 * param7 + 8 * param8;
}
let param1 = { valueOf: () => { GC(); return 5; } };
let param4 = { valueOf: () => { GC(); return 8; } };
let param6 = { valueOf: () => { GC(); return 10; } };
let param8 = { valueOf: () => { GC(); return 12; } };
let param1 = { valueOf: () => { gc(); return 5; } };
let param4 = { valueOf: () => { gc(); return 8; } };
let param6 = { valueOf: () => { gc(); return 10; } };
let param8 = { valueOf: () => { gc(); return 12; } };
let instance = builder.instantiate({ mod: { func: import_func } });
let main = ToPromising(instance.exports.main);
assertPromiseResult(
@@ -237,12 +246,12 @@ let kSig_r_riiiiiiii = makeSig([kWasmExternRef, kWasmI32, kWasmI32, kWasmI32,
let x = 12;
function import_func(suspender, param1, param2, param3, param4) {
GC();
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
x += param1 + param2 + param3 + param4;
}
let param2 = { valueOf: () => { GC(); return 3; } };
let param2 = { valueOf: () => { gc(); return 3; } };
let instance = builder.instantiate({ mod: { func: import_func } });
let main = ToPromising(instance.exports.main);
assertPromiseResult(main(5, param2), v => assertEquals(undefined, v));
@@ -270,13 +279,13 @@ let kSig_r_riiiiiiii = makeSig([kWasmExternRef, kWasmI32, kWasmI32, kWasmI32,
let x = 12;
function import_func(suspender, param1, param2, param3, param4) {
GC();
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
x += param1 + param2 + param3 + param4;
}
let param2 = { valueOf: () => { GC(); return 3; } };
let param3 = { valueOf: () => { GC(); return 6; } };
let param2 = { valueOf: () => { gc(); return 3; } };
let param3 = { valueOf: () => { gc(); return 6; } };
let instance = builder.instantiate({ mod: { func: import_func } });
let main = ToPromising(instance.exports.main);
assertPromiseResult(
@@ -301,7 +310,7 @@ let kSig_r_riiiiiiii = makeSig([kWasmExternRef, kWasmI32, kWasmI32, kWasmI32,
let x = 12;
function import_func(suspender, param) {
GC();
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
return x + param;
}
@@ -364,8 +373,8 @@ let kSig_i_rlili = makeSig([kWasmExternRef, kWasmI64, kWasmI32, kWasmI64, kWasmI
return Number(x);
}
let param2 = { valueOf: () => { GC(); return 6; } };
let param3 = { valueOf: () => { GC(); return 3n; } };
let param2 = { valueOf: () => { gc(); return 6; } };
let param3 = { valueOf: () => { gc(); return 3n; } };
let instance = builder.instantiate({ mod: { func: import_func } });
let main = ToPromising(instance.exports.main);
assertPromiseResult(main(9n, param2, param3, 0), v => assertEquals(60, v));
@@ -393,13 +402,13 @@ let kSig_r_riiili = makeSig([kWasmExternRef, kWasmI32, kWasmI32, kWasmI32, kWasm
let x = 12;
function import_func(suspender, param1, param2, param3, param4, param5) {
GC();
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
x += 2 * param1 + 3 * param2 + 4 * param3 + 5 * Number(param4) + 6 * param5;
}
let param2 = { valueOf: () => { GC(); return 6; } };
let param3 = { valueOf: () => { GC(); return 3; } };
let param2 = { valueOf: () => { gc(); return 6; } };
let param3 = { valueOf: () => { gc(); return 3; } };
let instance = builder.instantiate({ mod: { func: import_func } });
let main = ToPromising(instance.exports.main);
assertPromiseResult(
@@ -437,8 +446,8 @@ let kSig_r_riiilii = makeSig([kWasmExternRef, kWasmI32, kWasmI32, kWasmI32,
x += 2 * param1 + 3 * param2 + 4 * param3 + 5 * Number(param4) + 6 * param5 + 7 * param6;
}
let param2 = { valueOf: () => { GC(); return 6; } };
let param3 = { valueOf: () => { GC(); return 3; } };
let param2 = { valueOf: () => { gc(); return 6; } };
let param3 = { valueOf: () => { gc(); return 3; } };
let instance = builder.instantiate({ mod: { func: import_func } });
let main = ToPromising(instance.exports.main);
assertPromiseResult(
@@ -480,10 +489,10 @@ let kSig_r_rliilliiil = makeSig([kWasmExternRef, kWasmI64, kWasmI32, kWasmI32,
return x;
}
let param1 = { valueOf: () => { GC(); return 5n; } };
let param4 = { valueOf: () => { GC(); return 8n; } };
let param6 = { valueOf: () => { GC(); return 10; } };
let param8 = { valueOf: () => { GC(); return 12; } };
let param1 = { valueOf: () => { gc(); return 5n; } };
let param4 = { valueOf: () => { gc(); return 8n; } };
let param6 = { valueOf: () => { gc(); return 10; } };
let param8 = { valueOf: () => { gc(); return 12; } };
let instance = builder.instantiate({ mod: { func: import_func } });
let main = ToPromising(instance.exports.main);
assertPromiseResult(
@@ -531,7 +540,7 @@ let kSig_r_rliilliiil = makeSig([kWasmExternRef, kWasmI64, kWasmI32, kWasmI32,
.exportFunc();
function import_func(suspender) {
GC();
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
return 10000000000n;
}
@@ -555,7 +564,7 @@ let kSig_r_rliilliiil = makeSig([kWasmExternRef, kWasmI64, kWasmI32, kWasmI32,
.exportFunc();
function import_func(suspender) {
GC();
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
return 0.5;
}
@@ -579,7 +588,7 @@ let kSig_r_rliilliiil = makeSig([kWasmExternRef, kWasmI64, kWasmI32, kWasmI32,
.exportFunc();
function import_func(suspender) {
GC();
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
return 0.25;
}
@@ -605,7 +614,7 @@ let kSig_r_rliilliiil = makeSig([kWasmExternRef, kWasmI64, kWasmI32, kWasmI32,
let x = 12.5;
function import_func(suspender, param) {
GC();
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
x += param;
}
@@ -632,7 +641,7 @@ let kSig_r_rliilliiil = makeSig([kWasmExternRef, kWasmI64, kWasmI32, kWasmI32,
let x = 12.5;
function import_func(suspender, param) {
GC();
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
x += param;
}
@@ -669,16 +678,16 @@ let kSig_r_rffddddff = makeSig([kWasmExternRef, kWasmF32, kWasmF32, kWasmF64,
let x = 12;
function import_func(suspender, param1, param2, param3, param4, param5,
param6, param7, param8) {
GC();
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
x += param1 + 2 * param2 + 3 * param3 + 4 * param4 + 5 * param5
+ 6 * param6 + 7 * param7 + 8 * param8;
}
let param1 = { valueOf: () => { GC(); return 1.5; } };
let param4 = { valueOf: () => { GC(); return 4.5; } };
let param6 = { valueOf: () => { GC(); return 6.5; } };
let param8 = { valueOf: () => { GC(); return 8.5; } };
let param1 = { valueOf: () => { gc(); return 1.5; } };
let param4 = { valueOf: () => { gc(); return 4.5; } };
let param6 = { valueOf: () => { gc(); return 6.5; } };
let param8 = { valueOf: () => { gc(); return 8.5; } };
let instance = builder.instantiate({ mod: { func: import_func } });
let main = ToPromising(instance.exports.main);
assertPromiseResult(
@@ -720,7 +729,7 @@ let kSig_r_riiliffddlfdff = makeSig([kWasmExternRef, kWasmI32, kWasmI32, kWasmI6
let y = 1.0;
function import_func(suspender, parami1, parami2, paraml1, parami3, paramf1,
paramf2, paramd1, paramd2, paraml2, paramf3, paramd3, paramf4, paramf5) {
GC();
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
x += parami1 + 2 * parami2 + 3 * Number(paraml1) + 4 * parami3
+ 5 * Number(paraml2);
@@ -769,17 +778,17 @@ let kSig_r_riiliiiffddli = makeSig([kWasmExternRef, kWasmI32, kWasmI32, kWasmI64
let y = 1.0;
function import_func(suspender, param1, param2, param3, param4, param5,
param6, paramf1, paramf2, paramd1, paramd2, param7, param8) {
GC();
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
x += param1 + 2 * param2 + 3 * Number(param3) + 4 * param4 + 5 * param5
+ 6 * param6 + 7 * Number(param7) + 8 * param8;
y += paramf1 + paramf2 + paramd1 + paramd2;
}
let param1 = { valueOf: () => { GC(); return 5; } };
let param4 = { valueOf: () => { GC(); return 8; } };
let param6 = { valueOf: () => { GC(); return 10; } };
let param8 = { valueOf: () => { GC(); return 12; } };
let param1 = { valueOf: () => { gc(); return 5; } };
let param4 = { valueOf: () => { gc(); return 8; } };
let param6 = { valueOf: () => { gc(); return 10; } };
let param8 = { valueOf: () => { gc(); return 12; } };
let instance = builder.instantiate({ mod: { func: import_func } });
let main = ToPromising(instance.exports.main);
assertPromiseResult(
@@ -827,7 +836,7 @@ let kSig_f_riiliiiffddlifffdi = makeSig([kWasmExternRef, kWasmI32, kWasmI32,
function import_func(suspender, param1, param2, param3, param4, param5,
param6, paramf1, paramf2, paramd1, paramd2, param7, param8, paramf3,
paramf4, paramf5, paramd3, param9) {
GC();
gc();
assertInstanceof(suspender, WebAssembly.Suspender);
x += param1 + 2 * param2 + 3 * Number(param3) + 4 * param4 + 5 * param5
+ 6 * param6 + 7 * Number(param7) + 8 * param8 + 9 * param9;
@@ -1,44 +0,0 @@
// Copyright 2023 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --wasm-to-js-generic-wrapper --expose-gc --allow-natives-syntax
// Flags: --experimental-wasm-stack-switching
// Test the stack-switching export wrapper in combination with the generic
// import wrapper, in particular to test that the generic wrapper switches to
// the central stack.
d8.file.execute("test/mjsunit/wasm/stack-switching-export.js");
// Throw an exception from JS, catch it in wasm and then overflow the stack.
// This tests the implicit stack switch when the exception leaves JS (central
// stack) and re-enters wasm (secondary stack). If the stack limit is not
// updated during unwinding, the stack overflow is likely to crash.
(function testGenericWrapperException() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let sig_index = builder.addType(kSig_v_r);
let func_index = builder.addImport("mod", "func", kSig_v_v);
builder.addFunction("main", sig_index)
.addBody([
kExprTry, kWasmVoid,
kExprCallFunction, func_index,
kExprCatchAll,
kExprEnd,
kExprCallFunction, 2
])
.exportFunc();
builder.addFunction("stackOverflow", kSig_v_v)
.addBody([
kExprCallFunction, 2
]);
function import_func() {
%CheckIsOnCentralStack();
throw new Error();
}
let instance = builder.instantiate({ mod: { func: import_func } });
let main = ToPromising(instance.exports.main);
assertThrowsAsync(main(), RangeError, /Maximum call stack size exceeded/);
})();
+19 -124
View File
@@ -19,6 +19,19 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
/WebAssembly.Suspender must be invoked with 'new'/);
})();
function ToPromising(wasm_export) {
let sig = wasm_export.type();
assertTrue(sig.parameters.length > 0);
assertEquals('externref', sig.parameters[0]);
let wrapper_sig = {
parameters: sig.parameters.slice(1),
results: ['externref']
};
return new WebAssembly.Function(
wrapper_sig, wasm_export, {promising: 'first'});
}
(function TestSuspenderTypes() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
@@ -625,12 +638,10 @@ function TestNestedSuspenders(suspend) {
assertEquals(42, instance.exports.test(null));
})();
(function TestSwitchingToTheCentralStackForRuntime() {
(function TestSwitchingToTheCentralStack() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let table = builder.addTable(kWasmExternRef, 1);
let array_index = builder.addArray(kWasmI32, true);
let new_space_full_index = builder.addImport('m', 'new_space_full', kSig_v_v);
builder.addFunction("test", kSig_i_r)
.addBody([
kExprLocalGet, 0,
@@ -639,136 +650,20 @@ function TestNestedSuspenders(suspend) {
builder.addFunction("test2", kSig_i_r)
.addBody([
kExprI32Const, 1]).exportFunc();
let sig_l_r = makeSig([kWasmExternRef], [kWasmI64]);
builder.addFunction("test3", sig_l_r)
.addBody([
kExprCallFunction, new_space_full_index,
...wasmI64Const(0)
]).exportFunc();
builder.addFunction("test4", kSig_v_r)
.addBody([
kExprCallFunction, new_space_full_index,
kExprI32Const, 1,
kGCPrefix, kExprArrayNewDefault, array_index,
kExprDrop]).exportFunc();
function new_space_full() {
%SimulateNewspaceFull();
}
let instance = builder.instantiate({m: {new_space_full}});
let instance = builder.instantiate();
let wrapper = ToPromising(instance.exports.test);
let wrapper2 = ToPromising(instance.exports.test2);
let wrapper3 = ToPromising(instance.exports.test3);
let wrapper4 = ToPromising(instance.exports.test4);
function switchesToCS(fn) {
const beforeCall = %WasmSwitchToTheCentralStackCount();
fn();
return %WasmSwitchToTheCentralStackCount() - beforeCall;
}
// Calling exported functions from the central stack.
assertEquals(0, switchesToCS(() => instance.exports.test({})));
assertEquals(0, switchesToCS(() => instance.exports.test2({})));
assertEquals(0, switchesToCS(() => instance.exports.test3({})));
assertEquals(0, switchesToCS(() => instance.exports.test4({})));
assertEquals(switchesToCS(() => instance.exports.test({})), 0);
assertEquals(switchesToCS(() => instance.exports.test2({})), 0);
// Runtime call to table.grow.
switchesToCS(wrapper);
assertEquals(switchesToCS(wrapper), 1);
// No runtime calls.
switchesToCS(wrapper2);
// Runtime call to allocate the bigint.
switchesToCS(wrapper3);
// Runtime call for array.new.
switchesToCS(wrapper4);
})();
(function TestSwitchingToTheCentralStackForJS() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
import_index = builder.addImport('m', 'import', kSig_i_r);
builder.addFunction("test", kSig_i_r)
.addBody([
kExprLocalGet, 0,
kExprCallFunction, import_index,
]).exportFunc();
let js_import = new WebAssembly.Function(
{parameters: ['externref'], results: ['i32']},
() => {
%CheckIsOnCentralStack();
return 123;
},
{suspending: 'first'});
let instance = builder.instantiate({m: {import: js_import}});
let wrapped_export = ToPromising(instance.exports.test);
assertPromiseResult(wrapped_export(), v => assertEquals(123, v));
})();
// Test that the wasm-to-js stack params get scanned.
(function TestSwitchingToTheCentralStackManyParams() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
const num_params = 10;
let params = Array(num_params + 1 /* suspender */).fill(kWasmExternRef);
const sig = makeSig(params, [kWasmExternRef]);
const import_index = builder.addImport('m', 'import_', sig);
let body = [];
for (let i = 0; i < num_params + 1; ++i) {
body.push(kExprLocalGet, i);
}
body.push(kExprCallFunction, import_index);
builder.addFunction("test", sig)
.addBody(body).exportFunc();
function import_js(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) {
gc();
return [arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9];
};
import_js();
let import_ = new WebAssembly.Function(
{parameters: Array(num_params + 1).fill('externref'), results: ['externref']},
import_js,
{suspending: 'first'});
let instance = builder.instantiate({m: {import_}});
let wrapper = ToPromising(instance.exports.test);
let args = Array(num_params).fill({});
assertPromiseResult(wrapper(...args), results => { assertEquals(args, results); });
})();
// Similar to TestNestedSuspenders, but trigger an infinite recursion inside the
// outer wasm function after the import call. This is likely to crash if the
// stack limit is not properly restored when we return from the central stack.
// In particular in the nested case, we should preserve and restore the limit of
// each intermediate secondary stack.
(function TestCentralStackReentrency() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
inner_index = builder.addImport('m', 'inner', kSig_i_r);
outer_index = builder.addImport('m', 'outer', kSig_i_r);
let stack_overflow = builder.addFunction('stack_overflow', kSig_v_v)
.addBody([kExprCallFunction, 2]);
builder.addFunction("outer", kSig_i_r)
.addBody([
kExprLocalGet, 0,
kExprCallFunction, outer_index,
kExprCallFunction, stack_overflow.index,
]).exportFunc();
builder.addFunction("inner", kSig_i_r)
.addBody([
kExprLocalGet, 0,
kExprCallFunction, inner_index
]).exportFunc();
let inner = new WebAssembly.Function(
{parameters: ['externref'], results: ['i32']},
() => Promise.resolve(42),
{suspending: 'first'});
let export_inner;
let outer = new WebAssembly.Function(
{parameters: ['externref'], results: ['i32']},
() => export_inner(),
{suspending: 'first'});
let instance = builder.instantiate({m: {inner, outer}});
export_inner = ToPromising(instance.exports.inner);
let export_outer = ToPromising(instance.exports.outer);
assertThrowsAsync(export_outer(), RangeError,
/Maximum call stack size exceeded/);
assertEquals(switchesToCS(wrapper2), 0);
})();
-14
View File
@@ -2283,17 +2283,3 @@ let [wasmBrOnCast, wasmBrOnCastFail] = (function() {
function getOpcodeName(opcode) {
return globalThis.kWasmOpcodeNames?.[opcode] ?? 'unknown';
}
// Make a wasm export "promising" using JS Promise Integration.
function ToPromising(wasm_export) {
let sig = wasm_export.type();
assertTrue(sig.parameters.length > 0);
assertEquals('externref', sig.parameters[0]);
let wrapper_sig = {
parameters: sig.parameters.slice(1),
results: ['externref']
};
return new WebAssembly.Function(
wrapper_sig, wasm_export, {promising: 'first'});
}