From 27fe988b85e9b0b77eb5c376d4bdd1350dfc3e17 Mon Sep 17 00:00:00 2001 From: rmcilroy Date: Fri, 30 Sep 2016 02:02:59 -0700 Subject: [PATCH] [Interpreter] Replace BytecodeRegisterAllocator with a simple bump pointer. There are only a few occasions where we allocate a register in an outer expression allocation scope, which makes the costly free-list approach of the BytecodeRegisterAllocator unecessary. This CL replaces all occurrences with moves to the accumulator and stores to a register allocated in the correct scope. By doing this, we can simplify the BytecodeRegisterAllocator to be a simple bump-pointer allocator with registers released in the same order as allocated. The following changes are also made: - Make BytecodeRegisterOptimizer able to use registers which have been unallocated, but not yet reused - Remove RegisterExpressionResultScope and rename AccumulatorExpressionResultScope to ValueExpressionResultScope - Introduce RegisterList to represent consecutive register allocations, and use this for operands to call bytecodes. By avoiding the free-list handling, this gives another couple of percent on CodeLoad. BUG=v8:4280 Review-Url: https://codereview.chromium.org/2369873002 Cr-Commit-Position: refs/heads/master@{#39905} --- BUILD.gn | 1 - src/interpreter/bytecode-array-builder.cc | 88 +- src/interpreter/bytecode-array-builder.h | 122 +-- src/interpreter/bytecode-generator.cc | 926 ++++++------------ src/interpreter/bytecode-generator.h | 39 +- .../bytecode-register-allocator.cc | 210 ---- src/interpreter/bytecode-register-allocator.h | 152 +-- .../bytecode-register-optimizer.cc | 103 +- src/interpreter/bytecode-register-optimizer.h | 17 +- src/interpreter/mkpeephole.cc | 3 + src/v8.gyp | 1 - .../AssignmentsInBinaryExpression.golden | 56 +- .../BreakableBlocks.golden | 6 +- .../CallLookupSlot.golden | 4 +- .../ClassAndSuperClass.golden | 4 +- .../ClassDeclarations.golden | 4 +- .../CreateRestParameter.golden | 6 +- .../bytecode_expectations/Eval.golden | 4 +- .../bytecode_expectations/ForIn.golden | 10 +- .../bytecode_expectations/Generators.golden | 59 +- .../bytecode_expectations/LetVariable.golden | 3 +- .../bytecode_expectations/LookupSlot.golden | 20 +- .../ObjectLiterals.golden | 25 +- .../UnaryOperators.golden | 6 +- .../WithStatement.golden | 6 +- .../test-interpreter-intrinsics.cc | 4 +- test/cctest/interpreter/test-interpreter.cc | 67 +- .../bytecode-array-builder-unittest.cc | 59 +- .../bytecode-array-iterator-unittest.cc | 4 +- .../bytecode-register-allocator-unittest.cc | 248 ++--- .../bytecode-register-optimizer-unittest.cc | 77 +- 31 files changed, 859 insertions(+), 1475 deletions(-) delete mode 100644 src/interpreter/bytecode-register-allocator.cc diff --git a/BUILD.gn b/BUILD.gn index f59f69b01d..46c412626b 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1421,7 +1421,6 @@ v8_source_set("v8_base") { "src/interpreter/bytecode-peephole-table.h", "src/interpreter/bytecode-pipeline.cc", "src/interpreter/bytecode-pipeline.h", - "src/interpreter/bytecode-register-allocator.cc", "src/interpreter/bytecode-register-allocator.h", "src/interpreter/bytecode-register-optimizer.cc", "src/interpreter/bytecode-register-optimizer.h", diff --git a/src/interpreter/bytecode-array-builder.cc b/src/interpreter/bytecode-array-builder.cc index b6683cfd0e..d8698fe959 100644 --- a/src/interpreter/bytecode-array-builder.cc +++ b/src/interpreter/bytecode-array-builder.cc @@ -28,7 +28,7 @@ BytecodeArrayBuilder::BytecodeArrayBuilder( parameter_count_(parameter_count), local_register_count_(locals_count), context_register_count_(context_count), - temporary_allocator_(zone, fixed_register_count()), + register_allocator_(fixed_register_count()), bytecode_array_writer_(zone, &constant_array_builder_, source_position_mode), pipeline_(&bytecode_array_writer_) { @@ -46,7 +46,8 @@ BytecodeArrayBuilder::BytecodeArrayBuilder( if (FLAG_ignition_reo) { pipeline_ = new (zone) BytecodeRegisterOptimizer( - zone, &temporary_allocator_, parameter_count, pipeline_); + zone, ®ister_allocator_, fixed_register_count(), parameter_count, + pipeline_); } return_position_ = @@ -69,10 +70,6 @@ Register BytecodeArrayBuilder::Parameter(int parameter_index) const { return Register::FromParameterIndex(parameter_index, parameter_count()); } -bool BytecodeArrayBuilder::RegisterIsParameterOrLocal(Register reg) const { - return reg.is_parameter() || reg.index() < locals_count(); -} - Handle BytecodeArrayBuilder::ToBytecodeArray(Isolate* isolate) { DCHECK(return_seen_in_block_); DCHECK(!bytecode_generated_); @@ -80,8 +77,7 @@ Handle BytecodeArrayBuilder::ToBytecodeArray(Isolate* isolate) { Handle handler_table = handler_table_builder()->ToHandlerTable(isolate); - return pipeline_->ToBytecodeArray(isolate, - fixed_and_temporary_register_count(), + return pipeline_->ToBytecodeArray(isolate, total_register_count(), parameter_count(), handler_table); } @@ -729,45 +725,38 @@ void BytecodeArrayBuilder::EnsureReturn() { } BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable, - Register receiver_args, - size_t receiver_args_count, + RegisterList args, int feedback_slot, TailCallMode tail_call_mode) { if (tail_call_mode == TailCallMode::kDisallow) { Output(Bytecode::kCall, RegisterOperand(callable), - RegisterOperand(receiver_args), UnsignedOperand(receiver_args_count), + RegisterOperand(args.first_register()), + UnsignedOperand(args.register_count()), UnsignedOperand(feedback_slot)); } else { DCHECK(tail_call_mode == TailCallMode::kAllow); Output(Bytecode::kTailCall, RegisterOperand(callable), - RegisterOperand(receiver_args), UnsignedOperand(receiver_args_count), + RegisterOperand(args.first_register()), + UnsignedOperand(args.register_count()), UnsignedOperand(feedback_slot)); } return *this; } BytecodeArrayBuilder& BytecodeArrayBuilder::New(Register constructor, - Register first_arg, - size_t arg_count, + RegisterList args, int feedback_slot_id) { - if (!first_arg.is_valid()) { - DCHECK_EQ(0u, arg_count); - first_arg = Register(0); - } Output(Bytecode::kNew, RegisterOperand(constructor), - RegisterOperand(first_arg), UnsignedOperand(arg_count), + RegisterOperand(args.first_register()), + UnsignedOperand(args.register_count()), UnsignedOperand(feedback_slot_id)); return *this; } BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime( - Runtime::FunctionId function_id, Register first_arg, size_t arg_count) { + Runtime::FunctionId function_id, RegisterList args) { DCHECK_EQ(1, Runtime::FunctionForId(function_id)->result_size); DCHECK(Bytecodes::SizeForUnsignedOperand(function_id) <= OperandSize::kShort); - if (!first_arg.is_valid()) { - DCHECK_EQ(0u, arg_count); - first_arg = Register(0); - } Bytecode bytecode; uint32_t id; if (IntrinsicsHelper::IsSupported(function_id)) { @@ -777,29 +766,42 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime( bytecode = Bytecode::kCallRuntime; id = static_cast(function_id); } - Output(bytecode, id, RegisterOperand(first_arg), UnsignedOperand(arg_count)); + Output(bytecode, id, RegisterOperand(args.first_register()), + UnsignedOperand(args.register_count())); + return *this; +} + +BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime( + Runtime::FunctionId function_id, Register arg) { + return CallRuntime(function_id, RegisterList(arg.index(), 1)); +} + +BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime( + Runtime::FunctionId function_id) { + return CallRuntime(function_id, RegisterList()); +} + +BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntimeForPair( + Runtime::FunctionId function_id, RegisterList args, Register first_return) { + DCHECK_EQ(2, Runtime::FunctionForId(function_id)->result_size); + DCHECK(Bytecodes::SizeForUnsignedOperand(function_id) <= OperandSize::kShort); + Output(Bytecode::kCallRuntimeForPair, static_cast(function_id), + RegisterOperand(args.first_register()), + UnsignedOperand(args.register_count()), RegisterOperand(first_return)); return *this; } BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntimeForPair( - Runtime::FunctionId function_id, Register first_arg, size_t arg_count, - Register first_return) { - DCHECK_EQ(2, Runtime::FunctionForId(function_id)->result_size); - DCHECK(Bytecodes::SizeForUnsignedOperand(function_id) <= OperandSize::kShort); - if (!first_arg.is_valid()) { - DCHECK_EQ(0u, arg_count); - first_arg = Register(0); - } - Output(Bytecode::kCallRuntimeForPair, static_cast(function_id), - RegisterOperand(first_arg), UnsignedOperand(arg_count), - RegisterOperand(first_return)); - return *this; + Runtime::FunctionId function_id, Register arg, Register first_return) { + return CallRuntimeForPair(function_id, RegisterList(arg.index(), 1), + first_return); } -BytecodeArrayBuilder& BytecodeArrayBuilder::CallJSRuntime( - int context_index, Register receiver_args, size_t receiver_args_count) { +BytecodeArrayBuilder& BytecodeArrayBuilder::CallJSRuntime(int context_index, + RegisterList args) { Output(Bytecode::kCallJSRuntime, UnsignedOperand(context_index), - RegisterOperand(receiver_args), UnsignedOperand(receiver_args_count)); + RegisterOperand(args.first_register()), + UnsignedOperand(args.register_count())); return *this; } @@ -832,10 +834,6 @@ void BytecodeArrayBuilder::SetReturnPosition() { latest_source_info_.MakeStatementPosition(return_position_); } -bool BytecodeArrayBuilder::TemporaryRegisterIsLive(Register reg) const { - return temporary_register_allocator()->RegisterIsLive(reg); -} - bool BytecodeArrayBuilder::RegisterIsValid(Register reg) const { if (!reg.is_valid()) { return false; @@ -850,7 +848,7 @@ bool BytecodeArrayBuilder::RegisterIsValid(Register reg) const { } else if (reg.index() < fixed_register_count()) { return true; } else { - return TemporaryRegisterIsLive(reg); + return register_allocator()->RegisterIsLive(reg); } } diff --git a/src/interpreter/bytecode-array-builder.h b/src/interpreter/bytecode-array-builder.h index b54365a688..efee1f4e1b 100644 --- a/src/interpreter/bytecode-array-builder.h +++ b/src/interpreter/bytecode-array-builder.h @@ -61,23 +61,14 @@ class BytecodeArrayBuilder final : public ZoneObject { int fixed_register_count() const { return context_count() + locals_count(); } // Returns the number of fixed and temporary registers. - int fixed_and_temporary_register_count() const { - return fixed_register_count() + temporary_register_count(); - } - - int temporary_register_count() const { - return temporary_register_allocator()->allocation_count(); + int total_register_count() const { + DCHECK_LE(fixed_register_count(), + register_allocator()->maximum_register_count()); + return register_allocator()->maximum_register_count(); } Register Parameter(int parameter_index) const; - // Return true if the register |reg| represents a parameter or a - // local. - bool RegisterIsParameterOrLocal(Register reg) const; - - // Returns true if the register |reg| is a live temporary register. - bool TemporaryRegisterIsLive(Register reg) const; - // Constant loads to accumulator. BytecodeArrayBuilder& LoadConstantPoolEntry(size_t entry); BytecodeArrayBuilder& LoadLiteral(v8::internal::Smi* value); @@ -191,46 +182,39 @@ class BytecodeArrayBuilder final : public ZoneObject { BytecodeArrayBuilder& PopContext(Register context); // Call a JS function. The JSFunction or Callable to be called should be in - // |callable|, the receiver should be in |receiver_args| and all subsequent - // arguments should be in registers to - // . Type feedback is recorded in - // the |feedback_slot| in the type feedback vector. + // |callable|. The arguments should be in |args|, with the receiver in + // |args[0]|. Type feedback is recorded in the |feedback_slot| in the type + // feedback vector. BytecodeArrayBuilder& Call( - Register callable, Register receiver_args, size_t receiver_arg_count, - int feedback_slot, TailCallMode tail_call_mode = TailCallMode::kDisallow); - - BytecodeArrayBuilder& TailCall(Register callable, Register receiver_args, - size_t receiver_arg_count, int feedback_slot) { - return Call(callable, receiver_args, receiver_arg_count, feedback_slot, - TailCallMode::kAllow); - } + Register callable, RegisterList args, int feedback_slot, + TailCallMode tail_call_mode = TailCallMode::kDisallow); // Call the new operator. The accumulator holds the |new_target|. - // The |constructor| is in a register followed by |arg_count| - // consecutive arguments starting at |first_arg| for the constuctor - // invocation. - BytecodeArrayBuilder& New(Register constructor, Register first_arg, - size_t arg_count, int feedback_slot); + // The |constructor| is in a register and arguments are in |args|. + BytecodeArrayBuilder& New(Register constructor, RegisterList args, + int feedback_slot); - // Call the runtime function with |function_id|. The first argument should be - // in |first_arg| and all subsequent arguments should be in registers - // to . + // Call the runtime function with |function_id| and arguments |args|. BytecodeArrayBuilder& CallRuntime(Runtime::FunctionId function_id, - Register first_arg, size_t arg_count); + RegisterList args); + // Call the runtime function with |function_id| with single argument |arg|. + BytecodeArrayBuilder& CallRuntime(Runtime::FunctionId function_id, + Register arg); + // Call the runtime function with |function_id| with no arguments. + BytecodeArrayBuilder& CallRuntime(Runtime::FunctionId function_id); - // Call the runtime function with |function_id| that returns a pair of values. - // The first argument should be in |first_arg| and all subsequent arguments - // should be in registers to . The - // return values will be returned in and . + // Call the runtime function with |function_id| and arguments |args|, that + // returns a pair of values. The return values will be returned in + // and . BytecodeArrayBuilder& CallRuntimeForPair(Runtime::FunctionId function_id, - Register first_arg, size_t arg_count, + RegisterList args, Register first_return); + // Call the runtime function with |function_id| with single argument |arg|. + BytecodeArrayBuilder& CallRuntimeForPair(Runtime::FunctionId function_id, + Register arg, Register first_return); - // Call the JS runtime function with |context_index|. The the receiver should - // be in |receiver_args| and all subsequent arguments should be in registers - // to . - BytecodeArrayBuilder& CallJSRuntime(int context_index, Register receiver_args, - size_t receiver_args_count); + // Call the JS runtime function with |context_index| and arguments |args|. + BytecodeArrayBuilder& CallJSRuntime(int context_index, RegisterList args); // Operators (register holds the lhs value, accumulator holds the rhs value). // Type feedback will be recorded in the |feedback_slot| @@ -328,34 +312,16 @@ class BytecodeArrayBuilder final : public ZoneObject { latest_source_info_.MakeStatementPosition(expr->position()); } - // Accessors - TemporaryRegisterAllocator* temporary_register_allocator() { - return &temporary_allocator_; - } - const TemporaryRegisterAllocator* temporary_register_allocator() const { - return &temporary_allocator_; - } - Zone* zone() const { return zone_; } - void EnsureReturn(); - static uint32_t RegisterOperand(Register reg) { - return static_cast(reg.ToOperand()); + // Accessors + BytecodeRegisterAllocator* register_allocator() { + return ®ister_allocator_; } - - static uint32_t SignedOperand(int value) { - return static_cast(value); - } - - static uint32_t UnsignedOperand(int value) { - DCHECK_GE(value, 0); - return static_cast(value); - } - - static uint32_t UnsignedOperand(size_t value) { - DCHECK_LE(value, kMaxUInt32); - return static_cast(value); + const BytecodeRegisterAllocator* register_allocator() const { + return ®ister_allocator_; } + Zone* zone() const { return zone_; } private: friend class BytecodeRegisterAllocator; @@ -377,6 +343,24 @@ class BytecodeArrayBuilder final : public ZoneObject { uint32_t operand0 = 0, uint32_t operand1 = 0, uint32_t operand2 = 0, uint32_t operand3 = 0) const; + static uint32_t RegisterOperand(Register reg) { + return static_cast(reg.ToOperand()); + } + + static uint32_t SignedOperand(int value) { + return static_cast(value); + } + + static uint32_t UnsignedOperand(int value) { + DCHECK_GE(value, 0); + return static_cast(value); + } + + static uint32_t UnsignedOperand(size_t value) { + DCHECK_LE(value, kMaxUInt32); + return static_cast(value); + } + // Set position for return. void SetReturnPosition(); @@ -413,7 +397,7 @@ class BytecodeArrayBuilder final : public ZoneObject { int local_register_count_; int context_register_count_; int return_position_; - TemporaryRegisterAllocator temporary_allocator_; + BytecodeRegisterAllocator register_allocator_; BytecodeArrayWriter bytecode_array_writer_; BytecodePipelineStage* pipeline_; BytecodeSourceInfo latest_source_info_; diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc index 0f07fc0794..c7d333f0a5 100644 --- a/src/interpreter/bytecode-generator.cc +++ b/src/interpreter/bytecode-generator.cc @@ -374,75 +374,35 @@ class BytecodeGenerator::RegisterAllocationScope { public: explicit RegisterAllocationScope(BytecodeGenerator* generator) : generator_(generator), - outer_(generator->register_allocator()), - allocator_(builder()->zone(), - builder()->temporary_register_allocator()) { - generator_->set_register_allocator(this); - } + outer_next_register_index_( + generator->register_allocator()->next_register_index()) {} virtual ~RegisterAllocationScope() { - generator_->set_register_allocator(outer_); + generator_->register_allocator()->ReleaseRegisters( + outer_next_register_index_); } - Register NewRegister() { - RegisterAllocationScope* current_scope = generator()->register_allocator(); - if ((current_scope == this) || - (current_scope->outer() == this && - !current_scope->allocator_.HasConsecutiveAllocations())) { - // Regular case - Allocating registers in current or outer context. - // VisitForRegisterValue allocates register in outer context. - return allocator_.NewRegister(); - } else { - // If it is required to allocate a register other than current or outer - // scopes, allocate a new temporary register. It might be expensive to - // walk the full context chain and compute the list of consecutive - // reservations in the innerscopes. - UNIMPLEMENTED(); - return Register::invalid_value(); - } - } - - void PrepareForConsecutiveAllocations(int count) { - allocator_.PrepareForConsecutiveAllocations(count); - } - - Register NextConsecutiveRegister() { - return allocator_.NextConsecutiveRegister(); - } - - bool RegisterIsAllocatedInThisScope(Register reg) const { - return allocator_.RegisterIsAllocatedInThisScope(reg); - } - - RegisterAllocationScope* outer() const { return outer_; } - private: - BytecodeGenerator* generator() const { return generator_; } - BytecodeArrayBuilder* builder() const { return generator_->builder(); } - BytecodeGenerator* generator_; - RegisterAllocationScope* outer_; - BytecodeRegisterAllocator allocator_; + int outer_next_register_index_; DISALLOW_COPY_AND_ASSIGN(RegisterAllocationScope); }; -// Scoped base class for determining where the result of an expression -// is stored. +// Scoped base class for determining how the result of an expression will be +// used. class BytecodeGenerator::ExpressionResultScope { public: ExpressionResultScope(BytecodeGenerator* generator, Expression::Context kind) : generator_(generator), kind_(kind), outer_(generator->execution_result()), - allocator_(generator), - result_identified_(false) { + allocator_(generator) { generator_->set_execution_result(this); } virtual ~ExpressionResultScope() { generator_->set_execution_result(outer_); - DCHECK(result_identified() || generator_->HasStackOverflow()); } bool IsEffect() const { return kind_ == Expression::kEffect; } @@ -454,28 +414,11 @@ class BytecodeGenerator::ExpressionResultScope { return reinterpret_cast(this); } - virtual void SetResultInAccumulator() = 0; - virtual void SetResultInRegister(Register reg) = 0; - - protected: - ExpressionResultScope* outer() const { return outer_; } - BytecodeArrayBuilder* builder() const { return generator_->builder(); } - BytecodeGenerator* generator() const { return generator_; } - const RegisterAllocationScope* allocator() const { return &allocator_; } - - void set_result_identified() { - DCHECK(!result_identified()); - result_identified_ = true; - } - - bool result_identified() const { return result_identified_; } - private: BytecodeGenerator* generator_; Expression::Context kind_; ExpressionResultScope* outer_; RegisterAllocationScope allocator_; - bool result_identified_; DISALLOW_COPY_AND_ASSIGN(ExpressionResultScope); }; @@ -486,61 +429,15 @@ class BytecodeGenerator::EffectResultScope final : public ExpressionResultScope { public: explicit EffectResultScope(BytecodeGenerator* generator) - : ExpressionResultScope(generator, Expression::kEffect) { - set_result_identified(); - } - - virtual void SetResultInAccumulator() {} - virtual void SetResultInRegister(Register reg) {} + : ExpressionResultScope(generator, Expression::kEffect) {} }; // Scoped class used when the result of the current expression to be -// evaluated should go into the interpreter's accumulator register. -class BytecodeGenerator::AccumulatorResultScope final - : public ExpressionResultScope { +// evaluated should go into the interpreter's accumulator. +class BytecodeGenerator::ValueResultScope final : public ExpressionResultScope { public: - explicit AccumulatorResultScope(BytecodeGenerator* generator) + explicit ValueResultScope(BytecodeGenerator* generator) : ExpressionResultScope(generator, Expression::kValue) {} - - virtual void SetResultInAccumulator() { set_result_identified(); } - - virtual void SetResultInRegister(Register reg) { - builder()->LoadAccumulatorWithRegister(reg); - set_result_identified(); - } -}; - -// Scoped class used when the result of the current expression to be -// evaluated should go into an interpreter register. -class BytecodeGenerator::RegisterResultScope final - : public ExpressionResultScope { - public: - explicit RegisterResultScope(BytecodeGenerator* generator) - : ExpressionResultScope(generator, Expression::kValue) {} - - virtual void SetResultInAccumulator() { - result_register_ = allocator()->outer()->NewRegister(); - builder()->StoreAccumulatorInRegister(result_register_); - set_result_identified(); - } - - virtual void SetResultInRegister(Register reg) { - DCHECK(builder()->RegisterIsParameterOrLocal(reg) || - (builder()->TemporaryRegisterIsLive(reg) && - !allocator()->RegisterIsAllocatedInThisScope(reg))); - result_register_ = reg; - set_result_identified(); - } - - Register ResultRegister() { - if (generator()->HasStackOverflow() && !result_identified()) { - SetResultInAccumulator(); - } - return result_register_; - } - - private: - Register result_register_; }; // Scoped class used when the result of the current expression to be @@ -555,18 +452,10 @@ class BytecodeGenerator::TestResultScope final : public ExpressionResultScope { fallthrough_(fallthrough), result_consumed_by_test_(false) {} - virtual void SetResultInAccumulator() { set_result_identified(); } - - virtual void SetResultInRegister(Register reg) { - builder()->LoadAccumulatorWithRegister(reg); - set_result_identified(); - } - // Used when code special cases for TestResultScope and consumes any // possible value by testing and jumping to a then/else label. void SetResultConsumedByTest() { result_consumed_by_test_ = true; - set_result_identified(); } bool ResultConsumedByTest() { return result_consumed_by_test_; } @@ -678,7 +567,6 @@ BytecodeGenerator::BytecodeGenerator(CompilationInfo* info) execution_control_(nullptr), execution_context_(nullptr), execution_result_(nullptr), - register_allocator_(nullptr), generator_resume_points_(info->literal()->yield_count(), info->zone()), generator_state_(), loop_depth_(0), @@ -928,7 +816,7 @@ void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) { builder() ->LoadLiteral(variable->name()) .StoreAccumulatorInRegister(name) - .CallRuntime(Runtime::kDeclareEvalVar, name, 1); + .CallRuntime(Runtime::kDeclareEvalVar, name); break; } case VariableLocation::MODULE: @@ -966,14 +854,13 @@ void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) { break; } case VariableLocation::LOOKUP: { - register_allocator()->PrepareForConsecutiveAllocations(2); - Register name = register_allocator()->NextConsecutiveRegister(); - Register literal = register_allocator()->NextConsecutiveRegister(); - builder()->LoadLiteral(variable->name()).StoreAccumulatorInRegister(name); - + RegisterList args = register_allocator()->NewRegisterList(2); + builder() + ->LoadLiteral(variable->name()) + .StoreAccumulatorInRegister(args[0]); VisitForAccumulatorValue(decl->fun()); - builder()->StoreAccumulatorInRegister(literal).CallRuntime( - Runtime::kDeclareEvalFunction, name, 2); + builder()->StoreAccumulatorInRegister(args[1]).CallRuntime( + Runtime::kDeclareEvalFunction, args); break; } case VariableLocation::MODULE: @@ -1000,20 +887,15 @@ void BytecodeGenerator::VisitDeclarations( builder()->AllocateConstantPoolEntry()); int encoded_flags = info()->GetDeclareGlobalsFlags(); - register_allocator()->PrepareForConsecutiveAllocations(3); - - Register pairs = register_allocator()->NextConsecutiveRegister(); - Register flags = register_allocator()->NextConsecutiveRegister(); - Register function = register_allocator()->NextConsecutiveRegister(); - // Emit code to declare globals. + RegisterList args = register_allocator()->NewRegisterList(3); builder() ->LoadConstantPoolEntry(globals_builder()->constant_pool_entry()) - .StoreAccumulatorInRegister(pairs) + .StoreAccumulatorInRegister(args[0]) .LoadLiteral(Smi::FromInt(encoded_flags)) - .StoreAccumulatorInRegister(flags) - .MoveRegister(Register::function_closure(), function) - .CallRuntime(Runtime::kDeclareGlobalsForInterpreter, pairs, 3); + .StoreAccumulatorInRegister(args[1]) + .MoveRegister(Register::function_closure(), args[2]) + .CallRuntime(Runtime::kDeclareGlobalsForInterpreter, args); // Push and reset globals builder. global_declarations_.push_back(globals_builder()); @@ -1268,36 +1150,28 @@ void BytecodeGenerator::VisitForInAssignment(Expression* expr, } case NAMED_SUPER_PROPERTY: { RegisterAllocationScope register_scope(this); - register_allocator()->PrepareForConsecutiveAllocations(4); - Register receiver = register_allocator()->NextConsecutiveRegister(); - Register home_object = register_allocator()->NextConsecutiveRegister(); - Register name = register_allocator()->NextConsecutiveRegister(); - Register value = register_allocator()->NextConsecutiveRegister(); - builder()->StoreAccumulatorInRegister(value); + RegisterList args = register_allocator()->NewRegisterList(4); + builder()->StoreAccumulatorInRegister(args[3]); SuperPropertyReference* super_property = property->obj()->AsSuperPropertyReference(); - VisitForRegisterValue(super_property->this_var(), receiver); - VisitForRegisterValue(super_property->home_object(), home_object); + VisitForRegisterValue(super_property->this_var(), args[0]); + VisitForRegisterValue(super_property->home_object(), args[1]); builder() ->LoadLiteral(property->key()->AsLiteral()->AsPropertyName()) - .StoreAccumulatorInRegister(name); - BuildNamedSuperPropertyStore(receiver, home_object, name, value); + .StoreAccumulatorInRegister(args[2]) + .CallRuntime(StoreToSuperRuntimeId(), args); break; } case KEYED_SUPER_PROPERTY: { RegisterAllocationScope register_scope(this); - register_allocator()->PrepareForConsecutiveAllocations(4); - Register receiver = register_allocator()->NextConsecutiveRegister(); - Register home_object = register_allocator()->NextConsecutiveRegister(); - Register key = register_allocator()->NextConsecutiveRegister(); - Register value = register_allocator()->NextConsecutiveRegister(); - builder()->StoreAccumulatorInRegister(value); + RegisterList args = register_allocator()->NewRegisterList(4); + builder()->StoreAccumulatorInRegister(args[3]); SuperPropertyReference* super_property = property->obj()->AsSuperPropertyReference(); - VisitForRegisterValue(super_property->this_var(), receiver); - VisitForRegisterValue(super_property->home_object(), home_object); - VisitForRegisterValue(property->key(), key); - BuildKeyedSuperPropertyStore(receiver, home_object, key, value); + VisitForRegisterValue(super_property->this_var(), args[0]); + VisitForRegisterValue(super_property->home_object(), args[1]); + VisitForRegisterValue(property->key(), args[2]); + builder()->CallRuntime(StoreKeyedToSuperRuntimeId(), args); break; } } @@ -1321,13 +1195,10 @@ void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) { Register receiver = register_allocator()->NewRegister(); builder()->ConvertAccumulatorToObject(receiver); - register_allocator()->PrepareForConsecutiveAllocations(3); - Register cache_type = register_allocator()->NextConsecutiveRegister(); - Register cache_array = register_allocator()->NextConsecutiveRegister(); - Register cache_length = register_allocator()->NextConsecutiveRegister(); // Used as kRegTriple and kRegPair in ForInPrepare and ForInNext. - USE(cache_array); - builder()->ForInPrepare(receiver, cache_type); + RegisterList triple = register_allocator()->NewRegisterList(3); + Register cache_length = triple[2]; + builder()->ForInPrepare(receiver, triple.first_register()); // Set up loop counter Register index = register_allocator()->NewRegister(); @@ -1339,9 +1210,9 @@ void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) { builder()->SetExpressionAsStatementPosition(stmt->each()); builder()->ForInContinue(index, cache_length); loop_builder.BreakIfFalse(); - DCHECK(Register::AreContiguous(cache_type, cache_array)); FeedbackVectorSlot slot = stmt->ForInFeedbackSlot(); - builder()->ForInNext(receiver, index, cache_type, feedback_index(slot)); + builder()->ForInNext(receiver, index, triple.first_register(), + feedback_index(slot)); loop_builder.ContinueIfUndefined(); VisitForInAssignment(stmt->each(), stmt->EachFeedbackSlot()); VisitIterationBody(stmt, &loop_builder); @@ -1373,7 +1244,6 @@ void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) { void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { TryCatchBuilder try_control_builder(builder(), stmt->catch_prediction()); - Register no_reg; // Preserve the context in a dedicated register, so that it can be restored // when the handler is entered by the stack-unwinding machinery. @@ -1396,7 +1266,7 @@ void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { // If requested, clear message object as we enter the catch block. if (stmt->clear_pending_message()) { - builder()->CallRuntime(Runtime::kInterpreterClearPendingMessage, no_reg, 0); + builder()->CallRuntime(Runtime::kInterpreterClearPendingMessage); } // Load the catch context into the accumulator. @@ -1409,7 +1279,6 @@ void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { TryFinallyBuilder try_control_builder(builder(), stmt->catch_prediction()); - Register no_reg; // We keep a record of all paths that enter the finally-block to be able to // dispatch to the correct continuation point after the statements in the @@ -1457,7 +1326,7 @@ void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { // Clear message object as we enter the finally block. builder() - ->CallRuntime(Runtime::kInterpreterClearPendingMessage, no_reg, 0) + ->CallRuntime(Runtime::kInterpreterClearPendingMessage) .StoreAccumulatorInRegister(message); // Evaluate the finally-block. @@ -1465,7 +1334,7 @@ void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { try_control_builder.EndFinally(); // Pending message object is restored on exit. - builder()->CallRuntime(Runtime::kInterpreterSetPendingMessage, message, 1); + builder()->CallRuntime(Runtime::kInterpreterSetPendingMessage, message); // Dynamic dispatch after the finally-block. commands.ApplyDeferredCommands(); @@ -1482,16 +1351,15 @@ void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { size_t entry = builder()->AllocateConstantPoolEntry(); builder()->CreateClosure(entry, flags); function_literals_.push_back(std::make_pair(expr, entry)); - execution_result()->SetResultInAccumulator(); } void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr) { VisitClassLiteralForRuntimeDefinition(expr); // Load the "prototype" from the constructor. - register_allocator()->PrepareForConsecutiveAllocations(2); - Register literal = register_allocator()->NextConsecutiveRegister(); - Register prototype = register_allocator()->NextConsecutiveRegister(); + RegisterList args = register_allocator()->NewRegisterList(2); + Register literal = args[0]; + Register prototype = args[1]; FeedbackVectorSlot slot = expr->PrototypeSlot(); builder() ->StoreAccumulatorInRegister(literal) @@ -1499,7 +1367,7 @@ void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr) { .StoreAccumulatorInRegister(prototype); VisitClassLiteralProperties(expr, literal, prototype); - builder()->CallRuntime(Runtime::kToFastProperties, literal, 1); + builder()->CallRuntime(Runtime::kToFastProperties, literal); // Assign to class variable. if (expr->class_variable_proxy() != nullptr) { Variable* var = expr->class_variable_proxy()->var(); @@ -1508,42 +1376,30 @@ void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr) { : FeedbackVectorSlot::Invalid(); VisitVariableAssignment(var, Token::INIT, slot); } - execution_result()->SetResultInAccumulator(); } void BytecodeGenerator::VisitClassLiteralForRuntimeDefinition( ClassLiteral* expr) { - AccumulatorResultScope result_scope(this); - register_allocator()->PrepareForConsecutiveAllocations(4); - Register extends = register_allocator()->NextConsecutiveRegister(); - Register constructor = register_allocator()->NextConsecutiveRegister(); - Register start_position = register_allocator()->NextConsecutiveRegister(); - Register end_position = register_allocator()->NextConsecutiveRegister(); - + RegisterAllocationScope register_scope(this); + RegisterList args = register_allocator()->NewRegisterList(4); VisitForAccumulatorValueOrTheHole(expr->extends()); - builder()->StoreAccumulatorInRegister(extends); - - VisitForAccumulatorValue(expr->constructor()); + builder()->StoreAccumulatorInRegister(args[0]); + VisitForRegisterValue(expr->constructor(), args[1]); builder() - ->StoreAccumulatorInRegister(constructor) - .LoadLiteral(Smi::FromInt(expr->start_position())) - .StoreAccumulatorInRegister(start_position) + ->LoadLiteral(Smi::FromInt(expr->start_position())) + .StoreAccumulatorInRegister(args[2]) .LoadLiteral(Smi::FromInt(expr->end_position())) - .StoreAccumulatorInRegister(end_position) - .CallRuntime(Runtime::kDefineClass, extends, 4); - result_scope.SetResultInAccumulator(); + .StoreAccumulatorInRegister(args[3]) + .CallRuntime(Runtime::kDefineClass, args); } void BytecodeGenerator::VisitClassLiteralProperties(ClassLiteral* expr, Register literal, Register prototype) { RegisterAllocationScope register_scope(this); - register_allocator()->PrepareForConsecutiveAllocations(5); - Register receiver = register_allocator()->NextConsecutiveRegister(); - Register key = register_allocator()->NextConsecutiveRegister(); - Register value = register_allocator()->NextConsecutiveRegister(); - Register attr = register_allocator()->NextConsecutiveRegister(); - Register set_function_name = register_allocator()->NextConsecutiveRegister(); + RegisterList args = register_allocator()->NewRegisterList(5); + Register receiver = args[0], key = args[1], value = args[2], attr = args[3], + set_function_name = args[4]; bool attr_assigned = false; Register old_receiver = Register::invalid_value(); @@ -1561,16 +1417,22 @@ void BytecodeGenerator::VisitClassLiteralProperties(ClassLiteral* expr, VisitForAccumulatorValue(property->key()); builder()->ConvertAccumulatorToName(key); - // The static prototype property is read only. We handle the non computed - // property name case in the parser. Since this is the only case where we - // need to check for an own read only property we special case this so we do - // not need to do this for every property. - if (property->is_static() && property->is_computed_name()) { - VisitClassLiteralStaticPrototypeWithComputedName(key); - } - VisitForAccumulatorValue(property->value()); - builder()->StoreAccumulatorInRegister(value); + if (property->is_static() && property->is_computed_name()) { + // The static prototype property is read only. We handle the non computed + // property name case in the parser. Since this is the only case where we + // need to check for an own read only property we special case this so we + // do not need to do this for every property. + BytecodeLabel done; + builder() + ->LoadLiteral(prototype_string()) + .CompareOperation(Token::Value::EQ_STRICT, key) + .JumpIfFalse(&done) + .CallRuntime(Runtime::kThrowStaticPrototypeError) + .Bind(&done); + } + + VisitForRegisterValue(property->value(), value); VisitSetHomeObject(value, receiver, property); if (!attr_assigned) { @@ -1584,19 +1446,18 @@ void BytecodeGenerator::VisitClassLiteralProperties(ClassLiteral* expr, case ClassLiteral::Property::METHOD: { builder() ->LoadLiteral(Smi::FromInt(property->NeedsSetFunctionName())) - .StoreAccumulatorInRegister(set_function_name); - builder()->CallRuntime(Runtime::kDefineDataPropertyInLiteral, receiver, - 5); + .StoreAccumulatorInRegister(set_function_name) + .CallRuntime(Runtime::kDefineDataPropertyInLiteral, args); break; } case ClassLiteral::Property::GETTER: { builder()->CallRuntime(Runtime::kDefineGetterPropertyUnchecked, - receiver, 4); + args.Truncate(4)); break; } case ClassLiteral::Property::SETTER: { builder()->CallRuntime(Runtime::kDefineSetterPropertyUnchecked, - receiver, 4); + args.Truncate(4)); break; } case ClassLiteral::Property::FIELD: { @@ -1607,23 +1468,11 @@ void BytecodeGenerator::VisitClassLiteralProperties(ClassLiteral* expr, } } -void BytecodeGenerator::VisitClassLiteralStaticPrototypeWithComputedName( - Register key) { - BytecodeLabel done; - builder() - ->LoadLiteral(prototype_string()) - .CompareOperation(Token::Value::EQ_STRICT, key) - .JumpIfFalse(&done) - .CallRuntime(Runtime::kThrowStaticPrototypeError, Register(0), 0) - .Bind(&done); -} - void BytecodeGenerator::VisitNativeFunctionLiteral( NativeFunctionLiteral* expr) { size_t entry = builder()->AllocateConstantPoolEntry(); builder()->CreateClosure(entry, NOT_TENURED); native_function_literals_.push_back(std::make_pair(expr, entry)); - execution_result()->SetResultInAccumulator(); } void BytecodeGenerator::VisitDoExpression(DoExpression* expr) { @@ -1653,8 +1502,6 @@ void BytecodeGenerator::VisitConditional(Conditional* expr) { VisitForAccumulatorValue(expr->else_expression()); builder()->Bind(&end_label); } - - execution_result()->SetResultInAccumulator(); } void BytecodeGenerator::VisitLiteral(Literal* expr) { @@ -1675,7 +1522,6 @@ void BytecodeGenerator::VisitLiteral(Literal* expr) { } else { builder()->LoadLiteral(raw_value->value()); } - execution_result()->SetResultInAccumulator(); } } @@ -1683,7 +1529,6 @@ void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { // Materialize a regular expression literal. builder()->CreateRegExpLiteral(expr->pattern(), expr->literal_index(), expr->flags()); - execution_result()->SetResultInAccumulator(); } void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { @@ -1694,7 +1539,7 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { expr->ComputeFlags()); // Allocate in the outer scope since this register is used to return the // expression's results to the caller. - Register literal = register_allocator()->outer()->NewRegister(); + Register literal = register_allocator()->NewRegister(); builder()->CreateObjectLiteral(expr->constant_properties(), expr->literal_index(), flags, literal); @@ -1738,23 +1583,17 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { VisitForEffect(property->value()); } } else { - register_allocator()->PrepareForConsecutiveAllocations(4); - Register literal_argument = - register_allocator()->NextConsecutiveRegister(); - Register key = register_allocator()->NextConsecutiveRegister(); - Register value = register_allocator()->NextConsecutiveRegister(); - Register language = register_allocator()->NextConsecutiveRegister(); + RegisterList args = register_allocator()->NewRegisterList(4); - builder()->MoveRegister(literal, literal_argument); - VisitForAccumulatorValue(property->key()); - builder()->StoreAccumulatorInRegister(key); - VisitForAccumulatorValue(property->value()); - builder()->StoreAccumulatorInRegister(value); + builder()->MoveRegister(literal, args[0]); + VisitForRegisterValue(property->key(), args[1]); + VisitForRegisterValue(property->value(), args[2]); if (property->emit_store()) { builder() ->LoadLiteral(Smi::FromInt(SLOPPY)) - .StoreAccumulatorInRegister(language) - .CallRuntime(Runtime::kSetProperty, literal_argument, 4); + .StoreAccumulatorInRegister(args[3]) + .CallRuntime(Runtime::kSetProperty, args); + Register value = args[2]; VisitSetHomeObject(value, literal, property); } } @@ -1762,15 +1601,10 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { } case ObjectLiteral::Property::PROTOTYPE: { DCHECK(property->emit_store()); - register_allocator()->PrepareForConsecutiveAllocations(2); - Register literal_argument = - register_allocator()->NextConsecutiveRegister(); - Register value = register_allocator()->NextConsecutiveRegister(); - - builder()->MoveRegister(literal, literal_argument); - VisitForAccumulatorValue(property->value()); - builder()->StoreAccumulatorInRegister(value).CallRuntime( - Runtime::kInternalSetPrototype, literal_argument, 2); + RegisterList args = register_allocator()->NewRegisterList(2); + builder()->MoveRegister(literal, args[0]); + VisitForRegisterValue(property->value(), args[1]); + builder()->CallRuntime(Runtime::kInternalSetPrototype, args); break; } case ObjectLiteral::Property::GETTER: @@ -1791,23 +1625,15 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { for (AccessorTable::Iterator it = accessor_table.begin(); it != accessor_table.end(); ++it) { RegisterAllocationScope inner_register_scope(this); - register_allocator()->PrepareForConsecutiveAllocations(5); - Register literal_argument = register_allocator()->NextConsecutiveRegister(); - Register name = register_allocator()->NextConsecutiveRegister(); - Register getter = register_allocator()->NextConsecutiveRegister(); - Register setter = register_allocator()->NextConsecutiveRegister(); - Register attr = register_allocator()->NextConsecutiveRegister(); - - builder()->MoveRegister(literal, literal_argument); - VisitForAccumulatorValue(it->first); - builder()->StoreAccumulatorInRegister(name); - VisitObjectLiteralAccessor(literal, it->second->getter, getter); - VisitObjectLiteralAccessor(literal, it->second->setter, setter); + RegisterList args = register_allocator()->NewRegisterList(5); + builder()->MoveRegister(literal, args[0]); + VisitForRegisterValue(it->first, args[1]); + VisitObjectLiteralAccessor(literal, it->second->getter, args[2]); + VisitObjectLiteralAccessor(literal, it->second->setter, args[3]); builder() ->LoadLiteral(Smi::FromInt(NONE)) - .StoreAccumulatorInRegister(attr) - .CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, - literal_argument, 5); + .StoreAccumulatorInRegister(args[4]) + .CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, args); } // Object literals have two parts. The "static" part on the left contains no @@ -1825,59 +1651,56 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { if (property->kind() == ObjectLiteral::Property::PROTOTYPE) { DCHECK(property->emit_store()); - register_allocator()->PrepareForConsecutiveAllocations(2); - Register literal_argument = - register_allocator()->NextConsecutiveRegister(); - Register value = register_allocator()->NextConsecutiveRegister(); - - builder()->MoveRegister(literal, literal_argument); - VisitForAccumulatorValue(property->value()); - builder()->StoreAccumulatorInRegister(value).CallRuntime( - Runtime::kInternalSetPrototype, literal_argument, 2); + RegisterList args = register_allocator()->NewRegisterList(2); + builder()->MoveRegister(literal, args[0]); + VisitForRegisterValue(property->value(), args[1]); + builder()->CallRuntime(Runtime::kInternalSetPrototype, args); continue; } - register_allocator()->PrepareForConsecutiveAllocations(5); - Register literal_argument = register_allocator()->NextConsecutiveRegister(); - Register key = register_allocator()->NextConsecutiveRegister(); - Register value = register_allocator()->NextConsecutiveRegister(); - Register attr = register_allocator()->NextConsecutiveRegister(); - DCHECK(Register::AreContiguous(literal_argument, key, value, attr)); - Register set_function_name = - register_allocator()->NextConsecutiveRegister(); - - builder()->MoveRegister(literal, literal_argument); - VisitForAccumulatorValue(property->key()); - builder()->ConvertAccumulatorToName(key); - VisitForAccumulatorValue(property->value()); - builder()->StoreAccumulatorInRegister(value); - VisitSetHomeObject(value, literal, property); - builder()->LoadLiteral(Smi::FromInt(NONE)).StoreAccumulatorInRegister(attr); switch (property->kind()) { case ObjectLiteral::Property::CONSTANT: case ObjectLiteral::Property::COMPUTED: - case ObjectLiteral::Property::MATERIALIZED_LITERAL: + case ObjectLiteral::Property::MATERIALIZED_LITERAL: { + RegisterList args = register_allocator()->NewRegisterList(5); + builder()->MoveRegister(literal, args[0]); + VisitForAccumulatorValue(property->key()); + builder()->ConvertAccumulatorToName(args[1]); + VisitForRegisterValue(property->value(), args[2]); + VisitSetHomeObject(args[2], literal, property); builder() - ->LoadLiteral(Smi::FromInt(property->NeedsSetFunctionName())) - .StoreAccumulatorInRegister(set_function_name); - builder()->CallRuntime(Runtime::kDefineDataPropertyInLiteral, - literal_argument, 5); + ->LoadLiteral(Smi::FromInt(NONE)) + .StoreAccumulatorInRegister(args[3]) + .LoadLiteral(Smi::FromInt(property->NeedsSetFunctionName())) + .StoreAccumulatorInRegister(args[4]); + builder()->CallRuntime(Runtime::kDefineDataPropertyInLiteral, args); break; + } + case ObjectLiteral::Property::GETTER: + case ObjectLiteral::Property::SETTER: { + RegisterList args = register_allocator()->NewRegisterList(4); + builder()->MoveRegister(literal, args[0]); + VisitForAccumulatorValue(property->key()); + builder()->ConvertAccumulatorToName(args[1]); + VisitForRegisterValue(property->value(), args[2]); + VisitSetHomeObject(args[2], literal, property); + builder() + ->LoadLiteral(Smi::FromInt(NONE)) + .StoreAccumulatorInRegister(args[3]); + Runtime::FunctionId function_id = + property->kind() == ObjectLiteral::Property::GETTER + ? Runtime::kDefineGetterPropertyUnchecked + : Runtime::kDefineSetterPropertyUnchecked; + builder()->CallRuntime(function_id, args); + break; + } case ObjectLiteral::Property::PROTOTYPE: UNREACHABLE(); // Handled specially above. break; - case ObjectLiteral::Property::GETTER: - builder()->CallRuntime(Runtime::kDefineGetterPropertyUnchecked, - literal_argument, 4); - break; - case ObjectLiteral::Property::SETTER: - builder()->CallRuntime(Runtime::kDefineSetterPropertyUnchecked, - literal_argument, 4); - break; } } - execution_result()->SetResultInRegister(literal); + builder()->LoadAccumulatorWithRegister(literal); } void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { @@ -1921,7 +1744,6 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { // Restore literal array into accumulator. builder()->LoadAccumulatorWithRegister(literal); } - execution_result()->SetResultInAccumulator(); } void BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) { @@ -2009,91 +1831,44 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable, builder() ->LoadLiteral(it->second->export_name->string()) .StoreAccumulatorInRegister(export_name) - .CallRuntime(Runtime::kLoadModuleExport, export_name, 1); + .CallRuntime(Runtime::kLoadModuleExport, export_name); } else { auto it = descriptor->regular_imports().find(variable->raw_name()); DCHECK(it != descriptor->regular_imports().end()); - register_allocator()->PrepareForConsecutiveAllocations(2); - Register import_name = register_allocator()->NextConsecutiveRegister(); - Register module_request = - register_allocator()->NextConsecutiveRegister(); + RegisterList args = register_allocator()->NewRegisterList(2); builder() ->LoadLiteral(it->second->import_name->string()) - .StoreAccumulatorInRegister(import_name) + .StoreAccumulatorInRegister(args[0]) .LoadLiteral(Smi::FromInt(it->second->module_request)) - .StoreAccumulatorInRegister(module_request) - .CallRuntime(Runtime::kLoadModuleImport, import_name, 2); + .StoreAccumulatorInRegister(args[1]) + .CallRuntime(Runtime::kLoadModuleImport, args); } BuildHoleCheckForVariableLoad(variable); break; } } - execution_result()->SetResultInAccumulator(); } void BytecodeGenerator::VisitVariableLoadForAccumulatorValue( Variable* variable, FeedbackVectorSlot slot, TypeofMode typeof_mode) { - AccumulatorResultScope accumulator_result(this); + ValueResultScope accumulator_result(this); VisitVariableLoad(variable, slot, typeof_mode); } -Register BytecodeGenerator::VisitVariableLoadForRegisterValue( - Variable* variable, FeedbackVectorSlot slot, TypeofMode typeof_mode) { - RegisterResultScope register_scope(this); - VisitVariableLoad(variable, slot, typeof_mode); - return register_scope.ResultRegister(); -} - -void BytecodeGenerator::BuildNamedSuperPropertyLoad(Register receiver, - Register home_object, - Register name) { - DCHECK(Register::AreContiguous(receiver, home_object, name)); - builder()->CallRuntime(Runtime::kLoadFromSuper, receiver, 3); -} - -void BytecodeGenerator::BuildKeyedSuperPropertyLoad(Register receiver, - Register home_object, - Register key) { - DCHECK(Register::AreContiguous(receiver, home_object, key)); - builder()->CallRuntime(Runtime::kLoadKeyedFromSuper, receiver, 3); -} - -void BytecodeGenerator::BuildNamedSuperPropertyStore(Register receiver, - Register home_object, - Register name, - Register value) { - DCHECK(Register::AreContiguous(receiver, home_object, name, value)); - Runtime::FunctionId function_id = is_strict(language_mode()) - ? Runtime::kStoreToSuper_Strict - : Runtime::kStoreToSuper_Sloppy; - builder()->CallRuntime(function_id, receiver, 4); -} - -void BytecodeGenerator::BuildKeyedSuperPropertyStore(Register receiver, - Register home_object, - Register key, - Register value) { - DCHECK(Register::AreContiguous(receiver, home_object, key, value)); - Runtime::FunctionId function_id = is_strict(language_mode()) - ? Runtime::kStoreKeyedToSuper_Strict - : Runtime::kStoreKeyedToSuper_Sloppy; - builder()->CallRuntime(function_id, receiver, 4); -} - void BytecodeGenerator::BuildAbort(BailoutReason bailout_reason) { RegisterAllocationScope register_scope(this); Register reason = register_allocator()->NewRegister(); builder() ->LoadLiteral(Smi::FromInt(static_cast(bailout_reason))) .StoreAccumulatorInRegister(reason) - .CallRuntime(Runtime::kAbort, reason, 1); + .CallRuntime(Runtime::kAbort, reason); } void BytecodeGenerator::BuildThrowReferenceError(Handle name) { RegisterAllocationScope register_scope(this); Register name_reg = register_allocator()->NewRegister(); builder()->LoadLiteral(name).StoreAccumulatorInRegister(name_reg).CallRuntime( - Runtime::kThrowReferenceError, name_reg, 1); + Runtime::kThrowReferenceError, name_reg); } void BytecodeGenerator::BuildThrowIfHole(Handle name) { @@ -2166,7 +1941,7 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable, if (mode != CONST || op == Token::INIT) { builder()->StoreAccumulatorInRegister(destination); } else if (variable->throw_on_const_assignment(language_mode())) { - builder()->CallRuntime(Runtime::kThrowConstAssignError, Register(), 0); + builder()->CallRuntime(Runtime::kThrowConstAssignError); } break; } @@ -2201,7 +1976,7 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable, if (mode != CONST || op == Token::INIT) { builder()->StoreContextSlot(context_reg, variable->index(), depth); } else if (variable->throw_on_const_assignment(language_mode())) { - builder()->CallRuntime(Runtime::kThrowConstAssignError, Register(), 0); + builder()->CallRuntime(Runtime::kThrowConstAssignError); } break; } @@ -2213,7 +1988,7 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable, DCHECK(IsDeclaredVariableMode(mode)); if (mode == CONST && op != Token::INIT) { - builder()->CallRuntime(Runtime::kThrowConstAssignError, Register(), 0); + builder()->CallRuntime(Runtime::kThrowConstAssignError); break; } @@ -2228,14 +2003,12 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable, auto it = mod->regular_exports().find(variable->raw_name()); DCHECK(it != mod->regular_exports().end()); - register_allocator()->PrepareForConsecutiveAllocations(2); - Register export_name = register_allocator()->NextConsecutiveRegister(); - Register value = register_allocator()->NextConsecutiveRegister(); + RegisterList args = register_allocator()->NewRegisterList(2); builder() - ->StoreAccumulatorInRegister(value) + ->StoreAccumulatorInRegister(args[1]) .LoadLiteral(it->second->export_name->string()) - .StoreAccumulatorInRegister(export_name) - .CallRuntime(Runtime::kStoreModuleExport, export_name, 2); + .StoreAccumulatorInRegister(args[0]) + .CallRuntime(Runtime::kStoreModuleExport, args); break; } } @@ -2243,7 +2016,8 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable, void BytecodeGenerator::VisitAssignment(Assignment* expr) { DCHECK(expr->target()->IsValidReferenceExpressionOrThis()); - Register object, key, home_object, value; + Register object, key; + RegisterList super_property_args; Handle name; // Left-hand side can only be a property, a global or a variable slot. @@ -2262,44 +2036,29 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) { } case KEYED_PROPERTY: { object = VisitForRegisterValue(property->obj()); - if (expr->is_compound()) { - // Use VisitForAccumulator and store to register so that the key is - // still in the accumulator for loading the old value below. - key = register_allocator()->NewRegister(); - VisitForAccumulatorValue(property->key()); - builder()->StoreAccumulatorInRegister(key); - } else { - key = VisitForRegisterValue(property->key()); - } + key = VisitForRegisterValue(property->key()); break; } case NAMED_SUPER_PROPERTY: { - register_allocator()->PrepareForConsecutiveAllocations(4); - object = register_allocator()->NextConsecutiveRegister(); - home_object = register_allocator()->NextConsecutiveRegister(); - key = register_allocator()->NextConsecutiveRegister(); - value = register_allocator()->NextConsecutiveRegister(); + super_property_args = register_allocator()->NewRegisterList(4); SuperPropertyReference* super_property = property->obj()->AsSuperPropertyReference(); - VisitForRegisterValue(super_property->this_var(), object); - VisitForRegisterValue(super_property->home_object(), home_object); + VisitForRegisterValue(super_property->this_var(), super_property_args[0]); + VisitForRegisterValue(super_property->home_object(), + super_property_args[1]); builder() ->LoadLiteral(property->key()->AsLiteral()->AsPropertyName()) - .StoreAccumulatorInRegister(key); + .StoreAccumulatorInRegister(super_property_args[2]); break; } case KEYED_SUPER_PROPERTY: { - register_allocator()->PrepareForConsecutiveAllocations(4); - object = register_allocator()->NextConsecutiveRegister(); - home_object = register_allocator()->NextConsecutiveRegister(); - key = register_allocator()->NextConsecutiveRegister(); - value = register_allocator()->NextConsecutiveRegister(); - builder()->StoreAccumulatorInRegister(value); + super_property_args = register_allocator()->NewRegisterList(4); SuperPropertyReference* super_property = property->obj()->AsSuperPropertyReference(); - VisitForRegisterValue(super_property->this_var(), object); - VisitForRegisterValue(super_property->home_object(), home_object); - VisitForRegisterValue(property->key(), key); + VisitForRegisterValue(super_property->this_var(), super_property_args[0]); + VisitForRegisterValue(super_property->home_object(), + super_property_args[1]); + VisitForRegisterValue(property->key(), super_property_args[2]); break; } } @@ -2307,17 +2066,16 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) { // Evaluate the value and potentially handle compound assignments by loading // the left-hand side value and performing a binary operation. if (expr->is_compound()) { - Register old_value; + Register old_value = register_allocator()->NewRegister(); switch (assign_type) { case VARIABLE: { VariableProxy* proxy = expr->target()->AsVariableProxy(); - old_value = VisitVariableLoadForRegisterValue( - proxy->var(), proxy->VariableFeedbackSlot()); + VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot()); + builder()->StoreAccumulatorInRegister(old_value); break; } case NAMED_PROPERTY: { FeedbackVectorSlot slot = property->PropertyFeedbackSlot(); - old_value = register_allocator()->NewRegister(); builder() ->LoadNamedProperty(object, name, feedback_index(slot)) .StoreAccumulatorInRegister(old_value); @@ -2327,22 +2085,23 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) { // Key is already in accumulator at this point due to evaluating the // LHS above. FeedbackVectorSlot slot = property->PropertyFeedbackSlot(); - old_value = register_allocator()->NewRegister(); builder() ->LoadKeyedProperty(object, feedback_index(slot)) .StoreAccumulatorInRegister(old_value); break; } case NAMED_SUPER_PROPERTY: { - old_value = register_allocator()->NewRegister(); - BuildNamedSuperPropertyLoad(object, home_object, key); - builder()->StoreAccumulatorInRegister(old_value); + builder() + ->CallRuntime(Runtime::kLoadFromSuper, + super_property_args.Truncate(3)) + .StoreAccumulatorInRegister(old_value); break; } case KEYED_SUPER_PROPERTY: { - old_value = register_allocator()->NewRegister(); - BuildKeyedSuperPropertyLoad(object, home_object, key); - builder()->StoreAccumulatorInRegister(old_value); + builder() + ->CallRuntime(Runtime::kLoadKeyedFromSuper, + super_property_args.Truncate(3)) + .StoreAccumulatorInRegister(old_value); break; } } @@ -2375,17 +2134,18 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) { language_mode()); break; case NAMED_SUPER_PROPERTY: { - builder()->StoreAccumulatorInRegister(value); - BuildNamedSuperPropertyStore(object, home_object, key, value); + builder() + ->StoreAccumulatorInRegister(super_property_args[3]) + .CallRuntime(StoreToSuperRuntimeId(), super_property_args); break; } case KEYED_SUPER_PROPERTY: { - builder()->StoreAccumulatorInRegister(value); - BuildKeyedSuperPropertyStore(object, home_object, key, value); + builder() + ->StoreAccumulatorInRegister(super_property_args[3]) + .CallRuntime(StoreKeyedToSuperRuntimeId(), super_property_args); break; } } - execution_result()->SetResultInAccumulator(); } void BytecodeGenerator::VisitYield(Yield* expr) { @@ -2415,12 +2175,12 @@ void BytecodeGenerator::VisitYield(Yield* expr) { Register input = register_allocator()->NewRegister(); builder() - ->CallRuntime(Runtime::kInlineGeneratorGetInputOrDebugPos, generator, 1) + ->CallRuntime(Runtime::kInlineGeneratorGetInputOrDebugPos, generator) .StoreAccumulatorInRegister(input); Register resume_mode = register_allocator()->NewRegister(); builder() - ->CallRuntime(Runtime::kInlineGeneratorGetResumeMode, generator, 1) + ->CallRuntime(Runtime::kInlineGeneratorGetResumeMode, generator) .StoreAccumulatorInRegister(resume_mode); // Now dispatch on resume mode. @@ -2440,14 +2200,12 @@ void BytecodeGenerator::VisitYield(Yield* expr) { builder()->Bind(&resume_with_return); { - register_allocator()->PrepareForConsecutiveAllocations(2); - Register value = register_allocator()->NextConsecutiveRegister(); - Register done = register_allocator()->NextConsecutiveRegister(); + RegisterList args = register_allocator()->NewRegisterList(2); builder() - ->MoveRegister(input, value) + ->MoveRegister(input, args[0]) .LoadTrue() - .StoreAccumulatorInRegister(done) - .CallRuntime(Runtime::kInlineCreateIterResultObject, value, 2); + .StoreAccumulatorInRegister(args[1]) + .CallRuntime(Runtime::kInlineCreateIterResultObject, args); execution_control()->ReturnAccumulator(); } @@ -2463,18 +2221,12 @@ void BytecodeGenerator::VisitYield(Yield* expr) { builder()->Bind(&resume_with_next); builder()->LoadAccumulatorWithRegister(input); } - execution_result()->SetResultInAccumulator(); } void BytecodeGenerator::VisitThrow(Throw* expr) { VisitForAccumulatorValue(expr->exception()); builder()->SetExpressionPosition(expr); builder()->Throw(); - // Throw statements are modeled as expressions instead of statements. These - // are converted from assignment statements in Rewriter::ReWrite pass. An - // assignment statement expects a value in the accumulator. This is a hack to - // avoid DCHECK fails assert accumulator has been set. - execution_result()->SetResultInAccumulator(); } void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) { @@ -2502,56 +2254,45 @@ void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) { VisitKeyedSuperPropertyLoad(expr, Register::invalid_value()); break; } - execution_result()->SetResultInAccumulator(); } void BytecodeGenerator::VisitPropertyLoadForAccumulator(Register obj, Property* expr) { - AccumulatorResultScope result_scope(this); + ValueResultScope result_scope(this); VisitPropertyLoad(obj, expr); } void BytecodeGenerator::VisitNamedSuperPropertyLoad(Property* property, Register opt_receiver_out) { RegisterAllocationScope register_scope(this); - register_allocator()->PrepareForConsecutiveAllocations(3); - - Register receiver, home_object, name; - receiver = register_allocator()->NextConsecutiveRegister(); - home_object = register_allocator()->NextConsecutiveRegister(); - name = register_allocator()->NextConsecutiveRegister(); SuperPropertyReference* super_property = property->obj()->AsSuperPropertyReference(); - VisitForRegisterValue(super_property->this_var(), receiver); - VisitForRegisterValue(super_property->home_object(), home_object); + RegisterList args = register_allocator()->NewRegisterList(3); + VisitForRegisterValue(super_property->this_var(), args[0]); + VisitForRegisterValue(super_property->home_object(), args[1]); builder() ->LoadLiteral(property->key()->AsLiteral()->AsPropertyName()) - .StoreAccumulatorInRegister(name); - BuildNamedSuperPropertyLoad(receiver, home_object, name); + .StoreAccumulatorInRegister(args[2]) + .CallRuntime(Runtime::kLoadFromSuper, args); if (opt_receiver_out.is_valid()) { - builder()->MoveRegister(receiver, opt_receiver_out); + builder()->MoveRegister(args[0], opt_receiver_out); } } void BytecodeGenerator::VisitKeyedSuperPropertyLoad(Property* property, Register opt_receiver_out) { RegisterAllocationScope register_scope(this); - register_allocator()->PrepareForConsecutiveAllocations(3); - - Register receiver, home_object, key; - receiver = register_allocator()->NextConsecutiveRegister(); - home_object = register_allocator()->NextConsecutiveRegister(); - key = register_allocator()->NextConsecutiveRegister(); SuperPropertyReference* super_property = property->obj()->AsSuperPropertyReference(); - VisitForRegisterValue(super_property->this_var(), receiver); - VisitForRegisterValue(super_property->home_object(), home_object); - VisitForRegisterValue(property->key(), key); - BuildKeyedSuperPropertyLoad(receiver, home_object, key); + RegisterList args = register_allocator()->NewRegisterList(3); + VisitForRegisterValue(super_property->this_var(), args[0]); + VisitForRegisterValue(super_property->home_object(), args[1]); + VisitForRegisterValue(property->key(), args[2]); + builder()->CallRuntime(Runtime::kLoadKeyedFromSuper, args); if (opt_receiver_out.is_valid()) { - builder()->MoveRegister(receiver, opt_receiver_out); + builder()->MoveRegister(args[0], opt_receiver_out); } } @@ -2566,36 +2307,13 @@ void BytecodeGenerator::VisitProperty(Property* expr) { } } -Register BytecodeGenerator::VisitArguments(ZoneList* args) { - if (args->length() == 0) { - return Register(); +void BytecodeGenerator::VisitArguments(ZoneList* args, + RegisterList arg_regs, + size_t first_argument_register) { + // Visit arguments. + for (int i = 0; i < static_cast(args->length()); i++) { + VisitForRegisterValue(args->at(i), arg_regs[first_argument_register + i]); } - - // Visit arguments and place in a contiguous block of temporary - // registers. Return the first temporary register corresponding to - // the first argument. - // - // NB the caller may have already called - // PrepareForConsecutiveAllocations() with args->length() + N. The - // second call here will be a no-op provided there have been N or - // less calls to NextConsecutiveRegister(). Otherwise, the arguments - // here will be consecutive, but they will not be consecutive with - // earlier consecutive allocations made by the caller. - register_allocator()->PrepareForConsecutiveAllocations(args->length()); - - // Visit for first argument that goes into returned register - Register first_arg = register_allocator()->NextConsecutiveRegister(); - VisitForAccumulatorValue(args->at(0)); - builder()->StoreAccumulatorInRegister(first_arg); - - // Visit remaining arguments - for (int i = 1; i < static_cast(args->length()); i++) { - Register ith_arg = register_allocator()->NextConsecutiveRegister(); - VisitForAccumulatorValue(args->at(i)); - builder()->StoreAccumulatorInRegister(ith_arg); - DCHECK(ith_arg.index() - i == first_arg.index()); - } - return first_arg; } void BytecodeGenerator::VisitCall(Call* expr) { @@ -2606,18 +2324,15 @@ void BytecodeGenerator::VisitCall(Call* expr) { return VisitCallSuper(expr); } + Register callee = register_allocator()->NewRegister(); + + // Add an argument register for the receiver. + RegisterList args = + register_allocator()->NewRegisterList(expr->arguments()->length() + 1); + Register receiver = args[0]; + // Prepare the callee and the receiver to the function call. This depends on // the semantics of the underlying call type. - - // The receiver and arguments need to be allocated consecutively for - // Call(). We allocate the callee and receiver consecutively for calls to - // %LoadLookupSlotForCall. Future optimizations could avoid this there are - // no arguments or the receiver and arguments are already consecutive. - ZoneList* args = expr->arguments(); - register_allocator()->PrepareForConsecutiveAllocations(args->length() + 2); - Register callee = register_allocator()->NextConsecutiveRegister(); - Register receiver = register_allocator()->NextConsecutiveRegister(); - switch (call_type) { case Call::NAMED_PROPERTY_CALL: case Call::KEYED_PROPERTY_CALL: { @@ -2650,8 +2365,7 @@ void BytecodeGenerator::VisitCall(Call* expr) { builder() ->LoadLiteral(variable->name()) .StoreAccumulatorInRegister(name) - .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, name, 1, - callee); + .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, name, callee); break; } // Fall through. @@ -2659,8 +2373,7 @@ void BytecodeGenerator::VisitCall(Call* expr) { } case Call::OTHER_CALL: { builder()->LoadUndefined().StoreAccumulatorInRegister(receiver); - VisitForAccumulatorValue(callee_expr); - builder()->StoreAccumulatorInRegister(callee); + VisitForRegisterValue(callee_expr, callee); break; } case Call::NAMED_SUPER_PROPERTY_CALL: { @@ -2680,42 +2393,34 @@ void BytecodeGenerator::VisitCall(Call* expr) { break; } - // Evaluate all arguments to the function call and store in sequential + // Evaluate all arguments to the function call and store in sequential args // registers. - Register arg = VisitArguments(args); - CHECK(args->length() == 0 || arg.index() == receiver.index() + 1); + VisitArguments(expr->arguments(), args, 1); // Resolve callee for a potential direct eval call. This block will mutate the // callee value. - if (call_type == Call::POSSIBLY_EVAL_CALL && args->length() > 0) { + if (call_type == Call::POSSIBLY_EVAL_CALL && + expr->arguments()->length() > 0) { RegisterAllocationScope inner_register_scope(this); - register_allocator()->PrepareForConsecutiveAllocations(6); - Register callee_for_eval = register_allocator()->NextConsecutiveRegister(); - Register source = register_allocator()->NextConsecutiveRegister(); - Register function = register_allocator()->NextConsecutiveRegister(); - Register language = register_allocator()->NextConsecutiveRegister(); - Register eval_scope_position = - register_allocator()->NextConsecutiveRegister(); - Register eval_position = register_allocator()->NextConsecutiveRegister(); - // Set up arguments for ResolvePossiblyDirectEval by copying callee, source // strings and function closure, and loading language and // position. + RegisterList runtime_call_args = register_allocator()->NewRegisterList(6); builder() - ->MoveRegister(callee, callee_for_eval) - .MoveRegister(arg, source) - .MoveRegister(Register::function_closure(), function) + ->MoveRegister(callee, runtime_call_args[0]) + .MoveRegister(args[1], runtime_call_args[1]) + .MoveRegister(Register::function_closure(), runtime_call_args[2]) .LoadLiteral(Smi::FromInt(language_mode())) - .StoreAccumulatorInRegister(language) + .StoreAccumulatorInRegister(runtime_call_args[3]) .LoadLiteral( Smi::FromInt(execution_context()->scope()->start_position())) - .StoreAccumulatorInRegister(eval_scope_position) + .StoreAccumulatorInRegister(runtime_call_args[4]) .LoadLiteral(Smi::FromInt(expr->position())) - .StoreAccumulatorInRegister(eval_position); + .StoreAccumulatorInRegister(runtime_call_args[5]); // Call ResolvePossiblyDirectEval and modify the callee. builder() - ->CallRuntime(Runtime::kResolvePossiblyDirectEval, callee_for_eval, 6) + ->CallRuntime(Runtime::kResolvePossiblyDirectEval, runtime_call_args) .StoreAccumulatorInRegister(callee); } @@ -2732,9 +2437,7 @@ void BytecodeGenerator::VisitCall(Call* expr) { } else { feedback_slot_index = feedback_index(expr->CallFeedbackICSlot()); } - builder()->Call(callee, receiver, 1 + args->length(), feedback_slot_index, - expr->tail_call_mode()); - execution_result()->SetResultInAccumulator(); + builder()->Call(callee, args, feedback_slot_index, expr->tail_call_mode()); } void BytecodeGenerator::VisitCallSuper(Call* expr) { @@ -2742,17 +2445,15 @@ void BytecodeGenerator::VisitCallSuper(Call* expr) { SuperCallReference* super = expr->expression()->AsSuperCallReference(); // Prepare the constructor to the super call. - Register this_function = register_allocator()->NewRegister(); - VisitForAccumulatorValue(super->this_function_var()); - builder() - ->StoreAccumulatorInRegister(this_function) - .CallRuntime(Runtime::kInlineGetSuperConstructor, this_function, 1); + Register this_function = VisitForRegisterValue(super->this_function_var()); + builder()->CallRuntime(Runtime::kInlineGetSuperConstructor, this_function); Register constructor = this_function; // Re-use dead this_function register. builder()->StoreAccumulatorInRegister(constructor); - ZoneList* args = expr->arguments(); - Register first_arg = VisitArguments(args); + RegisterList args = + register_allocator()->NewRegisterList(expr->arguments()->length()); + VisitArguments(expr->arguments(), args); // The new target is loaded into the accumulator from the // {new.target} variable. @@ -2766,52 +2467,45 @@ void BytecodeGenerator::VisitCallSuper(Call* expr) { // Type feedback is not necessary for super constructor calls. The type // information can be inferred in most cases. Slot id 0 indicates type // feedback is not required. - builder()->New(constructor, first_arg, args->length(), 0); - execution_result()->SetResultInAccumulator(); + builder()->New(constructor, args, 0); } void BytecodeGenerator::VisitCallNew(CallNew* expr) { - Register constructor = register_allocator()->NewRegister(); - VisitForAccumulatorValue(expr->expression()); - builder()->StoreAccumulatorInRegister(constructor); - - ZoneList* args = expr->arguments(); - Register first_arg = VisitArguments(args); + Register constructor = VisitForRegisterValue(expr->expression()); + RegisterList args = + register_allocator()->NewRegisterList(expr->arguments()->length()); + VisitArguments(expr->arguments(), args); builder()->SetExpressionPosition(expr); // The accumulator holds new target which is the same as the // constructor for CallNew. builder() ->LoadAccumulatorWithRegister(constructor) - .New(constructor, first_arg, args->length(), - feedback_index(expr->CallNewFeedbackSlot())); - execution_result()->SetResultInAccumulator(); + .New(constructor, args, feedback_index(expr->CallNewFeedbackSlot())); } void BytecodeGenerator::VisitCallRuntime(CallRuntime* expr) { - ZoneList* args = expr->arguments(); if (expr->is_jsruntime()) { // Allocate a register for the receiver and load it with undefined. - register_allocator()->PrepareForConsecutiveAllocations(1 + args->length()); - Register receiver = register_allocator()->NextConsecutiveRegister(); + RegisterList args = + register_allocator()->NewRegisterList(expr->arguments()->length() + 1); + Register receiver = args[0]; builder()->LoadUndefined().StoreAccumulatorInRegister(receiver); - Register first_arg = VisitArguments(args); - CHECK(args->length() == 0 || first_arg.index() == receiver.index() + 1); - builder()->CallJSRuntime(expr->context_index(), receiver, - 1 + args->length()); + VisitArguments(expr->arguments(), args, 1); + builder()->CallJSRuntime(expr->context_index(), args); } else { // Evaluate all arguments to the runtime call. - Register first_arg = VisitArguments(args); + RegisterList args = + register_allocator()->NewRegisterList(expr->arguments()->length()); + VisitArguments(expr->arguments(), args); Runtime::FunctionId function_id = expr->function()->function_id; - builder()->CallRuntime(function_id, first_arg, args->length()); + builder()->CallRuntime(function_id, args); } - execution_result()->SetResultInAccumulator(); } void BytecodeGenerator::VisitVoid(UnaryOperation* expr) { VisitForEffect(expr->expression()); builder()->LoadUndefined(); - execution_result()->SetResultInAccumulator(); } void BytecodeGenerator::VisitTypeOf(UnaryOperation* expr) { @@ -2825,7 +2519,6 @@ void BytecodeGenerator::VisitTypeOf(UnaryOperation* expr) { VisitForAccumulatorValue(expr->expression()); } builder()->TypeOf(); - execution_result()->SetResultInAccumulator(); } void BytecodeGenerator::VisitNot(UnaryOperation* expr) { @@ -2842,7 +2535,6 @@ void BytecodeGenerator::VisitNot(UnaryOperation* expr) { } else { VisitForAccumulatorValue(expr->expression()); builder()->LogicalNot(); - execution_result()->SetResultInAccumulator(); } } @@ -2917,7 +2609,7 @@ void BytecodeGenerator::VisitDelete(UnaryOperation* expr) { builder() ->LoadLiteral(variable->name()) .StoreAccumulatorInRegister(name_reg) - .CallRuntime(Runtime::kDeleteLookupSlot, name_reg, 1); + .CallRuntime(Runtime::kDeleteLookupSlot, name_reg); break; } default: @@ -2928,7 +2620,6 @@ void BytecodeGenerator::VisitDelete(UnaryOperation* expr) { VisitForEffect(expr->expression()); builder()->LoadTrue(); } - execution_result()->SetResultInAccumulator(); } void BytecodeGenerator::VisitCountOperation(CountOperation* expr) { @@ -2941,7 +2632,8 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) { bool is_postfix = expr->is_postfix() && !execution_result()->IsEffect(); // Evaluate LHS expression and get old value. - Register object, home_object, key, old_value, value; + Register object, key, old_value; + RegisterList super_property_args; Handle name; switch (assign_type) { case VARIABLE: { @@ -2969,43 +2661,35 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) { break; } case NAMED_SUPER_PROPERTY: { - register_allocator()->PrepareForConsecutiveAllocations(4); - object = register_allocator()->NextConsecutiveRegister(); - home_object = register_allocator()->NextConsecutiveRegister(); - key = register_allocator()->NextConsecutiveRegister(); - value = register_allocator()->NextConsecutiveRegister(); + super_property_args = register_allocator()->NewRegisterList(4); + RegisterList load_super_args = super_property_args.Truncate(3); SuperPropertyReference* super_property = property->obj()->AsSuperPropertyReference(); - VisitForRegisterValue(super_property->this_var(), object); - VisitForRegisterValue(super_property->home_object(), home_object); + VisitForRegisterValue(super_property->this_var(), load_super_args[0]); + VisitForRegisterValue(super_property->home_object(), load_super_args[1]); builder() ->LoadLiteral(property->key()->AsLiteral()->AsPropertyName()) - .StoreAccumulatorInRegister(key); - BuildNamedSuperPropertyLoad(object, home_object, key); + .StoreAccumulatorInRegister(load_super_args[2]) + .CallRuntime(Runtime::kLoadFromSuper, load_super_args); break; } case KEYED_SUPER_PROPERTY: { - register_allocator()->PrepareForConsecutiveAllocations(4); - object = register_allocator()->NextConsecutiveRegister(); - home_object = register_allocator()->NextConsecutiveRegister(); - key = register_allocator()->NextConsecutiveRegister(); - value = register_allocator()->NextConsecutiveRegister(); - builder()->StoreAccumulatorInRegister(value); + super_property_args = register_allocator()->NewRegisterList(4); + RegisterList load_super_args = super_property_args.Truncate(3); SuperPropertyReference* super_property = property->obj()->AsSuperPropertyReference(); - VisitForRegisterValue(super_property->this_var(), object); - VisitForRegisterValue(super_property->home_object(), home_object); - VisitForRegisterValue(property->key(), key); - BuildKeyedSuperPropertyLoad(object, home_object, key); + VisitForRegisterValue(super_property->this_var(), load_super_args[0]); + VisitForRegisterValue(super_property->home_object(), load_super_args[1]); + VisitForRegisterValue(property->key(), load_super_args[2]); + builder()->CallRuntime(Runtime::kLoadKeyedFromSuper, load_super_args); break; } } // Save result for postfix expressions. if (is_postfix) { - old_value = register_allocator()->outer()->NewRegister(); - // Convert old value into a number before saving it. + old_value = register_allocator()->NewRegister(); builder()->ConvertAccumulatorToNumber(old_value); } @@ -3033,22 +2717,22 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) { break; } case NAMED_SUPER_PROPERTY: { - builder()->StoreAccumulatorInRegister(value); - BuildNamedSuperPropertyStore(object, home_object, key, value); + builder() + ->StoreAccumulatorInRegister(super_property_args[3]) + .CallRuntime(StoreToSuperRuntimeId(), super_property_args); break; } case KEYED_SUPER_PROPERTY: { - builder()->StoreAccumulatorInRegister(value); - BuildKeyedSuperPropertyStore(object, home_object, key, value); + builder() + ->StoreAccumulatorInRegister(super_property_args[3]) + .CallRuntime(StoreKeyedToSuperRuntimeId(), super_property_args); break; } } // Restore old value for postfix expressions. if (is_postfix) { - execution_result()->SetResultInRegister(old_value); - } else { - execution_result()->SetResultInAccumulator(); + builder()->LoadAccumulatorWithRegister(old_value); } } @@ -3075,7 +2759,6 @@ void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) { builder()->SetExpressionPosition(expr); FeedbackVectorSlot slot = expr->CompareOperationFeedbackSlot(); builder()->CompareOperation(expr->op(), lhs, feedback_index(slot)); - execution_result()->SetResultInAccumulator(); } void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) { @@ -3085,7 +2768,6 @@ void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) { VisitForAccumulatorValue(expr->right()); FeedbackVectorSlot slot = expr->BinaryOperationFeedbackSlot(); builder()->BinaryOperation(expr->op(), lhs, feedback_index(slot)); - execution_result()->SetResultInAccumulator(); } void BytecodeGenerator::VisitSpread(Spread* expr) { UNREACHABLE(); } @@ -3095,7 +2777,7 @@ void BytecodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) { } void BytecodeGenerator::VisitThisFunction(ThisFunction* expr) { - execution_result()->SetResultInRegister(Register::function_closure()); + builder()->LoadAccumulatorWithRegister(Register::function_closure()); } void BytecodeGenerator::VisitSuperCallReference(SuperCallReference* expr) { @@ -3105,8 +2787,7 @@ void BytecodeGenerator::VisitSuperCallReference(SuperCallReference* expr) { void BytecodeGenerator::VisitSuperPropertyReference( SuperPropertyReference* expr) { - builder()->CallRuntime(Runtime::kThrowUnsupportedSuperError, Register(0), 0); - execution_result()->SetResultInAccumulator(); + builder()->CallRuntime(Runtime::kThrowUnsupportedSuperError); } void BytecodeGenerator::VisitCommaExpression(BinaryOperation* binop) { @@ -3146,7 +2827,6 @@ void BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) { VisitForAccumulatorValue(right); builder()->Bind(&end_label); } - execution_result()->SetResultInAccumulator(); } } @@ -3182,7 +2862,6 @@ void BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) { VisitForAccumulatorValue(right); builder()->Bind(&end_label); } - execution_result()->SetResultInAccumulator(); } } @@ -3191,44 +2870,36 @@ void BytecodeGenerator::VisitRewritableExpression(RewritableExpression* expr) { } void BytecodeGenerator::BuildNewLocalActivationContext() { - AccumulatorResultScope accumulator_execution_result(this); + ValueResultScope value_execution_result(this); Scope* scope = this->scope(); // Create the appropriate context. if (scope->is_script_scope()) { - RegisterAllocationScope register_scope(this); - register_allocator()->PrepareForConsecutiveAllocations(2); - Register closure = register_allocator()->NextConsecutiveRegister(); - Register scope_info = register_allocator()->NextConsecutiveRegister(); + RegisterList args = register_allocator()->NewRegisterList(2); builder() ->LoadAccumulatorWithRegister(Register::function_closure()) - .StoreAccumulatorInRegister(closure) + .StoreAccumulatorInRegister(args[0]) .LoadLiteral(scope->scope_info()) - .StoreAccumulatorInRegister(scope_info) - .CallRuntime(Runtime::kNewScriptContext, closure, 2); + .StoreAccumulatorInRegister(args[1]) + .CallRuntime(Runtime::kNewScriptContext, args); } else if (scope->is_module_scope()) { // We don't need to do anything for the outer script scope. DCHECK(scope->outer_scope()->is_script_scope()); - RegisterAllocationScope register_scope(this); - register_allocator()->PrepareForConsecutiveAllocations(3); - Register module = register_allocator()->NextConsecutiveRegister(); - Register closure = register_allocator()->NextConsecutiveRegister(); - Register scope_info = register_allocator()->NextConsecutiveRegister(); // A JSFunction representing a module is called with the module object as // its sole argument, which we pass on to PushModuleContext. + RegisterList args = register_allocator()->NewRegisterList(3); builder() - ->MoveRegister(builder()->Parameter(1), module) + ->MoveRegister(builder()->Parameter(1), args[0]) .LoadAccumulatorWithRegister(Register::function_closure()) - .StoreAccumulatorInRegister(closure) + .StoreAccumulatorInRegister(args[1]) .LoadLiteral(scope->scope_info()) - .StoreAccumulatorInRegister(scope_info) - .CallRuntime(Runtime::kPushModuleContext, module, 3); + .StoreAccumulatorInRegister(args[2]) + .CallRuntime(Runtime::kPushModuleContext, args); } else { int slot_count = scope->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; builder()->CreateFunctionContext(slot_count); } - execution_result()->SetResultInAccumulator(); } void BytecodeGenerator::BuildLocalActivationContextInitialization() { @@ -3260,28 +2931,26 @@ void BytecodeGenerator::BuildLocalActivationContextInitialization() { } void BytecodeGenerator::BuildNewLocalBlockContext(Scope* scope) { - AccumulatorResultScope accumulator_execution_result(this); + ValueResultScope value_execution_result(this); DCHECK(scope->is_block_scope()); VisitFunctionClosureForContext(); builder()->CreateBlockContext(scope->scope_info()); - execution_result()->SetResultInAccumulator(); } void BytecodeGenerator::BuildNewLocalWithContext(Scope* scope) { - AccumulatorResultScope accumulator_execution_result(this); + ValueResultScope value_execution_result(this); Register extension_object = register_allocator()->NewRegister(); builder()->ConvertAccumulatorToObject(extension_object); VisitFunctionClosureForContext(); builder()->CreateWithContext(extension_object, scope->scope_info()); - execution_result()->SetResultInAccumulator(); } void BytecodeGenerator::BuildNewLocalCatchContext(Variable* variable, Scope* scope) { - AccumulatorResultScope accumulator_execution_result(this); + ValueResultScope value_execution_result(this); DCHECK(variable->IsContextSlot()); Register exception = register_allocator()->NewRegister(); @@ -3289,17 +2958,14 @@ void BytecodeGenerator::BuildNewLocalCatchContext(Variable* variable, VisitFunctionClosureForContext(); builder()->CreateCatchContext(exception, variable->name(), scope->scope_info()); - execution_result()->SetResultInAccumulator(); } void BytecodeGenerator::VisitObjectLiteralAccessor( Register home_object, ObjectLiteralProperty* property, Register value_out) { - // TODO(rmcilroy): Replace value_out with VisitForRegister(); if (property == nullptr) { builder()->LoadNull().StoreAccumulatorInRegister(value_out); } else { - VisitForAccumulatorValue(property->value()); - builder()->StoreAccumulatorInRegister(value_out); + VisitForRegisterValue(property->value(), value_out); VisitSetHomeObject(value_out, home_object, property); } } @@ -3367,7 +3033,7 @@ void BytecodeGenerator::VisitNewTargetVariable(Variable* variable) { } void BytecodeGenerator::VisitFunctionClosureForContext() { - AccumulatorResultScope accumulator_execution_result(this); + ValueResultScope value_execution_result(this); DeclarationScope* closure_scope = execution_context()->scope()->GetClosureScope(); if (closure_scope->is_script_scope()) { @@ -3390,12 +3056,11 @@ void BytecodeGenerator::VisitFunctionClosureForContext() { closure_scope->is_module_scope()); builder()->LoadAccumulatorWithRegister(Register::function_closure()); } - execution_result()->SetResultInAccumulator(); } // Visits the expression |expr| and places the result in the accumulator. void BytecodeGenerator::VisitForAccumulatorValue(Expression* expr) { - AccumulatorResultScope accumulator_scope(this); + ValueResultScope accumulator_scope(this); Visit(expr); } @@ -3416,16 +3081,17 @@ void BytecodeGenerator::VisitForEffect(Expression* expr) { // Visits the expression |expr| and returns the register containing // the expression result. Register BytecodeGenerator::VisitForRegisterValue(Expression* expr) { - RegisterResultScope register_scope(this); - Visit(expr); - return register_scope.ResultRegister(); + VisitForAccumulatorValue(expr); + Register result = register_allocator()->NewRegister(); + builder()->StoreAccumulatorInRegister(result); + return result; } // Visits the expression |expr| and stores the expression result in // |destination|. void BytecodeGenerator::VisitForRegisterValue(Expression* expr, Register destination) { - AccumulatorResultScope register_scope(this); + ValueResultScope register_scope(this); Visit(expr); builder()->StoreAccumulatorInRegister(destination); } @@ -3474,6 +3140,16 @@ int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { return TypeFeedbackVector::GetIndex(slot); } +Runtime::FunctionId BytecodeGenerator::StoreToSuperRuntimeId() { + return is_strict(language_mode()) ? Runtime::kStoreToSuper_Strict + : Runtime::kStoreToSuper_Sloppy; +} + +Runtime::FunctionId BytecodeGenerator::StoreKeyedToSuperRuntimeId() { + return is_strict(language_mode()) ? Runtime::kStoreKeyedToSuper_Strict + : Runtime::kStoreKeyedToSuper_Sloppy; +} + } // namespace interpreter } // namespace internal } // namespace v8 diff --git a/src/interpreter/bytecode-generator.h b/src/interpreter/bytecode-generator.h index a483dfb6a8..c738e0fafc 100644 --- a/src/interpreter/bytecode-generator.h +++ b/src/interpreter/bytecode-generator.h @@ -36,7 +36,6 @@ class BytecodeGenerator final : public AstVisitor { void VisitStatements(ZoneList* statments); private: - class AccumulatorResultScope; class ContextScope; class ControlScope; class ControlScopeForBreakable; @@ -47,9 +46,9 @@ class BytecodeGenerator final : public AstVisitor { class ExpressionResultScope; class EffectResultScope; class GlobalDeclarationsBuilder; - class RegisterResultScope; class RegisterAllocationScope; class TestResultScope; + class ValueResultScope; enum class TestFallthrough { kThen, kElse, kNone }; @@ -73,8 +72,10 @@ class BytecodeGenerator final : public AstVisitor { // Used by flow control routines to evaluate loop condition. void VisitCondition(Expression* expr); - // Helper visitors which perform common operations. - Register VisitArguments(ZoneList* arguments); + // Visit the arguments expressions in |args| and store them in |args_regs| + // starting at register |first_argument_register| in the list. + void VisitArguments(ZoneList* args, RegisterList arg_regs, + size_t first_argument_register = 0); // Visit a keyed super property load. The optional // |opt_receiver_out| register will have the receiver stored to it @@ -104,15 +105,6 @@ class BytecodeGenerator final : public AstVisitor { void VisitVariableAssignment(Variable* variable, Token::Value op, FeedbackVectorSlot slot); - void BuildNamedSuperPropertyStore(Register receiver, Register home_object, - Register name, Register value); - void BuildKeyedSuperPropertyStore(Register receiver, Register home_object, - Register key, Register value); - void BuildNamedSuperPropertyLoad(Register receiver, Register home_object, - Register name); - void BuildKeyedSuperPropertyLoad(Register receiver, Register home_object, - Register key); - void BuildAbort(BailoutReason bailout_reason); void BuildThrowIfHole(Handle name); void BuildThrowIfNotHole(Handle name); @@ -139,7 +131,6 @@ class BytecodeGenerator final : public AstVisitor { void VisitClassLiteralForRuntimeDefinition(ClassLiteral* expr); void VisitClassLiteralProperties(ClassLiteral* expr, Register literal, Register prototype); - void VisitClassLiteralStaticPrototypeWithComputedName(Register name); void VisitThisFunctionVariable(Variable* variable); void VisitNewTargetVariable(Variable* variable); void VisitBlockDeclarationsAndStatements(Block* stmt); @@ -169,13 +160,10 @@ class BytecodeGenerator final : public AstVisitor { void VisitForTest(Expression* expr, BytecodeLabels* then_labels, BytecodeLabels* else_labels, TestFallthrough fallthrough); - // Methods for tracking and remapping register. - void RecordStoreToRegister(Register reg); - Register LoadFromAliasedRegister(Register reg); - - // Initialize an array of temporary registers with consecutive registers. - template - void InitializeWithConsecutiveRegisters(Register (®isters)[N]); + // Returns the runtime function id for a store to super for the function's + // language mode. + inline Runtime::FunctionId StoreToSuperRuntimeId(); + inline Runtime::FunctionId StoreKeyedToSuperRuntimeId(); inline BytecodeArrayBuilder* builder() const { return builder_; } inline Zone* zone() const { return zone_; } @@ -194,12 +182,8 @@ class BytecodeGenerator final : public AstVisitor { execution_result_ = execution_result; } ExpressionResultScope* execution_result() const { return execution_result_; } - inline void set_register_allocator( - RegisterAllocationScope* register_allocator) { - register_allocator_ = register_allocator; - } - RegisterAllocationScope* register_allocator() const { - return register_allocator_; + BytecodeRegisterAllocator* register_allocator() const { + return builder()->register_allocator(); } GlobalDeclarationsBuilder* globals_builder() { return globals_builder_; } @@ -223,7 +207,6 @@ class BytecodeGenerator final : public AstVisitor { ControlScope* execution_control_; ContextScope* execution_context_; ExpressionResultScope* execution_result_; - RegisterAllocationScope* register_allocator_; ZoneVector generator_resume_points_; Register generator_state_; diff --git a/src/interpreter/bytecode-register-allocator.cc b/src/interpreter/bytecode-register-allocator.cc deleted file mode 100644 index 10afcdc76d..0000000000 --- a/src/interpreter/bytecode-register-allocator.cc +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright 2015 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. - -#include "src/interpreter/bytecode-register-allocator.h" - -#include "src/interpreter/bytecode-array-builder.h" - -namespace v8 { -namespace internal { -namespace interpreter { - -TemporaryRegisterAllocator::TemporaryRegisterAllocator(Zone* zone, - int allocation_base) - : free_temporaries_(zone), - allocation_base_(allocation_base), - allocation_count_(0), - observer_(nullptr) {} - -Register TemporaryRegisterAllocator::first_temporary_register() const { - DCHECK(allocation_count() > 0); - return Register(allocation_base()); -} - -Register TemporaryRegisterAllocator::last_temporary_register() const { - DCHECK(allocation_count() > 0); - return Register(allocation_base() + allocation_count() - 1); -} - -void TemporaryRegisterAllocator::set_observer( - TemporaryRegisterObserver* observer) { - DCHECK(observer_ == nullptr); - observer_ = observer; -} - -int TemporaryRegisterAllocator::AllocateTemporaryRegister() { - allocation_count_ += 1; - return allocation_base() + allocation_count() - 1; -} - -int TemporaryRegisterAllocator::BorrowTemporaryRegister() { - if (free_temporaries_.empty()) { - return AllocateTemporaryRegister(); - } else { - auto pos = free_temporaries_.begin(); - int retval = *pos; - free_temporaries_.erase(pos); - return retval; - } -} - -int TemporaryRegisterAllocator::BorrowTemporaryRegisterNotInRange( - int start_index, int end_index) { - if (free_temporaries_.empty()) { - int next_allocation = allocation_base() + allocation_count(); - while (next_allocation >= start_index && next_allocation <= end_index) { - free_temporaries_.insert(AllocateTemporaryRegister()); - next_allocation += 1; - } - return AllocateTemporaryRegister(); - } - - ZoneSet::iterator index = free_temporaries_.lower_bound(start_index); - if (index == free_temporaries_.begin()) { - // If start_index is the first free register, check for a register - // greater than end_index. - index = free_temporaries_.upper_bound(end_index); - if (index == free_temporaries_.end()) { - return AllocateTemporaryRegister(); - } - } else { - // If there is a free register < start_index - index--; - } - - int retval = *index; - free_temporaries_.erase(index); - return retval; -} - -int TemporaryRegisterAllocator::PrepareForConsecutiveTemporaryRegisters( - size_t count) { - if (count == 0) { - return -1; - } - - // TODO(oth): replace use of set<> here for free_temporaries with a - // more efficient structure. And/or partition into two searches - - // one before the translation window and one after. - - // A run will require at least |count| free temporaries. - while (free_temporaries_.size() < count) { - free_temporaries_.insert(AllocateTemporaryRegister()); - } - - // Search within existing temporaries for a run. - auto start = free_temporaries_.begin(); - size_t run_length = 0; - for (auto run_end = start; run_end != free_temporaries_.end(); run_end++) { - int expected = *start + static_cast(run_length); - if (*run_end != expected) { - start = run_end; - run_length = 0; - } - if (++run_length == count) { - return *start; - } - } - - // Continue run if possible across existing last temporary. - if (allocation_count_ > 0 && (start == free_temporaries_.end() || - *start + static_cast(run_length) != - last_temporary_register().index() + 1)) { - run_length = 0; - } - - // Pad temporaries if extended run would cross translation boundary. - Register reg_first(*start); - Register reg_last(*start + static_cast(count) - 1); - - // Ensure enough registers for run. - while (run_length++ < count) { - free_temporaries_.insert(AllocateTemporaryRegister()); - } - - int run_start = - last_temporary_register().index() - static_cast(count) + 1; - return run_start; -} - -bool TemporaryRegisterAllocator::RegisterIsLive(Register reg) const { - if (allocation_count_ > 0) { - DCHECK(reg >= first_temporary_register() && - reg <= last_temporary_register()); - return free_temporaries_.find(reg.index()) == free_temporaries_.end(); - } else { - return false; - } -} - -void TemporaryRegisterAllocator::BorrowConsecutiveTemporaryRegister( - int reg_index) { - DCHECK(free_temporaries_.find(reg_index) != free_temporaries_.end()); - free_temporaries_.erase(reg_index); -} - -void TemporaryRegisterAllocator::ReturnTemporaryRegister(int reg_index) { - DCHECK(free_temporaries_.find(reg_index) == free_temporaries_.end()); - free_temporaries_.insert(reg_index); - if (observer_) { - observer_->TemporaryRegisterFreeEvent(Register(reg_index)); - } -} - -BytecodeRegisterAllocator::BytecodeRegisterAllocator( - Zone* zone, TemporaryRegisterAllocator* allocator) - : base_allocator_(allocator), - allocated_(zone), - next_consecutive_register_(-1), - next_consecutive_count_(-1) {} - -BytecodeRegisterAllocator::~BytecodeRegisterAllocator() { - for (auto i = allocated_.rbegin(); i != allocated_.rend(); i++) { - base_allocator()->ReturnTemporaryRegister(*i); - } - allocated_.clear(); -} - -Register BytecodeRegisterAllocator::NewRegister() { - int allocated = -1; - if (next_consecutive_count_ <= 0) { - allocated = base_allocator()->BorrowTemporaryRegister(); - } else { - allocated = base_allocator()->BorrowTemporaryRegisterNotInRange( - next_consecutive_register_, - next_consecutive_register_ + next_consecutive_count_ - 1); - } - allocated_.push_back(allocated); - return Register(allocated); -} - -bool BytecodeRegisterAllocator::RegisterIsAllocatedInThisScope( - Register reg) const { - for (auto i = allocated_.begin(); i != allocated_.end(); i++) { - if (*i == reg.index()) return true; - } - return false; -} - -void BytecodeRegisterAllocator::PrepareForConsecutiveAllocations(size_t count) { - if (static_cast(count) > next_consecutive_count_) { - next_consecutive_register_ = - base_allocator()->PrepareForConsecutiveTemporaryRegisters(count); - next_consecutive_count_ = static_cast(count); - } -} - -Register BytecodeRegisterAllocator::NextConsecutiveRegister() { - DCHECK_GE(next_consecutive_register_, 0); - DCHECK_GT(next_consecutive_count_, 0); - base_allocator()->BorrowConsecutiveTemporaryRegister( - next_consecutive_register_); - allocated_.push_back(next_consecutive_register_); - next_consecutive_count_--; - return Register(next_consecutive_register_++); -} - -} // namespace interpreter -} // namespace internal -} // namespace v8 diff --git a/src/interpreter/bytecode-register-allocator.h b/src/interpreter/bytecode-register-allocator.h index 63b302a79e..ab57bf4e00 100644 --- a/src/interpreter/bytecode-register-allocator.h +++ b/src/interpreter/bytecode-register-allocator.h @@ -5,6 +5,7 @@ #ifndef V8_INTERPRETER_BYTECODE_REGISTER_ALLOCATOR_H_ #define V8_INTERPRETER_BYTECODE_REGISTER_ALLOCATOR_H_ +#include "src/interpreter/bytecode-register.h" #include "src/interpreter/bytecodes.h" #include "src/zone/zone-containers.h" @@ -12,99 +13,98 @@ namespace v8 { namespace internal { namespace interpreter { -class BytecodeArrayBuilder; -class Register; -class TemporaryRegisterObserver; - -class TemporaryRegisterAllocator final { +class RegisterList { public: - TemporaryRegisterAllocator(Zone* zone, int start_index); + RegisterList() : first_reg_index_(Register().index()), register_count_(0) {} + RegisterList(int first_reg_index, int register_count) + : first_reg_index_(first_reg_index), register_count_(register_count) {} - // Borrow a temporary register. - int BorrowTemporaryRegister(); + // Returns a new RegisterList which is a truncated version of this list, with + // |count| registers. + const RegisterList Truncate(int new_count) { + DCHECK_GE(new_count, 0); + DCHECK_LT(new_count, register_count_); + return RegisterList(first_reg_index_, new_count); + } - // Borrow a temporary register from the register range outside of - // |start_index| to |end_index|. - int BorrowTemporaryRegisterNotInRange(int start_index, int end_index); + const Register operator[](size_t i) const { + DCHECK_LT(static_cast(i), register_count_); + return Register(first_reg_index_ + static_cast(i)); + } - // Return a temporary register when no longer used. - void ReturnTemporaryRegister(int reg_index); + const Register first_register() const { + return (register_count() == 0) ? Register(0) : (*this)[0]; + } - // Ensure a run of consecutive registers is available. Each register in - // the range should be borrowed with BorrowConsecutiveTemporaryRegister(). - // Returns the start index of the run. - int PrepareForConsecutiveTemporaryRegisters(size_t count); - - // Borrow a register from a range prepared with - // PrepareForConsecutiveTemporaryRegisters(). - void BorrowConsecutiveTemporaryRegister(int reg_index); - - // Returns true if |reg| is a temporary register and is currently - // borrowed. - bool RegisterIsLive(Register reg) const; - - // Returns the first register in the range of temporary registers. - Register first_temporary_register() const; - - // Returns the last register in the range of temporary registers. - Register last_temporary_register() const; - - // Returns the start index of temporary register allocations. - int allocation_base() const { return allocation_base_; } - - // Returns the number of temporary register allocations made. - int allocation_count() const { return allocation_count_; } - - // Sets an observer for temporary register events. - void set_observer(TemporaryRegisterObserver* observer); + int register_count() const { return register_count_; } private: - // Allocate a temporary register. - int AllocateTemporaryRegister(); - - ZoneSet free_temporaries_; - int allocation_base_; - int allocation_count_; - TemporaryRegisterObserver* observer_; - - DISALLOW_COPY_AND_ASSIGN(TemporaryRegisterAllocator); + int first_reg_index_; + int register_count_; }; -class TemporaryRegisterObserver { - public: - virtual ~TemporaryRegisterObserver() {} - virtual void TemporaryRegisterFreeEvent(Register reg) = 0; -}; - -// A class that allows the instantiator to allocate temporary registers that are -// cleaned up when scope is closed. +// A class that allows the allocation of contiguous temporary registers. class BytecodeRegisterAllocator final { public: - explicit BytecodeRegisterAllocator(Zone* zone, - TemporaryRegisterAllocator* allocator); - ~BytecodeRegisterAllocator(); - Register NewRegister(); + // Enables observation of register allocation and free events. + class Observer { + public: + virtual ~Observer() {} + virtual void RegisterAllocateEvent(Register reg) = 0; + virtual void RegisterListAllocateEvent(RegisterList reg_list) = 0; + virtual void RegisterListFreeEvent(RegisterList reg_list) = 0; + }; - // Ensure |count| consecutive allocations are available. - void PrepareForConsecutiveAllocations(size_t count); + explicit BytecodeRegisterAllocator(int start_index) + : next_register_index_(start_index), + max_register_count_(start_index), + observer_(nullptr) {} + ~BytecodeRegisterAllocator() {} - // Get the next consecutive allocation after calling - // PrepareForConsecutiveAllocations. - Register NextConsecutiveRegister(); + // Returns a new register. + Register NewRegister() { + Register reg(next_register_index_++); + max_register_count_ = std::max(next_register_index_, max_register_count_); + if (observer_) { + observer_->RegisterAllocateEvent(reg); + } + return reg; + } - // Returns true if |reg| is allocated in this allocator. - bool RegisterIsAllocatedInThisScope(Register reg) const; + // Returns a consecutive list of |count| new registers. + RegisterList NewRegisterList(int count) { + RegisterList reg_list(next_register_index_, count); + next_register_index_ += count; + max_register_count_ = std::max(next_register_index_, max_register_count_); + if (observer_) { + observer_->RegisterListAllocateEvent(reg_list); + } + return reg_list; + } - // Returns true if unused consecutive allocations remain. - bool HasConsecutiveAllocations() const { return next_consecutive_count_ > 0; } + // Release all registers above |register_index|. + void ReleaseRegisters(int register_index) { + if (observer_) { + observer_->RegisterListFreeEvent( + RegisterList(register_index, next_register_index_ - register_index)); + } + next_register_index_ = register_index; + } + + // Returns true if the register |reg| is a live register. + bool RegisterIsLive(Register reg) const { + return reg.index() < next_register_index_; + } + + void set_observer(Observer* observer) { observer_ = observer; } + + int next_register_index() const { return next_register_index_; } + int maximum_register_count() const { return max_register_count_; } private: - TemporaryRegisterAllocator* base_allocator() const { return base_allocator_; } - - TemporaryRegisterAllocator* base_allocator_; - ZoneVector allocated_; - int next_consecutive_register_; - int next_consecutive_count_; + int next_register_index_; + int max_register_count_; + Observer* observer_; DISALLOW_COPY_AND_ASSIGN(BytecodeRegisterAllocator); }; diff --git a/src/interpreter/bytecode-register-optimizer.cc b/src/interpreter/bytecode-register-optimizer.cc index 12be57b48c..9ee80749bb 100644 --- a/src/interpreter/bytecode-register-optimizer.cc +++ b/src/interpreter/bytecode-register-optimizer.cc @@ -15,10 +15,12 @@ const uint32_t BytecodeRegisterOptimizer::kInvalidEquivalenceId; // register is materialized in the bytecode stream. class BytecodeRegisterOptimizer::RegisterInfo final : public ZoneObject { public: - RegisterInfo(Register reg, uint32_t equivalence_id, bool materialized) + RegisterInfo(Register reg, uint32_t equivalence_id, bool materialized, + bool allocated) : register_(reg), equivalence_id_(equivalence_id), materialized_(materialized), + allocated_(allocated), next_(this), prev_(this) {} @@ -48,12 +50,17 @@ class BytecodeRegisterOptimizer::RegisterInfo final : public ZoneObject { // exists. RegisterInfo* GetEquivalentToMaterialize(); + // Marks all temporary registers of the equivalence set as unmaterialized. + void MarkTemporariesAsUnmaterialized(Register temporary_base); + // Get an equivalent register. Returns this if none exists. RegisterInfo* GetEquivalent(); Register register_value() const { return register_; } bool materialized() const { return materialized_; } void set_materialized(bool materialized) { materialized_ = materialized; } + bool allocated() const { return allocated_; } + void set_allocated(bool allocated) { allocated_ = allocated; } void set_equivalence_id(uint32_t equivalence_id) { equivalence_id_ = equivalence_id; } @@ -63,6 +70,7 @@ class BytecodeRegisterOptimizer::RegisterInfo final : public ZoneObject { Register register_; uint32_t equivalence_id_; bool materialized_; + bool allocated_; // Equivalence set pointers. RegisterInfo* next_; @@ -155,8 +163,9 @@ BytecodeRegisterOptimizer::RegisterInfo::GetEquivalentToMaterialize() { if (visitor->materialized()) { return nullptr; } - if (best_info == nullptr || - visitor->register_value() < best_info->register_value()) { + if (visitor->allocated() && + (best_info == nullptr || + visitor->register_value() < best_info->register_value())) { best_info = visitor; } visitor = visitor->next_; @@ -164,17 +173,31 @@ BytecodeRegisterOptimizer::RegisterInfo::GetEquivalentToMaterialize() { return best_info; } +void BytecodeRegisterOptimizer::RegisterInfo::MarkTemporariesAsUnmaterialized( + Register temporary_base) { + DCHECK(this->register_value() < temporary_base); + DCHECK(this->materialized()); + RegisterInfo* visitor = this->next_; + while (visitor != this) { + if (visitor->register_value() >= temporary_base) { + visitor->set_materialized(false); + } + visitor = visitor->next_; + } +} + BytecodeRegisterOptimizer::RegisterInfo* BytecodeRegisterOptimizer::RegisterInfo::GetEquivalent() { return next_; } BytecodeRegisterOptimizer::BytecodeRegisterOptimizer( - Zone* zone, TemporaryRegisterAllocator* register_allocator, - int parameter_count, BytecodePipelineStage* next_stage) + Zone* zone, BytecodeRegisterAllocator* register_allocator, + int fixed_registers_count, int parameter_count, + BytecodePipelineStage* next_stage) : accumulator_(Register::virtual_accumulator()), - temporary_base_(register_allocator->allocation_base()), - max_register_index_(register_allocator->allocation_base() - 1), + temporary_base_(fixed_registers_count), + max_register_index_(fixed_registers_count - 1), register_info_table_(zone), equivalence_id_(0), next_stage_(next_stage), @@ -199,7 +222,7 @@ BytecodeRegisterOptimizer::BytecodeRegisterOptimizer( static_cast(temporary_base_.index())); for (size_t i = 0; i < register_info_table_.size(); ++i) { register_info_table_[i] = new (zone) RegisterInfo( - RegisterFromRegisterInfoTableIndex(i), NextEquivalenceId(), true); + RegisterFromRegisterInfoTableIndex(i), NextEquivalenceId(), true, true); DCHECK_EQ(register_info_table_[i]->register_value().index(), RegisterFromRegisterInfoTableIndex(i).index()); } @@ -296,7 +319,7 @@ void BytecodeRegisterOptimizer::FlushState() { // own equivalence set. RegisterInfo* equivalent; while ((equivalent = reg_info->GetEquivalent()) != reg_info) { - if (!equivalent->materialized()) { + if (equivalent->allocated() && !equivalent->materialized()) { OutputRegisterTransfer(reg_info, equivalent); } equivalent->MoveToNewEquivalenceSet(NextEquivalenceId(), true); @@ -404,6 +427,13 @@ void BytecodeRegisterOptimizer::RegisterTransfer( // Emit a placeholder nop to maintain source position info. EmitNopForSourceInfo(source_info); } + + bool input_is_observable = RegisterIsObservable(input_info->register_value()); + if (input_is_observable) { + // If input is observable by the debugger, mark all other temporaries + // registers as unmaterialized so that this register is used in preference. + input_info->MarkTemporariesAsUnmaterialized(temporary_base_); + } } void BytecodeRegisterOptimizer::EmitNopForSourceInfo( @@ -426,14 +456,14 @@ void BytecodeRegisterOptimizer::DoMov(BytecodeNode* node) { RegisterInfo* input_info = GetRegisterInfo(input); Register output = GetRegisterOutputOperand( 1, node->bytecode(), node->operands(), node->operand_count()); - RegisterInfo* output_info = GetOrCreateRegisterInfo(output); + RegisterInfo* output_info = GetRegisterInfo(output); RegisterTransfer(input_info, output_info, node->source_info_ptr()); } void BytecodeRegisterOptimizer::DoStar(BytecodeNode* node) { Register output = GetRegisterOutputOperand( 0, node->bytecode(), node->operands(), node->operand_count()); - RegisterInfo* output_info = GetOrCreateRegisterInfo(output); + RegisterInfo* output_info = GetRegisterInfo(output); RegisterTransfer(accumulator_info_, output_info, node->source_info_ptr()); } @@ -451,7 +481,7 @@ void BytecodeRegisterOptimizer::PrepareRegisterRangeOutputOperand( Register start, int count) { for (int i = 0; i < count; ++i) { Register reg(start.index() + i); - RegisterInfo* reg_info = GetOrCreateRegisterInfo(reg); + RegisterInfo* reg_info = GetRegisterInfo(reg); PrepareRegisterOutputOperand(reg_info); } } @@ -461,7 +491,7 @@ Register BytecodeRegisterOptimizer::GetEquivalentRegisterForInputOperand( // For a temporary register, RegInfo state may need be created. For // locals and parameters, the RegInfo state is created in the // BytecodeRegisterOptimizer constructor. - RegisterInfo* reg_info = GetOrCreateRegisterInfo(reg); + RegisterInfo* reg_info = GetRegisterInfo(reg); if (reg_info->materialized()) { return reg; } else { @@ -570,8 +600,8 @@ Register BytecodeRegisterOptimizer::GetRegisterOutputOperand( BytecodeRegisterOptimizer::RegisterInfo* BytecodeRegisterOptimizer::GetRegisterInfo(Register reg) { size_t index = GetRegisterInfoTableIndex(reg); - return (index < register_info_table_.size()) ? register_info_table_[index] - : nullptr; + DCHECK_LT(index, register_info_table_.size()); + return register_info_table_[index]; } BytecodeRegisterOptimizer::RegisterInfo* @@ -592,26 +622,37 @@ BytecodeRegisterOptimizer::NewRegisterInfo(Register reg) { void BytecodeRegisterOptimizer::GrowRegisterMap(Register reg) { DCHECK(RegisterIsTemporary(reg)); size_t index = GetRegisterInfoTableIndex(reg); - DCHECK_GE(index, register_info_table_.size()); - size_t new_size = index + 1; - size_t old_size = register_info_table_.size(); - register_info_table_.resize(new_size); - for (size_t i = old_size; i < new_size; ++i) { - register_info_table_[i] = new (zone()) RegisterInfo( - RegisterFromRegisterInfoTableIndex(i), NextEquivalenceId(), false); + if (index >= register_info_table_.size()) { + size_t new_size = index + 1; + size_t old_size = register_info_table_.size(); + register_info_table_.resize(new_size); + for (size_t i = old_size; i < new_size; ++i) { + register_info_table_[i] = + new (zone()) RegisterInfo(RegisterFromRegisterInfoTableIndex(i), + NextEquivalenceId(), false, false); + } } } -void BytecodeRegisterOptimizer::TemporaryRegisterFreeEvent(Register reg) { - RegisterInfo* info = GetRegisterInfo(reg); - if (info != nullptr) { - // If register is materialized and part of equivalence set, make - // sure another member of the set holds the value before the - // temporary register is removed. - if (info->materialized()) { - CreateMaterializedEquivalent(info); +void BytecodeRegisterOptimizer::RegisterAllocateEvent(Register reg) { + GetOrCreateRegisterInfo(reg)->set_allocated(true); +} + +void BytecodeRegisterOptimizer::RegisterListAllocateEvent( + RegisterList reg_list) { + if (reg_list.register_count() != 0) { + int first_index = reg_list.first_register().index(); + GrowRegisterMap(Register(first_index + reg_list.register_count() - 1)); + for (int i = 0; i < reg_list.register_count(); i++) { + GetRegisterInfo(Register(first_index + i))->set_allocated(true); } - info->MoveToNewEquivalenceSet(kInvalidEquivalenceId, false); + } +} + +void BytecodeRegisterOptimizer::RegisterListFreeEvent(RegisterList reg_list) { + int first_index = reg_list.first_register().index(); + for (int i = 0; i < reg_list.register_count(); i++) { + GetRegisterInfo(Register(first_index + i))->set_allocated(false); } } diff --git a/src/interpreter/bytecode-register-optimizer.h b/src/interpreter/bytecode-register-optimizer.h index e6a4396801..eda22e5f4d 100644 --- a/src/interpreter/bytecode-register-optimizer.h +++ b/src/interpreter/bytecode-register-optimizer.h @@ -15,13 +15,14 @@ namespace interpreter { // registers. The bytecode generator uses temporary registers // liberally for correctness and convenience and this stage removes // transfers that are not required and preserves correctness. -class BytecodeRegisterOptimizer final : public BytecodePipelineStage, - public TemporaryRegisterObserver, - public ZoneObject { +class BytecodeRegisterOptimizer final + : public BytecodePipelineStage, + public BytecodeRegisterAllocator::Observer, + public ZoneObject { public: BytecodeRegisterOptimizer(Zone* zone, - TemporaryRegisterAllocator* register_allocator, - int parameter_count, + BytecodeRegisterAllocator* register_allocator, + int fixed_registers_count, int parameter_count, BytecodePipelineStage* next_stage); virtual ~BytecodeRegisterOptimizer() {} @@ -39,8 +40,10 @@ class BytecodeRegisterOptimizer final : public BytecodePipelineStage, class RegisterInfo; - // TemporaryRegisterObserver interface. - void TemporaryRegisterFreeEvent(Register reg) override; + // BytecodeRegisterAllocator::Observer interface. + void RegisterAllocateEvent(Register reg) override; + void RegisterListAllocateEvent(RegisterList reg_list) override; + void RegisterListFreeEvent(RegisterList reg) override; // Helpers for BytecodePipelineStage interface. void FlushState(); diff --git a/src/interpreter/mkpeephole.cc b/src/interpreter/mkpeephole.cc index 8e9d5fea47..270fe83ef9 100644 --- a/src/interpreter/mkpeephole.cc +++ b/src/interpreter/mkpeephole.cc @@ -146,6 +146,9 @@ PeepholeActionAndData PeepholeActionTableWriter::LookupActionAndData( Bytecode::kIllegal}; } + // TODO(rmcilroy): Add elide for consecutive mov to and from the same + // register. + // Remove ToBoolean coercion from conditional jumps where possible. if (Bytecodes::WritesBooleanToAccumulator(last)) { if (Bytecodes::IsJumpIfToBoolean(current)) { diff --git a/src/v8.gyp b/src/v8.gyp index 9408033839..9d538d07c7 100644 --- a/src/v8.gyp +++ b/src/v8.gyp @@ -993,7 +993,6 @@ 'interpreter/bytecode-pipeline.h', 'interpreter/bytecode-register.cc', 'interpreter/bytecode-register.h', - 'interpreter/bytecode-register-allocator.cc', 'interpreter/bytecode-register-allocator.h', 'interpreter/bytecode-register-optimizer.cc', 'interpreter/bytecode-register-optimizer.h', diff --git a/test/cctest/interpreter/bytecode_expectations/AssignmentsInBinaryExpression.golden b/test/cctest/interpreter/bytecode_expectations/AssignmentsInBinaryExpression.golden index d13b5ddbad..f9a3196cda 100644 --- a/test/cctest/interpreter/bytecode_expectations/AssignmentsInBinaryExpression.golden +++ b/test/cctest/interpreter/bytecode_expectations/AssignmentsInBinaryExpression.golden @@ -65,7 +65,7 @@ snippet: " x = x + (x = 100) + (x = 101); return x; " -frame size: 3 +frame size: 2 parameter count: 1 bytecode array length: 28 bytecodes: [ @@ -76,10 +76,10 @@ bytecodes: [ B(Mov), R(0), R(1), B(Star), R(0), /* 57 E> */ B(Add), R(1), U8(2), - B(Star), R(2), + B(Star), R(1), B(LdaSmi), U8(101), B(Star), R(0), - /* 69 E> */ B(Add), R(2), U8(3), + /* 69 E> */ B(Add), R(1), U8(3), B(Star), R(0), /* 77 S> */ B(Nop), /* 87 S> */ B(Return), @@ -96,7 +96,7 @@ snippet: " x++; return x; " -frame size: 3 +frame size: 2 parameter count: 1 bytecode array length: 29 bytecodes: [ @@ -106,10 +106,10 @@ bytecodes: [ /* 46 S> */ B(LdaSmi), U8(56), B(Star), R(0), /* 61 E> */ B(Sub), R(0), U8(2), - B(Star), R(2), + B(Star), R(1), B(LdaSmi), U8(57), B(Star), R(0), - /* 68 E> */ B(Add), R(2), U8(3), + /* 68 E> */ B(Add), R(1), U8(3), B(Star), R(0), /* 75 S> */ B(Inc), U8(4), B(Star), R(0), @@ -127,7 +127,7 @@ snippet: " var y = x + (x = 1) + (x = 2) + (x = 3); return y; " -frame size: 4 +frame size: 3 parameter count: 1 bytecode array length: 37 bytecodes: [ @@ -138,10 +138,10 @@ bytecodes: [ B(Mov), R(0), R(2), B(Star), R(0), /* 61 E> */ B(Add), R(2), U8(2), - B(Star), R(3), + B(Star), R(2), B(LdaSmi), U8(2), B(Star), R(0), - /* 71 E> */ B(Add), R(3), U8(3), + /* 71 E> */ B(Add), R(2), U8(3), B(Star), R(2), B(LdaSmi), U8(3), B(Star), R(0), @@ -161,7 +161,7 @@ snippet: " var x = x + (x = 1) + (x = 2) + (x = 3); return x; " -frame size: 3 +frame size: 2 parameter count: 1 bytecode array length: 37 bytecodes: [ @@ -172,10 +172,10 @@ bytecodes: [ B(Mov), R(0), R(1), B(Star), R(0), /* 61 E> */ B(Add), R(1), U8(2), - B(Star), R(2), + B(Star), R(1), B(LdaSmi), U8(2), B(Star), R(0), - /* 71 E> */ B(Add), R(2), U8(3), + /* 71 E> */ B(Add), R(1), U8(3), B(Star), R(1), B(LdaSmi), U8(3), B(Star), R(0), @@ -194,7 +194,7 @@ snippet: " var x = 10, y = 20; return x + (x = 1) + (x + 1) * (y = 2) + (y = 3) + (x = 4) + (y = 5) + y; " -frame size: 5 +frame size: 4 parameter count: 1 bytecode array length: 72 bytecodes: [ @@ -207,28 +207,28 @@ bytecodes: [ B(Mov), R(0), R(2), B(Star), R(0), /* 68 E> */ B(Add), R(2), U8(2), - B(Star), R(3), + B(Star), R(2), /* 76 E> */ B(AddSmi), U8(1), R(0), U8(3), - B(Star), R(4), + B(Star), R(3), B(LdaSmi), U8(2), B(Star), R(1), - /* 88 E> */ B(Mul), R(4), U8(4), - B(Add), R(3), U8(5), + /* 88 E> */ B(Mul), R(3), U8(4), + B(Add), R(2), U8(5), B(Star), R(2), B(LdaSmi), U8(3), B(Star), R(1), /* 98 E> */ B(Add), R(2), U8(6), - B(Star), R(3), + B(Star), R(2), B(LdaSmi), U8(4), B(Star), R(0), - /* 108 E> */ B(Add), R(3), U8(7), + /* 108 E> */ B(Add), R(2), U8(7), B(Star), R(2), B(LdaSmi), U8(5), B(Star), R(1), /* 118 E> */ B(Add), R(2), U8(8), - B(Star), R(3), + B(Star), R(2), B(Ldar), R(1), - /* 125 E> */ B(Add), R(3), U8(9), + /* 125 E> */ B(Add), R(2), U8(9), /* 128 S> */ B(Return), ] constant pool: [ @@ -241,7 +241,7 @@ snippet: " var x = 17; return 1 + x + (x++) + (++x); " -frame size: 4 +frame size: 3 parameter count: 1 bytecode array length: 41 bytecodes: [ @@ -252,18 +252,18 @@ bytecodes: [ B(Star), R(1), B(Ldar), R(0), /* 57 E> */ B(Add), R(1), U8(2), - B(Star), R(2), + B(Star), R(1), B(Ldar), R(0), - B(ToNumber), R(1), + B(ToNumber), R(2), B(Inc), U8(3), B(Star), R(0), - B(Ldar), R(1), - /* 63 E> */ B(Add), R(2), U8(4), - B(Star), R(3), + B(Ldar), R(2), + /* 63 E> */ B(Add), R(1), U8(4), + B(Star), R(1), B(Ldar), R(0), B(Inc), U8(5), B(Star), R(0), - /* 72 E> */ B(Add), R(3), U8(6), + /* 72 E> */ B(Add), R(1), U8(6), /* 76 S> */ B(Return), ] constant pool: [ diff --git a/test/cctest/interpreter/bytecode_expectations/BreakableBlocks.golden b/test/cctest/interpreter/bytecode_expectations/BreakableBlocks.golden index 2e9abab8ef..302533c6fd 100644 --- a/test/cctest/interpreter/bytecode_expectations/BreakableBlocks.golden +++ b/test/cctest/interpreter/bytecode_expectations/BreakableBlocks.golden @@ -47,7 +47,7 @@ snippet: " } return sum; " -frame size: 5 +frame size: 4 parameter count: 1 bytecode array length: 69 bytecodes: [ @@ -71,9 +71,9 @@ bytecodes: [ B(Star), R(0), /* 142 S> */ B(Ldar), R(2), /* 150 E> */ B(Add), R(1), U8(7), - B(Star), R(4), + B(Star), R(3), B(LdaSmi), U8(12), - /* 152 E> */ B(TestEqual), R(4), U8(8), + /* 152 E> */ B(TestEqual), R(3), U8(8), B(JumpIfFalse), U8(4), /* 161 S> */ B(Jump), U8(20), /* 118 S> */ B(Ldar), R(2), diff --git a/test/cctest/interpreter/bytecode_expectations/CallLookupSlot.golden b/test/cctest/interpreter/bytecode_expectations/CallLookupSlot.golden index eb94eb8619..737374472b 100644 --- a/test/cctest/interpreter/bytecode_expectations/CallLookupSlot.golden +++ b/test/cctest/interpreter/bytecode_expectations/CallLookupSlot.golden @@ -26,8 +26,8 @@ bytecodes: [ /* 34 S> */ B(CreateClosure), U8(0), U8(2), /* 36 E> */ B(StaLookupSlotSloppy), U8(1), /* 52 S> */ B(LdaConstant), U8(2), - B(Star), R(3), - B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), R(3), U8(1), R(1), + B(Star), R(4), + B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), R(4), U8(1), R(1), B(LdaConstant), U8(3), B(Star), R(3), B(LdaZero), diff --git a/test/cctest/interpreter/bytecode_expectations/ClassAndSuperClass.golden b/test/cctest/interpreter/bytecode_expectations/ClassAndSuperClass.golden index 3cb9b16788..e64071f155 100644 --- a/test/cctest/interpreter/bytecode_expectations/ClassAndSuperClass.golden +++ b/test/cctest/interpreter/bytecode_expectations/ClassAndSuperClass.golden @@ -35,8 +35,8 @@ bytecodes: [ B(CallRuntime), U16(Runtime::kLoadFromSuper), R(3), U8(3), B(Star), R(1), /* 117 E> */ B(Call), R(1), R(this), U8(1), U8(2), - B(Star), R(3), - B(AddSmi), U8(1), R(3), U8(8), + B(Star), R(1), + B(AddSmi), U8(1), R(1), U8(8), /* 131 S> */ B(Return), ] constant pool: [ diff --git a/test/cctest/interpreter/bytecode_expectations/ClassDeclarations.golden b/test/cctest/interpreter/bytecode_expectations/ClassDeclarations.golden index 5098fbef5f..05a76ef044 100644 --- a/test/cctest/interpreter/bytecode_expectations/ClassDeclarations.golden +++ b/test/cctest/interpreter/bytecode_expectations/ClassDeclarations.golden @@ -223,8 +223,8 @@ bytecodes: [ B(Star), R(2), /* 87 S> */ B(JumpIfNotHole), U8(11), B(LdaConstant), U8(2), - B(Star), R(5), - B(CallRuntime), U16(Runtime::kThrowReferenceError), R(5), U8(1), + B(Star), R(4), + B(CallRuntime), U16(Runtime::kThrowReferenceError), R(4), U8(1), B(Star), R(4), /* 94 E> */ B(New), R(4), R(0), U8(0), U8(4), /* 103 S> */ B(Return), diff --git a/test/cctest/interpreter/bytecode_expectations/CreateRestParameter.golden b/test/cctest/interpreter/bytecode_expectations/CreateRestParameter.golden index 23489f3b98..d94c13b920 100644 --- a/test/cctest/interpreter/bytecode_expectations/CreateRestParameter.golden +++ b/test/cctest/interpreter/bytecode_expectations/CreateRestParameter.golden @@ -79,7 +79,7 @@ snippet: " function f(a, ...restArgs) { return restArgs[0] + arguments[0]; } f(); " -frame size: 5 +frame size: 4 parameter count: 2 bytecode array length: 26 bytecodes: [ @@ -92,10 +92,10 @@ bytecodes: [ /* 10 E> */ B(StackCheck), B(Mov), R(arg0), R(1), /* 29 S> */ B(LdaZero), - /* 44 E> */ B(LdrKeyedProperty), R(0), U8(2), R(4), + /* 44 E> */ B(LdrKeyedProperty), R(0), U8(2), R(3), B(LdaZero), /* 59 E> */ B(LdaKeyedProperty), R(2), U8(4), - B(Add), R(4), U8(6), + B(Add), R(3), U8(6), /* 64 S> */ B(Return), ] constant pool: [ diff --git a/test/cctest/interpreter/bytecode_expectations/Eval.golden b/test/cctest/interpreter/bytecode_expectations/Eval.golden index a41e8ae100..95076a29ff 100644 --- a/test/cctest/interpreter/bytecode_expectations/Eval.golden +++ b/test/cctest/interpreter/bytecode_expectations/Eval.golden @@ -24,8 +24,8 @@ bytecodes: [ B(StaContextSlot), R(context), U8(5), U8(0), /* 30 E> */ B(StackCheck), /* 34 S> */ B(LdaConstant), U8(0), - B(Star), R(3), - B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), R(3), U8(1), R(1), + B(Star), R(4), + B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), R(4), U8(1), R(1), B(LdaConstant), U8(1), B(Star), R(3), B(LdaZero), diff --git a/test/cctest/interpreter/bytecode_expectations/ForIn.golden b/test/cctest/interpreter/bytecode_expectations/ForIn.golden index a3b15b1da5..05ee119626 100644 --- a/test/cctest/interpreter/bytecode_expectations/ForIn.golden +++ b/test/cctest/interpreter/bytecode_expectations/ForIn.golden @@ -146,7 +146,7 @@ snippet: " if (x['a'] == 20) break; } " -frame size: 8 +frame size: 7 parameter count: 1 bytecode array length: 83 bytecodes: [ @@ -168,15 +168,15 @@ bytecodes: [ /* 67 E> */ B(StaNamedPropertySloppy), R(0), U8(2), U8(10), /* 62 E> */ B(StackCheck), /* 95 S> */ B(Nop), - /* 100 E> */ B(LdrNamedProperty), R(0), U8(2), U8(4), R(7), + /* 100 E> */ B(LdrNamedProperty), R(0), U8(2), U8(4), R(6), B(LdaSmi), U8(10), - /* 106 E> */ B(TestEqual), R(7), U8(6), + /* 106 E> */ B(TestEqual), R(6), U8(6), B(JumpIfFalse), U8(4), /* 113 S> */ B(Jump), U8(17), /* 125 S> */ B(Nop), - /* 130 E> */ B(LdrNamedProperty), R(0), U8(2), U8(7), R(7), + /* 130 E> */ B(LdrNamedProperty), R(0), U8(2), U8(7), R(6), B(LdaSmi), U8(20), - /* 136 E> */ B(TestEqual), R(7), U8(9), + /* 136 E> */ B(TestEqual), R(6), U8(9), B(JumpIfFalse), U8(4), /* 143 S> */ B(Jump), U8(9), B(ForInStep), R(5), diff --git a/test/cctest/interpreter/bytecode_expectations/Generators.golden b/test/cctest/interpreter/bytecode_expectations/Generators.golden index 4d16d98840..4890828614 100644 --- a/test/cctest/interpreter/bytecode_expectations/Generators.golden +++ b/test/cctest/interpreter/bytecode_expectations/Generators.golden @@ -181,17 +181,17 @@ bytecodes: [ B(LdaFalse), B(Star), R(6), B(CallRuntime), U16(Runtime::k_CreateIterResultObject), R(5), U8(2), - B(Star), R(7), - B(LdrContextSlot), R(context), U8(5), U8(0), R(5), + B(Star), R(5), + B(LdrContextSlot), R(context), U8(5), U8(0), R(6), B(LdaSmi), U8(1), - B(SuspendGenerator), R(5), - B(Ldar), R(7), + B(SuspendGenerator), R(6), + B(Ldar), R(5), /* 25 S> */ B(Return), B(LdaSmi), U8(-2), B(Star), R(1), - B(CallRuntime), U16(Runtime::k_GeneratorGetInputOrDebugPos), R(5), U8(1), - B(Star), R(6), - B(CallRuntime), U16(Runtime::k_GeneratorGetResumeMode), R(5), U8(1), + B(CallRuntime), U16(Runtime::k_GeneratorGetInputOrDebugPos), R(6), U8(1), + B(Star), R(7), + B(CallRuntime), U16(Runtime::k_GeneratorGetResumeMode), R(6), U8(1), B(Star), R(8), B(LdaZero), B(TestEqualStrict), R(8), U8(0), @@ -202,13 +202,13 @@ bytecodes: [ B(Jump), U8(2), B(LdaTrue), B(Star), R(10), - B(Mov), R(6), R(9), + B(Mov), R(7), R(9), B(CallRuntime), U16(Runtime::k_CreateIterResultObject), R(9), U8(2), B(Star), R(3), B(LdaSmi), U8(1), B(Star), R(2), B(Jump), U8(35), - B(Ldar), R(6), + B(Ldar), R(7), /* 16 E> */ B(Throw), B(LdrUndefined), R(5), B(LdaTrue), @@ -267,7 +267,7 @@ snippet: " " frame size: 18 parameter count: 1 -bytecode array length: 807 +bytecode array length: 805 bytecodes: [ B(Ldar), R(new_target), B(JumpIfUndefined), U8(28), @@ -379,23 +379,23 @@ bytecodes: [ /* 36 S> */ B(LdaContextSlot), R(context), U8(4), U8(0), B(JumpIfNotHole), U8(11), B(LdaConstant), U8(8), - B(Star), R(13), - B(CallRuntime), U16(Runtime::kThrowReferenceError), R(13), U8(1), + B(Star), R(14), + B(CallRuntime), U16(Runtime::kThrowReferenceError), R(14), U8(1), B(Star), R(12), B(LdaFalse), B(Star), R(13), B(CallRuntime), U16(Runtime::k_CreateIterResultObject), R(12), U8(2), - B(Star), R(14), - B(LdrContextSlot), R(1), U8(5), U8(0), R(12), + B(Star), R(12), + B(LdrContextSlot), R(1), U8(5), U8(0), R(13), B(LdaSmi), U8(1), - B(SuspendGenerator), R(12), - B(Ldar), R(14), + B(SuspendGenerator), R(13), + B(Ldar), R(12), /* 44 S> */ B(Return), B(LdaSmi), U8(-2), B(Star), R(4), - B(CallRuntime), U16(Runtime::k_GeneratorGetInputOrDebugPos), R(12), U8(1), - B(Star), R(13), - B(CallRuntime), U16(Runtime::k_GeneratorGetResumeMode), R(12), U8(1), + B(CallRuntime), U16(Runtime::k_GeneratorGetInputOrDebugPos), R(13), U8(1), + B(Star), R(14), + B(CallRuntime), U16(Runtime::k_GeneratorGetResumeMode), R(13), U8(1), B(Star), R(15), B(LdaZero), B(TestEqualStrict), R(15), U8(0), @@ -406,7 +406,7 @@ bytecodes: [ B(Jump), U8(2), B(LdaTrue), B(Star), R(17), - B(Mov), R(13), R(16), + B(Mov), R(14), R(16), B(CallRuntime), U16(Runtime::k_CreateIterResultObject), R(16), U8(2), B(PopContext), R(2), B(PopContext), R(2), @@ -417,14 +417,13 @@ bytecodes: [ B(Star), R(9), B(LdaZero), B(Star), R(8), - B(Jump), U8(76), - B(Ldar), R(13), + B(Jump), U8(74), + B(Ldar), R(14), /* 36 E> */ B(Throw), - B(Ldar), R(13), B(PopContext), R(2), B(LdaZero), B(StaContextSlot), R(1), U8(9), U8(0), - B(Wide), B(JumpLoop), U16(-234), U16(0), + B(Wide), B(JumpLoop), U16(-232), U16(0), B(Jump), U8(44), B(Star), R(12), B(Ldar), R(closure), @@ -585,7 +584,7 @@ constant pool: [ FIXED_ARRAY_TYPE, ONE_BYTE_INTERNALIZED_STRING_TYPE ["x"], Smi [146], - Smi [169], + Smi [167], ONE_BYTE_INTERNALIZED_STRING_TYPE [".catch"], FIXED_ARRAY_TYPE, ONE_BYTE_INTERNALIZED_STRING_TYPE ["return"], @@ -595,12 +594,12 @@ constant pool: [ Smi [129], Smi [166], Smi [155], - Smi [603], + Smi [601], ] handlers: [ - [48, 720, 726], - [153, 460, 466], - [156, 416, 418], - [574, 588, 590], + [48, 718, 724], + [153, 458, 464], + [156, 414, 416], + [572, 586, 588], ] diff --git a/test/cctest/interpreter/bytecode_expectations/LetVariable.golden b/test/cctest/interpreter/bytecode_expectations/LetVariable.golden index b2f4d38402..5c6897dc08 100644 --- a/test/cctest/interpreter/bytecode_expectations/LetVariable.golden +++ b/test/cctest/interpreter/bytecode_expectations/LetVariable.golden @@ -58,7 +58,7 @@ snippet: " " frame size: 3 parameter count: 1 -bytecode array length: 26 +bytecode array length: 29 bytecodes: [ B(LdaTheHole), B(Star), R(0), @@ -70,6 +70,7 @@ bytecodes: [ B(LdaConstant), U8(0), B(Star), R(2), /* 45 E> */ B(CallRuntime), U16(Runtime::kThrowReferenceError), R(2), U8(1), + B(Mov), R(1), R(0), B(Mov), R(1), R(0), B(LdaUndefined), /* 52 S> */ B(Return), diff --git a/test/cctest/interpreter/bytecode_expectations/LookupSlot.golden b/test/cctest/interpreter/bytecode_expectations/LookupSlot.golden index 91765da1bb..02a5802957 100644 --- a/test/cctest/interpreter/bytecode_expectations/LookupSlot.golden +++ b/test/cctest/interpreter/bytecode_expectations/LookupSlot.golden @@ -25,8 +25,8 @@ bytecodes: [ B(StaContextSlot), R(context), U8(5), U8(0), /* 10 E> */ B(StackCheck), /* 14 S> */ B(LdaConstant), U8(0), - B(Star), R(3), - B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), R(3), U8(1), R(1), + B(Star), R(4), + B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), R(4), U8(1), R(1), B(LdaConstant), U8(1), B(Star), R(3), B(LdaZero), @@ -70,8 +70,8 @@ bytecodes: [ B(StaContextSlot), R(context), U8(5), U8(0), /* 10 E> */ B(StackCheck), /* 14 S> */ B(LdaConstant), U8(0), - B(Star), R(3), - B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), R(3), U8(1), R(1), + B(Star), R(4), + B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), R(4), U8(1), R(1), B(LdaConstant), U8(1), B(Star), R(3), B(LdaZero), @@ -118,8 +118,8 @@ bytecodes: [ /* 14 S> */ B(LdaSmi), U8(20), /* 16 E> */ B(StaLookupSlotSloppy), U8(0), /* 22 S> */ B(LdaConstant), U8(1), - B(Star), R(3), - B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), R(3), U8(1), R(1), + B(Star), R(4), + B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), R(4), U8(1), R(1), B(LdaConstant), U8(2), B(Star), R(3), B(LdaZero), @@ -167,8 +167,8 @@ bytecodes: [ B(StaContextSlot), R(context), U8(5), U8(0), /* 38 E> */ B(StackCheck), /* 44 S> */ B(LdaConstant), U8(0), - B(Star), R(3), - B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), R(3), U8(1), R(1), + B(Star), R(4), + B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), R(4), U8(1), R(1), B(LdaConstant), U8(1), B(Star), R(3), B(LdaZero), @@ -217,8 +217,8 @@ bytecodes: [ B(StaContextSlot), R(context), U8(5), U8(0), /* 34 E> */ B(StackCheck), /* 40 S> */ B(LdaConstant), U8(0), - B(Star), R(3), - B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), R(3), U8(1), R(1), + B(Star), R(4), + B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), R(4), U8(1), R(1), B(LdaConstant), U8(1), B(Star), R(3), B(LdaZero), diff --git a/test/cctest/interpreter/bytecode_expectations/ObjectLiterals.golden b/test/cctest/interpreter/bytecode_expectations/ObjectLiterals.golden index 16d10357fc..77accc93b4 100644 --- a/test/cctest/interpreter/bytecode_expectations/ObjectLiterals.golden +++ b/test/cctest/interpreter/bytecode_expectations/ObjectLiterals.golden @@ -157,7 +157,7 @@ bytecodes: [ B(Star), R(5), B(Mov), R(0), R(1), B(CallRuntime), U16(Runtime::kDefineAccessorPropertyUnchecked), R(1), U8(5), - B(Ldar), R(0), + B(Ldar), R(1), /* 68 S> */ B(Return), ] constant pool: [ @@ -188,7 +188,7 @@ bytecodes: [ B(Star), R(5), B(Mov), R(0), R(1), B(CallRuntime), U16(Runtime::kDefineAccessorPropertyUnchecked), R(1), U8(5), - B(Ldar), R(0), + B(Ldar), R(1), /* 102 S> */ B(Return), ] constant pool: [ @@ -220,7 +220,7 @@ bytecodes: [ B(Star), R(5), B(Mov), R(0), R(1), B(CallRuntime), U16(Runtime::kDefineAccessorPropertyUnchecked), R(1), U8(5), - B(Ldar), R(0), + B(Ldar), R(1), /* 74 S> */ B(Return), ] constant pool: [ @@ -250,7 +250,7 @@ bytecodes: [ B(Mov), R(1), R(2), B(Mov), R(0), R(4), /* 57 E> */ B(CallRuntime), U16(Runtime::kSetProperty), R(2), U8(4), - B(Ldar), R(1), + B(Ldar), R(2), /* 62 S> */ B(Return), ] constant pool: [ @@ -273,7 +273,7 @@ bytecodes: [ B(Star), R(2), B(Mov), R(0), R(1), B(CallRuntime), U16(Runtime::kInternalSetPrototype), R(1), U8(2), - B(Ldar), R(0), + B(Ldar), R(1), /* 62 S> */ B(Return), ] constant pool: [ @@ -303,7 +303,7 @@ bytecodes: [ B(Star), R(6), B(Mov), R(1), R(2), B(CallRuntime), U16(Runtime::kDefineDataPropertyInLiteral), R(2), U8(5), - B(Ldar), R(1), + B(Ldar), R(2), /* 69 S> */ B(Return), ] constant pool: [ @@ -335,7 +335,7 @@ bytecodes: [ B(Star), R(6), B(Mov), R(1), R(2), B(CallRuntime), U16(Runtime::kDefineDataPropertyInLiteral), R(2), U8(5), - B(Ldar), R(1), + B(Ldar), R(2), /* 77 S> */ B(Return), ] constant pool: [ @@ -352,7 +352,7 @@ snippet: " " frame size: 7 parameter count: 1 -bytecode array length: 49 +bytecode array length: 46 bytecodes: [ /* 30 E> */ B(StackCheck), /* 42 S> */ B(LdaConstant), U8(0), @@ -368,10 +368,9 @@ bytecodes: [ B(Mov), R(1), R(2), B(CallRuntime), U16(Runtime::kDefineDataPropertyInLiteral), R(2), U8(5), B(CreateObjectLiteral), U8(1), U8(0), U8(35), R(4), - B(Mov), R(1), R(2), B(Mov), R(4), R(3), B(CallRuntime), U16(Runtime::kInternalSetPrototype), R(2), U8(2), - B(Ldar), R(1), + B(Ldar), R(2), /* 84 S> */ B(Return), ] constant pool: [ @@ -387,7 +386,7 @@ snippet: " " frame size: 7 parameter count: 1 -bytecode array length: 73 +bytecode array length: 67 bytecodes: [ /* 30 E> */ B(StackCheck), /* 42 S> */ B(LdaConstant), U8(0), @@ -408,7 +407,6 @@ bytecodes: [ B(Star), R(4), B(LdaZero), B(Star), R(5), - B(Mov), R(1), R(2), B(CallRuntime), U16(Runtime::kDefineGetterPropertyUnchecked), R(2), U8(4), B(LdaConstant), U8(3), B(ToName), R(3), @@ -416,9 +414,8 @@ bytecodes: [ B(Star), R(4), B(LdaZero), B(Star), R(5), - B(Mov), R(1), R(2), B(CallRuntime), U16(Runtime::kDefineSetterPropertyUnchecked), R(2), U8(4), - B(Ldar), R(1), + B(Ldar), R(2), /* 99 S> */ B(Return), ] constant pool: [ diff --git a/test/cctest/interpreter/bytecode_expectations/UnaryOperators.golden b/test/cctest/interpreter/bytecode_expectations/UnaryOperators.golden index e86e2bf5b4..4e73ab6977 100644 --- a/test/cctest/interpreter/bytecode_expectations/UnaryOperators.golden +++ b/test/cctest/interpreter/bytecode_expectations/UnaryOperators.golden @@ -95,7 +95,7 @@ snippet: " var y = void (x * x - 1); return y; " -frame size: 4 +frame size: 3 parameter count: 1 bytecode array length: 23 bytecodes: [ @@ -104,8 +104,8 @@ bytecodes: [ B(Star), R(0), /* 56 S> */ B(Nop), /* 66 E> */ B(Mul), R(0), U8(2), - B(Star), R(3), - B(SubSmi), U8(1), R(3), U8(3), + B(Star), R(2), + B(SubSmi), U8(1), R(2), U8(3), B(LdrUndefined), R(1), B(Ldar), R(1), /* 74 S> */ B(Nop), diff --git a/test/cctest/interpreter/bytecode_expectations/WithStatement.golden b/test/cctest/interpreter/bytecode_expectations/WithStatement.golden index a420624a5a..f8dea9a84f 100644 --- a/test/cctest/interpreter/bytecode_expectations/WithStatement.golden +++ b/test/cctest/interpreter/bytecode_expectations/WithStatement.golden @@ -10,16 +10,16 @@ wrap: yes snippet: " with ({x:42}) { return x; } " -frame size: 3 +frame size: 2 parameter count: 1 bytecode array length: 22 bytecodes: [ /* 30 E> */ B(StackCheck), /* 34 S> */ B(CreateObjectLiteral), U8(0), U8(0), U8(1), R(1), B(Ldar), R(1), - B(ToObject), R(2), + B(ToObject), R(1), B(Ldar), R(closure), - B(CreateWithContext), R(2), U8(1), + B(CreateWithContext), R(1), U8(1), B(PushContext), R(0), /* 50 S> */ B(LdaLookupSlot), U8(2), B(PopContext), R(0), diff --git a/test/cctest/interpreter/test-interpreter-intrinsics.cc b/test/cctest/interpreter/test-interpreter-intrinsics.cc index 9591e2810e..3cb2beffd4 100644 --- a/test/cctest/interpreter/test-interpreter-intrinsics.cc +++ b/test/cctest/interpreter/test-interpreter-intrinsics.cc @@ -26,8 +26,8 @@ class InvokeIntrinsicHelper { Handle Invoke(A... args) { CHECK(IntrinsicsHelper::IsSupported(function_id_)); BytecodeArrayBuilder builder(isolate_, zone_, sizeof...(args), 0, 0); - builder.CallRuntime(function_id_, builder.Parameter(0), sizeof...(args)) - .Return(); + RegisterList reg_list(builder.Parameter(0).index(), sizeof...(args)); + builder.CallRuntime(function_id_, reg_list).Return(); InterpreterTester tester(isolate_, builder.ToBytecodeArray(isolate_)); auto callable = tester.GetCallable(); return callable(args...).ToHandleChecked(); diff --git a/test/cctest/interpreter/test-interpreter.cc b/test/cctest/interpreter/test-interpreter.cc index 4d2539cc2b..39d035fab4 100644 --- a/test/cctest/interpreter/test-interpreter.cc +++ b/test/cctest/interpreter/test-interpreter.cc @@ -1236,12 +1236,13 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) { // Check with no args. { BytecodeArrayBuilder builder(isolate, handles.main_zone(), 1, 0, 1); - + Register reg = builder.register_allocator()->NewRegister(); + RegisterList args = builder.register_allocator()->NewRegisterList(1); builder.LoadNamedProperty(builder.Parameter(0), name, slot_index) - .StoreAccumulatorInRegister(Register(0)); + .StoreAccumulatorInRegister(reg) + .MoveRegister(builder.Parameter(0), args[0]); - builder.Call(Register(0), builder.Parameter(0), 1, call_slot_index, - tail_call_mode); + builder.Call(reg, args, call_slot_index, tail_call_mode); builder.Return(); Handle bytecode_array = builder.ToBytecodeArray(isolate); @@ -1258,11 +1259,12 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) { // Check that receiver is passed properly. { BytecodeArrayBuilder builder(isolate, handles.main_zone(), 1, 0, 1); - + Register reg = builder.register_allocator()->NewRegister(); + RegisterList args = builder.register_allocator()->NewRegisterList(1); builder.LoadNamedProperty(builder.Parameter(0), name, slot_index) - .StoreAccumulatorInRegister(Register(0)); - builder.Call(Register(0), builder.Parameter(0), 1, call_slot_index, - tail_call_mode); + .StoreAccumulatorInRegister(reg) + .MoveRegister(builder.Parameter(0), args[0]); + builder.Call(reg, args, call_slot_index, tail_call_mode); builder.Return(); Handle bytecode_array = builder.ToBytecodeArray(isolate); @@ -1281,17 +1283,19 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) { // Check with two parameters (+ receiver). { BytecodeArrayBuilder builder(isolate, handles.main_zone(), 1, 0, 4); + Register reg = builder.register_allocator()->NewRegister(); + RegisterList args = builder.register_allocator()->NewRegisterList(3); builder.LoadNamedProperty(builder.Parameter(0), name, slot_index) - .StoreAccumulatorInRegister(Register(0)) + .StoreAccumulatorInRegister(reg) .LoadAccumulatorWithRegister(builder.Parameter(0)) - .StoreAccumulatorInRegister(Register(1)) + .StoreAccumulatorInRegister(args[0]) .LoadLiteral(Smi::FromInt(51)) - .StoreAccumulatorInRegister(Register(2)) + .StoreAccumulatorInRegister(args[1]) .LoadLiteral(Smi::FromInt(11)) - .StoreAccumulatorInRegister(Register(3)); + .StoreAccumulatorInRegister(args[2]); - builder.Call(Register(0), Register(1), 3, call_slot_index, tail_call_mode); + builder.Call(reg, args, call_slot_index, tail_call_mode); builder.Return(); @@ -1311,33 +1315,35 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) { // Check with 10 parameters (+ receiver). { BytecodeArrayBuilder builder(isolate, handles.main_zone(), 1, 0, 12); + Register reg = builder.register_allocator()->NewRegister(); + RegisterList args = builder.register_allocator()->NewRegisterList(11); builder.LoadNamedProperty(builder.Parameter(0), name, slot_index) - .StoreAccumulatorInRegister(Register(0)) + .StoreAccumulatorInRegister(reg) .LoadAccumulatorWithRegister(builder.Parameter(0)) - .StoreAccumulatorInRegister(Register(1)) + .StoreAccumulatorInRegister(args[0]) .LoadLiteral(factory->NewStringFromAsciiChecked("a")) - .StoreAccumulatorInRegister(Register(2)) + .StoreAccumulatorInRegister(args[1]) .LoadLiteral(factory->NewStringFromAsciiChecked("b")) - .StoreAccumulatorInRegister(Register(3)) + .StoreAccumulatorInRegister(args[2]) .LoadLiteral(factory->NewStringFromAsciiChecked("c")) - .StoreAccumulatorInRegister(Register(4)) + .StoreAccumulatorInRegister(args[3]) .LoadLiteral(factory->NewStringFromAsciiChecked("d")) - .StoreAccumulatorInRegister(Register(5)) + .StoreAccumulatorInRegister(args[4]) .LoadLiteral(factory->NewStringFromAsciiChecked("e")) - .StoreAccumulatorInRegister(Register(6)) + .StoreAccumulatorInRegister(args[5]) .LoadLiteral(factory->NewStringFromAsciiChecked("f")) - .StoreAccumulatorInRegister(Register(7)) + .StoreAccumulatorInRegister(args[6]) .LoadLiteral(factory->NewStringFromAsciiChecked("g")) - .StoreAccumulatorInRegister(Register(8)) + .StoreAccumulatorInRegister(args[7]) .LoadLiteral(factory->NewStringFromAsciiChecked("h")) - .StoreAccumulatorInRegister(Register(9)) + .StoreAccumulatorInRegister(args[8]) .LoadLiteral(factory->NewStringFromAsciiChecked("i")) - .StoreAccumulatorInRegister(Register(10)) + .StoreAccumulatorInRegister(args[9]) .LoadLiteral(factory->NewStringFromAsciiChecked("j")) - .StoreAccumulatorInRegister(Register(11)); + .StoreAccumulatorInRegister(args[10]); - builder.Call(Register(0), Register(1), 11, call_slot_index, tail_call_mode); + builder.Call(reg, args, call_slot_index, tail_call_mode); builder.Return(); @@ -2112,12 +2118,13 @@ TEST(InterpreterCallRuntime) { Isolate* isolate = handles.main_isolate(); BytecodeArrayBuilder builder(isolate, handles.main_zone(), 1, 0, 2); + RegisterList args = builder.register_allocator()->NewRegisterList(2); builder.LoadLiteral(Smi::FromInt(15)) - .StoreAccumulatorInRegister(Register(0)) + .StoreAccumulatorInRegister(args[0]) .LoadLiteral(Smi::FromInt(40)) - .StoreAccumulatorInRegister(Register(1)) - .CallRuntime(Runtime::kAdd, Register(0), 2) + .StoreAccumulatorInRegister(args[1]) + .CallRuntime(Runtime::kAdd, args) .Return(); Handle bytecode_array = builder.ToBytecodeArray(isolate); @@ -2136,7 +2143,7 @@ TEST(InterpreterInvokeIntrinsic) { builder.LoadLiteral(Smi::FromInt(15)) .StoreAccumulatorInRegister(Register(0)) - .CallRuntime(Runtime::kInlineIsArray, Register(0), 1) + .CallRuntime(Runtime::kInlineIsArray, Register(0)) .Return(); Handle bytecode_array = builder.ToBytecodeArray(isolate); diff --git a/test/unittests/interpreter/bytecode-array-builder-unittest.cc b/test/unittests/interpreter/bytecode-array-builder-unittest.cc index 259931ec7d..2647fcac6a 100644 --- a/test/unittests/interpreter/bytecode-array-builder-unittest.cc +++ b/test/unittests/interpreter/bytecode-array-builder-unittest.cc @@ -33,6 +33,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { Register reg(0); Register other(reg.index() + 1); Register wide(128); + RegisterList reg_list; // Emit argument creation operations. builder.CreateArguments(CreateArgumentsType::kMappedArguments) @@ -123,16 +124,11 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { .CreateObjectLiteral(factory->NewFixedArray(1), 0, 0, reg); // Call operations. - builder.Call(reg, other, 0, 1) - .Call(reg, wide, 0, 1) - .TailCall(reg, other, 0, 1) - .TailCall(reg, wide, 0, 1) - .CallRuntime(Runtime::kIsArray, reg, 1) - .CallRuntime(Runtime::kIsArray, wide, 1) - .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, reg, 1, other) - .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, wide, 1, other) - .CallJSRuntime(Context::SPREAD_ITERABLE_INDEX, reg, 1) - .CallJSRuntime(Context::SPREAD_ITERABLE_INDEX, wide, 1); + builder.Call(reg, reg_list, 1) + .Call(reg, reg_list, 1, TailCallMode::kAllow) + .CallRuntime(Runtime::kIsArray, reg) + .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, reg_list, other) + .CallJSRuntime(Context::SPREAD_ITERABLE_INDEX, reg_list); // Emit binary operator invocations. builder.BinaryOperation(Token::Value::ADD, reg, 1) @@ -179,8 +175,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { builder.Delete(reg, LanguageMode::SLOPPY).Delete(reg, LanguageMode::STRICT); // Emit new. - builder.New(reg, reg, 0, 1); - builder.New(wide, wide, 0, 1); + builder.New(reg, reg_list, 1); // Emit test operator invocations. builder.CompareOperation(Token::Value::EQ, reg, 1) @@ -337,8 +332,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { .ResumeGenerator(reg); // Intrinsics handled by the interpreter. - builder.CallRuntime(Runtime::kInlineIsArray, reg, 1) - .CallRuntime(Runtime::kInlineIsArray, wide, 1); + builder.CallRuntime(Runtime::kInlineIsArray, reg_list); // Emit debugger bytecode. builder.Debugger(); @@ -359,7 +353,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { // Generate BytecodeArray. Handle the_array = builder.ToBytecodeArray(isolate()); CHECK_EQ(the_array->frame_size(), - builder.fixed_and_temporary_register_count() * kPointerSize); + builder.total_register_count() * kPointerSize); // Build scorecard of bytecodes encountered in the BytecodeArray. std::vector scorecard(Bytecodes::ToByte(Bytecode::kLast) + 1); @@ -428,21 +422,18 @@ TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) { for (int contexts = 0; contexts < 4; contexts++) { for (int temps = 0; temps < 3; temps++) { BytecodeArrayBuilder builder(isolate(), zone(), 0, contexts, locals); - BytecodeRegisterAllocator temporaries( - zone(), builder.temporary_register_allocator()); + BytecodeRegisterAllocator* allocator(builder.register_allocator()); for (int i = 0; i < locals + contexts; i++) { builder.LoadLiteral(Smi::FromInt(0)); builder.StoreAccumulatorInRegister(Register(i)); } for (int i = 0; i < temps; i++) { + Register temp = allocator->NewRegister(); builder.LoadLiteral(Smi::FromInt(0)); - builder.StoreAccumulatorInRegister(temporaries.NewRegister()); - } - if (temps > 0) { + builder.StoreAccumulatorInRegister(temp); // Ensure temporaries are used so not optimized away by the // register optimizer. - builder.New(Register(locals + contexts), Register(locals + contexts), - static_cast(temps), 0); + builder.ConvertAccumulatorToName(temp); } builder.Return(); @@ -478,30 +469,6 @@ TEST_F(BytecodeArrayBuilderTest, Parameters) { } -TEST_F(BytecodeArrayBuilderTest, RegisterType) { - CanonicalHandleScope canonical(isolate()); - BytecodeArrayBuilder builder(isolate(), zone(), 10, 0, 3); - BytecodeRegisterAllocator register_allocator( - zone(), builder.temporary_register_allocator()); - Register temp0 = register_allocator.NewRegister(); - Register param0(builder.Parameter(0)); - Register param9(builder.Parameter(9)); - Register temp1 = register_allocator.NewRegister(); - Register reg0(0); - Register reg1(1); - Register reg2(2); - Register temp2 = register_allocator.NewRegister(); - CHECK_EQ(builder.RegisterIsParameterOrLocal(temp0), false); - CHECK_EQ(builder.RegisterIsParameterOrLocal(temp1), false); - CHECK_EQ(builder.RegisterIsParameterOrLocal(temp2), false); - CHECK_EQ(builder.RegisterIsParameterOrLocal(param0), true); - CHECK_EQ(builder.RegisterIsParameterOrLocal(param9), true); - CHECK_EQ(builder.RegisterIsParameterOrLocal(reg0), true); - CHECK_EQ(builder.RegisterIsParameterOrLocal(reg1), true); - CHECK_EQ(builder.RegisterIsParameterOrLocal(reg2), true); -} - - TEST_F(BytecodeArrayBuilderTest, Constants) { CanonicalHandleScope canonical(isolate()); BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0); diff --git a/test/unittests/interpreter/bytecode-array-iterator-unittest.cc b/test/unittests/interpreter/bytecode-array-iterator-unittest.cc index b844180dc0..536122ac17 100644 --- a/test/unittests/interpreter/bytecode-array-iterator-unittest.cc +++ b/test/unittests/interpreter/bytecode-array-iterator-unittest.cc @@ -54,9 +54,9 @@ TEST_F(BytecodeArrayIteratorTest, IteratesBytecodeArray) { .LoadNamedProperty(reg_1, name, feedback_slot) .BinaryOperation(Token::Value::ADD, reg_0, 3) .StoreAccumulatorInRegister(param) - .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, param, 1, reg_0) + .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, param, reg_0) .ForInPrepare(reg_0, reg_0) - .CallRuntime(Runtime::kLoadIC_Miss, reg_0, 1) + .CallRuntime(Runtime::kLoadIC_Miss, reg_0) .Debugger() .LoadGlobal(0x10000000, TypeofMode::NOT_INSIDE_TYPEOF) .Return(); diff --git a/test/unittests/interpreter/bytecode-register-allocator-unittest.cc b/test/unittests/interpreter/bytecode-register-allocator-unittest.cc index d4dc111d69..f06e454cc9 100644 --- a/test/unittests/interpreter/bytecode-register-allocator-unittest.cc +++ b/test/unittests/interpreter/bytecode-register-allocator-unittest.cc @@ -12,199 +12,83 @@ namespace v8 { namespace internal { namespace interpreter { -class TemporaryRegisterAllocatorTest : public TestWithIsolateAndZone { - public: - TemporaryRegisterAllocatorTest() : allocator_(zone(), 0) {} - ~TemporaryRegisterAllocatorTest() override {} - TemporaryRegisterAllocator* allocator() { return &allocator_; } - - private: - TemporaryRegisterAllocator allocator_; -}; - -TEST_F(TemporaryRegisterAllocatorTest, FirstAllocation) { - CHECK_EQ(allocator()->allocation_count(), 0); - int reg0_index = allocator()->BorrowTemporaryRegister(); - CHECK_EQ(reg0_index, 0); - CHECK_EQ(allocator()->allocation_count(), 1); - CHECK(allocator()->RegisterIsLive(Register(reg0_index))); - allocator()->ReturnTemporaryRegister(reg0_index); - CHECK(!allocator()->RegisterIsLive(Register(reg0_index))); - CHECK_EQ(allocator()->allocation_count(), 1); - CHECK(allocator()->first_temporary_register() == Register(0)); - CHECK(allocator()->last_temporary_register() == Register(0)); -} - -TEST_F(TemporaryRegisterAllocatorTest, SimpleAllocations) { - for (int i = 0; i < 13; i++) { - int reg_index = allocator()->BorrowTemporaryRegister(); - CHECK_EQ(reg_index, i); - CHECK_EQ(allocator()->allocation_count(), i + 1); - } - for (int i = 0; i < 13; i++) { - CHECK(allocator()->RegisterIsLive(Register(i))); - allocator()->ReturnTemporaryRegister(i); - CHECK(!allocator()->RegisterIsLive(Register(i))); - int reg_index = allocator()->BorrowTemporaryRegister(); - CHECK_EQ(reg_index, i); - CHECK_EQ(allocator()->allocation_count(), 13); - } - for (int i = 0; i < 13; i++) { - CHECK(allocator()->RegisterIsLive(Register(i))); - allocator()->ReturnTemporaryRegister(i); - CHECK(!allocator()->RegisterIsLive(Register(i))); - } -} - -TEST_F(TemporaryRegisterAllocatorTest, SimpleRangeAllocation) { - static const int kRunLength = 7; - int start = allocator()->PrepareForConsecutiveTemporaryRegisters(kRunLength); - CHECK(!allocator()->RegisterIsLive(Register(start))); - for (int i = 0; i < kRunLength; i++) { - CHECK(!allocator()->RegisterIsLive(Register(start + i))); - allocator()->BorrowConsecutiveTemporaryRegister(start + i); - CHECK(allocator()->RegisterIsLive(Register(start + i))); - } -} - -TEST_F(TemporaryRegisterAllocatorTest, RangeAllocationAbuttingFree) { - static const int kFreeCount = 3; - static const int kRunLength = 6; - - for (int i = 0; i < kFreeCount; i++) { - int to_free = allocator()->BorrowTemporaryRegister(); - CHECK_EQ(to_free, i); - } - for (int i = 0; i < kFreeCount; i++) { - allocator()->ReturnTemporaryRegister(i); - } - - int start = allocator()->PrepareForConsecutiveTemporaryRegisters(kRunLength); - CHECK(!allocator()->RegisterIsLive(Register(start))); - for (int i = 0; i < kRunLength; i++) { - CHECK(!allocator()->RegisterIsLive(Register(start + i))); - allocator()->BorrowConsecutiveTemporaryRegister(start + i); - CHECK(allocator()->RegisterIsLive(Register(start + i))); - } -} - -TEST_F(TemporaryRegisterAllocatorTest, RangeAllocationAbuttingHole) { - static const int kPreAllocatedCount = 7; - static const int kPreAllocatedFreeCount = 6; - static const int kRunLength = 8; - - for (int i = 0; i < kPreAllocatedCount; i++) { - int to_free = allocator()->BorrowTemporaryRegister(); - CHECK_EQ(to_free, i); - } - for (int i = 0; i < kPreAllocatedFreeCount; i++) { - allocator()->ReturnTemporaryRegister(i); - } - int start = allocator()->PrepareForConsecutiveTemporaryRegisters(kRunLength); - CHECK(!allocator()->RegisterIsLive(Register(start))); - CHECK_EQ(start, kPreAllocatedCount); - for (int i = 0; i < kRunLength; i++) { - CHECK(!allocator()->RegisterIsLive(Register(start + i))); - allocator()->BorrowConsecutiveTemporaryRegister(start + i); - CHECK(allocator()->RegisterIsLive(Register(start + i))); - } -} - -TEST_F(TemporaryRegisterAllocatorTest, RangeAllocationAvailableInTemporaries) { - static const int kNotRunLength = 13; - static const int kRunLength = 8; - - // Allocate big batch - for (int i = 0; i < kNotRunLength * 2 + kRunLength; i++) { - int allocated = allocator()->BorrowTemporaryRegister(); - CHECK_EQ(allocated, i); - } - // Free every other register either side of target. - for (int i = 0; i < kNotRunLength; i++) { - if ((i & 2) == 1) { - allocator()->ReturnTemporaryRegister(i); - allocator()->ReturnTemporaryRegister(kNotRunLength + kRunLength + i); - } - } - // Free all registers for target. - for (int i = kNotRunLength; i < kNotRunLength + kRunLength; i++) { - allocator()->ReturnTemporaryRegister(i); - } - - int start = allocator()->PrepareForConsecutiveTemporaryRegisters(kRunLength); - CHECK_EQ(start, kNotRunLength); - for (int i = 0; i < kRunLength; i++) { - CHECK(!allocator()->RegisterIsLive(Register(start + i))); - allocator()->BorrowConsecutiveTemporaryRegister(start + i); - CHECK(allocator()->RegisterIsLive(Register(start + i))); - } -} - -TEST_F(TemporaryRegisterAllocatorTest, NotInRange) { - for (int i = 0; i < 10; i++) { - int reg = allocator()->BorrowTemporaryRegisterNotInRange(2, 5); - CHECK(reg == i || (reg > 2 && reg == i + 4)); - } - for (int i = 0; i < 10; i++) { - if (i < 2) { - allocator()->ReturnTemporaryRegister(i); - } else { - allocator()->ReturnTemporaryRegister(i + 4); - } - } - int reg0 = allocator()->BorrowTemporaryRegisterNotInRange(0, 3); - CHECK_EQ(reg0, 4); - int reg1 = allocator()->BorrowTemporaryRegisterNotInRange(3, 10); - CHECK_EQ(reg1, 2); - int reg2 = allocator()->BorrowTemporaryRegisterNotInRange(2, 6); - CHECK_EQ(reg2, 1); - allocator()->ReturnTemporaryRegister(reg0); - allocator()->ReturnTemporaryRegister(reg1); - allocator()->ReturnTemporaryRegister(reg2); -} - class BytecodeRegisterAllocatorTest : public TestWithIsolateAndZone { public: - BytecodeRegisterAllocatorTest() {} + BytecodeRegisterAllocatorTest() : allocator_(0) {} ~BytecodeRegisterAllocatorTest() override {} + + BytecodeRegisterAllocator* allocator() { return &allocator_; } + + private: + BytecodeRegisterAllocator allocator_; }; -TEST_F(BytecodeRegisterAllocatorTest, TemporariesRecycled) { - BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0); +TEST_F(BytecodeRegisterAllocatorTest, SimpleAllocations) { + CHECK_EQ(allocator()->maximum_register_count(), 0); + Register reg0 = allocator()->NewRegister(); + CHECK_EQ(reg0.index(), 0); + CHECK_EQ(allocator()->maximum_register_count(), 1); + CHECK_EQ(allocator()->next_register_index(), 1); + CHECK(allocator()->RegisterIsLive(reg0)); - int first; - { - BytecodeRegisterAllocator allocator(zone(), - builder.temporary_register_allocator()); - first = allocator.NewRegister().index(); - allocator.NewRegister(); - allocator.NewRegister(); - allocator.NewRegister(); - } + allocator()->ReleaseRegisters(0); + CHECK(!allocator()->RegisterIsLive(reg0)); + CHECK_EQ(allocator()->maximum_register_count(), 1); + CHECK_EQ(allocator()->next_register_index(), 0); - int second; - { - BytecodeRegisterAllocator allocator(zone(), - builder.temporary_register_allocator()); - second = allocator.NewRegister().index(); - } + reg0 = allocator()->NewRegister(); + Register reg1 = allocator()->NewRegister(); + CHECK_EQ(reg0.index(), 0); + CHECK_EQ(reg1.index(), 1); + CHECK(allocator()->RegisterIsLive(reg0)); + CHECK(allocator()->RegisterIsLive(reg1)); + CHECK_EQ(allocator()->maximum_register_count(), 2); + CHECK_EQ(allocator()->next_register_index(), 2); - CHECK_EQ(first, second); + allocator()->ReleaseRegisters(1); + CHECK(allocator()->RegisterIsLive(reg0)); + CHECK(!allocator()->RegisterIsLive(reg1)); + CHECK_EQ(allocator()->maximum_register_count(), 2); + CHECK_EQ(allocator()->next_register_index(), 1); } -TEST_F(BytecodeRegisterAllocatorTest, ConsecutiveRegisters) { - BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0); - BytecodeRegisterAllocator allocator(zone(), - builder.temporary_register_allocator()); - allocator.PrepareForConsecutiveAllocations(4); - Register reg0 = allocator.NextConsecutiveRegister(); - Register other = allocator.NewRegister(); - Register reg1 = allocator.NextConsecutiveRegister(); - Register reg2 = allocator.NextConsecutiveRegister(); - Register reg3 = allocator.NextConsecutiveRegister(); - USE(other); +TEST_F(BytecodeRegisterAllocatorTest, RegisterListAllocations) { + CHECK_EQ(allocator()->maximum_register_count(), 0); + RegisterList reg_list = allocator()->NewRegisterList(3); + CHECK_EQ(reg_list.first_register().index(), 0); + CHECK_EQ(reg_list.register_count(), 3); + CHECK_EQ(reg_list[0].index(), 0); + CHECK_EQ(reg_list[1].index(), 1); + CHECK_EQ(reg_list[2].index(), 2); + CHECK_EQ(allocator()->maximum_register_count(), 3); + CHECK_EQ(allocator()->next_register_index(), 3); + CHECK(allocator()->RegisterIsLive(reg_list[2])); - CHECK(Register::AreContiguous(reg0, reg1, reg2, reg3)); + Register reg = allocator()->NewRegister(); + RegisterList reg_list_2 = allocator()->NewRegisterList(2); + CHECK_EQ(reg.index(), 3); + CHECK_EQ(reg_list_2.first_register().index(), 4); + CHECK_EQ(reg_list_2.register_count(), 2); + CHECK_EQ(reg_list_2[0].index(), 4); + CHECK_EQ(reg_list_2[1].index(), 5); + CHECK_EQ(allocator()->maximum_register_count(), 6); + CHECK_EQ(allocator()->next_register_index(), 6); + CHECK(allocator()->RegisterIsLive(reg)); + CHECK(allocator()->RegisterIsLive(reg_list_2[1])); + + allocator()->ReleaseRegisters(reg.index()); + CHECK(!allocator()->RegisterIsLive(reg)); + CHECK(!allocator()->RegisterIsLive(reg_list_2[0])); + CHECK(!allocator()->RegisterIsLive(reg_list_2[1])); + CHECK(allocator()->RegisterIsLive(reg_list[2])); + CHECK_EQ(allocator()->maximum_register_count(), 6); + CHECK_EQ(allocator()->next_register_index(), 3); + + RegisterList empty_reg_list = allocator()->NewRegisterList(0); + CHECK_EQ(empty_reg_list.first_register().index(), 0); + CHECK_EQ(empty_reg_list.register_count(), 0); + CHECK_EQ(allocator()->maximum_register_count(), 6); + CHECK_EQ(allocator()->next_register_index(), 3); } } // namespace interpreter diff --git a/test/unittests/interpreter/bytecode-register-optimizer-unittest.cc b/test/unittests/interpreter/bytecode-register-optimizer-unittest.cc index 072a3121d3..ae7c159563 100644 --- a/test/unittests/interpreter/bytecode-register-optimizer-unittest.cc +++ b/test/unittests/interpreter/bytecode-register-optimizer-unittest.cc @@ -22,10 +22,10 @@ class BytecodeRegisterOptimizerTest : public BytecodePipelineStage, ~BytecodeRegisterOptimizerTest() override { delete register_allocator_; } void Initialize(int number_of_parameters, int number_of_locals) { - register_allocator_ = - new TemporaryRegisterAllocator(zone(), number_of_locals); - register_optimizer_ = new (zone()) BytecodeRegisterOptimizer( - zone(), register_allocator_, number_of_parameters, this); + register_allocator_ = new BytecodeRegisterAllocator(number_of_locals); + register_optimizer_ = new (zone()) + BytecodeRegisterOptimizer(zone(), register_allocator_, number_of_locals, + number_of_parameters, this); } void Write(BytecodeNode* node) override { output_.push_back(*node); } @@ -40,15 +40,13 @@ class BytecodeRegisterOptimizerTest : public BytecodePipelineStage, return Handle(); } - TemporaryRegisterAllocator* allocator() { return register_allocator_; } + BytecodeRegisterAllocator* allocator() { return register_allocator_; } BytecodeRegisterOptimizer* optimizer() { return register_optimizer_; } - Register NewTemporary() { - return Register(allocator()->BorrowTemporaryRegister()); - } + Register NewTemporary() { return allocator()->NewRegister(); } - void KillTemporary(Register reg) { - allocator()->ReturnTemporaryRegister(reg.index()); + void ReleaseTemporaries(Register reg) { + allocator()->ReleaseRegisters(reg.index()); } size_t write_count() const { return output_.size(); } @@ -56,7 +54,7 @@ class BytecodeRegisterOptimizerTest : public BytecodePipelineStage, const std::vector* output() { return &output_; } private: - TemporaryRegisterAllocator* register_allocator_; + BytecodeRegisterAllocator* register_allocator_; BytecodeRegisterOptimizer* register_optimizer_; std::vector output_; @@ -130,7 +128,7 @@ TEST_F(BytecodeRegisterOptimizerTest, TemporaryNotEmitted) { BytecodeNode node1(Bytecode::kStar, NewTemporary().ToOperand()); optimizer()->Write(&node1); CHECK_EQ(write_count(), 0); - KillTemporary(temp); + ReleaseTemporaries(temp); CHECK_EQ(write_count(), 0); BytecodeNode node2(Bytecode::kReturn); optimizer()->Write(&node2); @@ -140,6 +138,61 @@ TEST_F(BytecodeRegisterOptimizerTest, TemporaryNotEmitted) { CHECK_EQ(output()->at(1).bytecode(), Bytecode::kReturn); } +TEST_F(BytecodeRegisterOptimizerTest, ReleasedRegisterUsed) { + Initialize(3, 1); + BytecodeNode node0(Bytecode::kLdaSmi, 3); + optimizer()->Write(&node0); + CHECK_EQ(write_count(), 1); + Register temp0 = NewTemporary(); + Register temp1 = NewTemporary(); + BytecodeNode node1(Bytecode::kStar, temp1.ToOperand()); + optimizer()->Write(&node1); + CHECK_EQ(write_count(), 1); + BytecodeNode node2(Bytecode::kLdaSmi, 1); + optimizer()->Write(&node2); + CHECK_EQ(write_count(), 3); + BytecodeNode node3(Bytecode::kMov, temp1.ToOperand(), temp0.ToOperand()); + optimizer()->Write(&node3); + CHECK_EQ(write_count(), 3); + ReleaseTemporaries(temp1); + CHECK_EQ(write_count(), 3); + BytecodeNode node4(Bytecode::kLdar, temp0.ToOperand()); + optimizer()->Write(&node4); + CHECK_EQ(write_count(), 3); + BytecodeNode node5(Bytecode::kReturn); + optimizer()->Write(&node5); + CHECK_EQ(write_count(), 5); + CHECK_EQ(output()->at(3).bytecode(), Bytecode::kLdar); + CHECK_EQ(output()->at(3).operand(0), temp1.ToOperand()); + CHECK_EQ(output()->at(4).bytecode(), Bytecode::kReturn); +} + +TEST_F(BytecodeRegisterOptimizerTest, ReleasedRegisterNotFlushed) { + Initialize(3, 1); + BytecodeNode node0(Bytecode::kLdaSmi, 3); + optimizer()->Write(&node0); + CHECK_EQ(write_count(), 1); + Register temp0 = NewTemporary(); + Register temp1 = NewTemporary(); + BytecodeNode node1(Bytecode::kStar, temp0.ToOperand()); + optimizer()->Write(&node1); + CHECK_EQ(write_count(), 1); + BytecodeNode node2(Bytecode::kStar, temp1.ToOperand()); + optimizer()->Write(&node2); + CHECK_EQ(write_count(), 1); + ReleaseTemporaries(temp1); + BytecodeLabel label; + BytecodeNode jump(Bytecode::kJump, 0, nullptr); + optimizer()->WriteJump(&jump, &label); + BytecodeNode node3(Bytecode::kReturn); + optimizer()->Write(&node3); + CHECK_EQ(write_count(), 4); + CHECK_EQ(output()->at(1).bytecode(), Bytecode::kStar); + CHECK_EQ(output()->at(1).operand(0), temp0.ToOperand()); + CHECK_EQ(output()->at(2).bytecode(), Bytecode::kJump); + CHECK_EQ(output()->at(3).bytecode(), Bytecode::kReturn); +} + TEST_F(BytecodeRegisterOptimizerTest, StoresToLocalsImmediate) { Initialize(3, 1); Register parameter = Register::FromParameterIndex(1, 3);