Commit b1553b91 authored by Marja Hölttä's avatar Marja Hölttä Committed by V8 LUCI CQ

[interpreter] Omit calling default ctors

If we see a default ctor, walk up the constructors until we find a non-
default one.

Default ctors can only be skipped if there are no class fields / private
brands.

This CL implements the Ignition parts; Sparkplug, Maglev and TF will
be implemented as follow ups. (This is fine, since this feature is
behind a flag.)

Bug: v8:13091
Change-Id: Ie8ca8aedb01bd4b13adf1063332a5cdf41ab358a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3804601Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Reviewed-by: 's avatarNico Hartmann <nicohartmann@chromium.org>
Commit-Queue: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82872}
parent 168fcef9
......@@ -1160,6 +1160,11 @@ void BaselineCompiler::VisitGetSuperConstructor() {
StoreRegister(0, prototype);
}
void BaselineCompiler::VisitFindNonDefaultConstructor() {
// TODO(v8:13091): Implement.
CHECK(false);
}
namespace {
constexpr Builtin ConvertReceiverModeToCompactBuiltin(
ConvertReceiverMode mode) {
......
......@@ -2747,6 +2747,13 @@ TNode<BoolT> CodeStubAssembler::LoadScopeInfoHasExtensionField(
return IsSetWord<ScopeInfo::HasContextExtensionSlotBit>(value);
}
TNode<BoolT> CodeStubAssembler::LoadScopeInfoClassScopeHasPrivateBrand(
TNode<ScopeInfo> scope_info) {
TNode<IntPtrT> value =
LoadAndUntagObjectField(scope_info, ScopeInfo::kFlagsOffset);
return IsSetWord<ScopeInfo::ClassScopeHasPrivateBrandBit>(value);
}
void CodeStubAssembler::StoreContextElementNoWriteBarrier(
TNode<Context> context, int slot_index, TNode<Object> value) {
int offset = Context::SlotOffset(slot_index);
......@@ -2837,8 +2844,7 @@ TNode<Map> CodeStubAssembler::LoadJSArrayElementsMap(
LoadContextElement(native_context, Context::ArrayMapIndex(kind)));
}
TNode<BoolT> CodeStubAssembler::IsGeneratorFunction(
TNode<JSFunction> function) {
TNode<Uint32T> CodeStubAssembler::LoadFunctionKind(TNode<JSFunction> function) {
const TNode<SharedFunctionInfo> shared_function_info =
LoadObjectField<SharedFunctionInfo>(
function, JSFunction::kSharedFunctionInfoOffset);
......@@ -2847,6 +2853,12 @@ TNode<BoolT> CodeStubAssembler::IsGeneratorFunction(
DecodeWord32<SharedFunctionInfo::FunctionKindBits>(
LoadObjectField<Uint32T>(shared_function_info,
SharedFunctionInfo::kFlagsOffset));
return function_kind;
}
TNode<BoolT> CodeStubAssembler::IsGeneratorFunction(
TNode<JSFunction> function) {
const TNode<Uint32T> function_kind = LoadFunctionKind(function);
// See IsGeneratorFunction(FunctionKind kind).
return IsInRange(
......
......@@ -138,6 +138,7 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
V(array_to_string, array_to_string, ArrayToString) \
V(BooleanMap, boolean_map, BooleanMap) \
V(boolean_to_string, boolean_to_string, BooleanToString) \
V(class_fields_symbol, class_fields_symbol, ClassFieldsSymbol) \
V(ConsOneByteStringMap, cons_one_byte_string_map, ConsOneByteStringMap) \
V(ConsStringMap, cons_string_map, ConsStringMap) \
V(constructor_string, constructor_string, ConstructorString) \
......@@ -1628,6 +1629,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// ScopeInfo:
TNode<ScopeInfo> LoadScopeInfo(TNode<Context> context);
TNode<BoolT> LoadScopeInfoHasExtensionField(TNode<ScopeInfo> scope_info);
TNode<BoolT> LoadScopeInfoClassScopeHasPrivateBrand(
TNode<ScopeInfo> scope_info);
// Context manipulation:
void StoreContextElementNoWriteBarrier(TNode<Context> context, int slot_index,
......@@ -1656,6 +1659,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<NativeContext> native_context);
TNode<BoolT> IsJSFunctionWithPrototypeSlot(TNode<HeapObject> object);
TNode<Uint32T> LoadFunctionKind(TNode<JSFunction> function);
TNode<BoolT> IsGeneratorFunction(TNode<JSFunction> function);
void BranchIfHasPrototypeProperty(TNode<JSFunction> function,
TNode<Int32T> function_map_bit_field,
......
......@@ -3235,6 +3235,11 @@ void BytecodeGraphBuilder::VisitGetSuperConstructor() {
Environment::kAttachFrameState);
}
void BytecodeGraphBuilder::VisitFindNonDefaultConstructor() {
// TODO(v8:13091): Implement.
CHECK(false);
}
void BytecodeGraphBuilder::BuildCompareOp(const Operator* op) {
DCHECK(JSOperator::IsBinaryWithFeedback(op->opcode()));
PrepareEagerCheckpoint();
......
......@@ -628,6 +628,7 @@ DEFINE_BOOL(stress_lazy_source_positions, false,
"collect lazy source positions immediately after lazy compile")
DEFINE_STRING(print_bytecode_filter, "*",
"filter for selecting which functions to print bytecode")
DEFINE_BOOL(omit_default_ctors, false, "omit calling default ctors in bytecode")
#ifdef V8_TRACE_UNOPTIMIZED
DEFINE_BOOL(trace_unoptimized, false,
"trace the bytecodes executed by all unoptimized execution")
......
......@@ -526,6 +526,14 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::GetSuperConstructor(Register out) {
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::FindNonDefaultConstructor(
Register this_function, Register new_target, Register constructor,
Register instance) {
OutputFindNonDefaultConstructor(this_function, new_target, constructor,
instance);
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::CompareOperation(
Token::Value op, Register reg, int feedback_slot) {
switch (op) {
......
......@@ -386,6 +386,11 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final {
// throws a TypeError exception.
BytecodeArrayBuilder& GetSuperConstructor(Register out);
BytecodeArrayBuilder& FindNonDefaultConstructor(Register this_function,
Register new_target,
Register constructor,
Register instance);
// Deletes property from an object. This expects that accumulator contains
// the key to be deleted and the register contains a reference to the object.
BytecodeArrayBuilder& Delete(Register object, LanguageMode language_mode);
......
......@@ -5646,34 +5646,60 @@ void BytecodeGenerator::VisitCallSuper(Call* expr) {
// Prepare the constructor to the super call.
Register this_function = VisitForRegisterValue(super->this_function_var());
Register constructor = register_allocator()->NewRegister();
builder()
->LoadAccumulatorWithRegister(this_function)
.GetSuperConstructor(constructor);
Register instance = register_allocator()->NewRegister();
BytecodeLabel super_ctor_call_done;
bool omit_super_ctor = FLAG_omit_default_ctors &&
IsDerivedConstructor(info()->literal()->kind());
if (spread_position == Call::kHasNonFinalSpread) {
// First generate the array containing all arguments.
BuildCreateArrayLiteral(args, nullptr);
RegisterList construct_args = register_allocator()->NewRegisterList(3);
builder()->StoreAccumulatorInRegister(construct_args[1]);
VisitForRegisterValue(super->new_target_var(), construct_args[2]);
if (omit_super_ctor) {
BuildSuperCallOptimization(this_function, construct_args[2],
construct_args[0], instance,
&super_ctor_call_done);
} else {
builder()
->LoadAccumulatorWithRegister(this_function)
.GetSuperConstructor(construct_args[0]);
}
// Check if the constructor is in fact a constructor.
builder()->ThrowIfNotSuperConstructor(constructor);
builder()->ThrowIfNotSuperConstructor(construct_args[0]);
// Now pass that array to %reflect_construct.
RegisterList construct_args = register_allocator()->NewRegisterList(3);
builder()->StoreAccumulatorInRegister(construct_args[1]);
builder()->MoveRegister(constructor, construct_args[0]);
VisitForRegisterValue(super->new_target_var(), construct_args[2]);
builder()->CallJSRuntime(Context::REFLECT_CONSTRUCT_INDEX, construct_args);
} else {
RegisterList args_regs = register_allocator()->NewGrowableRegisterList();
VisitArguments(args, &args_regs);
// The new target is loaded into the new_target register from the
// {new.target} variable.
Register new_target = register_allocator()->NewRegister();
VisitForRegisterValue(super->new_target_var(), new_target);
// Use the same register for storing the 'constructor' or the 'instance',
// they won't both be needed at the same time. If we jump to super_ctor_call
// done, only 'instance' is used, and if we don't, only 'constructor' is
// used.
Register& constructor = instance;
if (omit_super_ctor) {
BuildSuperCallOptimization(this_function, new_target, constructor,
instance, &super_ctor_call_done);
} else {
builder()
->LoadAccumulatorWithRegister(this_function)
.GetSuperConstructor(constructor);
}
// Check if the constructor is in fact a constructor.
builder()->ThrowIfNotSuperConstructor(constructor);
// The new target is loaded into the accumulator from the
// {new.target} variable.
VisitForAccumulatorValue(super->new_target_var());
builder()->LoadAccumulatorWithRegister(new_target);
builder()->SetExpressionPosition(expr);
int feedback_slot_index = feedback_index(feedback_spec()->AddCallICSlot());
......@@ -5693,6 +5719,8 @@ void BytecodeGenerator::VisitCallSuper(Call* expr) {
builder()->Construct(constructor, args_regs, feedback_slot_index);
}
}
builder()->StoreAccumulatorInRegister(instance);
builder()->Bind(&super_ctor_call_done);
// Explicit calls to the super constructor using super() perform an
// implicit binding assignment to the 'this' variable.
......@@ -5701,12 +5729,10 @@ void BytecodeGenerator::VisitCallSuper(Call* expr) {
// 'this' isn't accessed in default constructors.
if (!IsDefaultConstructor(info()->literal()->kind())) {
Variable* var = closure_scope()->GetReceiverScope()->receiver();
builder()->LoadAccumulatorWithRegister(instance);
BuildVariableAssignment(var, Token::INIT, HoleCheckMode::kRequired);
}
Register instance = register_allocator()->NewRegister();
builder()->StoreAccumulatorInRegister(instance);
// The constructor scope always needs ScopeInfo, so we are certain that
// the first constructor scope found in the outer scope chain is the
// scope that we are looking for for this super() call.
......@@ -5746,6 +5772,15 @@ void BytecodeGenerator::VisitCallSuper(Call* expr) {
builder()->LoadAccumulatorWithRegister(instance);
}
void BytecodeGenerator::BuildSuperCallOptimization(
Register this_function, Register new_target, Register constructor,
Register instance, BytecodeLabel* super_ctor_call_done) {
DCHECK(FLAG_omit_default_ctors);
builder()->FindNonDefaultConstructor(this_function, new_target, constructor,
instance);
builder()->JumpIfTrue(ToBooleanMode::kAlreadyBoolean, super_ctor_call_done);
}
void BytecodeGenerator::VisitCallNew(CallNew* expr) {
RegisterList args = register_allocator()->NewGrowableRegisterList();
......
......@@ -406,6 +406,10 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
template <typename ExpressionFunc>
void BuildOptionalChain(ExpressionFunc expression_func);
void BuildSuperCallOptimization(Register this_function, Register new_target,
Register constructor, Register instance,
BytecodeLabel* super_ctor_call_done);
// Visitors for obtaining expression result in the accumulator, in a
// register, or just getting the effect. Some visitors return a TypeHint which
// specifies the type of the result of the visited expression.
......
......@@ -227,6 +227,9 @@ namespace interpreter {
\
/* GetSuperConstructor operator */ \
V(GetSuperConstructor, ImplicitRegisterUse::kReadAccumulator, \
OperandType::kRegOut) \
V(FindNonDefaultConstructor, ImplicitRegisterUse::kWriteAccumulator, \
OperandType::kReg, OperandType::kReg, OperandType::kRegOut, \
OperandType::kRegOut) \
\
/* Call operations */ \
......
......@@ -2781,6 +2781,100 @@ IGNITION_HANDLER(ThrowIfNotSuperConstructor, InterpreterAssembler) {
}
}
// FinNonDefaultConstructor <this_function> <new_target> <constructor>
// <instance>
//
// Walks the prototype chain from <this_function>'s super ctor until we see a
// non-default ctor. If the walk ends at a default base ctor, creates an
// instance and stores it in <instance> and stores true into the accumulator.
// Otherwise, stores the first non-default ctor into <constructor> and false
// into the accumulator.
IGNITION_HANDLER(FindNonDefaultConstructor, InterpreterAssembler) {
TNode<Context> context = GetContext();
TVARIABLE(Object, constructor);
Label loop(this, &constructor), found_default_base_ctor(this, &constructor),
found_something_else(this, &constructor);
TNode<JSFunction> this_function = CAST(LoadRegisterAtOperandIndex(0));
constructor = GetSuperConstructor(this_function);
// Disable the optimization if the debugger is active, so that we can still
// put breakpoints into default constructors.
GotoIf(IsDebugActive(), &found_something_else);
// Disable the optimization if the array iterator has been changed. V8 uses
// the array iterator for the spread in default ctors, even though it
// shouldn't, according to the spec. This ensures that omitting default ctors
// doesn't change the behavior. See crbug.com/v8/13249.
GotoIf(IsArrayIteratorProtectorCellInvalid(), &found_something_else);
TNode<Object> new_target = LoadRegisterAtOperandIndex(1);
Goto(&loop);
BIND(&loop);
{
// We know constructor can't be a SMI, since it's a prototype. If it's not a
// JSFunction, the error will be thrown by the ThrowIfNotSuperConstructor
// which follows this bytecode.
GotoIfNot(IsJSFunction(CAST(constructor.value())), &found_something_else);
// If there are class fields, bail out. TODO(v8:13091): Handle them here.
TNode<Oddball> has_class_fields =
HasProperty(context, constructor.value(), ClassFieldsSymbolConstant(),
kHasProperty);
GotoIf(IsTrue(has_class_fields), &found_something_else);
// If there are private methods, bail out. TODO(v8:13091): Handle them here.
TNode<Context> function_context =
LoadJSFunctionContext(CAST(constructor.value()));
TNode<ScopeInfo> scope_info = LoadScopeInfo(function_context);
GotoIf(LoadScopeInfoClassScopeHasPrivateBrand(scope_info),
&found_something_else);
const TNode<Uint32T> function_kind =
LoadFunctionKind(CAST(constructor.value()));
// A default base ctor -> stop the search.
GotoIf(Word32Equal(
function_kind,
static_cast<uint32_t>(FunctionKind::kDefaultBaseConstructor)),
&found_default_base_ctor);
// Something else than a default derived ctor (e.g., a non-default base
// ctor, a non-default derived ctor, or a normal function) -> stop the
// search.
GotoIfNot(Word32Equal(function_kind,
static_cast<uint32_t>(
FunctionKind::kDefaultDerivedConstructor)),
&found_something_else);
constructor = GetSuperConstructor(CAST(constructor.value()));
Goto(&loop);
}
// We don't need to re-check the proctector, since the loop cannot call into
// user code. Even if GetSuperConstructor returns a Proxy, we will throw since
// it's not a constructor, and not invoke [[GetPrototypeOf]] on it.
// TODO(v8:13091): make sure this is still valid after we handle class fields.
BIND(&found_default_base_ctor);
{
// Create an object directly, without calling the default base ctor.
TNode<Object> instance = CallBuiltin(Builtin::kFastNewObject, context,
constructor.value(), new_target);
StoreRegisterAtOperandIndex(instance, 3);
SetAccumulator(TrueConstant());
Dispatch();
}
BIND(&found_something_else);
{
// Not a base ctor (or bailed out).
StoreRegisterAtOperandIndex(constructor.value(), 2);
SetAccumulator(FalseConstant());
Dispatch();
}
}
// Debugger
//
// Call runtime to handle debugger statement.
......
......@@ -1577,6 +1577,11 @@ void MaglevGraphBuilder::VisitGetSuperConstructor() {
StoreRegister(iterator_.GetRegisterOperand(0), map_proto);
}
void MaglevGraphBuilder::VisitFindNonDefaultConstructor() {
// TODO(v8:13091): Implement.
CHECK(false);
}
void MaglevGraphBuilder::InlineCallFromRegisters(
int argc_count, ConvertReceiverMode receiver_mode,
compiler::JSFunctionRef function) {
......
// Copyright 2022 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: --omit-default-ctors --no-sparkplug
// TODO(v8:13091): Enable sparkplug.
// This behavior is not spec compliant, see crbug.com/v8/13249.
(function ArrayIteratorMonkeyPatched() {
let iterationCount = 0;
const oldIterator = Array.prototype[Symbol.iterator];
Array.prototype[Symbol.iterator] =
function () { ++iterationCount; return oldIterator.call(this); };
class A {}
class B extends A {}
class C extends B {}
assertEquals(0, iterationCount);
new C();
// C default ctor doing "...args" and B default ctor doing "...args".
assertEquals(2, iterationCount);
Array.prototype[Symbol.iterator] = oldIterator;
})();
This diff is collapsed.
......@@ -488,6 +488,9 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
// Type Information for DevTools is turned on.
scorecard[Bytecodes::ToByte(Bytecode::kCollectTypeProfile)] = 1;
// This bytecode is too inconvenient to test manually.
scorecard[Bytecodes::ToByte(Bytecode::kFindNonDefaultConstructor)] = 1;
// Check return occurs at the end and only once in the BytecodeArray.
CHECK_EQ(final_bytecode, Bytecode::kReturn);
CHECK_EQ(scorecard[Bytecodes::ToByte(final_bytecode)], 1);
......
......@@ -87,22 +87,22 @@ snippet: "
test = new B().constructor;
})();
"
frame size: 6
frame size: 5
parameter count: 1
bytecode array length: 39
bytecodes: [
B(Mov), R(closure), R(1),
/* 118 S> */ B(Ldar), R(1),
B(GetSuperConstructor), R(3),
B(LdaSmi), I8(1),
B(ThrowIfNotSuperConstructor), R(3),
/* 118 S> */ B(LdaSmi), I8(1),
B(Star4),
B(Ldar), R(1),
/* 118 E> */ B(GetSuperConstructor), R(3),
B(ThrowIfNotSuperConstructor), R(3),
B(Ldar), R(0),
/* 118 E> */ B(Construct), R(3), R(4), U8(1), U8(0),
B(Star5),
B(Star3),
B(Ldar), R(this),
B(ThrowSuperAlreadyCalledIfNotHole),
B(Mov), R(5), R(this),
B(Mov), R(3), R(this),
/* 128 S> */ B(Ldar), R(this),
B(ThrowSuperNotCalledIfHole),
B(LdaSmi), I8(2),
......@@ -130,20 +130,20 @@ snippet: "
test = new B().constructor;
})();
"
frame size: 5
frame size: 4
parameter count: 1
bytecode array length: 36
bytecodes: [
B(Mov), R(closure), R(1),
/* 117 S> */ B(Ldar), R(1),
B(GetSuperConstructor), R(3),
/* 117 E> */ B(GetSuperConstructor), R(3),
B(ThrowIfNotSuperConstructor), R(3),
B(Ldar), R(0),
/* 117 E> */ B(Construct), R(3), R(0), U8(0), U8(0),
B(Star4),
B(Star3),
B(Ldar), R(this),
B(ThrowSuperAlreadyCalledIfNotHole),
B(Mov), R(4), R(this),
B(Mov), R(3), R(this),
/* 126 S> */ B(Ldar), R(this),
B(ThrowSuperNotCalledIfHole),
B(LdaSmi), I8(2),
......
......@@ -159,32 +159,35 @@ snippet: "
"
frame size: 9
parameter count: 1
bytecode array length: 58
bytecode array length: 63
bytecodes: [
/* 89 S> */ B(LdaImmutableCurrentContextSlot), U8(4),
B(GetSuperConstructor), R(1),
B(ThrowIfNotSuperConstructor), R(1),
B(Star0),
B(LdaImmutableCurrentContextSlot), U8(3),
/* 89 E> */ B(Construct), R(1), R(0), U8(0), U8(0),
B(Star2),
B(Ldar), R(0),
/* 89 E> */ B(GetSuperConstructor), R(1),
B(ThrowIfNotSuperConstructor), R(1),
B(Ldar), R(2),
/* 89 E> */ B(Construct), R(1), R(0), U8(0), U8(0),
B(Star1),
B(LdaCurrentContextSlot), U8(2),
B(ThrowSuperAlreadyCalledIfNotHole),
B(Ldar), R(2),
B(Ldar), R(1),
B(StaCurrentContextSlot), U8(2),
B(LdaImmutableContextSlot), R(context), U8(3), U8(1),
B(Star4),
B(LdaSmi), I8(1),
B(Star6),
B(Mov), R(2), R(3),
B(Mov), R(1), R(3),
B(Mov), R(context), R(5),
B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(3), U8(4),
B(GetNamedProperty), R(0), U8(0), U8(2),
B(JumpIfUndefined), U8(10),
B(Star8),
B(CallProperty0), R(8), R(2), U8(4),
B(Mov), R(2), R(7),
B(Ldar), R(2),
B(CallProperty0), R(8), R(1), U8(4),
B(Mov), R(1), R(7),
B(Ldar), R(1),
/* 96 S> */ B(Return),
]
constant pool: [
......@@ -208,32 +211,35 @@ snippet: "
"
frame size: 9
parameter count: 1
bytecode array length: 58
bytecode array length: 63
bytecodes: [
/* 88 S> */ B(LdaImmutableCurrentContextSlot), U8(4),
B(GetSuperConstructor), R(1),
B(ThrowIfNotSuperConstructor), R(1),
B(Star0),
B(LdaImmutableCurrentContextSlot), U8(3),
/* 88 E> */ B(Construct), R(1), R(0), U8(0), U8(0),
B(Star2),
B(Ldar), R(0),
/* 88 E> */ B(GetSuperConstructor), R(1),
B(ThrowIfNotSuperConstructor), R(1),
B(Ldar), R(2),
/* 88 E> */ B(Construct), R(1), R(0), U8(0), U8(0),
B(Star1),
B(LdaCurrentContextSlot), U8(2),
B(ThrowSuperAlreadyCalledIfNotHole),
B(Ldar), R(2),
B(Ldar), R(1),
B(StaCurrentContextSlot), U8(2),
B(LdaImmutableContextSlot), R(context), U8(3), U8(1),
B(Star4),
B(LdaSmi), I8(1),
B(Star6),
B(Mov), R(2), R(3),
B(Mov), R(1), R(3),
B(Mov), R(context), R(5),
B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(3), U8(4),
B(GetNamedProperty), R(0), U8(0), U8(2),
B(JumpIfUndefined), U8(10),
B(Star8),
B(CallProperty0), R(8), R(2), U8(4),
B(Mov), R(2), R(7),
B(Ldar), R(2),
B(CallProperty0), R(8), R(1), U8(4),
B(Mov), R(1), R(7),
B(Ldar), R(1),
/* 95 S> */ B(Return),
]
constant pool: [
......@@ -256,32 +262,35 @@ snippet: "
"
frame size: 9
parameter count: 1
bytecode array length: 58
bytecode array length: 63
bytecodes: [
/* 88 S> */ B(LdaImmutableCurrentContextSlot), U8(4),
B(GetSuperConstructor), R(1),
B(ThrowIfNotSuperConstructor), R(1),
B(Star0),
B(LdaImmutableCurrentContextSlot), U8(3),
/* 88 E> */ B(Construct), R(1), R(0), U8(0), U8(0),
B(Star2),
B(Ldar), R(0),
/* 88 E> */ B(GetSuperConstructor), R(1),
B(ThrowIfNotSuperConstructor), R(1),
B(Ldar), R(2),
/* 88 E> */ B(Construct), R(1), R(0), U8(0), U8(0),
B(Star1),
B(LdaCurrentContextSlot), U8(2),
B(ThrowSuperAlreadyCalledIfNotHole),
B(Ldar), R(2),
B(Ldar), R(1),
B(StaCurrentContextSlot), U8(2),
B(LdaImmutableContextSlot), R(context), U8(3), U8(1),
B(Star4),
B(LdaSmi), I8(1),
B(Star6),
B(Mov), R(2), R(3),
B(Mov), R(1), R(3),
B(Mov), R(context), R(5),
B(CallRuntime), U16(Runtime::kAddPrivateBrand), R(3), U8(4),
B(GetNamedProperty), R(0), U8(0), U8(2),
B(JumpIfUndefined), U8(10),
B(Star8),
B(CallProperty0), R(8), R(2), U8(4),
B(Mov), R(2), R(7),
B(Ldar), R(2),
B(CallProperty0), R(8), R(1), U8(4),
B(Mov), R(1), R(7),
B(Ldar), R(1),
/* 95 S> */ B(Return),
]
constant pool: [
......
......@@ -25,7 +25,7 @@ bytecodes: [
B(Star2),
B(Mov), R(closure), R(1),
/* 93 S> */ B(Ldar), R(1),
B(GetSuperConstructor), R(4),
/* 93 E> */ B(GetSuperConstructor), R(4),
B(ThrowIfNotSuperConstructor), R(4),
B(Ldar), R(0),
/* 93 E> */ B(ConstructWithSpread), R(4), R(2), U8(1), U8(0),
......@@ -49,7 +49,7 @@ snippet: "
test = new B(1, 2, 3).constructor;
})();
"
frame size: 9
frame size: 8
parameter count: 1
bytecode array length: 38
bytecodes: [
......@@ -57,18 +57,18 @@ bytecodes: [
B(Star3),
B(Mov), R(closure), R(1),
B(Mov), R(3), R(2),
/* 140 S> */ B(Ldar), R(closure),
B(GetSuperConstructor), R(5),
B(LdaSmi), I8(1),
/* 140 S> */ B(LdaSmi), I8(1),
B(Star6),
/* 152 E> */ B(ThrowIfNotSuperConstructor), R(5),
B(Ldar), R(closure),
/* 140 E> */ B(GetSuperConstructor), R(5),
B(ThrowIfNotSuperConstructor), R(5),
B(Ldar), R(0),
B(Mov), R(3), R(7),
/* 140 E> */ B(ConstructWithSpread), R(5), R(6), U8(2), U8(0),
B(Star8),
B(Star5),
B(Ldar), R(this),
B(ThrowSuperAlreadyCalledIfNotHole),
B(Mov), R(8), R(this),
B(Mov), R(5), R(this),
B(Ldar), R(this),
B(ThrowSuperNotCalledIfHole),
/* 159 S> */ B(Return),
......@@ -93,15 +93,13 @@ snippet: "
"
frame size: 11
parameter count: 1
bytecode array length: 97
bytecode array length: 94
bytecodes: [
/* 128 E> */ B(CreateRestParameter),
B(Star3),
B(Mov), R(closure), R(1),
B(Mov), R(3), R(2),
/* 140 S> */ B(Ldar), R(closure),
B(GetSuperConstructor), R(5),
B(CreateArrayLiteral), U8(0), U8(0), U8(37),
/* 140 S> */ B(CreateArrayLiteral), U8(0), U8(0), U8(37),
B(Star7),
B(LdaSmi), I8(1),
/* 152 S> */ B(Star6),
......@@ -124,14 +122,15 @@ bytecodes: [
B(JumpLoop), U8(31), I8(0), U8(18),
B(LdaSmi), I8(1),
B(StaInArrayLiteral), R(7), R(6), U8(12),
B(ThrowIfNotSuperConstructor), R(5),
B(Mov), R(5), R(6),
B(Ldar), R(4),
/* 140 E> */ B(GetSuperConstructor), R(6),
B(ThrowIfNotSuperConstructor), R(6),
B(Mov), R(0), R(8),
/* 140 E> */ B(CallJSRuntime), U8(%reflect_construct), R(6), U8(3),
B(Star9),
B(CallJSRuntime), U8(%reflect_construct), R(6), U8(3),
B(Star5),
B(Ldar), R(this),
B(ThrowSuperAlreadyCalledIfNotHole),
B(Mov), R(9), R(this),
B(Mov), R(5), R(this),
B(Ldar), R(this),
B(ThrowSuperNotCalledIfHole),
/* 162 S> */ B(Return),
......
......@@ -77,10 +77,10 @@ INCOMPATIBLE_FLAGS_PER_VARIANT = {
"--liftoff-only", "--wasm-speculative-inlining",
"--wasm-dynamic-tiering"
],
"sparkplug": ["--jitless"],
"sparkplug": ["--jitless", "--no-sparkplug"],
"concurrent_sparkplug": ["--jitless"],
"maglev": ["--jitless"],
"always_sparkplug": ["--jitless"],
"always_sparkplug": ["--jitless", "--no-sparkplug"],
"code_serializer": [
"--cache=after-execute", "--cache=full-code-cache", "--cache=none"
],
......
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