Commit 4e329f8c authored by Andreas Haas's avatar Andreas Haas Committed by V8 LUCI CQ

Reland: [wasm] WasmCompileLazyFrame scanning

The original CL did not handle the case where a GC gets triggered by
the allocation of the error object when compilation fails.

Orignal message:

Feedback vector allocation can trigger a GC, and thereby make the
WasmCompileLazyFrame visible for the GC. This CL add stack scanning
for the WasmCompileLazyFrame.

Design doc: http://doc/1peovM6N6C4nSEdC77l4uxU1L0njA0RTaOjy5F12r2CQ

Change-Id: I9be66c696e27f9ecf8228daf40ad6258f0e963d1

Bug: v8:12852
Fix: v8:13133
Change-Id: I9be66c696e27f9ecf8228daf40ad6258f0e963d1
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3804599Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82138}
parent 0669c5bf
...@@ -2688,7 +2688,7 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) { ...@@ -2688,7 +2688,7 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
CHECK_EQ(highest_fp_reg.code() - lowest_fp_reg.code() + 1, CHECK_EQ(highest_fp_reg.code() - lowest_fp_reg.code() + 1,
arraysize(wasm::kFpParamRegisters)); arraysize(wasm::kFpParamRegisters));
CHECK_EQ(gp_regs.Count(), CHECK_EQ(gp_regs.Count(),
WasmCompileLazyFrameConstants::kNumberOfSavedGpParamRegs); WasmCompileLazyFrameConstants::kNumberOfSavedGpParamRegs + 1);
CHECK_EQ(highest_fp_reg.code() - lowest_fp_reg.code() + 1, CHECK_EQ(highest_fp_reg.code() - lowest_fp_reg.code() + 1,
WasmCompileLazyFrameConstants::kNumberOfSavedFpParamRegs); WasmCompileLazyFrameConstants::kNumberOfSavedFpParamRegs);
...@@ -2699,10 +2699,13 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) { ...@@ -2699,10 +2699,13 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
__ push(kWasmInstanceRegister); __ push(kWasmInstanceRegister);
// Push the function index as second argument. // Push the function index as second argument.
__ push(kWasmCompileLazyFuncIndexRegister); __ push(kWasmCompileLazyFuncIndexRegister);
// Allocate a stack slot for the NativeModule, the pushed value does not
// matter.
__ push(r8);
// Initialize the JavaScript context with 0. CEntry will use it to // Initialize the JavaScript context with 0. CEntry will use it to
// set the current context on the isolate. // set the current context on the isolate.
__ Move(cp, Smi::zero()); __ Move(cp, Smi::zero());
__ CallRuntime(Runtime::kWasmCompileLazy, 2); __ CallRuntime(Runtime::kWasmCompileLazy, 3);
// The runtime function returns the jump table slot offset as a Smi. Use // The runtime function returns the jump table slot offset as a Smi. Use
// that to compute the jump target in r8. // that to compute the jump target in r8.
__ mov(r8, Operand::SmiUntag(kReturnRegister0)); __ mov(r8, Operand::SmiUntag(kReturnRegister0));
......
...@@ -3075,7 +3075,8 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) { ...@@ -3075,7 +3075,8 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
CHECK_EQ(0, saved_gp_regs.Count() % 2); CHECK_EQ(0, saved_gp_regs.Count() % 2);
// The Wasm instance must be part of the saved registers. // The Wasm instance must be part of the saved registers.
CHECK(saved_gp_regs.has(kWasmInstanceRegister)); CHECK(saved_gp_regs.has(kWasmInstanceRegister));
CHECK_EQ(WasmCompileLazyFrameConstants::kNumberOfSavedGpParamRegs, // + instance + alignment
CHECK_EQ(WasmCompileLazyFrameConstants::kNumberOfSavedGpParamRegs + 2,
saved_gp_regs.Count()); saved_gp_regs.Count());
return saved_gp_regs; return saved_gp_regs;
})(); })();
...@@ -3102,13 +3103,14 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) { ...@@ -3102,13 +3103,14 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
__ PushXRegList(kSavedGpRegs); __ PushXRegList(kSavedGpRegs);
__ PushQRegList(kSavedFpRegs); __ PushQRegList(kSavedFpRegs);
// Pass instance and function index as explicit arguments to the runtime // Pass instance, function index, and an additional stack slot for the
// function. // native module, as explicit arguments to the runtime function. The first
__ Push(kWasmInstanceRegister, kWasmCompileLazyFuncIndexRegister); // pushed register is for alignment. {x0} and {x1} are picked arbitrarily.
__ Push(x0, kWasmInstanceRegister, kWasmCompileLazyFuncIndexRegister, x1);
// Initialize the JavaScript context with 0. CEntry will use it to // Initialize the JavaScript context with 0. CEntry will use it to
// set the current context on the isolate. // set the current context on the isolate.
__ Mov(cp, Smi::zero()); __ Mov(cp, Smi::zero());
__ CallRuntime(Runtime::kWasmCompileLazy, 2); __ CallRuntime(Runtime::kWasmCompileLazy, 3);
// Untag the returned Smi into into x17 (ip1), for later use. // Untag the returned Smi into into x17 (ip1), for later use.
static_assert(!kSavedGpRegs.has(x17)); static_assert(!kSavedGpRegs.has(x17));
......
...@@ -2915,7 +2915,8 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) { ...@@ -2915,7 +2915,8 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
// Save all parameter registers (see wasm-linkage.h). They might be // Save all parameter registers (see wasm-linkage.h). They might be
// overwritten in the runtime call below. We don't have any callee-saved // overwritten in the runtime call below. We don't have any callee-saved
// registers in wasm, so no need to store anything else. // registers in wasm, so no need to store anything else.
static_assert(WasmCompileLazyFrameConstants::kNumberOfSavedGpParamRegs == static_assert(
WasmCompileLazyFrameConstants::kNumberOfSavedGpParamRegs + 1 ==
arraysize(wasm::kGpParamRegisters), arraysize(wasm::kGpParamRegisters),
"frame size mismatch"); "frame size mismatch");
for (Register reg : wasm::kGpParamRegisters) { for (Register reg : wasm::kGpParamRegisters) {
...@@ -2935,10 +2936,13 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) { ...@@ -2935,10 +2936,13 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
__ Push(kWasmInstanceRegister); __ Push(kWasmInstanceRegister);
// Push the function index as second argument. // Push the function index as second argument.
__ Push(kWasmCompileLazyFuncIndexRegister); __ Push(kWasmCompileLazyFuncIndexRegister);
// Allocate a stack slot, where the runtime function can spill a pointer to
// the the NativeModule.
__ Push(esp);
// Initialize the JavaScript context with 0. CEntry will use it to // Initialize the JavaScript context with 0. CEntry will use it to
// set the current context on the isolate. // set the current context on the isolate.
__ Move(kContextRegister, Smi::zero()); __ Move(kContextRegister, Smi::zero());
__ CallRuntime(Runtime::kWasmCompileLazy, 2); __ CallRuntime(Runtime::kWasmCompileLazy, 3);
// The runtime function returns the jump table slot offset as a Smi. Use // The runtime function returns the jump table slot offset as a Smi. Use
// that to compute the jump target in edi. // that to compute the jump target in edi.
__ SmiUntag(kReturnRegister0); __ SmiUntag(kReturnRegister0);
......
...@@ -2838,7 +2838,8 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) { ...@@ -2838,7 +2838,8 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
// Save all parameter registers (see wasm-linkage.h). They might be // Save all parameter registers (see wasm-linkage.h). They might be
// overwritten in the runtime call below. We don't have any callee-saved // overwritten in the runtime call below. We don't have any callee-saved
// registers in wasm, so no need to store anything else. // registers in wasm, so no need to store anything else.
static_assert(WasmCompileLazyFrameConstants::kNumberOfSavedGpParamRegs == static_assert(
WasmCompileLazyFrameConstants::kNumberOfSavedGpParamRegs + 1 ==
arraysize(wasm::kGpParamRegisters), arraysize(wasm::kGpParamRegisters),
"frame size mismatch"); "frame size mismatch");
for (Register reg : wasm::kGpParamRegisters) { for (Register reg : wasm::kGpParamRegisters) {
...@@ -2858,10 +2859,14 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) { ...@@ -2858,10 +2859,14 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
__ Push(kWasmInstanceRegister); __ Push(kWasmInstanceRegister);
// Push the function index as second argument. // Push the function index as second argument.
__ Push(r15); __ Push(r15);
// Allocate a stack slot, where the runtime function can spill a pointer to
// the the NativeModule.
__ Push(rsp);
// Initialize the JavaScript context with 0. CEntry will use it to // Initialize the JavaScript context with 0. CEntry will use it to
// set the current context on the isolate. // set the current context on the isolate.
__ Move(kContextRegister, Smi::zero()); __ Move(kContextRegister, Smi::zero());
__ CallRuntime(Runtime::kWasmCompileLazy, 2); __ CallRuntime(Runtime::kWasmCompileLazy, 3);
// The runtime function returns the jump table slot offset as a Smi. Use // The runtime function returns the jump table slot offset as a Smi. Use
// that to compute the jump target in r15. // that to compute the jump target in r15.
__ SmiUntag(kReturnRegister0); __ SmiUntag(kReturnRegister0);
......
...@@ -57,18 +57,26 @@ class EntryFrameConstants : public AllStatic { ...@@ -57,18 +57,26 @@ class EntryFrameConstants : public AllStatic {
class WasmCompileLazyFrameConstants : public TypedFrameConstants { class WasmCompileLazyFrameConstants : public TypedFrameConstants {
public: public:
static constexpr int kNumberOfSavedGpParamRegs = 4; // Number of gp parameters, without the instance.
static constexpr int kNumberOfSavedGpParamRegs = 3;
static constexpr int kNumberOfSavedFpParamRegs = 8; static constexpr int kNumberOfSavedFpParamRegs = 8;
// FP-relative. // On arm, spilled registers are implicitly sorted backwards by number.
// The instance is pushed as part of the saved registers. Being in {r3}, it is // We spill:
// at position 1 in the list [r0, r2, r3, r6] (kGpParamRegisters sorted by // r3: param0 = instance
// number and indexed zero-based from the back). // r0, r2, r6: param1, param2, param3
static constexpr int kWasmInstanceOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(1); // in the following FP-relative order: [r6, r3, r2, r0].
static constexpr int kFixedFrameSizeFromFp = static constexpr int kInstanceSpillOffset =
TypedFrameConstants::kFixedFrameSizeFromFp + TYPED_FRAME_PUSHED_VALUE_OFFSET(1);
kNumberOfSavedGpParamRegs * kPointerSize +
kNumberOfSavedFpParamRegs * kDoubleSize; static constexpr int kParameterSpillsOffset[] = {
TYPED_FRAME_PUSHED_VALUE_OFFSET(3), TYPED_FRAME_PUSHED_VALUE_OFFSET(2),
TYPED_FRAME_PUSHED_VALUE_OFFSET(0)};
// SP-relative.
static constexpr int kWasmInstanceOffset = 2 * kSystemPointerSize;
static constexpr int kFunctionIndexOffset = 1 * kSystemPointerSize;
static constexpr int kNativeModuleOffset = 0;
}; };
// Frame constructed by the {WasmDebugBreak} builtin. // Frame constructed by the {WasmDebugBreak} builtin.
......
...@@ -74,20 +74,29 @@ class EntryFrameConstants : public AllStatic { ...@@ -74,20 +74,29 @@ class EntryFrameConstants : public AllStatic {
class WasmCompileLazyFrameConstants : public TypedFrameConstants { class WasmCompileLazyFrameConstants : public TypedFrameConstants {
public: public:
static constexpr int kNumberOfSavedGpParamRegs = 8; // Number of gp parameters, without the instance.
static constexpr int kNumberOfSavedGpParamRegs = 6;
static constexpr int kNumberOfSavedFpParamRegs = 8; static constexpr int kNumberOfSavedFpParamRegs = 8;
// FP-relative. // On arm, spilled registers are implicitly sorted backwards by number.
// The instance is pushed as part of the saved registers. Being in {r7}, it is // We spill:
// the first register pushed (highest register code in // x7: param0 = instance
// {wasm::kGpParamRegisters}). Because of padding of the frame header, it is // x0, x2, x3, x4, x5, x6: param1, param2, ..., param6
// actually one word further down the stack though (thus at position {1}). // x1: for alignment
static constexpr int kWasmInstanceOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(1); // in the following FP-relative order: [x7, x6, x5, x4, x3, x2, x1, x0].
static constexpr int kFixedFrameSizeFromFp = // For frame alignment, the first spill slot is at position '1', not at '0'.
// Header is padded to 16 byte (see {MacroAssembler::EnterFrame}). static constexpr int kInstanceSpillOffset =
RoundUp<16>(TypedFrameConstants::kFixedFrameSizeFromFp) + TYPED_FRAME_PUSHED_VALUE_OFFSET(1);
kNumberOfSavedGpParamRegs * kSystemPointerSize +
kNumberOfSavedFpParamRegs * kSimd128Size; static constexpr int kParameterSpillsOffset[] = {
TYPED_FRAME_PUSHED_VALUE_OFFSET(8), TYPED_FRAME_PUSHED_VALUE_OFFSET(6),
TYPED_FRAME_PUSHED_VALUE_OFFSET(5), TYPED_FRAME_PUSHED_VALUE_OFFSET(4),
TYPED_FRAME_PUSHED_VALUE_OFFSET(3), TYPED_FRAME_PUSHED_VALUE_OFFSET(2)};
// SP-relative.
static constexpr int kWasmInstanceOffset = 2 * kSystemPointerSize;
static constexpr int kFunctionIndexOffset = 1 * kSystemPointerSize;
static constexpr int kNativeModuleOffset = 0;
}; };
// Frame constructed by the {WasmDebugBreak} builtin. // Frame constructed by the {WasmDebugBreak} builtin.
......
...@@ -2577,21 +2577,96 @@ void StackSwitchFrame::GetStateForJumpBuffer(wasm::JumpBuffer* jmpbuf, ...@@ -2577,21 +2577,96 @@ void StackSwitchFrame::GetStateForJumpBuffer(wasm::JumpBuffer* jmpbuf,
DCHECK_NE(*state->pc_address, kNullAddress); DCHECK_NE(*state->pc_address, kNullAddress);
} }
WasmInstanceObject WasmCompileLazyFrame::wasm_instance() const { int WasmCompileLazyFrame::GetFunctionIndex() const {
return WasmInstanceObject::cast(*wasm_instance_slot()); Object func_index(Memory<Address>(
sp() + WasmCompileLazyFrameConstants::kFunctionIndexOffset));
return Smi::ToInt(func_index);
}
wasm::NativeModule* WasmCompileLazyFrame::GetNativeModule() const {
return *reinterpret_cast<wasm::NativeModule**>(
sp() + WasmCompileLazyFrameConstants::kNativeModuleOffset);
} }
FullObjectSlot WasmCompileLazyFrame::wasm_instance_slot() const { FullObjectSlot WasmCompileLazyFrame::wasm_instance_slot() const {
const int offset = WasmCompileLazyFrameConstants::kWasmInstanceOffset; return FullObjectSlot(&Memory<Address>(
return FullObjectSlot(&Memory<Address>(fp() + offset)); sp() + WasmCompileLazyFrameConstants::kWasmInstanceOffset));
} }
void WasmCompileLazyFrame::Iterate(RootVisitor* v) const { void WasmCompileLazyFrame::Iterate(RootVisitor* v) const {
const int header_size = WasmCompileLazyFrameConstants::kFixedFrameSizeFromFp; FullObjectSlot spilled_instance_slot(&Memory<Address>(
FullObjectSlot base(&Memory<Address>(sp())); fp() + WasmCompileLazyFrameConstants::kInstanceSpillOffset));
FullObjectSlot limit(&Memory<Address>(fp() - header_size)); v->VisitRootPointer(Root::kStackRoots, "spilled wasm instance",
v->VisitRootPointers(Root::kStackRoots, nullptr, base, limit); spilled_instance_slot);
v->VisitRootPointer(Root::kStackRoots, nullptr, wasm_instance_slot()); v->VisitRootPointer(Root::kStackRoots, "wasm instance parameter",
wasm_instance_slot());
int func_index = GetFunctionIndex();
wasm::NativeModule* native_module = GetNativeModule();
if (!native_module) {
// This GC was triggered by lazy compilation, because otherwise this frame
// would not be on the stack. The native module gets set on the stack after
// a successful compilation. The native module being nullptr means that
// compilation failed, and we don't have to preserve any references because
// the stack will get unwound immediately after the GC.
return;
}
// Scan the spill slots of the parameter registers. Parameters in WebAssembly
// get reordered such that first all value parameters get put into registers.
// If there are more registers than value parameters, the remaining registers
// are used for reference parameters. Therefore we can determine which
// registers get used for which parameters by counting the number of value
// parameters and the number of reference parameters.
int num_int_params = 0;
int num_ref_params = 0;
const wasm::FunctionSig* sig =
native_module->module()->functions[func_index].sig;
for (auto param : sig->parameters()) {
if (param == wasm::kWasmI32) {
num_int_params++;
} else if (param == wasm::kWasmI64) {
num_int_params += kSystemPointerSize == 8 ? 1 : 2;
} else if (param.is_reference()) {
num_ref_params++;
}
}
// There are no reference parameters, there is nothing to scan.
if (num_ref_params == 0) return;
int num_int_params_in_registers = std::min(
num_int_params, WasmCompileLazyFrameConstants::kNumberOfSavedGpParamRegs);
int num_ref_params_in_registers = std::min(
num_ref_params, WasmCompileLazyFrameConstants::kNumberOfSavedGpParamRegs -
num_int_params_in_registers);
for (int i = 0; i < num_ref_params_in_registers; ++i) {
FullObjectSlot spill_slot(
fp() + WasmCompileLazyFrameConstants::kParameterSpillsOffset
[num_int_params_in_registers + i]);
v->VisitRootPointer(Root::kStackRoots, "register parameter", spill_slot);
}
// Next we scan the slots of stack parameters.
wasm::WasmCode* wasm_code = native_module->GetCode(func_index);
uint32_t first_tagged_stack_slot = wasm_code->first_tagged_parameter_slot();
uint32_t num_tagged_stack_slots = wasm_code->num_tagged_parameter_slots();
// Visit tagged parameters that have been passed to the function of this
// frame. Conceptionally these parameters belong to the parent frame. However,
// the exact count is only known by this frame (in the presence of tail calls,
// this information cannot be derived from the call site).
if (num_tagged_stack_slots > 0) {
FullObjectSlot tagged_parameter_base(&Memory<Address>(caller_sp()));
tagged_parameter_base += first_tagged_stack_slot;
FullObjectSlot tagged_parameter_limit =
tagged_parameter_base + num_tagged_stack_slots;
v->VisitRootPointers(Root::kStackRoots, "stack parameter",
tagged_parameter_base, tagged_parameter_limit);
}
} }
#endif // V8_ENABLE_WEBASSEMBLY #endif // V8_ENABLE_WEBASSEMBLY
......
...@@ -1113,9 +1113,12 @@ class WasmCompileLazyFrame : public TypedFrame { ...@@ -1113,9 +1113,12 @@ class WasmCompileLazyFrame : public TypedFrame {
public: public:
Type type() const override { return WASM_COMPILE_LAZY; } Type type() const override { return WASM_COMPILE_LAZY; }
WasmInstanceObject wasm_instance() const;
FullObjectSlot wasm_instance_slot() const; FullObjectSlot wasm_instance_slot() const;
int GetFunctionIndex() const;
wasm::NativeModule* GetNativeModule() const;
// Garbage collection support. // Garbage collection support.
void Iterate(RootVisitor* v) const override; void Iterate(RootVisitor* v) const override;
......
...@@ -36,15 +36,21 @@ class EntryFrameConstants : public AllStatic { ...@@ -36,15 +36,21 @@ class EntryFrameConstants : public AllStatic {
class WasmCompileLazyFrameConstants : public TypedFrameConstants { class WasmCompileLazyFrameConstants : public TypedFrameConstants {
public: public:
static constexpr int kNumberOfSavedGpParamRegs = 4; // Number of gp parameters, without the instance.
static constexpr int kNumberOfSavedGpParamRegs = 3;
static constexpr int kNumberOfSavedFpParamRegs = 6; static constexpr int kNumberOfSavedFpParamRegs = 6;
// FP-relative. static constexpr int kInstanceSpillOffset =
static constexpr int kWasmInstanceOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(0); TYPED_FRAME_PUSHED_VALUE_OFFSET(0);
static constexpr int kFixedFrameSizeFromFp =
TypedFrameConstants::kFixedFrameSizeFromFp + static constexpr int kParameterSpillsOffset[] = {
kNumberOfSavedGpParamRegs * kSystemPointerSize + TYPED_FRAME_PUSHED_VALUE_OFFSET(1), TYPED_FRAME_PUSHED_VALUE_OFFSET(2),
kNumberOfSavedFpParamRegs * kSimd128Size; TYPED_FRAME_PUSHED_VALUE_OFFSET(3)};
// SP-relative.
static constexpr int kWasmInstanceOffset = 2 * kSystemPointerSize;
static constexpr int kFunctionIndexOffset = 1 * kSystemPointerSize;
static constexpr int kNativeModuleOffset = 0;
}; };
// Frame constructed by the {WasmDebugBreak} builtin. // Frame constructed by the {WasmDebugBreak} builtin.
......
...@@ -45,15 +45,22 @@ class EntryFrameConstants : public AllStatic { ...@@ -45,15 +45,22 @@ class EntryFrameConstants : public AllStatic {
class WasmCompileLazyFrameConstants : public TypedFrameConstants { class WasmCompileLazyFrameConstants : public TypedFrameConstants {
public: public:
static constexpr int kNumberOfSavedGpParamRegs = 6; // Number of gp parameters, without the instance.
static constexpr int kNumberOfSavedGpParamRegs = 5;
static constexpr int kNumberOfSavedFpParamRegs = 6; static constexpr int kNumberOfSavedFpParamRegs = 6;
// FP-relative. static constexpr int kInstanceSpillOffset =
static constexpr int kWasmInstanceOffset = TYPED_FRAME_PUSHED_VALUE_OFFSET(0); TYPED_FRAME_PUSHED_VALUE_OFFSET(0);
static constexpr int kFixedFrameSizeFromFp =
TypedFrameConstants::kFixedFrameSizeFromFp + static constexpr int kParameterSpillsOffset[] = {
kNumberOfSavedGpParamRegs * kSystemPointerSize + TYPED_FRAME_PUSHED_VALUE_OFFSET(1), TYPED_FRAME_PUSHED_VALUE_OFFSET(2),
kNumberOfSavedFpParamRegs * kSimd128Size; TYPED_FRAME_PUSHED_VALUE_OFFSET(3), TYPED_FRAME_PUSHED_VALUE_OFFSET(4),
TYPED_FRAME_PUSHED_VALUE_OFFSET(5)};
// SP-relative.
static constexpr int kWasmInstanceOffset = 2 * kSystemPointerSize;
static constexpr int kFunctionIndexOffset = 1 * kSystemPointerSize;
static constexpr int kNativeModuleOffset = 0;
}; };
// Frame constructed by the {WasmDebugBreak} builtin. // Frame constructed by the {WasmDebugBreak} builtin.
......
...@@ -219,35 +219,22 @@ RUNTIME_FUNCTION(Runtime_WasmStackGuard) { ...@@ -219,35 +219,22 @@ RUNTIME_FUNCTION(Runtime_WasmStackGuard) {
} }
RUNTIME_FUNCTION(Runtime_WasmCompileLazy) { RUNTIME_FUNCTION(Runtime_WasmCompileLazy) {
// The parameters of the called function we are going to compile have been
// spilled on the stack. Some of these parameters may be references. As we
// don't know which parameters are references, we have to make sure that no GC
// is triggered during the compilation of the function.
base::Optional<DisallowGarbageCollection> no_gc(base::in_place);
ClearThreadInWasmScope wasm_flag(isolate); ClearThreadInWasmScope wasm_flag(isolate);
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK_EQ(2, args.length()); DCHECK_EQ(3, args.length());
// TODO(jkummerow): This can be an unhandlified object once
// {wasm::CompileLazy()} no longer allocates even when speculative inlining
// is enabled.
Handle<WasmInstanceObject> instance(WasmInstanceObject::cast(args[0]), Handle<WasmInstanceObject> instance(WasmInstanceObject::cast(args[0]),
isolate); isolate);
int func_index = args.smi_value_at(1); int func_index = args.smi_value_at(1);
wasm::NativeModule** native_module_stack_slot =
#ifdef DEBUG reinterpret_cast<wasm::NativeModule**>(args.address_of_arg_at(2));
FrameFinder<WasmCompileLazyFrame> frame_finder(isolate); *native_module_stack_slot = nullptr;
DCHECK_EQ(*instance, frame_finder.frame()->wasm_instance());
#endif
DCHECK(isolate->context().is_null()); DCHECK(isolate->context().is_null());
isolate->set_context(instance->native_context()); isolate->set_context(instance->native_context());
bool success = wasm::CompileLazy(isolate, instance, func_index); bool success = wasm::CompileLazy(isolate, instance, func_index,
native_module_stack_slot);
if (!success) { if (!success) {
{ {
// Compilation of function failed. We have to allocate the exception
// object. This allocation may trigger a GC, but that's okay, because the
// parameters on the stack will not be used anymore anyways.
no_gc.reset();
wasm::ThrowLazyCompilationError( wasm::ThrowLazyCompilationError(
isolate, instance->module_object().native_module(), func_index); isolate, instance->module_object().native_module(), func_index);
} }
......
...@@ -603,7 +603,7 @@ namespace internal { ...@@ -603,7 +603,7 @@ namespace internal {
F(WasmTableGrow, 3, 1) \ F(WasmTableGrow, 3, 1) \
F(WasmTableFill, 5, 1) \ F(WasmTableFill, 5, 1) \
F(WasmIsValidRefValue, 3, 1) \ F(WasmIsValidRefValue, 3, 1) \
F(WasmCompileLazy, 2, 1) \ F(WasmCompileLazy, 3, 1) \
F(WasmCompileWrapper, 2, 1) \ F(WasmCompileWrapper, 2, 1) \
F(WasmTriggerTierUp, 1, 1) \ F(WasmTriggerTierUp, 1, 1) \
F(WasmDebugBreak, 0, 1) \ F(WasmDebugBreak, 0, 1) \
......
...@@ -1135,7 +1135,7 @@ bool IsLazyModule(const WasmModule* module) { ...@@ -1135,7 +1135,7 @@ bool IsLazyModule(const WasmModule* module) {
} // namespace } // namespace
bool CompileLazy(Isolate* isolate, Handle<WasmInstanceObject> instance, bool CompileLazy(Isolate* isolate, Handle<WasmInstanceObject> instance,
int func_index) { int func_index, NativeModule** out_native_module) {
Handle<WasmModuleObject> module_object(instance->module_object(), isolate); Handle<WasmModuleObject> module_object(instance->module_object(), isolate);
NativeModule* native_module = module_object->native_module(); NativeModule* native_module = module_object->native_module();
const WasmModule* module = native_module->module(); const WasmModule* module = native_module->module();
...@@ -1189,15 +1189,6 @@ bool CompileLazy(Isolate* isolate, Handle<WasmInstanceObject> instance, ...@@ -1189,15 +1189,6 @@ bool CompileLazy(Isolate* isolate, Handle<WasmInstanceObject> instance,
return false; return false;
} }
// Allocate feedback vector if needed.
if (result.feedback_vector_slots > 0) {
DCHECK(FLAG_wasm_speculative_inlining);
Handle<FixedArray> vector = isolate->factory()->NewFixedArrayWithZeroes(
result.feedback_vector_slots);
instance->feedback_vectors().set(
declared_function_index(module, func_index), *vector);
}
WasmCodeRefScope code_ref_scope; WasmCodeRefScope code_ref_scope;
WasmCode* code; WasmCode* code;
{ {
...@@ -1226,6 +1217,17 @@ bool CompileLazy(Isolate* isolate, Handle<WasmInstanceObject> instance, ...@@ -1226,6 +1217,17 @@ bool CompileLazy(Isolate* isolate, Handle<WasmInstanceObject> instance,
compilation_state->CommitTopTierCompilationUnit(tiering_unit); compilation_state->CommitTopTierCompilationUnit(tiering_unit);
} }
// Allocate feedback vector if needed.
if (result.feedback_vector_slots > 0) {
DCHECK(FLAG_wasm_speculative_inlining);
// We have to save the native_module on the stack, in case the allocation
// triggers a GC and we need the module to scan WasmCompileLazy stack frame.
*out_native_module = native_module;
Handle<FixedArray> vector = isolate->factory()->NewFixedArrayWithZeroes(
result.feedback_vector_slots);
instance->feedback_vectors().set(
declared_function_index(module, func_index), *vector);
}
return true; return true;
} }
......
...@@ -80,7 +80,8 @@ WasmCode* CompileImportWrapper( ...@@ -80,7 +80,8 @@ WasmCode* CompileImportWrapper(
// Triggered by the WasmCompileLazy builtin. The return value indicates whether // Triggered by the WasmCompileLazy builtin. The return value indicates whether
// compilation was successful. Lazy compilation can fail only if validation is // compilation was successful. Lazy compilation can fail only if validation is
// also lazy. // also lazy.
bool CompileLazy(Isolate*, Handle<WasmInstanceObject>, int func_index); bool CompileLazy(Isolate*, Handle<WasmInstanceObject>, int func_index,
NativeModule** out_native_module);
// Throws the compilation error after failed lazy compilation. // Throws the compilation error after failed lazy compilation.
void ThrowLazyCompilationError(Isolate* isolate, void ThrowLazyCompilationError(Isolate* isolate,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment