diff options
author | Michaël Zasso <targos@protonmail.com> | 2022-09-21 13:28:42 +0200 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2022-10-11 07:24:33 +0200 |
commit | 6bd756d7c6dfb7dc25daee329ad70df68c14223e (patch) | |
tree | af93818c545f5bd04cafd4a0c19817e19a475641 /deps/v8/src/interpreter/bytecode-generator.cc | |
parent | 624dadb00706a9fc08f919ac72941cdaba7e3ec9 (diff) | |
download | node-new-6bd756d7c6dfb7dc25daee329ad70df68c14223e.tar.gz |
deps: update V8 to 10.7.193.13
PR-URL: https://github.com/nodejs/node/pull/44741
Fixes: https://github.com/nodejs/node/issues/44650
Fixes: https://github.com/nodejs/node/issues/37472
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Jiawen Geng <technicalcute@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Diffstat (limited to 'deps/v8/src/interpreter/bytecode-generator.cc')
-rw-r--r-- | deps/v8/src/interpreter/bytecode-generator.cc | 248 |
1 files changed, 176 insertions, 72 deletions
diff --git a/deps/v8/src/interpreter/bytecode-generator.cc b/deps/v8/src/interpreter/bytecode-generator.cc index 4a0299df55..c027fb8b07 100644 --- a/deps/v8/src/interpreter/bytecode-generator.cc +++ b/deps/v8/src/interpreter/bytecode-generator.cc @@ -23,16 +23,15 @@ #include "src/interpreter/bytecode-jump-table.h" #include "src/interpreter/bytecode-label.h" #include "src/interpreter/bytecode-register-allocator.h" +#include "src/interpreter/bytecode-register-optimizer.h" #include "src/interpreter/bytecode-register.h" #include "src/interpreter/control-flow-builders.h" #include "src/logging/local-logger.h" #include "src/logging/log.h" #include "src/numbers/conversions.h" #include "src/objects/debug-objects.h" -#include "src/objects/literal-objects-inl.h" -#include "src/objects/objects-inl.h" #include "src/objects/smi.h" -#include "src/objects/template-objects-inl.h" +#include "src/objects/template-objects.h" #include "src/parsing/parse-info.h" #include "src/parsing/token.h" #include "src/utils/ostreams.h" @@ -200,7 +199,7 @@ class V8_NODISCARD BytecodeGenerator::ControlScope::DeferredCommands final { // There's always a rethrow path. // TODO(leszeks): We could decouple deferred_ index and token to allow us // to still push this lazily. - STATIC_ASSERT(kRethrowToken == 0); + static_assert(kRethrowToken == 0); deferred_.push_back({CMD_RETHROW, nullptr, kRethrowToken}); } @@ -2016,6 +2015,8 @@ void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { VisitForAccumulatorValue(stmt->tag()); if (use_jump_table) { + // Release temps so that they can be reused in clauses. + RegisterAllocationScope allocation_scope(this); // This also fills empty slots in jump table. Register r2 = register_allocator()->NewRegister(); @@ -2095,6 +2096,7 @@ void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { case_compare_ctr++); } } + register_allocator()->ReleaseRegister(tag_holder); } // For fall-throughs after comparisons (or out-of-range/non-Smi's for jump @@ -2246,7 +2248,8 @@ void BytecodeGenerator::VisitIterationBody(IterationStatement* stmt, } void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { - LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt); + LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt, + feedback_spec()); if (stmt->cond()->ToBooleanIsFalse()) { // Since we know that the condition is false, we don't create a loop. // Therefore, we don't create a LoopScope (and thus we don't create a header @@ -2268,7 +2271,8 @@ void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { } void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) { - LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt); + LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt, + feedback_spec()); if (stmt->cond()->ToBooleanIsFalse()) { // If the condition is false there is no need to generate the loop. @@ -2291,7 +2295,8 @@ void BytecodeGenerator::VisitForStatement(ForStatement* stmt) { Visit(stmt->init()); } - LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt); + LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt, + feedback_spec()); if (stmt->cond() && stmt->cond()->ToBooleanIsFalse()) { // If the condition is known to be false there is no need to generate // body, next or condition blocks. Init block should be generated. @@ -2343,7 +2348,8 @@ void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) { // The loop { - LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt); + LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt, + feedback_spec()); LoopScope loop_scope(this, &loop_builder); builder()->SetExpressionAsStatementPosition(stmt->each()); builder()->ForInContinue(index, cache_length); @@ -2414,39 +2420,43 @@ void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) { BuildTryFinally( // Try block. [&]() { - Register next_result = register_allocator()->NewRegister(); - - LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt); + LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt, + feedback_spec()); LoopScope loop_scope(this, &loop_builder); builder()->LoadTrue().StoreAccumulatorInRegister(done); - // Call the iterator's .next() method. Break from the loop if the `done` - // property is truthy, otherwise load the value from the iterator result - // and append the argument. - builder()->SetExpressionAsStatementPosition(stmt->each()); - BuildIteratorNext(iterator, next_result); - builder()->LoadNamedProperty( - next_result, ast_string_constants()->done_string(), - feedback_index(feedback_spec()->AddLoadICSlot())); - loop_builder.BreakIfTrue(ToBooleanMode::kConvertToBoolean); + { + RegisterAllocationScope allocation_scope(this); + Register next_result = register_allocator()->NewRegister(); - builder() - // value = value.value - ->LoadNamedProperty( - next_result, ast_string_constants()->value_string(), - feedback_index(feedback_spec()->AddLoadICSlot())); - // done = false, before the assignment to each happens, so that done is - // false if the assignment throws. - builder() - ->StoreAccumulatorInRegister(next_result) - .LoadFalse() - .StoreAccumulatorInRegister(done); + // Call the iterator's .next() method. Break from the loop if the + // `done` property is truthy, otherwise load the value from the + // iterator result and append the argument. + builder()->SetExpressionAsStatementPosition(stmt->each()); + BuildIteratorNext(iterator, next_result); + builder()->LoadNamedProperty( + next_result, ast_string_constants()->done_string(), + feedback_index(feedback_spec()->AddLoadICSlot())); + loop_builder.BreakIfTrue(ToBooleanMode::kConvertToBoolean); - // Assign to the 'each' target. - AssignmentLhsData lhs_data = PrepareAssignmentLhs(stmt->each()); - builder()->LoadAccumulatorWithRegister(next_result); - BuildAssignment(lhs_data, Token::ASSIGN, LookupHoistingMode::kNormal); + builder() + // value = value.value + ->LoadNamedProperty( + next_result, ast_string_constants()->value_string(), + feedback_index(feedback_spec()->AddLoadICSlot())); + // done = false, before the assignment to each happens, so that done + // is false if the assignment throws. + builder() + ->StoreAccumulatorInRegister(next_result) + .LoadFalse() + .StoreAccumulatorInRegister(done); + + // Assign to the 'each' target. + AssignmentLhsData lhs_data = PrepareAssignmentLhs(stmt->each()); + builder()->LoadAccumulatorWithRegister(next_result); + BuildAssignment(lhs_data, Token::ASSIGN, LookupHoistingMode::kNormal); + } VisitIterationBody(stmt, &loop_builder); }, @@ -2515,7 +2525,7 @@ void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { DCHECK_EQ(expr->scope()->outer_scope(), current_scope()); uint8_t flags = CreateClosureFlags::Encode( expr->pretenure(), closure_scope()->is_function_scope(), - info()->flags().might_always_opt()); + info()->flags().might_always_turbofan()); size_t entry = builder()->AllocateDeferredConstantPoolEntry(); builder()->CreateClosure(entry, GetCachedCreateClosureSlot(expr), flags); function_literals_.push_back(std::make_pair(expr, entry)); @@ -2578,6 +2588,8 @@ void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr, Register name) { ->LoadLiteral(class_name) .StoreAccumulatorInRegister(brand) .CallRuntime(Runtime::kCreatePrivateBrandSymbol, brand); + register_allocator()->ReleaseRegister(brand); + BuildVariableAssignment(expr->scope()->brand(), Token::INIT, HoleCheckMode::kElided); } @@ -2700,8 +2712,6 @@ void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr, Register name) { builder()->CallRuntime(Runtime::kDefineClass, args); } - Register prototype = register_allocator()->NewRegister(); - builder()->StoreAccumulatorInRegister(prototype); // Assign to the home object variable. Accumulator already contains the // prototype. @@ -2802,11 +2812,19 @@ void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr, Register name) { // Make sure to associate the source position for the class // after the block context is created. Otherwise we have a mismatch // between the scope and the context, where we already are in a - // block context for the class, but not yet in the class scope. - BytecodeSourceInfo source_info = builder()->PopSourcePosition(); + // block context for the class, but not yet in the class scope. Only do + // this if the current source position is inside the class scope though. + // For example: + // * `var x = class {};` will break on `class` which is inside + // the class scope, so we expect the BlockContext to be pushed. + // + // * `new class x {};` will break on `new` which is outside the + // class scope, so we expect the BlockContext to not be pushed yet. + base::Optional<BytecodeSourceInfo> source_info = + builder()->MaybePopSourcePosition(expr->scope()->start_position()); BuildNewLocalBlockContext(expr->scope()); ContextScope scope(this, expr->scope()); - builder()->PushSourcePosition(source_info); + if (source_info) builder()->PushSourcePosition(*source_info); BuildClassLiteral(expr, name); } else { BuildClassLiteral(expr, name); @@ -3322,7 +3340,7 @@ void BytecodeGenerator::BuildFillArrayWithIterator( DCHECK(index.is_valid()); DCHECK(value.is_valid()); - LoopBuilder loop_builder(builder(), nullptr, nullptr); + LoopBuilder loop_builder(builder(), nullptr, nullptr, feedback_spec()); LoopScope loop_scope(this, &loop_builder); // Call the iterator's .next() method. Break from the loop if the `done` @@ -3351,8 +3369,10 @@ void BytecodeGenerator::BuildFillArrayWithIterator( void BytecodeGenerator::BuildCreateArrayLiteral( const ZonePtrList<Expression>* elements, ArrayLiteral* expr) { RegisterAllocationScope register_scope(this); - Register index = register_allocator()->NewRegister(); + // Make this the first register allocated so that it has a chance of aliasing + // the next register allocated after returning from this function. Register array = register_allocator()->NewRegister(); + Register index = register_allocator()->NewRegister(); SharedFeedbackSlot element_slot(feedback_spec(), FeedbackSlotKind::kStoreInArrayLiteral); ZonePtrList<Expression>::const_iterator current = elements->begin(); @@ -3517,6 +3537,21 @@ void BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) { BuildVariableLoad(proxy->var(), proxy->hole_check_mode()); } +bool BytecodeGenerator::IsVariableInRegister(Variable* var, Register reg) { + BytecodeRegisterOptimizer* optimizer = builder()->GetRegisterOptimizer(); + if (optimizer) { + return optimizer->IsVariableInRegister(var, reg); + } + return false; +} + +void BytecodeGenerator::SetVariableInRegister(Variable* var, Register reg) { + BytecodeRegisterOptimizer* optimizer = builder()->GetRegisterOptimizer(); + if (optimizer) { + optimizer->SetVariableInRegister(var, reg); + } +} + void BytecodeGenerator::BuildVariableLoad(Variable* variable, HoleCheckMode hole_check_mode, TypeofMode typeof_mode) { @@ -3576,12 +3611,20 @@ void BytecodeGenerator::BuildVariableLoad(Variable* variable, (variable->maybe_assigned() == kNotAssigned) ? BytecodeArrayBuilder::kImmutableSlot : BytecodeArrayBuilder::kMutableSlot; + Register acc = Register::virtual_accumulator(); + if (immutable == BytecodeArrayBuilder::kImmutableSlot && + IsVariableInRegister(variable, acc)) { + return; + } builder()->LoadContextSlot(context_reg, variable->index(), depth, immutable); if (hole_check_mode == HoleCheckMode::kRequired) { BuildThrowIfHole(variable); } + if (immutable == BytecodeArrayBuilder::kImmutableSlot) { + SetVariableInRegister(variable, acc); + } break; } case VariableLocation::LOOKUP: { @@ -4719,7 +4762,7 @@ void BytecodeGenerator::VisitYield(Yield* expr) { Runtime::kInlineGeneratorGetResumeMode, generator_object()); // Now dispatch on resume mode. - STATIC_ASSERT(JSGeneratorObject::kNext + 1 == JSGeneratorObject::kReturn); + static_assert(JSGeneratorObject::kNext + 1 == JSGeneratorObject::kReturn); BytecodeJumpTable* jump_table = builder()->AllocateJumpTable(2, JSGeneratorObject::kNext); @@ -4853,7 +4896,7 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) { // - One for awaiting the iterator result yielded by the delegated // iterator - LoopBuilder loop_builder(builder(), nullptr, nullptr); + LoopBuilder loop_builder(builder(), nullptr, nullptr, feedback_spec()); LoopScope loop_scope(this, &loop_builder); { @@ -4868,7 +4911,7 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) { // Fallthrough to default case. // TODO(ignition): Add debug code to check that {resume_mode} really is // {JSGeneratorObject::kNext} in this case. - STATIC_ASSERT(JSGeneratorObject::kNext == 0); + static_assert(JSGeneratorObject::kNext == 0); { FeedbackSlot slot = feedback_spec()->AddCallICSlot(); builder()->CallProperty(iterator.next(), iterator_and_input, @@ -4876,7 +4919,7 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) { builder()->Jump(after_switch.New()); } - STATIC_ASSERT(JSGeneratorObject::kReturn == 1); + static_assert(JSGeneratorObject::kReturn == 1); builder()->Bind(switch_jump_table, JSGeneratorObject::kReturn); { const AstRawString* return_string = @@ -4897,7 +4940,7 @@ void BytecodeGenerator::VisitYieldStar(YieldStar* expr) { } } - STATIC_ASSERT(JSGeneratorObject::kThrow == 2); + static_assert(JSGeneratorObject::kThrow == 2); builder()->Bind(switch_jump_table, JSGeneratorObject::kThrow); { const AstRawString* throw_string = @@ -5605,34 +5648,70 @@ 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); + // This register will initially hold the constructor, then afterward it will + // hold the instance -- the lifetimes of the two don't need to overlap, and + // this way FindNonDefaultConstructor can choose to write either the instance + // or the constructor into the same register. + Register constructor_then_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. + RegisterAllocationScope register_scope(this); + RegisterList construct_args(constructor_then_instance); + const Register& constructor = constructor_then_instance; + + // Generate the array containing all arguments. BuildCreateArrayLiteral(args, nullptr); + Register args_array = + register_allocator()->GrowRegisterList(&construct_args); + builder()->StoreAccumulatorInRegister(args_array); + + Register new_target = + register_allocator()->GrowRegisterList(&construct_args); + VisitForRegisterValue(super->new_target_var(), new_target); + + if (omit_super_ctor) { + BuildSuperCallOptimization(this_function, new_target, + constructor_then_instance, + &super_ctor_call_done); + } else { + builder() + ->LoadAccumulatorWithRegister(this_function) + .GetSuperConstructor(constructor); + } // Check if the constructor is in fact a constructor. builder()->ThrowIfNotSuperConstructor(constructor); // 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 { + RegisterAllocationScope register_scope(this); 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); + + const Register& constructor = constructor_then_instance; + if (omit_super_ctor) { + BuildSuperCallOptimization(this_function, new_target, + constructor_then_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()); @@ -5653,6 +5732,11 @@ void BytecodeGenerator::VisitCallSuper(Call* expr) { } } + // From here onwards, constructor_then_instance will hold the instance. + const Register& instance = constructor_then_instance; + 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. // @@ -5660,12 +5744,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. @@ -5705,6 +5787,17 @@ void BytecodeGenerator::VisitCallSuper(Call* expr) { builder()->LoadAccumulatorWithRegister(instance); } +void BytecodeGenerator::BuildSuperCallOptimization( + Register this_function, Register new_target, + Register constructor_then_instance, BytecodeLabel* super_ctor_call_done) { + DCHECK(FLAG_omit_default_ctors); + RegisterList output = register_allocator()->NewRegisterList(2); + builder()->FindNonDefaultConstructor(this_function, new_target, output); + builder()->MoveRegister(output[1], constructor_then_instance); + builder()->LoadAccumulatorWithRegister(output[0]).JumpIfTrue( + ToBooleanMode::kAlreadyBoolean, super_ctor_call_done); +} + void BytecodeGenerator::VisitCallNew(CallNew* expr) { RegisterList args = register_allocator()->NewGrowableRegisterList(); @@ -6157,6 +6250,14 @@ void BytecodeGenerator::BuildLiteralCompareNil( } } +void BytecodeGenerator::BuildLiteralStrictCompareBoolean(Literal* literal) { + DCHECK(literal->IsBooleanLiteral()); + Register result = register_allocator()->NewRegister(); + builder()->StoreAccumulatorInRegister(result); + builder()->LoadBoolean(literal->AsBooleanLiteral()); + builder()->CompareReference(result); +} + void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) { Expression* sub_expr; Literal* literal; @@ -6172,6 +6273,11 @@ void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) { } else { builder()->CompareTypeOf(literal_flag); } + } else if (expr->IsLiteralStrictCompareBoolean(&sub_expr, &literal)) { + DCHECK(expr->op() == Token::EQ_STRICT); + VisitForAccumulatorValue(sub_expr); + builder()->SetExpressionPosition(expr); + BuildLiteralStrictCompareBoolean(literal); } else if (expr->IsLiteralCompareUndefined(&sub_expr)) { VisitForAccumulatorValue(sub_expr); builder()->SetExpressionPosition(expr); @@ -6182,7 +6288,6 @@ void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) { BuildLiteralCompareNil(expr->op(), BytecodeArrayBuilder::kNullValue); } else { if (expr->op() == Token::IN && expr->left()->IsPrivateName()) { - DCHECK(FLAG_harmony_private_brand_checks); Variable* var = expr->left()->AsVariableProxy()->var(); if (IsPrivateMethodOrAccessorVariableMode(var->mode())) { BuildPrivateMethodIn(var, expr->right()); @@ -6337,16 +6442,11 @@ void BytecodeGenerator::BuildGetIterator(IteratorType hint) { feedback_index(feedback_spec()->AddCallICSlot()); // Let method be GetMethod(obj, @@iterator) and - // iterator be Call(method, obj). + // iterator be Call(method, obj). If iterator is + // not JSReceiver, then throw TypeError. builder()->StoreAccumulatorInRegister(obj).GetIterator( obj, load_feedback_index, call_feedback_index); } - - // If Type(iterator) is not Object, throw a TypeError exception. - BytecodeLabel no_type_error; - builder()->JumpIfJSReceiver(&no_type_error); - builder()->CallRuntime(Runtime::kThrowSymbolIteratorInvalid); - builder()->Bind(&no_type_error); } } @@ -6852,6 +6952,7 @@ void BytecodeGenerator::BuildNewLocalActivationContext() { Register arg = register_allocator()->NewRegister(); builder()->LoadLiteral(scope).StoreAccumulatorInRegister(arg).CallRuntime( Runtime::kNewFunctionContext, arg); + register_allocator()->ReleaseRegister(arg); } } @@ -6895,6 +6996,8 @@ void BytecodeGenerator::BuildNewLocalWithContext(Scope* scope) { builder()->ToObject(extension_object); builder()->CreateWithContext(extension_object, scope); + + register_allocator()->ReleaseRegister(extension_object); } void BytecodeGenerator::BuildNewLocalCatchContext(Scope* scope) { @@ -6904,6 +7007,7 @@ void BytecodeGenerator::BuildNewLocalCatchContext(Scope* scope) { Register exception = register_allocator()->NewRegister(); builder()->StoreAccumulatorInRegister(exception); builder()->CreateCatchContext(exception, scope); + register_allocator()->ReleaseRegister(exception); } void BytecodeGenerator::VisitLiteralAccessor(LiteralProperty* property, |