Revert "Reland^3 "[wasm][x64] Run JS imports on the central stack""
This reverts commitbe830f359c. 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 commit2d6e2bd529> 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 commit4be9ff946b> > > > 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 commit9d9f49d201> > > > > > 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. > > > - Merging8bbc90166dinto 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:
1 parent
e1f7254f7a
commit
083b24225f
58 files changed
+281
-994
No files matched your search
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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) \
|
||||
\
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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") \
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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)),
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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
|
||||
@@ -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]);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
##############################################################################
|
||||
|
||||
@@ -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,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);
|
||||
})();
|
||||
@@ -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'});
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user