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