Commit 27fe988b authored by rmcilroy's avatar rmcilroy Committed by Commit bot

[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}
parent ee605756
...@@ -1421,7 +1421,6 @@ v8_source_set("v8_base") { ...@@ -1421,7 +1421,6 @@ v8_source_set("v8_base") {
"src/interpreter/bytecode-peephole-table.h", "src/interpreter/bytecode-peephole-table.h",
"src/interpreter/bytecode-pipeline.cc", "src/interpreter/bytecode-pipeline.cc",
"src/interpreter/bytecode-pipeline.h", "src/interpreter/bytecode-pipeline.h",
"src/interpreter/bytecode-register-allocator.cc",
"src/interpreter/bytecode-register-allocator.h", "src/interpreter/bytecode-register-allocator.h",
"src/interpreter/bytecode-register-optimizer.cc", "src/interpreter/bytecode-register-optimizer.cc",
"src/interpreter/bytecode-register-optimizer.h", "src/interpreter/bytecode-register-optimizer.h",
......
...@@ -28,7 +28,7 @@ BytecodeArrayBuilder::BytecodeArrayBuilder( ...@@ -28,7 +28,7 @@ BytecodeArrayBuilder::BytecodeArrayBuilder(
parameter_count_(parameter_count), parameter_count_(parameter_count),
local_register_count_(locals_count), local_register_count_(locals_count),
context_register_count_(context_count), context_register_count_(context_count),
temporary_allocator_(zone, fixed_register_count()), register_allocator_(fixed_register_count()),
bytecode_array_writer_(zone, &constant_array_builder_, bytecode_array_writer_(zone, &constant_array_builder_,
source_position_mode), source_position_mode),
pipeline_(&bytecode_array_writer_) { pipeline_(&bytecode_array_writer_) {
...@@ -46,7 +46,8 @@ BytecodeArrayBuilder::BytecodeArrayBuilder( ...@@ -46,7 +46,8 @@ BytecodeArrayBuilder::BytecodeArrayBuilder(
if (FLAG_ignition_reo) { if (FLAG_ignition_reo) {
pipeline_ = new (zone) BytecodeRegisterOptimizer( pipeline_ = new (zone) BytecodeRegisterOptimizer(
zone, &temporary_allocator_, parameter_count, pipeline_); zone, &register_allocator_, fixed_register_count(), parameter_count,
pipeline_);
} }
return_position_ = return_position_ =
...@@ -69,10 +70,6 @@ Register BytecodeArrayBuilder::Parameter(int parameter_index) const { ...@@ -69,10 +70,6 @@ Register BytecodeArrayBuilder::Parameter(int parameter_index) const {
return Register::FromParameterIndex(parameter_index, parameter_count()); return Register::FromParameterIndex(parameter_index, parameter_count());
} }
bool BytecodeArrayBuilder::RegisterIsParameterOrLocal(Register reg) const {
return reg.is_parameter() || reg.index() < locals_count();
}
Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray(Isolate* isolate) { Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray(Isolate* isolate) {
DCHECK(return_seen_in_block_); DCHECK(return_seen_in_block_);
DCHECK(!bytecode_generated_); DCHECK(!bytecode_generated_);
...@@ -80,8 +77,7 @@ Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray(Isolate* isolate) { ...@@ -80,8 +77,7 @@ Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray(Isolate* isolate) {
Handle<FixedArray> handler_table = Handle<FixedArray> handler_table =
handler_table_builder()->ToHandlerTable(isolate); handler_table_builder()->ToHandlerTable(isolate);
return pipeline_->ToBytecodeArray(isolate, return pipeline_->ToBytecodeArray(isolate, total_register_count(),
fixed_and_temporary_register_count(),
parameter_count(), handler_table); parameter_count(), handler_table);
} }
...@@ -729,45 +725,38 @@ void BytecodeArrayBuilder::EnsureReturn() { ...@@ -729,45 +725,38 @@ void BytecodeArrayBuilder::EnsureReturn() {
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable, BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable,
Register receiver_args, RegisterList args,
size_t receiver_args_count,
int feedback_slot, int feedback_slot,
TailCallMode tail_call_mode) { TailCallMode tail_call_mode) {
if (tail_call_mode == TailCallMode::kDisallow) { if (tail_call_mode == TailCallMode::kDisallow) {
Output(Bytecode::kCall, RegisterOperand(callable), Output(Bytecode::kCall, RegisterOperand(callable),
RegisterOperand(receiver_args), UnsignedOperand(receiver_args_count), RegisterOperand(args.first_register()),
UnsignedOperand(args.register_count()),
UnsignedOperand(feedback_slot)); UnsignedOperand(feedback_slot));
} else { } else {
DCHECK(tail_call_mode == TailCallMode::kAllow); DCHECK(tail_call_mode == TailCallMode::kAllow);
Output(Bytecode::kTailCall, RegisterOperand(callable), Output(Bytecode::kTailCall, RegisterOperand(callable),
RegisterOperand(receiver_args), UnsignedOperand(receiver_args_count), RegisterOperand(args.first_register()),
UnsignedOperand(args.register_count()),
UnsignedOperand(feedback_slot)); UnsignedOperand(feedback_slot));
} }
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::New(Register constructor, BytecodeArrayBuilder& BytecodeArrayBuilder::New(Register constructor,
Register first_arg, RegisterList args,
size_t arg_count,
int feedback_slot_id) { int feedback_slot_id) {
if (!first_arg.is_valid()) {
DCHECK_EQ(0u, arg_count);
first_arg = Register(0);
}
Output(Bytecode::kNew, RegisterOperand(constructor), Output(Bytecode::kNew, RegisterOperand(constructor),
RegisterOperand(first_arg), UnsignedOperand(arg_count), RegisterOperand(args.first_register()),
UnsignedOperand(args.register_count()),
UnsignedOperand(feedback_slot_id)); UnsignedOperand(feedback_slot_id));
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime( 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_EQ(1, Runtime::FunctionForId(function_id)->result_size);
DCHECK(Bytecodes::SizeForUnsignedOperand(function_id) <= OperandSize::kShort); DCHECK(Bytecodes::SizeForUnsignedOperand(function_id) <= OperandSize::kShort);
if (!first_arg.is_valid()) {
DCHECK_EQ(0u, arg_count);
first_arg = Register(0);
}
Bytecode bytecode; Bytecode bytecode;
uint32_t id; uint32_t id;
if (IntrinsicsHelper::IsSupported(function_id)) { if (IntrinsicsHelper::IsSupported(function_id)) {
...@@ -777,29 +766,42 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime( ...@@ -777,29 +766,42 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntime(
bytecode = Bytecode::kCallRuntime; bytecode = Bytecode::kCallRuntime;
id = static_cast<uint32_t>(function_id); id = static_cast<uint32_t>(function_id);
} }
Output(bytecode, id, RegisterOperand(first_arg), UnsignedOperand(arg_count)); Output(bytecode, id, RegisterOperand(args.first_register()),
UnsignedOperand(args.register_count()));
return *this; 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( BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntimeForPair(
Runtime::FunctionId function_id, Register first_arg, size_t arg_count, Runtime::FunctionId function_id, RegisterList args, Register first_return) {
Register first_return) {
DCHECK_EQ(2, Runtime::FunctionForId(function_id)->result_size); DCHECK_EQ(2, Runtime::FunctionForId(function_id)->result_size);
DCHECK(Bytecodes::SizeForUnsignedOperand(function_id) <= OperandSize::kShort); 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<uint16_t>(function_id), Output(Bytecode::kCallRuntimeForPair, static_cast<uint16_t>(function_id),
RegisterOperand(first_arg), UnsignedOperand(arg_count), RegisterOperand(args.first_register()),
RegisterOperand(first_return)); UnsignedOperand(args.register_count()), RegisterOperand(first_return));
return *this; return *this;
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::CallJSRuntime( BytecodeArrayBuilder& BytecodeArrayBuilder::CallRuntimeForPair(
int context_index, Register receiver_args, size_t receiver_args_count) { 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,
RegisterList args) {
Output(Bytecode::kCallJSRuntime, UnsignedOperand(context_index), Output(Bytecode::kCallJSRuntime, UnsignedOperand(context_index),
RegisterOperand(receiver_args), UnsignedOperand(receiver_args_count)); RegisterOperand(args.first_register()),
UnsignedOperand(args.register_count()));
return *this; return *this;
} }
...@@ -832,10 +834,6 @@ void BytecodeArrayBuilder::SetReturnPosition() { ...@@ -832,10 +834,6 @@ void BytecodeArrayBuilder::SetReturnPosition() {
latest_source_info_.MakeStatementPosition(return_position_); latest_source_info_.MakeStatementPosition(return_position_);
} }
bool BytecodeArrayBuilder::TemporaryRegisterIsLive(Register reg) const {
return temporary_register_allocator()->RegisterIsLive(reg);
}
bool BytecodeArrayBuilder::RegisterIsValid(Register reg) const { bool BytecodeArrayBuilder::RegisterIsValid(Register reg) const {
if (!reg.is_valid()) { if (!reg.is_valid()) {
return false; return false;
...@@ -850,7 +848,7 @@ bool BytecodeArrayBuilder::RegisterIsValid(Register reg) const { ...@@ -850,7 +848,7 @@ bool BytecodeArrayBuilder::RegisterIsValid(Register reg) const {
} else if (reg.index() < fixed_register_count()) { } else if (reg.index() < fixed_register_count()) {
return true; return true;
} else { } else {
return TemporaryRegisterIsLive(reg); return register_allocator()->RegisterIsLive(reg);
} }
} }
......
...@@ -61,23 +61,14 @@ class BytecodeArrayBuilder final : public ZoneObject { ...@@ -61,23 +61,14 @@ class BytecodeArrayBuilder final : public ZoneObject {
int fixed_register_count() const { return context_count() + locals_count(); } int fixed_register_count() const { return context_count() + locals_count(); }
// Returns the number of fixed and temporary registers. // Returns the number of fixed and temporary registers.
int fixed_and_temporary_register_count() const { int total_register_count() const {
return fixed_register_count() + temporary_register_count(); DCHECK_LE(fixed_register_count(),
} register_allocator()->maximum_register_count());
return register_allocator()->maximum_register_count();
int temporary_register_count() const {
return temporary_register_allocator()->allocation_count();
} }
Register Parameter(int parameter_index) const; 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. // Constant loads to accumulator.
BytecodeArrayBuilder& LoadConstantPoolEntry(size_t entry); BytecodeArrayBuilder& LoadConstantPoolEntry(size_t entry);
BytecodeArrayBuilder& LoadLiteral(v8::internal::Smi* value); BytecodeArrayBuilder& LoadLiteral(v8::internal::Smi* value);
...@@ -191,46 +182,39 @@ class BytecodeArrayBuilder final : public ZoneObject { ...@@ -191,46 +182,39 @@ class BytecodeArrayBuilder final : public ZoneObject {
BytecodeArrayBuilder& PopContext(Register context); BytecodeArrayBuilder& PopContext(Register context);
// Call a JS function. The JSFunction or Callable to be called should be in // 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 // |callable|. The arguments should be in |args|, with the receiver in
// arguments should be in registers <receiver_args + 1> to // |args[0]|. Type feedback is recorded in the |feedback_slot| in the type
// <receiver_args + receiver_arg_count - 1>. Type feedback is recorded in // feedback vector.
// the |feedback_slot| in the type feedback vector.
BytecodeArrayBuilder& Call( BytecodeArrayBuilder& Call(
Register callable, Register receiver_args, size_t receiver_arg_count, Register callable, RegisterList args, int feedback_slot,
int feedback_slot, TailCallMode tail_call_mode = TailCallMode::kDisallow); 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);
}
// Call the new operator. The accumulator holds the |new_target|. // Call the new operator. The accumulator holds the |new_target|.
// The |constructor| is in a register followed by |arg_count| // The |constructor| is in a register and arguments are in |args|.
// consecutive arguments starting at |first_arg| for the constuctor BytecodeArrayBuilder& New(Register constructor, RegisterList args,
// invocation. int feedback_slot);
BytecodeArrayBuilder& New(Register constructor, Register first_arg,
size_t arg_count, int feedback_slot); // Call the runtime function with |function_id| and arguments |args|.
// Call the runtime function with |function_id|. The first argument should be
// in |first_arg| and all subsequent arguments should be in registers
// <first_arg + 1> to <first_arg + arg_count - 1>.
BytecodeArrayBuilder& CallRuntime(Runtime::FunctionId function_id, 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. // Call the runtime function with |function_id| and arguments |args|, that
// The first argument should be in |first_arg| and all subsequent arguments // returns a pair of values. The return values will be returned in
// should be in registers <first_arg + 1> to <first_arg + arg_count - 1>. The // <first_return> and <first_return + 1>.
// return values will be returned in <first_return> and <first_return + 1>.
BytecodeArrayBuilder& CallRuntimeForPair(Runtime::FunctionId function_id, BytecodeArrayBuilder& CallRuntimeForPair(Runtime::FunctionId function_id,
Register first_arg, size_t arg_count, RegisterList args,
Register first_return); 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 // Call the JS runtime function with |context_index| and arguments |args|.
// be in |receiver_args| and all subsequent arguments should be in registers BytecodeArrayBuilder& CallJSRuntime(int context_index, RegisterList args);
// <receiver + 1> to <receiver + receiver_args_count - 1>.
BytecodeArrayBuilder& CallJSRuntime(int context_index, Register receiver_args,
size_t receiver_args_count);
// Operators (register holds the lhs value, accumulator holds the rhs value). // Operators (register holds the lhs value, accumulator holds the rhs value).
// Type feedback will be recorded in the |feedback_slot| // Type feedback will be recorded in the |feedback_slot|
...@@ -328,34 +312,16 @@ class BytecodeArrayBuilder final : public ZoneObject { ...@@ -328,34 +312,16 @@ class BytecodeArrayBuilder final : public ZoneObject {
latest_source_info_.MakeStatementPosition(expr->position()); 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(); void EnsureReturn();
static uint32_t RegisterOperand(Register reg) { // Accessors
return static_cast<uint32_t>(reg.ToOperand()); BytecodeRegisterAllocator* register_allocator() {
} return &register_allocator_;
static uint32_t SignedOperand(int value) {
return static_cast<uint32_t>(value);
}
static uint32_t UnsignedOperand(int value) {
DCHECK_GE(value, 0);
return static_cast<uint32_t>(value);
} }
const BytecodeRegisterAllocator* register_allocator() const {
static uint32_t UnsignedOperand(size_t value) { return &register_allocator_;
DCHECK_LE(value, kMaxUInt32);
return static_cast<uint32_t>(value);
} }
Zone* zone() const { return zone_; }
private: private:
friend class BytecodeRegisterAllocator; friend class BytecodeRegisterAllocator;
...@@ -377,6 +343,24 @@ class BytecodeArrayBuilder final : public ZoneObject { ...@@ -377,6 +343,24 @@ class BytecodeArrayBuilder final : public ZoneObject {
uint32_t operand0 = 0, uint32_t operand1 = 0, uint32_t operand0 = 0, uint32_t operand1 = 0,
uint32_t operand2 = 0, uint32_t operand3 = 0) const; uint32_t operand2 = 0, uint32_t operand3 = 0) const;
static uint32_t RegisterOperand(Register reg) {
return static_cast<uint32_t>(reg.ToOperand());
}
static uint32_t SignedOperand(int value) {
return static_cast<uint32_t>(value);
}
static uint32_t UnsignedOperand(int value) {
DCHECK_GE(value, 0);
return static_cast<uint32_t>(value);
}
static uint32_t UnsignedOperand(size_t value) {
DCHECK_LE(value, kMaxUInt32);
return static_cast<uint32_t>(value);
}
// Set position for return. // Set position for return.
void SetReturnPosition(); void SetReturnPosition();
...@@ -413,7 +397,7 @@ class BytecodeArrayBuilder final : public ZoneObject { ...@@ -413,7 +397,7 @@ class BytecodeArrayBuilder final : public ZoneObject {
int local_register_count_; int local_register_count_;
int context_register_count_; int context_register_count_;
int return_position_; int return_position_;
TemporaryRegisterAllocator temporary_allocator_; BytecodeRegisterAllocator register_allocator_;
BytecodeArrayWriter bytecode_array_writer_; BytecodeArrayWriter bytecode_array_writer_;
BytecodePipelineStage* pipeline_; BytecodePipelineStage* pipeline_;
BytecodeSourceInfo latest_source_info_; BytecodeSourceInfo latest_source_info_;
......
This diff is collapsed.
...@@ -36,7 +36,6 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> { ...@@ -36,7 +36,6 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void VisitStatements(ZoneList<Statement*>* statments); void VisitStatements(ZoneList<Statement*>* statments);
private: private:
class AccumulatorResultScope;
class ContextScope; class ContextScope;
class ControlScope; class ControlScope;
class ControlScopeForBreakable; class ControlScopeForBreakable;
...@@ -47,9 +46,9 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> { ...@@ -47,9 +46,9 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
class ExpressionResultScope; class ExpressionResultScope;
class EffectResultScope; class EffectResultScope;
class GlobalDeclarationsBuilder; class GlobalDeclarationsBuilder;
class RegisterResultScope;
class RegisterAllocationScope; class RegisterAllocationScope;
class TestResultScope; class TestResultScope;
class ValueResultScope;
enum class TestFallthrough { kThen, kElse, kNone }; enum class TestFallthrough { kThen, kElse, kNone };
...@@ -73,8 +72,10 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> { ...@@ -73,8 +72,10 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
// Used by flow control routines to evaluate loop condition. // Used by flow control routines to evaluate loop condition.
void VisitCondition(Expression* expr); void VisitCondition(Expression* expr);
// Helper visitors which perform common operations. // Visit the arguments expressions in |args| and store them in |args_regs|
Register VisitArguments(ZoneList<Expression*>* arguments); // starting at register |first_argument_register| in the list.
void VisitArguments(ZoneList<Expression*>* args, RegisterList arg_regs,
size_t first_argument_register = 0);
// Visit a keyed super property load. The optional // Visit a keyed super property load. The optional
// |opt_receiver_out| register will have the receiver stored to it // |opt_receiver_out| register will have the receiver stored to it
...@@ -104,15 +105,6 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> { ...@@ -104,15 +105,6 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void VisitVariableAssignment(Variable* variable, Token::Value op, void VisitVariableAssignment(Variable* variable, Token::Value op,
FeedbackVectorSlot slot); 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 BuildAbort(BailoutReason bailout_reason);
void BuildThrowIfHole(Handle<String> name); void BuildThrowIfHole(Handle<String> name);
void BuildThrowIfNotHole(Handle<String> name); void BuildThrowIfNotHole(Handle<String> name);
...@@ -139,7 +131,6 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> { ...@@ -139,7 +131,6 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void VisitClassLiteralForRuntimeDefinition(ClassLiteral* expr); void VisitClassLiteralForRuntimeDefinition(ClassLiteral* expr);
void VisitClassLiteralProperties(ClassLiteral* expr, Register literal, void VisitClassLiteralProperties(ClassLiteral* expr, Register literal,
Register prototype); Register prototype);
void VisitClassLiteralStaticPrototypeWithComputedName(Register name);
void VisitThisFunctionVariable(Variable* variable); void VisitThisFunctionVariable(Variable* variable);
void VisitNewTargetVariable(Variable* variable); void VisitNewTargetVariable(Variable* variable);
void VisitBlockDeclarationsAndStatements(Block* stmt); void VisitBlockDeclarationsAndStatements(Block* stmt);
...@@ -169,13 +160,10 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> { ...@@ -169,13 +160,10 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void VisitForTest(Expression* expr, BytecodeLabels* then_labels, void VisitForTest(Expression* expr, BytecodeLabels* then_labels,
BytecodeLabels* else_labels, TestFallthrough fallthrough); BytecodeLabels* else_labels, TestFallthrough fallthrough);
// Methods for tracking and remapping register. // Returns the runtime function id for a store to super for the function's
void RecordStoreToRegister(Register reg); // language mode.
Register LoadFromAliasedRegister(Register reg); inline Runtime::FunctionId StoreToSuperRuntimeId();
inline Runtime::FunctionId StoreKeyedToSuperRuntimeId();
// Initialize an array of temporary registers with consecutive registers.
template <size_t N>
void InitializeWithConsecutiveRegisters(Register (&registers)[N]);
inline BytecodeArrayBuilder* builder() const { return builder_; } inline BytecodeArrayBuilder* builder() const { return builder_; }
inline Zone* zone() const { return zone_; } inline Zone* zone() const { return zone_; }
...@@ -194,12 +182,8 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> { ...@@ -194,12 +182,8 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
execution_result_ = execution_result; execution_result_ = execution_result;
} }
ExpressionResultScope* execution_result() const { return execution_result_; } ExpressionResultScope* execution_result() const { return execution_result_; }
inline void set_register_allocator( BytecodeRegisterAllocator* register_allocator() const {
RegisterAllocationScope* register_allocator) { return builder()->register_allocator();
register_allocator_ = register_allocator;
}
RegisterAllocationScope* register_allocator() const {
return register_allocator_;
} }
GlobalDeclarationsBuilder* globals_builder() { return globals_builder_; } GlobalDeclarationsBuilder* globals_builder() { return globals_builder_; }
...@@ -223,7 +207,6 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> { ...@@ -223,7 +207,6 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
ControlScope* execution_control_; ControlScope* execution_control_;
ContextScope* execution_context_; ContextScope* execution_context_;
ExpressionResultScope* execution_result_; ExpressionResultScope* execution_result_;
RegisterAllocationScope* register_allocator_;
ZoneVector<BytecodeLabel> generator_resume_points_; ZoneVector<BytecodeLabel> generator_resume_points_;
Register generator_state_; Register generator_state_;
......
// 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<int>::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<int>(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<int>(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<int>(count) - 1);
// Ensure enough registers for run.
while (run_length++ < count) {
free_temporaries_.insert(AllocateTemporaryRegister());
}
int run_start =
last_temporary_register().index() - static_cast<int>(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<int>(count) > next_consecutive_count_) {
next_consecutive_register_ =
base_allocator()->PrepareForConsecutiveTemporaryRegisters(count);
next_consecutive_count_ = static_cast<int>(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
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef V8_INTERPRETER_BYTECODE_REGISTER_ALLOCATOR_H_ #ifndef V8_INTERPRETER_BYTECODE_REGISTER_ALLOCATOR_H_
#define 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/interpreter/bytecodes.h"
#include "src/zone/zone-containers.h" #include "src/zone/zone-containers.h"
...@@ -12,99 +13,98 @@ namespace v8 { ...@@ -12,99 +13,98 @@ namespace v8 {
namespace internal { namespace internal {
namespace interpreter { namespace interpreter {
class BytecodeArrayBuilder; class RegisterList {
class Register;
class TemporaryRegisterObserver;
class TemporaryRegisterAllocator final {
public: public:
TemporaryRegisterAllocator(Zone* zone, int start_index); RegisterList() : first_reg_index_(Register().index()), register_count_(0) {}
RegisterList(int first_reg_index, int register_count)
// Borrow a temporary register. : first_reg_index_(first_reg_index), register_count_(register_count) {}
int BorrowTemporaryRegister();
// Borrow a temporary register from the register range outside of
// |start_index| to |end_index|.
int BorrowTemporaryRegisterNotInRange(int start_index, int end_index);
// Return a temporary register when no longer used.
void ReturnTemporaryRegister(int reg_index);
// 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 // Returns a new RegisterList which is a truncated version of this list, with
// PrepareForConsecutiveTemporaryRegisters(). // |count| registers.
void BorrowConsecutiveTemporaryRegister(int reg_index); const RegisterList Truncate(int new_count) {
DCHECK_GE(new_count, 0);
DCHECK_LT(new_count, register_count_);
return RegisterList(first_reg_index_, new_count);
}
// Returns true if |reg| is a temporary register and is currently const Register operator[](size_t i) const {
// borrowed. DCHECK_LT(static_cast<int>(i), register_count_);
bool RegisterIsLive(Register reg) const; return Register(first_reg_index_ + static_cast<int>(i));
}
// Returns the first register in the range of temporary registers. const Register first_register() const {
Register first_temporary_register() const; return (register_count() == 0) ? Register(0) : (*this)[0];
}
// Returns the last register in the range of temporary registers. int register_count() const { return register_count_; }
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);
private: private:
// Allocate a temporary register. int first_reg_index_;
int AllocateTemporaryRegister(); int register_count_;
ZoneSet<int> free_temporaries_;
int allocation_base_;
int allocation_count_;
TemporaryRegisterObserver* observer_;
DISALLOW_COPY_AND_ASSIGN(TemporaryRegisterAllocator);
}; };
class TemporaryRegisterObserver { // A class that allows the allocation of contiguous temporary registers.
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.
class BytecodeRegisterAllocator final { class BytecodeRegisterAllocator final {
public: public:
explicit BytecodeRegisterAllocator(Zone* zone, // Enables observation of register allocation and free events.
TemporaryRegisterAllocator* allocator); class Observer {
~BytecodeRegisterAllocator(); public:
Register NewRegister(); virtual ~Observer() {}
virtual void RegisterAllocateEvent(Register reg) = 0;
// Ensure |count| consecutive allocations are available. virtual void RegisterListAllocateEvent(RegisterList reg_list) = 0;
void PrepareForConsecutiveAllocations(size_t count); virtual void RegisterListFreeEvent(RegisterList reg_list) = 0;
};
// Get the next consecutive allocation after calling
// PrepareForConsecutiveAllocations. explicit BytecodeRegisterAllocator(int start_index)
Register NextConsecutiveRegister(); : next_register_index_(start_index),
max_register_count_(start_index),
// Returns true if |reg| is allocated in this allocator. observer_(nullptr) {}
bool RegisterIsAllocatedInThisScope(Register reg) const; ~BytecodeRegisterAllocator() {}
// Returns true if unused consecutive allocations remain. // Returns a new register.
bool HasConsecutiveAllocations() const { return next_consecutive_count_ > 0; } 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 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;
}
// 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: private:
TemporaryRegisterAllocator* base_allocator() const { return base_allocator_; } int next_register_index_;
int max_register_count_;
TemporaryRegisterAllocator* base_allocator_; Observer* observer_;
ZoneVector<int> allocated_;
int next_consecutive_register_;
int next_consecutive_count_;
DISALLOW_COPY_AND_ASSIGN(BytecodeRegisterAllocator); DISALLOW_COPY_AND_ASSIGN(BytecodeRegisterAllocator);
}; };
......
...@@ -15,10 +15,12 @@ const uint32_t BytecodeRegisterOptimizer::kInvalidEquivalenceId; ...@@ -15,10 +15,12 @@ const uint32_t BytecodeRegisterOptimizer::kInvalidEquivalenceId;
// register is materialized in the bytecode stream. // register is materialized in the bytecode stream.
class BytecodeRegisterOptimizer::RegisterInfo final : public ZoneObject { class BytecodeRegisterOptimizer::RegisterInfo final : public ZoneObject {
public: public:
RegisterInfo(Register reg, uint32_t equivalence_id, bool materialized) RegisterInfo(Register reg, uint32_t equivalence_id, bool materialized,
bool allocated)
: register_(reg), : register_(reg),
equivalence_id_(equivalence_id), equivalence_id_(equivalence_id),
materialized_(materialized), materialized_(materialized),
allocated_(allocated),
next_(this), next_(this),
prev_(this) {} prev_(this) {}
...@@ -48,12 +50,17 @@ class BytecodeRegisterOptimizer::RegisterInfo final : public ZoneObject { ...@@ -48,12 +50,17 @@ class BytecodeRegisterOptimizer::RegisterInfo final : public ZoneObject {
// exists. // exists.
RegisterInfo* GetEquivalentToMaterialize(); 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. // Get an equivalent register. Returns this if none exists.
RegisterInfo* GetEquivalent(); RegisterInfo* GetEquivalent();
Register register_value() const { return register_; } Register register_value() const { return register_; }
bool materialized() const { return materialized_; } bool materialized() const { return materialized_; }
void set_materialized(bool materialized) { materialized_ = 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) { void set_equivalence_id(uint32_t equivalence_id) {
equivalence_id_ = equivalence_id; equivalence_id_ = equivalence_id;
} }
...@@ -63,6 +70,7 @@ class BytecodeRegisterOptimizer::RegisterInfo final : public ZoneObject { ...@@ -63,6 +70,7 @@ class BytecodeRegisterOptimizer::RegisterInfo final : public ZoneObject {
Register register_; Register register_;
uint32_t equivalence_id_; uint32_t equivalence_id_;
bool materialized_; bool materialized_;
bool allocated_;
// Equivalence set pointers. // Equivalence set pointers.
RegisterInfo* next_; RegisterInfo* next_;
...@@ -155,8 +163,9 @@ BytecodeRegisterOptimizer::RegisterInfo::GetEquivalentToMaterialize() { ...@@ -155,8 +163,9 @@ BytecodeRegisterOptimizer::RegisterInfo::GetEquivalentToMaterialize() {
if (visitor->materialized()) { if (visitor->materialized()) {
return nullptr; return nullptr;
} }
if (best_info == nullptr || if (visitor->allocated() &&
visitor->register_value() < best_info->register_value()) { (best_info == nullptr ||
visitor->register_value() < best_info->register_value())) {
best_info = visitor; best_info = visitor;
} }
visitor = visitor->next_; visitor = visitor->next_;
...@@ -164,17 +173,31 @@ BytecodeRegisterOptimizer::RegisterInfo::GetEquivalentToMaterialize() { ...@@ -164,17 +173,31 @@ BytecodeRegisterOptimizer::RegisterInfo::GetEquivalentToMaterialize() {
return best_info; 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*
BytecodeRegisterOptimizer::RegisterInfo::GetEquivalent() { BytecodeRegisterOptimizer::RegisterInfo::GetEquivalent() {
return next_; return next_;
} }
BytecodeRegisterOptimizer::BytecodeRegisterOptimizer( BytecodeRegisterOptimizer::BytecodeRegisterOptimizer(
Zone* zone, TemporaryRegisterAllocator* register_allocator, Zone* zone, BytecodeRegisterAllocator* register_allocator,
int parameter_count, BytecodePipelineStage* next_stage) int fixed_registers_count, int parameter_count,
BytecodePipelineStage* next_stage)
: accumulator_(Register::virtual_accumulator()), : accumulator_(Register::virtual_accumulator()),
temporary_base_(register_allocator->allocation_base()), temporary_base_(fixed_registers_count),
max_register_index_(register_allocator->allocation_base() - 1), max_register_index_(fixed_registers_count - 1),
register_info_table_(zone), register_info_table_(zone),
equivalence_id_(0), equivalence_id_(0),
next_stage_(next_stage), next_stage_(next_stage),
...@@ -199,7 +222,7 @@ BytecodeRegisterOptimizer::BytecodeRegisterOptimizer( ...@@ -199,7 +222,7 @@ BytecodeRegisterOptimizer::BytecodeRegisterOptimizer(
static_cast<size_t>(temporary_base_.index())); static_cast<size_t>(temporary_base_.index()));
for (size_t i = 0; i < register_info_table_.size(); ++i) { for (size_t i = 0; i < register_info_table_.size(); ++i) {
register_info_table_[i] = new (zone) RegisterInfo( 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(), DCHECK_EQ(register_info_table_[i]->register_value().index(),
RegisterFromRegisterInfoTableIndex(i).index()); RegisterFromRegisterInfoTableIndex(i).index());
} }
...@@ -296,7 +319,7 @@ void BytecodeRegisterOptimizer::FlushState() { ...@@ -296,7 +319,7 @@ void BytecodeRegisterOptimizer::FlushState() {
// own equivalence set. // own equivalence set.
RegisterInfo* equivalent; RegisterInfo* equivalent;
while ((equivalent = reg_info->GetEquivalent()) != reg_info) { while ((equivalent = reg_info->GetEquivalent()) != reg_info) {
if (!equivalent->materialized()) { if (equivalent->allocated() && !equivalent->materialized()) {
OutputRegisterTransfer(reg_info, equivalent); OutputRegisterTransfer(reg_info, equivalent);
} }
equivalent->MoveToNewEquivalenceSet(NextEquivalenceId(), true); equivalent->MoveToNewEquivalenceSet(NextEquivalenceId(), true);
...@@ -404,6 +427,13 @@ void BytecodeRegisterOptimizer::RegisterTransfer( ...@@ -404,6 +427,13 @@ void BytecodeRegisterOptimizer::RegisterTransfer(
// Emit a placeholder nop to maintain source position info. // Emit a placeholder nop to maintain source position info.
EmitNopForSourceInfo(source_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( void BytecodeRegisterOptimizer::EmitNopForSourceInfo(
...@@ -426,14 +456,14 @@ void BytecodeRegisterOptimizer::DoMov(BytecodeNode* node) { ...@@ -426,14 +456,14 @@ void BytecodeRegisterOptimizer::DoMov(BytecodeNode* node) {
RegisterInfo* input_info = GetRegisterInfo(input); RegisterInfo* input_info = GetRegisterInfo(input);
Register output = GetRegisterOutputOperand( Register output = GetRegisterOutputOperand(
1, node->bytecode(), node->operands(), node->operand_count()); 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()); RegisterTransfer(input_info, output_info, node->source_info_ptr());
} }
void BytecodeRegisterOptimizer::DoStar(BytecodeNode* node) { void BytecodeRegisterOptimizer::DoStar(BytecodeNode* node) {
Register output = GetRegisterOutputOperand( Register output = GetRegisterOutputOperand(
0, node->bytecode(), node->operands(), node->operand_count()); 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()); RegisterTransfer(accumulator_info_, output_info, node->source_info_ptr());
} }
...@@ -451,7 +481,7 @@ void BytecodeRegisterOptimizer::PrepareRegisterRangeOutputOperand( ...@@ -451,7 +481,7 @@ void BytecodeRegisterOptimizer::PrepareRegisterRangeOutputOperand(
Register start, int count) { Register start, int count) {
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
Register reg(start.index() + i); Register reg(start.index() + i);
RegisterInfo* reg_info = GetOrCreateRegisterInfo(reg); RegisterInfo* reg_info = GetRegisterInfo(reg);
PrepareRegisterOutputOperand(reg_info); PrepareRegisterOutputOperand(reg_info);
} }
} }
...@@ -461,7 +491,7 @@ Register BytecodeRegisterOptimizer::GetEquivalentRegisterForInputOperand( ...@@ -461,7 +491,7 @@ Register BytecodeRegisterOptimizer::GetEquivalentRegisterForInputOperand(
// For a temporary register, RegInfo state may need be created. For // For a temporary register, RegInfo state may need be created. For
// locals and parameters, the RegInfo state is created in the // locals and parameters, the RegInfo state is created in the
// BytecodeRegisterOptimizer constructor. // BytecodeRegisterOptimizer constructor.
RegisterInfo* reg_info = GetOrCreateRegisterInfo(reg); RegisterInfo* reg_info = GetRegisterInfo(reg);
if (reg_info->materialized()) { if (reg_info->materialized()) {
return reg; return reg;
} else { } else {
...@@ -570,8 +600,8 @@ Register BytecodeRegisterOptimizer::GetRegisterOutputOperand( ...@@ -570,8 +600,8 @@ Register BytecodeRegisterOptimizer::GetRegisterOutputOperand(
BytecodeRegisterOptimizer::RegisterInfo* BytecodeRegisterOptimizer::RegisterInfo*
BytecodeRegisterOptimizer::GetRegisterInfo(Register reg) { BytecodeRegisterOptimizer::GetRegisterInfo(Register reg) {
size_t index = GetRegisterInfoTableIndex(reg); size_t index = GetRegisterInfoTableIndex(reg);
return (index < register_info_table_.size()) ? register_info_table_[index] DCHECK_LT(index, register_info_table_.size());
: nullptr; return register_info_table_[index];
} }
BytecodeRegisterOptimizer::RegisterInfo* BytecodeRegisterOptimizer::RegisterInfo*
...@@ -592,26 +622,37 @@ BytecodeRegisterOptimizer::NewRegisterInfo(Register reg) { ...@@ -592,26 +622,37 @@ BytecodeRegisterOptimizer::NewRegisterInfo(Register reg) {
void BytecodeRegisterOptimizer::GrowRegisterMap(Register reg) { void BytecodeRegisterOptimizer::GrowRegisterMap(Register reg) {
DCHECK(RegisterIsTemporary(reg)); DCHECK(RegisterIsTemporary(reg));
size_t index = GetRegisterInfoTableIndex(reg); size_t index = GetRegisterInfoTableIndex(reg);
DCHECK_GE(index, register_info_table_.size()); if (index >= register_info_table_.size()) {
size_t new_size = index + 1; size_t new_size = index + 1;
size_t old_size = register_info_table_.size(); size_t old_size = register_info_table_.size();
register_info_table_.resize(new_size); register_info_table_.resize(new_size);
for (size_t i = old_size; i < new_size; ++i) { for (size_t i = old_size; i < new_size; ++i) {
register_info_table_[i] = new (zone()) RegisterInfo( register_info_table_[i] =
RegisterFromRegisterInfoTableIndex(i), NextEquivalenceId(), false); new (zone()) RegisterInfo(RegisterFromRegisterInfoTableIndex(i),
NextEquivalenceId(), false, false);
}
} }
} }
void BytecodeRegisterOptimizer::TemporaryRegisterFreeEvent(Register reg) { void BytecodeRegisterOptimizer::RegisterAllocateEvent(Register reg) {
RegisterInfo* info = GetRegisterInfo(reg); GetOrCreateRegisterInfo(reg)->set_allocated(true);
if (info != nullptr) { }
// If register is materialized and part of equivalence set, make
// sure another member of the set holds the value before the void BytecodeRegisterOptimizer::RegisterListAllocateEvent(
// temporary register is removed. RegisterList reg_list) {
if (info->materialized()) { if (reg_list.register_count() != 0) {
CreateMaterializedEquivalent(info); 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);
} }
} }
......
...@@ -15,13 +15,14 @@ namespace interpreter { ...@@ -15,13 +15,14 @@ namespace interpreter {
// registers. The bytecode generator uses temporary registers // registers. The bytecode generator uses temporary registers
// liberally for correctness and convenience and this stage removes // liberally for correctness and convenience and this stage removes
// transfers that are not required and preserves correctness. // transfers that are not required and preserves correctness.
class BytecodeRegisterOptimizer final : public BytecodePipelineStage, class BytecodeRegisterOptimizer final
public TemporaryRegisterObserver, : public BytecodePipelineStage,
public ZoneObject { public BytecodeRegisterAllocator::Observer,
public ZoneObject {
public: public:
BytecodeRegisterOptimizer(Zone* zone, BytecodeRegisterOptimizer(Zone* zone,
TemporaryRegisterAllocator* register_allocator, BytecodeRegisterAllocator* register_allocator,
int parameter_count, int fixed_registers_count, int parameter_count,
BytecodePipelineStage* next_stage); BytecodePipelineStage* next_stage);
virtual ~BytecodeRegisterOptimizer() {} virtual ~BytecodeRegisterOptimizer() {}
...@@ -39,8 +40,10 @@ class BytecodeRegisterOptimizer final : public BytecodePipelineStage, ...@@ -39,8 +40,10 @@ class BytecodeRegisterOptimizer final : public BytecodePipelineStage,
class RegisterInfo; class RegisterInfo;
// TemporaryRegisterObserver interface. // BytecodeRegisterAllocator::Observer interface.
void TemporaryRegisterFreeEvent(Register reg) override; void RegisterAllocateEvent(Register reg) override;
void RegisterListAllocateEvent(RegisterList reg_list) override;
void RegisterListFreeEvent(RegisterList reg) override;
// Helpers for BytecodePipelineStage interface. // Helpers for BytecodePipelineStage interface.
void FlushState(); void FlushState();
......
...@@ -146,6 +146,9 @@ PeepholeActionAndData PeepholeActionTableWriter::LookupActionAndData( ...@@ -146,6 +146,9 @@ PeepholeActionAndData PeepholeActionTableWriter::LookupActionAndData(
Bytecode::kIllegal}; Bytecode::kIllegal};
} }
// TODO(rmcilroy): Add elide for consecutive mov to and from the same
// register.
// Remove ToBoolean coercion from conditional jumps where possible. // Remove ToBoolean coercion from conditional jumps where possible.
if (Bytecodes::WritesBooleanToAccumulator(last)) { if (Bytecodes::WritesBooleanToAccumulator(last)) {
if (Bytecodes::IsJumpIfToBoolean(current)) { if (Bytecodes::IsJumpIfToBoolean(current)) {
......
...@@ -993,7 +993,6 @@ ...@@ -993,7 +993,6 @@
'interpreter/bytecode-pipeline.h', 'interpreter/bytecode-pipeline.h',
'interpreter/bytecode-register.cc', 'interpreter/bytecode-register.cc',
'interpreter/bytecode-register.h', 'interpreter/bytecode-register.h',
'interpreter/bytecode-register-allocator.cc',
'interpreter/bytecode-register-allocator.h', 'interpreter/bytecode-register-allocator.h',
'interpreter/bytecode-register-optimizer.cc', 'interpreter/bytecode-register-optimizer.cc',
'interpreter/bytecode-register-optimizer.h', 'interpreter/bytecode-register-optimizer.h',
......
...@@ -65,7 +65,7 @@ snippet: " ...@@ -65,7 +65,7 @@ snippet: "
x = x + (x = 100) + (x = 101); x = x + (x = 100) + (x = 101);
return x; return x;
" "
frame size: 3 frame size: 2
parameter count: 1 parameter count: 1
bytecode array length: 28 bytecode array length: 28
bytecodes: [ bytecodes: [
...@@ -76,10 +76,10 @@ bytecodes: [ ...@@ -76,10 +76,10 @@ bytecodes: [
B(Mov), R(0), R(1), B(Mov), R(0), R(1),
B(Star), R(0), B(Star), R(0),
/* 57 E> */ B(Add), R(1), U8(2), /* 57 E> */ B(Add), R(1), U8(2),
B(Star), R(2), B(Star), R(1),
B(LdaSmi), U8(101), B(LdaSmi), U8(101),
B(Star), R(0), B(Star), R(0),
/* 69 E> */ B(Add), R(2), U8(3), /* 69 E> */ B(Add), R(1), U8(3),
B(Star), R(0), B(Star), R(0),
/* 77 S> */ B(Nop), /* 77 S> */ B(Nop),
/* 87 S> */ B(Return), /* 87 S> */ B(Return),
...@@ -96,7 +96,7 @@ snippet: " ...@@ -96,7 +96,7 @@ snippet: "
x++; x++;
return x; return x;
" "
frame size: 3 frame size: 2
parameter count: 1 parameter count: 1
bytecode array length: 29 bytecode array length: 29
bytecodes: [ bytecodes: [
...@@ -106,10 +106,10 @@ bytecodes: [ ...@@ -106,10 +106,10 @@ bytecodes: [
/* 46 S> */ B(LdaSmi), U8(56), /* 46 S> */ B(LdaSmi), U8(56),
B(Star), R(0), B(Star), R(0),
/* 61 E> */ B(Sub), R(0), U8(2), /* 61 E> */ B(Sub), R(0), U8(2),
B(Star), R(2), B(Star), R(1),
B(LdaSmi), U8(57), B(LdaSmi), U8(57),
B(Star), R(0), B(Star), R(0),
/* 68 E> */ B(Add), R(2), U8(3), /* 68 E> */ B(Add), R(1), U8(3),
B(Star), R(0), B(Star), R(0),
/* 75 S> */ B(Inc), U8(4), /* 75 S> */ B(Inc), U8(4),
B(Star), R(0), B(Star), R(0),
...@@ -127,7 +127,7 @@ snippet: " ...@@ -127,7 +127,7 @@ snippet: "
var y = x + (x = 1) + (x = 2) + (x = 3); var y = x + (x = 1) + (x = 2) + (x = 3);
return y; return y;
" "
frame size: 4 frame size: 3
parameter count: 1 parameter count: 1
bytecode array length: 37 bytecode array length: 37
bytecodes: [ bytecodes: [
...@@ -138,10 +138,10 @@ bytecodes: [ ...@@ -138,10 +138,10 @@ bytecodes: [
B(Mov), R(0), R(2), B(Mov), R(0), R(2),
B(Star), R(0), B(Star), R(0),
/* 61 E> */ B(Add), R(2), U8(2), /* 61 E> */ B(Add), R(2), U8(2),
B(Star), R(3), B(Star), R(2),
B(LdaSmi), U8(2), B(LdaSmi), U8(2),
B(Star), R(0), 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(Star), R(2),
B(LdaSmi), U8(3), B(LdaSmi), U8(3),
B(Star), R(0), B(Star), R(0),
...@@ -161,7 +161,7 @@ snippet: " ...@@ -161,7 +161,7 @@ snippet: "
var x = x + (x = 1) + (x = 2) + (x = 3); var x = x + (x = 1) + (x = 2) + (x = 3);
return x; return x;
" "
frame size: 3 frame size: 2
parameter count: 1 parameter count: 1
bytecode array length: 37 bytecode array length: 37
bytecodes: [ bytecodes: [
...@@ -172,10 +172,10 @@ bytecodes: [ ...@@ -172,10 +172,10 @@ bytecodes: [
B(Mov), R(0), R(1), B(Mov), R(0), R(1),
B(Star), R(0), B(Star), R(0),
/* 61 E> */ B(Add), R(1), U8(2), /* 61 E> */ B(Add), R(1), U8(2),
B(Star), R(2), B(Star), R(1),
B(LdaSmi), U8(2), B(LdaSmi), U8(2),
B(Star), R(0), 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(Star), R(1),
B(LdaSmi), U8(3), B(LdaSmi), U8(3),
B(Star), R(0), B(Star), R(0),
...@@ -194,7 +194,7 @@ snippet: " ...@@ -194,7 +194,7 @@ snippet: "
var x = 10, y = 20; var x = 10, y = 20;
return x + (x = 1) + (x + 1) * (y = 2) + (y = 3) + (x = 4) + (y = 5) + y; return x + (x = 1) + (x + 1) * (y = 2) + (y = 3) + (x = 4) + (y = 5) + y;
" "
frame size: 5 frame size: 4
parameter count: 1 parameter count: 1
bytecode array length: 72 bytecode array length: 72
bytecodes: [ bytecodes: [
...@@ -207,28 +207,28 @@ bytecodes: [ ...@@ -207,28 +207,28 @@ bytecodes: [
B(Mov), R(0), R(2), B(Mov), R(0), R(2),
B(Star), R(0), B(Star), R(0),
/* 68 E> */ B(Add), R(2), U8(2), /* 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), /* 76 E> */ B(AddSmi), U8(1), R(0), U8(3),
B(Star), R(4), B(Star), R(3),
B(LdaSmi), U8(2), B(LdaSmi), U8(2),
B(Star), R(1), B(Star), R(1),
/* 88 E> */ B(Mul), R(4), U8(4), /* 88 E> */ B(Mul), R(3), U8(4),
B(Add), R(3), U8(5), B(Add), R(2), U8(5),
B(Star), R(2), B(Star), R(2),
B(LdaSmi), U8(3), B(LdaSmi), U8(3),
B(Star), R(1), B(Star), R(1),
/* 98 E> */ B(Add), R(2), U8(6), /* 98 E> */ B(Add), R(2), U8(6),
B(Star), R(3), B(Star), R(2),
B(LdaSmi), U8(4), B(LdaSmi), U8(4),
B(Star), R(0), 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(Star), R(2),
B(LdaSmi), U8(5), B(LdaSmi), U8(5),
B(Star), R(1), B(Star), R(1),
/* 118 E> */ B(Add), R(2), U8(8), /* 118 E> */ B(Add), R(2), U8(8),
B(Star), R(3), B(Star), R(2),
B(Ldar), R(1), B(Ldar), R(1),
/* 125 E> */ B(Add), R(3), U8(9), /* 125 E> */ B(Add), R(2), U8(9),
/* 128 S> */ B(Return), /* 128 S> */ B(Return),
] ]
constant pool: [ constant pool: [
...@@ -241,7 +241,7 @@ snippet: " ...@@ -241,7 +241,7 @@ snippet: "
var x = 17; var x = 17;
return 1 + x + (x++) + (++x); return 1 + x + (x++) + (++x);
" "
frame size: 4 frame size: 3
parameter count: 1 parameter count: 1
bytecode array length: 41 bytecode array length: 41
bytecodes: [ bytecodes: [
...@@ -252,18 +252,18 @@ bytecodes: [ ...@@ -252,18 +252,18 @@ bytecodes: [
B(Star), R(1), B(Star), R(1),
B(Ldar), R(0), B(Ldar), R(0),
/* 57 E> */ B(Add), R(1), U8(2), /* 57 E> */ B(Add), R(1), U8(2),
B(Star), R(2), B(Star), R(1),
B(Ldar), R(0), B(Ldar), R(0),
B(ToNumber), R(1), B(ToNumber), R(2),
B(Inc), U8(3), B(Inc), U8(3),
B(Star), R(0), B(Star), R(0),
B(Ldar), R(1), B(Ldar), R(2),
/* 63 E> */ B(Add), R(2), U8(4), /* 63 E> */ B(Add), R(1), U8(4),
B(Star), R(3), B(Star), R(1),
B(Ldar), R(0), B(Ldar), R(0),
B(Inc), U8(5), B(Inc), U8(5),
B(Star), R(0), B(Star), R(0),
/* 72 E> */ B(Add), R(3), U8(6), /* 72 E> */ B(Add), R(1), U8(6),
/* 76 S> */ B(Return), /* 76 S> */ B(Return),
] ]
constant pool: [ constant pool: [
......
...@@ -47,7 +47,7 @@ snippet: " ...@@ -47,7 +47,7 @@ snippet: "
} }
return sum; return sum;
" "
frame size: 5 frame size: 4
parameter count: 1 parameter count: 1
bytecode array length: 69 bytecode array length: 69
bytecodes: [ bytecodes: [
...@@ -71,9 +71,9 @@ bytecodes: [ ...@@ -71,9 +71,9 @@ bytecodes: [
B(Star), R(0), B(Star), R(0),
/* 142 S> */ B(Ldar), R(2), /* 142 S> */ B(Ldar), R(2),
/* 150 E> */ B(Add), R(1), U8(7), /* 150 E> */ B(Add), R(1), U8(7),
B(Star), R(4), B(Star), R(3),
B(LdaSmi), U8(12), B(LdaSmi), U8(12),
/* 152 E> */ B(TestEqual), R(4), U8(8), /* 152 E> */ B(TestEqual), R(3), U8(8),
B(JumpIfFalse), U8(4), B(JumpIfFalse), U8(4),
/* 161 S> */ B(Jump), U8(20), /* 161 S> */ B(Jump), U8(20),
/* 118 S> */ B(Ldar), R(2), /* 118 S> */ B(Ldar), R(2),
......
...@@ -26,8 +26,8 @@ bytecodes: [ ...@@ -26,8 +26,8 @@ bytecodes: [
/* 34 S> */ B(CreateClosure), U8(0), U8(2), /* 34 S> */ B(CreateClosure), U8(0), U8(2),
/* 36 E> */ B(StaLookupSlotSloppy), U8(1), /* 36 E> */ B(StaLookupSlotSloppy), U8(1),
/* 52 S> */ B(LdaConstant), U8(2), /* 52 S> */ B(LdaConstant), U8(2),
B(Star), R(3), B(Star), R(4),
B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), R(3), U8(1), R(1), B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), R(4), U8(1), R(1),
B(LdaConstant), U8(3), B(LdaConstant), U8(3),
B(Star), R(3), B(Star), R(3),
B(LdaZero), B(LdaZero),
......
...@@ -35,8 +35,8 @@ bytecodes: [ ...@@ -35,8 +35,8 @@ bytecodes: [
B(CallRuntime), U16(Runtime::kLoadFromSuper), R(3), U8(3), B(CallRuntime), U16(Runtime::kLoadFromSuper), R(3), U8(3),
B(Star), R(1), B(Star), R(1),
/* 117 E> */ B(Call), R(1), R(this), U8(1), U8(2), /* 117 E> */ B(Call), R(1), R(this), U8(1), U8(2),
B(Star), R(3), B(Star), R(1),
B(AddSmi), U8(1), R(3), U8(8), B(AddSmi), U8(1), R(1), U8(8),
/* 131 S> */ B(Return), /* 131 S> */ B(Return),
] ]
constant pool: [ constant pool: [
......
...@@ -223,8 +223,8 @@ bytecodes: [ ...@@ -223,8 +223,8 @@ bytecodes: [
B(Star), R(2), B(Star), R(2),
/* 87 S> */ B(JumpIfNotHole), U8(11), /* 87 S> */ B(JumpIfNotHole), U8(11),
B(LdaConstant), U8(2), B(LdaConstant), U8(2),
B(Star), R(5), B(Star), R(4),
B(CallRuntime), U16(Runtime::kThrowReferenceError), R(5), U8(1), B(CallRuntime), U16(Runtime::kThrowReferenceError), R(4), U8(1),
B(Star), R(4), B(Star), R(4),
/* 94 E> */ B(New), R(4), R(0), U8(0), U8(4), /* 94 E> */ B(New), R(4), R(0), U8(0), U8(4),
/* 103 S> */ B(Return), /* 103 S> */ B(Return),
......
...@@ -79,7 +79,7 @@ snippet: " ...@@ -79,7 +79,7 @@ snippet: "
function f(a, ...restArgs) { return restArgs[0] + arguments[0]; } function f(a, ...restArgs) { return restArgs[0] + arguments[0]; }
f(); f();
" "
frame size: 5 frame size: 4
parameter count: 2 parameter count: 2
bytecode array length: 26 bytecode array length: 26
bytecodes: [ bytecodes: [
...@@ -92,10 +92,10 @@ bytecodes: [ ...@@ -92,10 +92,10 @@ bytecodes: [
/* 10 E> */ B(StackCheck), /* 10 E> */ B(StackCheck),
B(Mov), R(arg0), R(1), B(Mov), R(arg0), R(1),
/* 29 S> */ B(LdaZero), /* 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), B(LdaZero),
/* 59 E> */ B(LdaKeyedProperty), R(2), U8(4), /* 59 E> */ B(LdaKeyedProperty), R(2), U8(4),
B(Add), R(4), U8(6), B(Add), R(3), U8(6),
/* 64 S> */ B(Return), /* 64 S> */ B(Return),
] ]
constant pool: [ constant pool: [
......
...@@ -24,8 +24,8 @@ bytecodes: [ ...@@ -24,8 +24,8 @@ bytecodes: [
B(StaContextSlot), R(context), U8(5), U8(0), B(StaContextSlot), R(context), U8(5), U8(0),
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 34 S> */ B(LdaConstant), U8(0), /* 34 S> */ B(LdaConstant), U8(0),
B(Star), R(3), B(Star), R(4),
B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), R(3), U8(1), R(1), B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), R(4), U8(1), R(1),
B(LdaConstant), U8(1), B(LdaConstant), U8(1),
B(Star), R(3), B(Star), R(3),
B(LdaZero), B(LdaZero),
......
...@@ -146,7 +146,7 @@ snippet: " ...@@ -146,7 +146,7 @@ snippet: "
if (x['a'] == 20) break; if (x['a'] == 20) break;
} }
" "
frame size: 8 frame size: 7
parameter count: 1 parameter count: 1
bytecode array length: 83 bytecode array length: 83
bytecodes: [ bytecodes: [
...@@ -168,15 +168,15 @@ bytecodes: [ ...@@ -168,15 +168,15 @@ bytecodes: [
/* 67 E> */ B(StaNamedPropertySloppy), R(0), U8(2), U8(10), /* 67 E> */ B(StaNamedPropertySloppy), R(0), U8(2), U8(10),
/* 62 E> */ B(StackCheck), /* 62 E> */ B(StackCheck),
/* 95 S> */ B(Nop), /* 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), B(LdaSmi), U8(10),
/* 106 E> */ B(TestEqual), R(7), U8(6), /* 106 E> */ B(TestEqual), R(6), U8(6),
B(JumpIfFalse), U8(4), B(JumpIfFalse), U8(4),
/* 113 S> */ B(Jump), U8(17), /* 113 S> */ B(Jump), U8(17),
/* 125 S> */ B(Nop), /* 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), B(LdaSmi), U8(20),
/* 136 E> */ B(TestEqual), R(7), U8(9), /* 136 E> */ B(TestEqual), R(6), U8(9),
B(JumpIfFalse), U8(4), B(JumpIfFalse), U8(4),
/* 143 S> */ B(Jump), U8(9), /* 143 S> */ B(Jump), U8(9),
B(ForInStep), R(5), B(ForInStep), R(5),
......
...@@ -181,17 +181,17 @@ bytecodes: [ ...@@ -181,17 +181,17 @@ bytecodes: [
B(LdaFalse), B(LdaFalse),
B(Star), R(6), B(Star), R(6),
B(CallRuntime), U16(Runtime::k_CreateIterResultObject), R(5), U8(2), B(CallRuntime), U16(Runtime::k_CreateIterResultObject), R(5), U8(2),
B(Star), R(7), B(Star), R(5),
B(LdrContextSlot), R(context), U8(5), U8(0), R(5), B(LdrContextSlot), R(context), U8(5), U8(0), R(6),
B(LdaSmi), U8(1), B(LdaSmi), U8(1),
B(SuspendGenerator), R(5), B(SuspendGenerator), R(6),
B(Ldar), R(7), B(Ldar), R(5),
/* 25 S> */ B(Return), /* 25 S> */ B(Return),
B(LdaSmi), U8(-2), B(LdaSmi), U8(-2),
B(Star), R(1), B(Star), R(1),
B(CallRuntime), U16(Runtime::k_GeneratorGetInputOrDebugPos), R(5), U8(1), B(CallRuntime), U16(Runtime::k_GeneratorGetInputOrDebugPos), R(6), U8(1),
B(Star), R(6), B(Star), R(7),
B(CallRuntime), U16(Runtime::k_GeneratorGetResumeMode), R(5), U8(1), B(CallRuntime), U16(Runtime::k_GeneratorGetResumeMode), R(6), U8(1),
B(Star), R(8), B(Star), R(8),
B(LdaZero), B(LdaZero),
B(TestEqualStrict), R(8), U8(0), B(TestEqualStrict), R(8), U8(0),
...@@ -202,13 +202,13 @@ bytecodes: [ ...@@ -202,13 +202,13 @@ bytecodes: [
B(Jump), U8(2), B(Jump), U8(2),
B(LdaTrue), B(LdaTrue),
B(Star), R(10), 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(CallRuntime), U16(Runtime::k_CreateIterResultObject), R(9), U8(2),
B(Star), R(3), B(Star), R(3),
B(LdaSmi), U8(1), B(LdaSmi), U8(1),
B(Star), R(2), B(Star), R(2),
B(Jump), U8(35), B(Jump), U8(35),
B(Ldar), R(6), B(Ldar), R(7),
/* 16 E> */ B(Throw), /* 16 E> */ B(Throw),
B(LdrUndefined), R(5), B(LdrUndefined), R(5),
B(LdaTrue), B(LdaTrue),
...@@ -267,7 +267,7 @@ snippet: " ...@@ -267,7 +267,7 @@ snippet: "
" "
frame size: 18 frame size: 18
parameter count: 1 parameter count: 1
bytecode array length: 807 bytecode array length: 805
bytecodes: [ bytecodes: [
B(Ldar), R(new_target), B(Ldar), R(new_target),
B(JumpIfUndefined), U8(28), B(JumpIfUndefined), U8(28),
...@@ -379,23 +379,23 @@ bytecodes: [ ...@@ -379,23 +379,23 @@ bytecodes: [
/* 36 S> */ B(LdaContextSlot), R(context), U8(4), U8(0), /* 36 S> */ B(LdaContextSlot), R(context), U8(4), U8(0),
B(JumpIfNotHole), U8(11), B(JumpIfNotHole), U8(11),
B(LdaConstant), U8(8), B(LdaConstant), U8(8),
B(Star), R(13), B(Star), R(14),
B(CallRuntime), U16(Runtime::kThrowReferenceError), R(13), U8(1), B(CallRuntime), U16(Runtime::kThrowReferenceError), R(14), U8(1),
B(Star), R(12), B(Star), R(12),
B(LdaFalse), B(LdaFalse),
B(Star), R(13), B(Star), R(13),
B(CallRuntime), U16(Runtime::k_CreateIterResultObject), R(12), U8(2), B(CallRuntime), U16(Runtime::k_CreateIterResultObject), R(12), U8(2),
B(Star), R(14), B(Star), R(12),
B(LdrContextSlot), R(1), U8(5), U8(0), R(12), B(LdrContextSlot), R(1), U8(5), U8(0), R(13),
B(LdaSmi), U8(1), B(LdaSmi), U8(1),
B(SuspendGenerator), R(12), B(SuspendGenerator), R(13),
B(Ldar), R(14), B(Ldar), R(12),
/* 44 S> */ B(Return), /* 44 S> */ B(Return),
B(LdaSmi), U8(-2), B(LdaSmi), U8(-2),
B(Star), R(4), B(Star), R(4),
B(CallRuntime), U16(Runtime::k_GeneratorGetInputOrDebugPos), R(12), U8(1), B(CallRuntime), U16(Runtime::k_GeneratorGetInputOrDebugPos), R(13), U8(1),
B(Star), R(13), B(Star), R(14),
B(CallRuntime), U16(Runtime::k_GeneratorGetResumeMode), R(12), U8(1), B(CallRuntime), U16(Runtime::k_GeneratorGetResumeMode), R(13), U8(1),
B(Star), R(15), B(Star), R(15),
B(LdaZero), B(LdaZero),
B(TestEqualStrict), R(15), U8(0), B(TestEqualStrict), R(15), U8(0),
...@@ -406,7 +406,7 @@ bytecodes: [ ...@@ -406,7 +406,7 @@ bytecodes: [
B(Jump), U8(2), B(Jump), U8(2),
B(LdaTrue), B(LdaTrue),
B(Star), R(17), 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(CallRuntime), U16(Runtime::k_CreateIterResultObject), R(16), U8(2),
B(PopContext), R(2), B(PopContext), R(2),
B(PopContext), R(2), B(PopContext), R(2),
...@@ -417,14 +417,13 @@ bytecodes: [ ...@@ -417,14 +417,13 @@ bytecodes: [
B(Star), R(9), B(Star), R(9),
B(LdaZero), B(LdaZero),
B(Star), R(8), B(Star), R(8),
B(Jump), U8(76), B(Jump), U8(74),
B(Ldar), R(13), B(Ldar), R(14),
/* 36 E> */ B(Throw), /* 36 E> */ B(Throw),
B(Ldar), R(13),
B(PopContext), R(2), B(PopContext), R(2),
B(LdaZero), B(LdaZero),
B(StaContextSlot), R(1), U8(9), U8(0), 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(Jump), U8(44),
B(Star), R(12), B(Star), R(12),
B(Ldar), R(closure), B(Ldar), R(closure),
...@@ -585,7 +584,7 @@ constant pool: [ ...@@ -585,7 +584,7 @@ constant pool: [
FIXED_ARRAY_TYPE, FIXED_ARRAY_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["x"], ONE_BYTE_INTERNALIZED_STRING_TYPE ["x"],
Smi [146], Smi [146],
Smi [169], Smi [167],
ONE_BYTE_INTERNALIZED_STRING_TYPE [".catch"], ONE_BYTE_INTERNALIZED_STRING_TYPE [".catch"],
FIXED_ARRAY_TYPE, FIXED_ARRAY_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["return"], ONE_BYTE_INTERNALIZED_STRING_TYPE ["return"],
...@@ -595,12 +594,12 @@ constant pool: [ ...@@ -595,12 +594,12 @@ constant pool: [
Smi [129], Smi [129],
Smi [166], Smi [166],
Smi [155], Smi [155],
Smi [603], Smi [601],
] ]
handlers: [ handlers: [
[48, 720, 726], [48, 718, 724],
[153, 460, 466], [153, 458, 464],
[156, 416, 418], [156, 414, 416],
[574, 588, 590], [572, 586, 588],
] ]
...@@ -58,7 +58,7 @@ snippet: " ...@@ -58,7 +58,7 @@ snippet: "
" "
frame size: 3 frame size: 3
parameter count: 1 parameter count: 1
bytecode array length: 26 bytecode array length: 29
bytecodes: [ bytecodes: [
B(LdaTheHole), B(LdaTheHole),
B(Star), R(0), B(Star), R(0),
...@@ -70,6 +70,7 @@ bytecodes: [ ...@@ -70,6 +70,7 @@ bytecodes: [
B(LdaConstant), U8(0), B(LdaConstant), U8(0),
B(Star), R(2), B(Star), R(2),
/* 45 E> */ B(CallRuntime), U16(Runtime::kThrowReferenceError), R(2), U8(1), /* 45 E> */ B(CallRuntime), U16(Runtime::kThrowReferenceError), R(2), U8(1),
B(Mov), R(1), R(0),
B(Mov), R(1), R(0), B(Mov), R(1), R(0),
B(LdaUndefined), B(LdaUndefined),
/* 52 S> */ B(Return), /* 52 S> */ B(Return),
......
...@@ -25,8 +25,8 @@ bytecodes: [ ...@@ -25,8 +25,8 @@ bytecodes: [
B(StaContextSlot), R(context), U8(5), U8(0), B(StaContextSlot), R(context), U8(5), U8(0),
/* 10 E> */ B(StackCheck), /* 10 E> */ B(StackCheck),
/* 14 S> */ B(LdaConstant), U8(0), /* 14 S> */ B(LdaConstant), U8(0),
B(Star), R(3), B(Star), R(4),
B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), R(3), U8(1), R(1), B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), R(4), U8(1), R(1),
B(LdaConstant), U8(1), B(LdaConstant), U8(1),
B(Star), R(3), B(Star), R(3),
B(LdaZero), B(LdaZero),
...@@ -70,8 +70,8 @@ bytecodes: [ ...@@ -70,8 +70,8 @@ bytecodes: [
B(StaContextSlot), R(context), U8(5), U8(0), B(StaContextSlot), R(context), U8(5), U8(0),
/* 10 E> */ B(StackCheck), /* 10 E> */ B(StackCheck),
/* 14 S> */ B(LdaConstant), U8(0), /* 14 S> */ B(LdaConstant), U8(0),
B(Star), R(3), B(Star), R(4),
B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), R(3), U8(1), R(1), B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), R(4), U8(1), R(1),
B(LdaConstant), U8(1), B(LdaConstant), U8(1),
B(Star), R(3), B(Star), R(3),
B(LdaZero), B(LdaZero),
...@@ -118,8 +118,8 @@ bytecodes: [ ...@@ -118,8 +118,8 @@ bytecodes: [
/* 14 S> */ B(LdaSmi), U8(20), /* 14 S> */ B(LdaSmi), U8(20),
/* 16 E> */ B(StaLookupSlotSloppy), U8(0), /* 16 E> */ B(StaLookupSlotSloppy), U8(0),
/* 22 S> */ B(LdaConstant), U8(1), /* 22 S> */ B(LdaConstant), U8(1),
B(Star), R(3), B(Star), R(4),
B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), R(3), U8(1), R(1), B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), R(4), U8(1), R(1),
B(LdaConstant), U8(2), B(LdaConstant), U8(2),
B(Star), R(3), B(Star), R(3),
B(LdaZero), B(LdaZero),
...@@ -167,8 +167,8 @@ bytecodes: [ ...@@ -167,8 +167,8 @@ bytecodes: [
B(StaContextSlot), R(context), U8(5), U8(0), B(StaContextSlot), R(context), U8(5), U8(0),
/* 38 E> */ B(StackCheck), /* 38 E> */ B(StackCheck),
/* 44 S> */ B(LdaConstant), U8(0), /* 44 S> */ B(LdaConstant), U8(0),
B(Star), R(3), B(Star), R(4),
B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), R(3), U8(1), R(1), B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), R(4), U8(1), R(1),
B(LdaConstant), U8(1), B(LdaConstant), U8(1),
B(Star), R(3), B(Star), R(3),
B(LdaZero), B(LdaZero),
...@@ -217,8 +217,8 @@ bytecodes: [ ...@@ -217,8 +217,8 @@ bytecodes: [
B(StaContextSlot), R(context), U8(5), U8(0), B(StaContextSlot), R(context), U8(5), U8(0),
/* 34 E> */ B(StackCheck), /* 34 E> */ B(StackCheck),
/* 40 S> */ B(LdaConstant), U8(0), /* 40 S> */ B(LdaConstant), U8(0),
B(Star), R(3), B(Star), R(4),
B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), R(3), U8(1), R(1), B(CallRuntimeForPair), U16(Runtime::kLoadLookupSlotForCall), R(4), U8(1), R(1),
B(LdaConstant), U8(1), B(LdaConstant), U8(1),
B(Star), R(3), B(Star), R(3),
B(LdaZero), B(LdaZero),
......
...@@ -157,7 +157,7 @@ bytecodes: [ ...@@ -157,7 +157,7 @@ bytecodes: [
B(Star), R(5), B(Star), R(5),
B(Mov), R(0), R(1), B(Mov), R(0), R(1),
B(CallRuntime), U16(Runtime::kDefineAccessorPropertyUnchecked), R(1), U8(5), B(CallRuntime), U16(Runtime::kDefineAccessorPropertyUnchecked), R(1), U8(5),
B(Ldar), R(0), B(Ldar), R(1),
/* 68 S> */ B(Return), /* 68 S> */ B(Return),
] ]
constant pool: [ constant pool: [
...@@ -188,7 +188,7 @@ bytecodes: [ ...@@ -188,7 +188,7 @@ bytecodes: [
B(Star), R(5), B(Star), R(5),
B(Mov), R(0), R(1), B(Mov), R(0), R(1),
B(CallRuntime), U16(Runtime::kDefineAccessorPropertyUnchecked), R(1), U8(5), B(CallRuntime), U16(Runtime::kDefineAccessorPropertyUnchecked), R(1), U8(5),
B(Ldar), R(0), B(Ldar), R(1),
/* 102 S> */ B(Return), /* 102 S> */ B(Return),
] ]
constant pool: [ constant pool: [
...@@ -220,7 +220,7 @@ bytecodes: [ ...@@ -220,7 +220,7 @@ bytecodes: [
B(Star), R(5), B(Star), R(5),
B(Mov), R(0), R(1), B(Mov), R(0), R(1),
B(CallRuntime), U16(Runtime::kDefineAccessorPropertyUnchecked), R(1), U8(5), B(CallRuntime), U16(Runtime::kDefineAccessorPropertyUnchecked), R(1), U8(5),
B(Ldar), R(0), B(Ldar), R(1),
/* 74 S> */ B(Return), /* 74 S> */ B(Return),
] ]
constant pool: [ constant pool: [
...@@ -250,7 +250,7 @@ bytecodes: [ ...@@ -250,7 +250,7 @@ bytecodes: [
B(Mov), R(1), R(2), B(Mov), R(1), R(2),
B(Mov), R(0), R(4), B(Mov), R(0), R(4),
/* 57 E> */ B(CallRuntime), U16(Runtime::kSetProperty), R(2), U8(4), /* 57 E> */ B(CallRuntime), U16(Runtime::kSetProperty), R(2), U8(4),
B(Ldar), R(1), B(Ldar), R(2),
/* 62 S> */ B(Return), /* 62 S> */ B(Return),
] ]
constant pool: [ constant pool: [
...@@ -273,7 +273,7 @@ bytecodes: [ ...@@ -273,7 +273,7 @@ bytecodes: [
B(Star), R(2), B(Star), R(2),
B(Mov), R(0), R(1), B(Mov), R(0), R(1),
B(CallRuntime), U16(Runtime::kInternalSetPrototype), R(1), U8(2), B(CallRuntime), U16(Runtime::kInternalSetPrototype), R(1), U8(2),
B(Ldar), R(0), B(Ldar), R(1),
/* 62 S> */ B(Return), /* 62 S> */ B(Return),
] ]
constant pool: [ constant pool: [
...@@ -303,7 +303,7 @@ bytecodes: [ ...@@ -303,7 +303,7 @@ bytecodes: [
B(Star), R(6), B(Star), R(6),
B(Mov), R(1), R(2), B(Mov), R(1), R(2),
B(CallRuntime), U16(Runtime::kDefineDataPropertyInLiteral), R(2), U8(5), B(CallRuntime), U16(Runtime::kDefineDataPropertyInLiteral), R(2), U8(5),
B(Ldar), R(1), B(Ldar), R(2),
/* 69 S> */ B(Return), /* 69 S> */ B(Return),
] ]
constant pool: [ constant pool: [
...@@ -335,7 +335,7 @@ bytecodes: [ ...@@ -335,7 +335,7 @@ bytecodes: [
B(Star), R(6), B(Star), R(6),
B(Mov), R(1), R(2), B(Mov), R(1), R(2),
B(CallRuntime), U16(Runtime::kDefineDataPropertyInLiteral), R(2), U8(5), B(CallRuntime), U16(Runtime::kDefineDataPropertyInLiteral), R(2), U8(5),
B(Ldar), R(1), B(Ldar), R(2),
/* 77 S> */ B(Return), /* 77 S> */ B(Return),
] ]
constant pool: [ constant pool: [
...@@ -352,7 +352,7 @@ snippet: " ...@@ -352,7 +352,7 @@ snippet: "
" "
frame size: 7 frame size: 7
parameter count: 1 parameter count: 1
bytecode array length: 49 bytecode array length: 46
bytecodes: [ bytecodes: [
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaConstant), U8(0), /* 42 S> */ B(LdaConstant), U8(0),
...@@ -368,10 +368,9 @@ bytecodes: [ ...@@ -368,10 +368,9 @@ bytecodes: [
B(Mov), R(1), R(2), B(Mov), R(1), R(2),
B(CallRuntime), U16(Runtime::kDefineDataPropertyInLiteral), R(2), U8(5), B(CallRuntime), U16(Runtime::kDefineDataPropertyInLiteral), R(2), U8(5),
B(CreateObjectLiteral), U8(1), U8(0), U8(35), R(4), B(CreateObjectLiteral), U8(1), U8(0), U8(35), R(4),
B(Mov), R(1), R(2),
B(Mov), R(4), R(3), B(Mov), R(4), R(3),
B(CallRuntime), U16(Runtime::kInternalSetPrototype), R(2), U8(2), B(CallRuntime), U16(Runtime::kInternalSetPrototype), R(2), U8(2),
B(Ldar), R(1), B(Ldar), R(2),
/* 84 S> */ B(Return), /* 84 S> */ B(Return),
] ]
constant pool: [ constant pool: [
...@@ -387,7 +386,7 @@ snippet: " ...@@ -387,7 +386,7 @@ snippet: "
" "
frame size: 7 frame size: 7
parameter count: 1 parameter count: 1
bytecode array length: 73 bytecode array length: 67
bytecodes: [ bytecodes: [
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaConstant), U8(0), /* 42 S> */ B(LdaConstant), U8(0),
...@@ -408,7 +407,6 @@ bytecodes: [ ...@@ -408,7 +407,6 @@ bytecodes: [
B(Star), R(4), B(Star), R(4),
B(LdaZero), B(LdaZero),
B(Star), R(5), B(Star), R(5),
B(Mov), R(1), R(2),
B(CallRuntime), U16(Runtime::kDefineGetterPropertyUnchecked), R(2), U8(4), B(CallRuntime), U16(Runtime::kDefineGetterPropertyUnchecked), R(2), U8(4),
B(LdaConstant), U8(3), B(LdaConstant), U8(3),
B(ToName), R(3), B(ToName), R(3),
...@@ -416,9 +414,8 @@ bytecodes: [ ...@@ -416,9 +414,8 @@ bytecodes: [
B(Star), R(4), B(Star), R(4),
B(LdaZero), B(LdaZero),
B(Star), R(5), B(Star), R(5),
B(Mov), R(1), R(2),
B(CallRuntime), U16(Runtime::kDefineSetterPropertyUnchecked), R(2), U8(4), B(CallRuntime), U16(Runtime::kDefineSetterPropertyUnchecked), R(2), U8(4),
B(Ldar), R(1), B(Ldar), R(2),
/* 99 S> */ B(Return), /* 99 S> */ B(Return),
] ]
constant pool: [ constant pool: [
......
...@@ -95,7 +95,7 @@ snippet: " ...@@ -95,7 +95,7 @@ snippet: "
var y = void (x * x - 1); var y = void (x * x - 1);
return y; return y;
" "
frame size: 4 frame size: 3
parameter count: 1 parameter count: 1
bytecode array length: 23 bytecode array length: 23
bytecodes: [ bytecodes: [
...@@ -104,8 +104,8 @@ bytecodes: [ ...@@ -104,8 +104,8 @@ bytecodes: [
B(Star), R(0), B(Star), R(0),
/* 56 S> */ B(Nop), /* 56 S> */ B(Nop),
/* 66 E> */ B(Mul), R(0), U8(2), /* 66 E> */ B(Mul), R(0), U8(2),
B(Star), R(3), B(Star), R(2),
B(SubSmi), U8(1), R(3), U8(3), B(SubSmi), U8(1), R(2), U8(3),
B(LdrUndefined), R(1), B(LdrUndefined), R(1),
B(Ldar), R(1), B(Ldar), R(1),
/* 74 S> */ B(Nop), /* 74 S> */ B(Nop),
......
...@@ -10,16 +10,16 @@ wrap: yes ...@@ -10,16 +10,16 @@ wrap: yes
snippet: " snippet: "
with ({x:42}) { return x; } with ({x:42}) { return x; }
" "
frame size: 3 frame size: 2
parameter count: 1 parameter count: 1
bytecode array length: 22 bytecode array length: 22
bytecodes: [ bytecodes: [
/* 30 E> */ B(StackCheck), /* 30 E> */ B(StackCheck),
/* 34 S> */ B(CreateObjectLiteral), U8(0), U8(0), U8(1), R(1), /* 34 S> */ B(CreateObjectLiteral), U8(0), U8(0), U8(1), R(1),
B(Ldar), R(1), B(Ldar), R(1),
B(ToObject), R(2), B(ToObject), R(1),
B(Ldar), R(closure), B(Ldar), R(closure),
B(CreateWithContext), R(2), U8(1), B(CreateWithContext), R(1), U8(1),
B(PushContext), R(0), B(PushContext), R(0),
/* 50 S> */ B(LdaLookupSlot), U8(2), /* 50 S> */ B(LdaLookupSlot), U8(2),
B(PopContext), R(0), B(PopContext), R(0),
......
...@@ -26,8 +26,8 @@ class InvokeIntrinsicHelper { ...@@ -26,8 +26,8 @@ class InvokeIntrinsicHelper {
Handle<Object> Invoke(A... args) { Handle<Object> Invoke(A... args) {
CHECK(IntrinsicsHelper::IsSupported(function_id_)); CHECK(IntrinsicsHelper::IsSupported(function_id_));
BytecodeArrayBuilder builder(isolate_, zone_, sizeof...(args), 0, 0); BytecodeArrayBuilder builder(isolate_, zone_, sizeof...(args), 0, 0);
builder.CallRuntime(function_id_, builder.Parameter(0), sizeof...(args)) RegisterList reg_list(builder.Parameter(0).index(), sizeof...(args));
.Return(); builder.CallRuntime(function_id_, reg_list).Return();
InterpreterTester tester(isolate_, builder.ToBytecodeArray(isolate_)); InterpreterTester tester(isolate_, builder.ToBytecodeArray(isolate_));
auto callable = tester.GetCallable<A...>(); auto callable = tester.GetCallable<A...>();
return callable(args...).ToHandleChecked(); return callable(args...).ToHandleChecked();
......
...@@ -1236,12 +1236,13 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) { ...@@ -1236,12 +1236,13 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) {
// Check with no args. // Check with no args.
{ {
BytecodeArrayBuilder builder(isolate, handles.main_zone(), 1, 0, 1); 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) 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, builder.Call(reg, args, call_slot_index, tail_call_mode);
tail_call_mode);
builder.Return(); builder.Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
...@@ -1258,11 +1259,12 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) { ...@@ -1258,11 +1259,12 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) {
// Check that receiver is passed properly. // Check that receiver is passed properly.
{ {
BytecodeArrayBuilder builder(isolate, handles.main_zone(), 1, 0, 1); 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) builder.LoadNamedProperty(builder.Parameter(0), name, slot_index)
.StoreAccumulatorInRegister(Register(0)); .StoreAccumulatorInRegister(reg)
builder.Call(Register(0), builder.Parameter(0), 1, call_slot_index, .MoveRegister(builder.Parameter(0), args[0]);
tail_call_mode); builder.Call(reg, args, call_slot_index, tail_call_mode);
builder.Return(); builder.Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
...@@ -1281,17 +1283,19 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) { ...@@ -1281,17 +1283,19 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) {
// Check with two parameters (+ receiver). // Check with two parameters (+ receiver).
{ {
BytecodeArrayBuilder builder(isolate, handles.main_zone(), 1, 0, 4); 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) builder.LoadNamedProperty(builder.Parameter(0), name, slot_index)
.StoreAccumulatorInRegister(Register(0)) .StoreAccumulatorInRegister(reg)
.LoadAccumulatorWithRegister(builder.Parameter(0)) .LoadAccumulatorWithRegister(builder.Parameter(0))
.StoreAccumulatorInRegister(Register(1)) .StoreAccumulatorInRegister(args[0])
.LoadLiteral(Smi::FromInt(51)) .LoadLiteral(Smi::FromInt(51))
.StoreAccumulatorInRegister(Register(2)) .StoreAccumulatorInRegister(args[1])
.LoadLiteral(Smi::FromInt(11)) .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(); builder.Return();
...@@ -1311,33 +1315,35 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) { ...@@ -1311,33 +1315,35 @@ static void TestInterpreterCall(TailCallMode tail_call_mode) {
// Check with 10 parameters (+ receiver). // Check with 10 parameters (+ receiver).
{ {
BytecodeArrayBuilder builder(isolate, handles.main_zone(), 1, 0, 12); 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) builder.LoadNamedProperty(builder.Parameter(0), name, slot_index)
.StoreAccumulatorInRegister(Register(0)) .StoreAccumulatorInRegister(reg)
.LoadAccumulatorWithRegister(builder.Parameter(0)) .LoadAccumulatorWithRegister(builder.Parameter(0))
.StoreAccumulatorInRegister(Register(1)) .StoreAccumulatorInRegister(args[0])
.LoadLiteral(factory->NewStringFromAsciiChecked("a")) .LoadLiteral(factory->NewStringFromAsciiChecked("a"))
.StoreAccumulatorInRegister(Register(2)) .StoreAccumulatorInRegister(args[1])
.LoadLiteral(factory->NewStringFromAsciiChecked("b")) .LoadLiteral(factory->NewStringFromAsciiChecked("b"))
.StoreAccumulatorInRegister(Register(3)) .StoreAccumulatorInRegister(args[2])
.LoadLiteral(factory->NewStringFromAsciiChecked("c")) .LoadLiteral(factory->NewStringFromAsciiChecked("c"))
.StoreAccumulatorInRegister(Register(4)) .StoreAccumulatorInRegister(args[3])
.LoadLiteral(factory->NewStringFromAsciiChecked("d")) .LoadLiteral(factory->NewStringFromAsciiChecked("d"))
.StoreAccumulatorInRegister(Register(5)) .StoreAccumulatorInRegister(args[4])
.LoadLiteral(factory->NewStringFromAsciiChecked("e")) .LoadLiteral(factory->NewStringFromAsciiChecked("e"))
.StoreAccumulatorInRegister(Register(6)) .StoreAccumulatorInRegister(args[5])
.LoadLiteral(factory->NewStringFromAsciiChecked("f")) .LoadLiteral(factory->NewStringFromAsciiChecked("f"))
.StoreAccumulatorInRegister(Register(7)) .StoreAccumulatorInRegister(args[6])
.LoadLiteral(factory->NewStringFromAsciiChecked("g")) .LoadLiteral(factory->NewStringFromAsciiChecked("g"))
.StoreAccumulatorInRegister(Register(8)) .StoreAccumulatorInRegister(args[7])
.LoadLiteral(factory->NewStringFromAsciiChecked("h")) .LoadLiteral(factory->NewStringFromAsciiChecked("h"))
.StoreAccumulatorInRegister(Register(9)) .StoreAccumulatorInRegister(args[8])
.LoadLiteral(factory->NewStringFromAsciiChecked("i")) .LoadLiteral(factory->NewStringFromAsciiChecked("i"))
.StoreAccumulatorInRegister(Register(10)) .StoreAccumulatorInRegister(args[9])
.LoadLiteral(factory->NewStringFromAsciiChecked("j")) .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(); builder.Return();
...@@ -2112,12 +2118,13 @@ TEST(InterpreterCallRuntime) { ...@@ -2112,12 +2118,13 @@ TEST(InterpreterCallRuntime) {
Isolate* isolate = handles.main_isolate(); Isolate* isolate = handles.main_isolate();
BytecodeArrayBuilder builder(isolate, handles.main_zone(), 1, 0, 2); BytecodeArrayBuilder builder(isolate, handles.main_zone(), 1, 0, 2);
RegisterList args = builder.register_allocator()->NewRegisterList(2);
builder.LoadLiteral(Smi::FromInt(15)) builder.LoadLiteral(Smi::FromInt(15))
.StoreAccumulatorInRegister(Register(0)) .StoreAccumulatorInRegister(args[0])
.LoadLiteral(Smi::FromInt(40)) .LoadLiteral(Smi::FromInt(40))
.StoreAccumulatorInRegister(Register(1)) .StoreAccumulatorInRegister(args[1])
.CallRuntime(Runtime::kAdd, Register(0), 2) .CallRuntime(Runtime::kAdd, args)
.Return(); .Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
...@@ -2136,7 +2143,7 @@ TEST(InterpreterInvokeIntrinsic) { ...@@ -2136,7 +2143,7 @@ TEST(InterpreterInvokeIntrinsic) {
builder.LoadLiteral(Smi::FromInt(15)) builder.LoadLiteral(Smi::FromInt(15))
.StoreAccumulatorInRegister(Register(0)) .StoreAccumulatorInRegister(Register(0))
.CallRuntime(Runtime::kInlineIsArray, Register(0), 1) .CallRuntime(Runtime::kInlineIsArray, Register(0))
.Return(); .Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
......
...@@ -33,6 +33,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { ...@@ -33,6 +33,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
Register reg(0); Register reg(0);
Register other(reg.index() + 1); Register other(reg.index() + 1);
Register wide(128); Register wide(128);
RegisterList reg_list;
// Emit argument creation operations. // Emit argument creation operations.
builder.CreateArguments(CreateArgumentsType::kMappedArguments) builder.CreateArguments(CreateArgumentsType::kMappedArguments)
...@@ -123,16 +124,11 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { ...@@ -123,16 +124,11 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.CreateObjectLiteral(factory->NewFixedArray(1), 0, 0, reg); .CreateObjectLiteral(factory->NewFixedArray(1), 0, 0, reg);
// Call operations. // Call operations.
builder.Call(reg, other, 0, 1) builder.Call(reg, reg_list, 1)
.Call(reg, wide, 0, 1) .Call(reg, reg_list, 1, TailCallMode::kAllow)
.TailCall(reg, other, 0, 1) .CallRuntime(Runtime::kIsArray, reg)
.TailCall(reg, wide, 0, 1) .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, reg_list, other)
.CallRuntime(Runtime::kIsArray, reg, 1) .CallJSRuntime(Context::SPREAD_ITERABLE_INDEX, reg_list);
.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);
// Emit binary operator invocations. // Emit binary operator invocations.
builder.BinaryOperation(Token::Value::ADD, reg, 1) builder.BinaryOperation(Token::Value::ADD, reg, 1)
...@@ -179,8 +175,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { ...@@ -179,8 +175,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
builder.Delete(reg, LanguageMode::SLOPPY).Delete(reg, LanguageMode::STRICT); builder.Delete(reg, LanguageMode::SLOPPY).Delete(reg, LanguageMode::STRICT);
// Emit new. // Emit new.
builder.New(reg, reg, 0, 1); builder.New(reg, reg_list, 1);
builder.New(wide, wide, 0, 1);
// Emit test operator invocations. // Emit test operator invocations.
builder.CompareOperation(Token::Value::EQ, reg, 1) builder.CompareOperation(Token::Value::EQ, reg, 1)
...@@ -337,8 +332,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { ...@@ -337,8 +332,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.ResumeGenerator(reg); .ResumeGenerator(reg);
// Intrinsics handled by the interpreter. // Intrinsics handled by the interpreter.
builder.CallRuntime(Runtime::kInlineIsArray, reg, 1) builder.CallRuntime(Runtime::kInlineIsArray, reg_list);
.CallRuntime(Runtime::kInlineIsArray, wide, 1);
// Emit debugger bytecode. // Emit debugger bytecode.
builder.Debugger(); builder.Debugger();
...@@ -359,7 +353,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { ...@@ -359,7 +353,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
// Generate BytecodeArray. // Generate BytecodeArray.
Handle<BytecodeArray> the_array = builder.ToBytecodeArray(isolate()); Handle<BytecodeArray> the_array = builder.ToBytecodeArray(isolate());
CHECK_EQ(the_array->frame_size(), 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. // Build scorecard of bytecodes encountered in the BytecodeArray.
std::vector<int> scorecard(Bytecodes::ToByte(Bytecode::kLast) + 1); std::vector<int> scorecard(Bytecodes::ToByte(Bytecode::kLast) + 1);
...@@ -428,21 +422,18 @@ TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) { ...@@ -428,21 +422,18 @@ TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) {
for (int contexts = 0; contexts < 4; contexts++) { for (int contexts = 0; contexts < 4; contexts++) {
for (int temps = 0; temps < 3; temps++) { for (int temps = 0; temps < 3; temps++) {
BytecodeArrayBuilder builder(isolate(), zone(), 0, contexts, locals); BytecodeArrayBuilder builder(isolate(), zone(), 0, contexts, locals);
BytecodeRegisterAllocator temporaries( BytecodeRegisterAllocator* allocator(builder.register_allocator());
zone(), builder.temporary_register_allocator());
for (int i = 0; i < locals + contexts; i++) { for (int i = 0; i < locals + contexts; i++) {
builder.LoadLiteral(Smi::FromInt(0)); builder.LoadLiteral(Smi::FromInt(0));
builder.StoreAccumulatorInRegister(Register(i)); builder.StoreAccumulatorInRegister(Register(i));
} }
for (int i = 0; i < temps; i++) { for (int i = 0; i < temps; i++) {
Register temp = allocator->NewRegister();
builder.LoadLiteral(Smi::FromInt(0)); builder.LoadLiteral(Smi::FromInt(0));
builder.StoreAccumulatorInRegister(temporaries.NewRegister()); builder.StoreAccumulatorInRegister(temp);
}
if (temps > 0) {
// Ensure temporaries are used so not optimized away by the // Ensure temporaries are used so not optimized away by the
// register optimizer. // register optimizer.
builder.New(Register(locals + contexts), Register(locals + contexts), builder.ConvertAccumulatorToName(temp);
static_cast<size_t>(temps), 0);
} }
builder.Return(); builder.Return();
...@@ -478,30 +469,6 @@ TEST_F(BytecodeArrayBuilderTest, Parameters) { ...@@ -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) { TEST_F(BytecodeArrayBuilderTest, Constants) {
CanonicalHandleScope canonical(isolate()); CanonicalHandleScope canonical(isolate());
BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0); BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0);
......
...@@ -54,9 +54,9 @@ TEST_F(BytecodeArrayIteratorTest, IteratesBytecodeArray) { ...@@ -54,9 +54,9 @@ TEST_F(BytecodeArrayIteratorTest, IteratesBytecodeArray) {
.LoadNamedProperty(reg_1, name, feedback_slot) .LoadNamedProperty(reg_1, name, feedback_slot)
.BinaryOperation(Token::Value::ADD, reg_0, 3) .BinaryOperation(Token::Value::ADD, reg_0, 3)
.StoreAccumulatorInRegister(param) .StoreAccumulatorInRegister(param)
.CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, param, 1, reg_0) .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, param, reg_0)
.ForInPrepare(reg_0, reg_0) .ForInPrepare(reg_0, reg_0)
.CallRuntime(Runtime::kLoadIC_Miss, reg_0, 1) .CallRuntime(Runtime::kLoadIC_Miss, reg_0)
.Debugger() .Debugger()
.LoadGlobal(0x10000000, TypeofMode::NOT_INSIDE_TYPEOF) .LoadGlobal(0x10000000, TypeofMode::NOT_INSIDE_TYPEOF)
.Return(); .Return();
......
...@@ -22,10 +22,10 @@ class BytecodeRegisterOptimizerTest : public BytecodePipelineStage, ...@@ -22,10 +22,10 @@ class BytecodeRegisterOptimizerTest : public BytecodePipelineStage,
~BytecodeRegisterOptimizerTest() override { delete register_allocator_; } ~BytecodeRegisterOptimizerTest() override { delete register_allocator_; }
void Initialize(int number_of_parameters, int number_of_locals) { void Initialize(int number_of_parameters, int number_of_locals) {
register_allocator_ = register_allocator_ = new BytecodeRegisterAllocator(number_of_locals);
new TemporaryRegisterAllocator(zone(), number_of_locals); register_optimizer_ = new (zone())
register_optimizer_ = new (zone()) BytecodeRegisterOptimizer( BytecodeRegisterOptimizer(zone(), register_allocator_, number_of_locals,
zone(), register_allocator_, number_of_parameters, this); number_of_parameters, this);
} }
void Write(BytecodeNode* node) override { output_.push_back(*node); } void Write(BytecodeNode* node) override { output_.push_back(*node); }
...@@ -40,15 +40,13 @@ class BytecodeRegisterOptimizerTest : public BytecodePipelineStage, ...@@ -40,15 +40,13 @@ class BytecodeRegisterOptimizerTest : public BytecodePipelineStage,
return Handle<BytecodeArray>(); return Handle<BytecodeArray>();
} }
TemporaryRegisterAllocator* allocator() { return register_allocator_; } BytecodeRegisterAllocator* allocator() { return register_allocator_; }
BytecodeRegisterOptimizer* optimizer() { return register_optimizer_; } BytecodeRegisterOptimizer* optimizer() { return register_optimizer_; }
Register NewTemporary() { Register NewTemporary() { return allocator()->NewRegister(); }
return Register(allocator()->BorrowTemporaryRegister());
}
void KillTemporary(Register reg) { void ReleaseTemporaries(Register reg) {
allocator()->ReturnTemporaryRegister(reg.index()); allocator()->ReleaseRegisters(reg.index());
} }
size_t write_count() const { return output_.size(); } size_t write_count() const { return output_.size(); }
...@@ -56,7 +54,7 @@ class BytecodeRegisterOptimizerTest : public BytecodePipelineStage, ...@@ -56,7 +54,7 @@ class BytecodeRegisterOptimizerTest : public BytecodePipelineStage,
const std::vector<BytecodeNode>* output() { return &output_; } const std::vector<BytecodeNode>* output() { return &output_; }
private: private:
TemporaryRegisterAllocator* register_allocator_; BytecodeRegisterAllocator* register_allocator_;
BytecodeRegisterOptimizer* register_optimizer_; BytecodeRegisterOptimizer* register_optimizer_;
std::vector<BytecodeNode> output_; std::vector<BytecodeNode> output_;
...@@ -130,7 +128,7 @@ TEST_F(BytecodeRegisterOptimizerTest, TemporaryNotEmitted) { ...@@ -130,7 +128,7 @@ TEST_F(BytecodeRegisterOptimizerTest, TemporaryNotEmitted) {
BytecodeNode node1(Bytecode::kStar, NewTemporary().ToOperand()); BytecodeNode node1(Bytecode::kStar, NewTemporary().ToOperand());
optimizer()->Write(&node1); optimizer()->Write(&node1);
CHECK_EQ(write_count(), 0); CHECK_EQ(write_count(), 0);
KillTemporary(temp); ReleaseTemporaries(temp);
CHECK_EQ(write_count(), 0); CHECK_EQ(write_count(), 0);
BytecodeNode node2(Bytecode::kReturn); BytecodeNode node2(Bytecode::kReturn);
optimizer()->Write(&node2); optimizer()->Write(&node2);
...@@ -140,6 +138,61 @@ TEST_F(BytecodeRegisterOptimizerTest, TemporaryNotEmitted) { ...@@ -140,6 +138,61 @@ TEST_F(BytecodeRegisterOptimizerTest, TemporaryNotEmitted) {
CHECK_EQ(output()->at(1).bytecode(), Bytecode::kReturn); 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) { TEST_F(BytecodeRegisterOptimizerTest, StoresToLocalsImmediate) {
Initialize(3, 1); Initialize(3, 1);
Register parameter = Register::FromParameterIndex(1, 3); Register parameter = Register::FromParameterIndex(1, 3);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment