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_;
......
......@@ -374,75 +374,35 @@ class BytecodeGenerator::RegisterAllocationScope {
public:
explicit RegisterAllocationScope(BytecodeGenerator* generator)
: generator_(generator),
outer_(generator->register_allocator()),
allocator_(builder()->zone(),
builder()->temporary_register_allocator()) {
generator_->set_register_allocator(this);
}
outer_next_register_index_(
generator->register_allocator()->next_register_index()) {}
virtual ~RegisterAllocationScope() {
generator_->set_register_allocator(outer_);
}
Register NewRegister() {
RegisterAllocationScope* current_scope = generator()->register_allocator();
if ((current_scope == this) ||
(current_scope->outer() == this &&
!current_scope->allocator_.HasConsecutiveAllocations())) {
// Regular case - Allocating registers in current or outer context.
// VisitForRegisterValue allocates register in outer context.
return allocator_.NewRegister();
} else {
// If it is required to allocate a register other than current or outer
// scopes, allocate a new temporary register. It might be expensive to
// walk the full context chain and compute the list of consecutive
// reservations in the innerscopes.
UNIMPLEMENTED();
return Register::invalid_value();
}
}
void PrepareForConsecutiveAllocations(int count) {
allocator_.PrepareForConsecutiveAllocations(count);
}
Register NextConsecutiveRegister() {
return allocator_.NextConsecutiveRegister();
generator_->register_allocator()->ReleaseRegisters(
outer_next_register_index_);
}
bool RegisterIsAllocatedInThisScope(Register reg) const {
return allocator_.RegisterIsAllocatedInThisScope(reg);
}
RegisterAllocationScope* outer() const { return outer_; }
private:
BytecodeGenerator* generator() const { return generator_; }
BytecodeArrayBuilder* builder() const { return generator_->builder(); }
BytecodeGenerator* generator_;
RegisterAllocationScope* outer_;
BytecodeRegisterAllocator allocator_;
int outer_next_register_index_;
DISALLOW_COPY_AND_ASSIGN(RegisterAllocationScope);
};
// Scoped base class for determining where the result of an expression
// is stored.
// Scoped base class for determining how the result of an expression will be
// used.
class BytecodeGenerator::ExpressionResultScope {
public:
ExpressionResultScope(BytecodeGenerator* generator, Expression::Context kind)
: generator_(generator),
kind_(kind),
outer_(generator->execution_result()),
allocator_(generator),
result_identified_(false) {
allocator_(generator) {
generator_->set_execution_result(this);
}
virtual ~ExpressionResultScope() {
generator_->set_execution_result(outer_);
DCHECK(result_identified() || generator_->HasStackOverflow());
}
bool IsEffect() const { return kind_ == Expression::kEffect; }
......@@ -454,28 +414,11 @@ class BytecodeGenerator::ExpressionResultScope {
return reinterpret_cast<TestResultScope*>(this);
}
virtual void SetResultInAccumulator() = 0;
virtual void SetResultInRegister(Register reg) = 0;
protected:
ExpressionResultScope* outer() const { return outer_; }
BytecodeArrayBuilder* builder() const { return generator_->builder(); }
BytecodeGenerator* generator() const { return generator_; }
const RegisterAllocationScope* allocator() const { return &allocator_; }
void set_result_identified() {
DCHECK(!result_identified());
result_identified_ = true;
}
bool result_identified() const { return result_identified_; }
private:
BytecodeGenerator* generator_;
Expression::Context kind_;
ExpressionResultScope* outer_;
RegisterAllocationScope allocator_;
bool result_identified_;
DISALLOW_COPY_AND_ASSIGN(ExpressionResultScope);
};
......@@ -486,61 +429,15 @@ class BytecodeGenerator::EffectResultScope final
: public ExpressionResultScope {
public:
explicit EffectResultScope(BytecodeGenerator* generator)
: ExpressionResultScope(generator, Expression::kEffect) {
set_result_identified();
}
virtual void SetResultInAccumulator() {}
virtual void SetResultInRegister(Register reg) {}
: ExpressionResultScope(generator, Expression::kEffect) {}
};
// Scoped class used when the result of the current expression to be
// evaluated should go into the interpreter's accumulator register.
class BytecodeGenerator::AccumulatorResultScope final
: public ExpressionResultScope {
// evaluated should go into the interpreter's accumulator.
class BytecodeGenerator::ValueResultScope final : public ExpressionResultScope {
public:
explicit AccumulatorResultScope(BytecodeGenerator* generator)
explicit ValueResultScope(BytecodeGenerator* generator)
: ExpressionResultScope(generator, Expression::kValue) {}
virtual void SetResultInAccumulator() { set_result_identified(); }
virtual void SetResultInRegister(Register reg) {
builder()->LoadAccumulatorWithRegister(reg);
set_result_identified();
}
};
// Scoped class used when the result of the current expression to be
// evaluated should go into an interpreter register.
class BytecodeGenerator::RegisterResultScope final
: public ExpressionResultScope {
public:
explicit RegisterResultScope(BytecodeGenerator* generator)
: ExpressionResultScope(generator, Expression::kValue) {}
virtual void SetResultInAccumulator() {
result_register_ = allocator()->outer()->NewRegister();
builder()->StoreAccumulatorInRegister(result_register_);
set_result_identified();
}
virtual void SetResultInRegister(Register reg) {
DCHECK(builder()->RegisterIsParameterOrLocal(reg) ||
(builder()->TemporaryRegisterIsLive(reg) &&
!allocator()->RegisterIsAllocatedInThisScope(reg)));
result_register_ = reg;
set_result_identified();
}
Register ResultRegister() {
if (generator()->HasStackOverflow() && !result_identified()) {
SetResultInAccumulator();
}
return result_register_;
}
private:
Register result_register_;
};
// Scoped class used when the result of the current expression to be
......@@ -555,18 +452,10 @@ class BytecodeGenerator::TestResultScope final : public ExpressionResultScope {
fallthrough_(fallthrough),
result_consumed_by_test_(false) {}
virtual void SetResultInAccumulator() { set_result_identified(); }
virtual void SetResultInRegister(Register reg) {
builder()->LoadAccumulatorWithRegister(reg);
set_result_identified();
}
// Used when code special cases for TestResultScope and consumes any
// possible value by testing and jumping to a then/else label.
void SetResultConsumedByTest() {
result_consumed_by_test_ = true;
set_result_identified();
}
bool ResultConsumedByTest() { return result_consumed_by_test_; }
......@@ -678,7 +567,6 @@ BytecodeGenerator::BytecodeGenerator(CompilationInfo* info)
execution_control_(nullptr),
execution_context_(nullptr),
execution_result_(nullptr),
register_allocator_(nullptr),
generator_resume_points_(info->literal()->yield_count(), info->zone()),
generator_state_(),
loop_depth_(0),
......@@ -928,7 +816,7 @@ void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) {
builder()
->LoadLiteral(variable->name())
.StoreAccumulatorInRegister(name)
.CallRuntime(Runtime::kDeclareEvalVar, name, 1);
.CallRuntime(Runtime::kDeclareEvalVar, name);
break;
}
case VariableLocation::MODULE:
......@@ -966,14 +854,13 @@ void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) {
break;
}
case VariableLocation::LOOKUP: {
register_allocator()->PrepareForConsecutiveAllocations(2);
Register name = register_allocator()->NextConsecutiveRegister();
Register literal = register_allocator()->NextConsecutiveRegister();
builder()->LoadLiteral(variable->name()).StoreAccumulatorInRegister(name);
RegisterList args = register_allocator()->NewRegisterList(2);
builder()
->LoadLiteral(variable->name())
.StoreAccumulatorInRegister(args[0]);
VisitForAccumulatorValue(decl->fun());
builder()->StoreAccumulatorInRegister(literal).CallRuntime(
Runtime::kDeclareEvalFunction, name, 2);
builder()->StoreAccumulatorInRegister(args[1]).CallRuntime(
Runtime::kDeclareEvalFunction, args);
break;
}
case VariableLocation::MODULE:
......@@ -1000,20 +887,15 @@ void BytecodeGenerator::VisitDeclarations(
builder()->AllocateConstantPoolEntry());
int encoded_flags = info()->GetDeclareGlobalsFlags();
register_allocator()->PrepareForConsecutiveAllocations(3);
Register pairs = register_allocator()->NextConsecutiveRegister();
Register flags = register_allocator()->NextConsecutiveRegister();
Register function = register_allocator()->NextConsecutiveRegister();
// Emit code to declare globals.
RegisterList args = register_allocator()->NewRegisterList(3);
builder()
->LoadConstantPoolEntry(globals_builder()->constant_pool_entry())
.StoreAccumulatorInRegister(pairs)
.StoreAccumulatorInRegister(args[0])
.LoadLiteral(Smi::FromInt(encoded_flags))
.StoreAccumulatorInRegister(flags)
.MoveRegister(Register::function_closure(), function)
.CallRuntime(Runtime::kDeclareGlobalsForInterpreter, pairs, 3);
.StoreAccumulatorInRegister(args[1])
.MoveRegister(Register::function_closure(), args[2])
.CallRuntime(Runtime::kDeclareGlobalsForInterpreter, args);
// Push and reset globals builder.
global_declarations_.push_back(globals_builder());
......@@ -1268,36 +1150,28 @@ void BytecodeGenerator::VisitForInAssignment(Expression* expr,
}
case NAMED_SUPER_PROPERTY: {
RegisterAllocationScope register_scope(this);
register_allocator()->PrepareForConsecutiveAllocations(4);
Register receiver = register_allocator()->NextConsecutiveRegister();
Register home_object = register_allocator()->NextConsecutiveRegister();
Register name = register_allocator()->NextConsecutiveRegister();
Register value = register_allocator()->NextConsecutiveRegister();
builder()->StoreAccumulatorInRegister(value);
RegisterList args = register_allocator()->NewRegisterList(4);
builder()->StoreAccumulatorInRegister(args[3]);
SuperPropertyReference* super_property =
property->obj()->AsSuperPropertyReference();
VisitForRegisterValue(super_property->this_var(), receiver);
VisitForRegisterValue(super_property->home_object(), home_object);
VisitForRegisterValue(super_property->this_var(), args[0]);
VisitForRegisterValue(super_property->home_object(), args[1]);
builder()
->LoadLiteral(property->key()->AsLiteral()->AsPropertyName())
.StoreAccumulatorInRegister(name);
BuildNamedSuperPropertyStore(receiver, home_object, name, value);
.StoreAccumulatorInRegister(args[2])
.CallRuntime(StoreToSuperRuntimeId(), args);
break;
}
case KEYED_SUPER_PROPERTY: {
RegisterAllocationScope register_scope(this);
register_allocator()->PrepareForConsecutiveAllocations(4);
Register receiver = register_allocator()->NextConsecutiveRegister();
Register home_object = register_allocator()->NextConsecutiveRegister();
Register key = register_allocator()->NextConsecutiveRegister();
Register value = register_allocator()->NextConsecutiveRegister();
builder()->StoreAccumulatorInRegister(value);
RegisterList args = register_allocator()->NewRegisterList(4);
builder()->StoreAccumulatorInRegister(args[3]);
SuperPropertyReference* super_property =
property->obj()->AsSuperPropertyReference();
VisitForRegisterValue(super_property->this_var(), receiver);
VisitForRegisterValue(super_property->home_object(), home_object);
VisitForRegisterValue(property->key(), key);
BuildKeyedSuperPropertyStore(receiver, home_object, key, value);
VisitForRegisterValue(super_property->this_var(), args[0]);
VisitForRegisterValue(super_property->home_object(), args[1]);
VisitForRegisterValue(property->key(), args[2]);
builder()->CallRuntime(StoreKeyedToSuperRuntimeId(), args);
break;
}
}
......@@ -1321,13 +1195,10 @@ void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) {
Register receiver = register_allocator()->NewRegister();
builder()->ConvertAccumulatorToObject(receiver);
register_allocator()->PrepareForConsecutiveAllocations(3);
Register cache_type = register_allocator()->NextConsecutiveRegister();
Register cache_array = register_allocator()->NextConsecutiveRegister();
Register cache_length = register_allocator()->NextConsecutiveRegister();
// Used as kRegTriple and kRegPair in ForInPrepare and ForInNext.
USE(cache_array);
builder()->ForInPrepare(receiver, cache_type);
RegisterList triple = register_allocator()->NewRegisterList(3);
Register cache_length = triple[2];
builder()->ForInPrepare(receiver, triple.first_register());
// Set up loop counter
Register index = register_allocator()->NewRegister();
......@@ -1339,9 +1210,9 @@ void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) {
builder()->SetExpressionAsStatementPosition(stmt->each());
builder()->ForInContinue(index, cache_length);
loop_builder.BreakIfFalse();
DCHECK(Register::AreContiguous(cache_type, cache_array));
FeedbackVectorSlot slot = stmt->ForInFeedbackSlot();
builder()->ForInNext(receiver, index, cache_type, feedback_index(slot));
builder()->ForInNext(receiver, index, triple.first_register(),
feedback_index(slot));
loop_builder.ContinueIfUndefined();
VisitForInAssignment(stmt->each(), stmt->EachFeedbackSlot());
VisitIterationBody(stmt, &loop_builder);
......@@ -1373,7 +1244,6 @@ void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
TryCatchBuilder try_control_builder(builder(), stmt->catch_prediction());
Register no_reg;
// Preserve the context in a dedicated register, so that it can be restored
// when the handler is entered by the stack-unwinding machinery.
......@@ -1396,7 +1266,7 @@ void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
// If requested, clear message object as we enter the catch block.
if (stmt->clear_pending_message()) {
builder()->CallRuntime(Runtime::kInterpreterClearPendingMessage, no_reg, 0);
builder()->CallRuntime(Runtime::kInterpreterClearPendingMessage);
}
// Load the catch context into the accumulator.
......@@ -1409,7 +1279,6 @@ void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
TryFinallyBuilder try_control_builder(builder(), stmt->catch_prediction());
Register no_reg;
// We keep a record of all paths that enter the finally-block to be able to
// dispatch to the correct continuation point after the statements in the
......@@ -1457,7 +1326,7 @@ void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
// Clear message object as we enter the finally block.
builder()
->CallRuntime(Runtime::kInterpreterClearPendingMessage, no_reg, 0)
->CallRuntime(Runtime::kInterpreterClearPendingMessage)
.StoreAccumulatorInRegister(message);
// Evaluate the finally-block.
......@@ -1465,7 +1334,7 @@ void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
try_control_builder.EndFinally();
// Pending message object is restored on exit.
builder()->CallRuntime(Runtime::kInterpreterSetPendingMessage, message, 1);
builder()->CallRuntime(Runtime::kInterpreterSetPendingMessage, message);
// Dynamic dispatch after the finally-block.
commands.ApplyDeferredCommands();
......@@ -1482,16 +1351,15 @@ void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
size_t entry = builder()->AllocateConstantPoolEntry();
builder()->CreateClosure(entry, flags);
function_literals_.push_back(std::make_pair(expr, entry));
execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr) {
VisitClassLiteralForRuntimeDefinition(expr);
// Load the "prototype" from the constructor.
register_allocator()->PrepareForConsecutiveAllocations(2);
Register literal = register_allocator()->NextConsecutiveRegister();
Register prototype = register_allocator()->NextConsecutiveRegister();
RegisterList args = register_allocator()->NewRegisterList(2);
Register literal = args[0];
Register prototype = args[1];
FeedbackVectorSlot slot = expr->PrototypeSlot();
builder()
->StoreAccumulatorInRegister(literal)
......@@ -1499,7 +1367,7 @@ void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr) {
.StoreAccumulatorInRegister(prototype);
VisitClassLiteralProperties(expr, literal, prototype);
builder()->CallRuntime(Runtime::kToFastProperties, literal, 1);
builder()->CallRuntime(Runtime::kToFastProperties, literal);
// Assign to class variable.
if (expr->class_variable_proxy() != nullptr) {
Variable* var = expr->class_variable_proxy()->var();
......@@ -1508,42 +1376,30 @@ void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr) {
: FeedbackVectorSlot::Invalid();
VisitVariableAssignment(var, Token::INIT, slot);
}
execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::VisitClassLiteralForRuntimeDefinition(
ClassLiteral* expr) {
AccumulatorResultScope result_scope(this);
register_allocator()->PrepareForConsecutiveAllocations(4);
Register extends = register_allocator()->NextConsecutiveRegister();
Register constructor = register_allocator()->NextConsecutiveRegister();
Register start_position = register_allocator()->NextConsecutiveRegister();
Register end_position = register_allocator()->NextConsecutiveRegister();
RegisterAllocationScope register_scope(this);
RegisterList args = register_allocator()->NewRegisterList(4);
VisitForAccumulatorValueOrTheHole(expr->extends());
builder()->StoreAccumulatorInRegister(extends);
VisitForAccumulatorValue(expr->constructor());
builder()->StoreAccumulatorInRegister(args[0]);
VisitForRegisterValue(expr->constructor(), args[1]);
builder()
->StoreAccumulatorInRegister(constructor)
.LoadLiteral(Smi::FromInt(expr->start_position()))
.StoreAccumulatorInRegister(start_position)
->LoadLiteral(Smi::FromInt(expr->start_position()))
.StoreAccumulatorInRegister(args[2])
.LoadLiteral(Smi::FromInt(expr->end_position()))
.StoreAccumulatorInRegister(end_position)
.CallRuntime(Runtime::kDefineClass, extends, 4);
result_scope.SetResultInAccumulator();
.StoreAccumulatorInRegister(args[3])
.CallRuntime(Runtime::kDefineClass, args);
}
void BytecodeGenerator::VisitClassLiteralProperties(ClassLiteral* expr,
Register literal,
Register prototype) {
RegisterAllocationScope register_scope(this);
register_allocator()->PrepareForConsecutiveAllocations(5);
Register receiver = register_allocator()->NextConsecutiveRegister();
Register key = register_allocator()->NextConsecutiveRegister();
Register value = register_allocator()->NextConsecutiveRegister();
Register attr = register_allocator()->NextConsecutiveRegister();
Register set_function_name = register_allocator()->NextConsecutiveRegister();
RegisterList args = register_allocator()->NewRegisterList(5);
Register receiver = args[0], key = args[1], value = args[2], attr = args[3],
set_function_name = args[4];
bool attr_assigned = false;
Register old_receiver = Register::invalid_value();
......@@ -1561,16 +1417,22 @@ void BytecodeGenerator::VisitClassLiteralProperties(ClassLiteral* expr,
VisitForAccumulatorValue(property->key());
builder()->ConvertAccumulatorToName(key);
// The static prototype property is read only. We handle the non computed
// property name case in the parser. Since this is the only case where we
// need to check for an own read only property we special case this so we do
// not need to do this for every property.
if (property->is_static() && property->is_computed_name()) {
VisitClassLiteralStaticPrototypeWithComputedName(key);
// The static prototype property is read only. We handle the non computed
// property name case in the parser. Since this is the only case where we
// need to check for an own read only property we special case this so we
// do not need to do this for every property.
BytecodeLabel done;
builder()
->LoadLiteral(prototype_string())
.CompareOperation(Token::Value::EQ_STRICT, key)
.JumpIfFalse(&done)
.CallRuntime(Runtime::kThrowStaticPrototypeError)
.Bind(&done);
}
VisitForAccumulatorValue(property->value());
builder()->StoreAccumulatorInRegister(value);
VisitForRegisterValue(property->value(), value);
VisitSetHomeObject(value, receiver, property);
if (!attr_assigned) {
......@@ -1584,19 +1446,18 @@ void BytecodeGenerator::VisitClassLiteralProperties(ClassLiteral* expr,
case ClassLiteral::Property::METHOD: {
builder()
->LoadLiteral(Smi::FromInt(property->NeedsSetFunctionName()))
.StoreAccumulatorInRegister(set_function_name);
builder()->CallRuntime(Runtime::kDefineDataPropertyInLiteral, receiver,
5);
.StoreAccumulatorInRegister(set_function_name)
.CallRuntime(Runtime::kDefineDataPropertyInLiteral, args);
break;
}
case ClassLiteral::Property::GETTER: {
builder()->CallRuntime(Runtime::kDefineGetterPropertyUnchecked,
receiver, 4);
args.Truncate(4));
break;
}
case ClassLiteral::Property::SETTER: {
builder()->CallRuntime(Runtime::kDefineSetterPropertyUnchecked,
receiver, 4);
args.Truncate(4));
break;
}
case ClassLiteral::Property::FIELD: {
......@@ -1607,23 +1468,11 @@ void BytecodeGenerator::VisitClassLiteralProperties(ClassLiteral* expr,
}
}
void BytecodeGenerator::VisitClassLiteralStaticPrototypeWithComputedName(
Register key) {
BytecodeLabel done;
builder()
->LoadLiteral(prototype_string())
.CompareOperation(Token::Value::EQ_STRICT, key)
.JumpIfFalse(&done)
.CallRuntime(Runtime::kThrowStaticPrototypeError, Register(0), 0)
.Bind(&done);
}
void BytecodeGenerator::VisitNativeFunctionLiteral(
NativeFunctionLiteral* expr) {
size_t entry = builder()->AllocateConstantPoolEntry();
builder()->CreateClosure(entry, NOT_TENURED);
native_function_literals_.push_back(std::make_pair(expr, entry));
execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::VisitDoExpression(DoExpression* expr) {
......@@ -1653,8 +1502,6 @@ void BytecodeGenerator::VisitConditional(Conditional* expr) {
VisitForAccumulatorValue(expr->else_expression());
builder()->Bind(&end_label);
}
execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::VisitLiteral(Literal* expr) {
......@@ -1675,7 +1522,6 @@ void BytecodeGenerator::VisitLiteral(Literal* expr) {
} else {
builder()->LoadLiteral(raw_value->value());
}
execution_result()->SetResultInAccumulator();
}
}
......@@ -1683,7 +1529,6 @@ void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
// Materialize a regular expression literal.
builder()->CreateRegExpLiteral(expr->pattern(), expr->literal_index(),
expr->flags());
execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
......@@ -1694,7 +1539,7 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
expr->ComputeFlags());
// Allocate in the outer scope since this register is used to return the
// expression's results to the caller.
Register literal = register_allocator()->outer()->NewRegister();
Register literal = register_allocator()->NewRegister();
builder()->CreateObjectLiteral(expr->constant_properties(),
expr->literal_index(), flags, literal);
......@@ -1738,23 +1583,17 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
VisitForEffect(property->value());
}
} else {
register_allocator()->PrepareForConsecutiveAllocations(4);
Register literal_argument =
register_allocator()->NextConsecutiveRegister();
Register key = register_allocator()->NextConsecutiveRegister();
Register value = register_allocator()->NextConsecutiveRegister();
Register language = register_allocator()->NextConsecutiveRegister();
builder()->MoveRegister(literal, literal_argument);
VisitForAccumulatorValue(property->key());
builder()->StoreAccumulatorInRegister(key);
VisitForAccumulatorValue(property->value());
builder()->StoreAccumulatorInRegister(value);
RegisterList args = register_allocator()->NewRegisterList(4);
builder()->MoveRegister(literal, args[0]);
VisitForRegisterValue(property->key(), args[1]);
VisitForRegisterValue(property->value(), args[2]);
if (property->emit_store()) {
builder()
->LoadLiteral(Smi::FromInt(SLOPPY))
.StoreAccumulatorInRegister(language)
.CallRuntime(Runtime::kSetProperty, literal_argument, 4);
.StoreAccumulatorInRegister(args[3])
.CallRuntime(Runtime::kSetProperty, args);
Register value = args[2];
VisitSetHomeObject(value, literal, property);
}
}
......@@ -1762,15 +1601,10 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
}
case ObjectLiteral::Property::PROTOTYPE: {
DCHECK(property->emit_store());
register_allocator()->PrepareForConsecutiveAllocations(2);
Register literal_argument =
register_allocator()->NextConsecutiveRegister();
Register value = register_allocator()->NextConsecutiveRegister();
builder()->MoveRegister(literal, literal_argument);
VisitForAccumulatorValue(property->value());
builder()->StoreAccumulatorInRegister(value).CallRuntime(
Runtime::kInternalSetPrototype, literal_argument, 2);
RegisterList args = register_allocator()->NewRegisterList(2);
builder()->MoveRegister(literal, args[0]);
VisitForRegisterValue(property->value(), args[1]);
builder()->CallRuntime(Runtime::kInternalSetPrototype, args);
break;
}
case ObjectLiteral::Property::GETTER:
......@@ -1791,23 +1625,15 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
for (AccessorTable::Iterator it = accessor_table.begin();
it != accessor_table.end(); ++it) {
RegisterAllocationScope inner_register_scope(this);
register_allocator()->PrepareForConsecutiveAllocations(5);
Register literal_argument = register_allocator()->NextConsecutiveRegister();
Register name = register_allocator()->NextConsecutiveRegister();
Register getter = register_allocator()->NextConsecutiveRegister();
Register setter = register_allocator()->NextConsecutiveRegister();
Register attr = register_allocator()->NextConsecutiveRegister();
builder()->MoveRegister(literal, literal_argument);
VisitForAccumulatorValue(it->first);
builder()->StoreAccumulatorInRegister(name);
VisitObjectLiteralAccessor(literal, it->second->getter, getter);
VisitObjectLiteralAccessor(literal, it->second->setter, setter);
RegisterList args = register_allocator()->NewRegisterList(5);
builder()->MoveRegister(literal, args[0]);
VisitForRegisterValue(it->first, args[1]);
VisitObjectLiteralAccessor(literal, it->second->getter, args[2]);
VisitObjectLiteralAccessor(literal, it->second->setter, args[3]);
builder()
->LoadLiteral(Smi::FromInt(NONE))
.StoreAccumulatorInRegister(attr)
.CallRuntime(Runtime::kDefineAccessorPropertyUnchecked,
literal_argument, 5);
.StoreAccumulatorInRegister(args[4])
.CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, args);
}
// Object literals have two parts. The "static" part on the left contains no
......@@ -1825,59 +1651,56 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
if (property->kind() == ObjectLiteral::Property::PROTOTYPE) {
DCHECK(property->emit_store());
register_allocator()->PrepareForConsecutiveAllocations(2);
Register literal_argument =
register_allocator()->NextConsecutiveRegister();
Register value = register_allocator()->NextConsecutiveRegister();
builder()->MoveRegister(literal, literal_argument);
VisitForAccumulatorValue(property->value());
builder()->StoreAccumulatorInRegister(value).CallRuntime(
Runtime::kInternalSetPrototype, literal_argument, 2);
RegisterList args = register_allocator()->NewRegisterList(2);
builder()->MoveRegister(literal, args[0]);
VisitForRegisterValue(property->value(), args[1]);
builder()->CallRuntime(Runtime::kInternalSetPrototype, args);
continue;
}
register_allocator()->PrepareForConsecutiveAllocations(5);
Register literal_argument = register_allocator()->NextConsecutiveRegister();
Register key = register_allocator()->NextConsecutiveRegister();
Register value = register_allocator()->NextConsecutiveRegister();
Register attr = register_allocator()->NextConsecutiveRegister();
DCHECK(Register::AreContiguous(literal_argument, key, value, attr));
Register set_function_name =
register_allocator()->NextConsecutiveRegister();
builder()->MoveRegister(literal, literal_argument);
VisitForAccumulatorValue(property->key());
builder()->ConvertAccumulatorToName(key);
VisitForAccumulatorValue(property->value());
builder()->StoreAccumulatorInRegister(value);
VisitSetHomeObject(value, literal, property);
builder()->LoadLiteral(Smi::FromInt(NONE)).StoreAccumulatorInRegister(attr);
switch (property->kind()) {
case ObjectLiteral::Property::CONSTANT:
case ObjectLiteral::Property::COMPUTED:
case ObjectLiteral::Property::MATERIALIZED_LITERAL:
case ObjectLiteral::Property::MATERIALIZED_LITERAL: {
RegisterList args = register_allocator()->NewRegisterList(5);
builder()->MoveRegister(literal, args[0]);
VisitForAccumulatorValue(property->key());
builder()->ConvertAccumulatorToName(args[1]);
VisitForRegisterValue(property->value(), args[2]);
VisitSetHomeObject(args[2], literal, property);
builder()
->LoadLiteral(Smi::FromInt(property->NeedsSetFunctionName()))
.StoreAccumulatorInRegister(set_function_name);
builder()->CallRuntime(Runtime::kDefineDataPropertyInLiteral,
literal_argument, 5);
break;
case ObjectLiteral::Property::PROTOTYPE:
UNREACHABLE(); // Handled specially above.
->LoadLiteral(Smi::FromInt(NONE))
.StoreAccumulatorInRegister(args[3])
.LoadLiteral(Smi::FromInt(property->NeedsSetFunctionName()))
.StoreAccumulatorInRegister(args[4]);
builder()->CallRuntime(Runtime::kDefineDataPropertyInLiteral, args);
break;
}
case ObjectLiteral::Property::GETTER:
builder()->CallRuntime(Runtime::kDefineGetterPropertyUnchecked,
literal_argument, 4);
case ObjectLiteral::Property::SETTER: {
RegisterList args = register_allocator()->NewRegisterList(4);
builder()->MoveRegister(literal, args[0]);
VisitForAccumulatorValue(property->key());
builder()->ConvertAccumulatorToName(args[1]);
VisitForRegisterValue(property->value(), args[2]);
VisitSetHomeObject(args[2], literal, property);
builder()
->LoadLiteral(Smi::FromInt(NONE))
.StoreAccumulatorInRegister(args[3]);
Runtime::FunctionId function_id =
property->kind() == ObjectLiteral::Property::GETTER
? Runtime::kDefineGetterPropertyUnchecked
: Runtime::kDefineSetterPropertyUnchecked;
builder()->CallRuntime(function_id, args);
break;
case ObjectLiteral::Property::SETTER:
builder()->CallRuntime(Runtime::kDefineSetterPropertyUnchecked,
literal_argument, 4);
}
case ObjectLiteral::Property::PROTOTYPE:
UNREACHABLE(); // Handled specially above.
break;
}
}
execution_result()->SetResultInRegister(literal);
builder()->LoadAccumulatorWithRegister(literal);
}
void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
......@@ -1921,7 +1744,6 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
// Restore literal array into accumulator.
builder()->LoadAccumulatorWithRegister(literal);
}
execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) {
......@@ -2009,91 +1831,44 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable,
builder()
->LoadLiteral(it->second->export_name->string())
.StoreAccumulatorInRegister(export_name)
.CallRuntime(Runtime::kLoadModuleExport, export_name, 1);
.CallRuntime(Runtime::kLoadModuleExport, export_name);
} else {
auto it = descriptor->regular_imports().find(variable->raw_name());
DCHECK(it != descriptor->regular_imports().end());
register_allocator()->PrepareForConsecutiveAllocations(2);
Register import_name = register_allocator()->NextConsecutiveRegister();
Register module_request =
register_allocator()->NextConsecutiveRegister();
RegisterList args = register_allocator()->NewRegisterList(2);
builder()
->LoadLiteral(it->second->import_name->string())
.StoreAccumulatorInRegister(import_name)
.StoreAccumulatorInRegister(args[0])
.LoadLiteral(Smi::FromInt(it->second->module_request))
.StoreAccumulatorInRegister(module_request)
.CallRuntime(Runtime::kLoadModuleImport, import_name, 2);
.StoreAccumulatorInRegister(args[1])
.CallRuntime(Runtime::kLoadModuleImport, args);
}
BuildHoleCheckForVariableLoad(variable);
break;
}
}
execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::VisitVariableLoadForAccumulatorValue(
Variable* variable, FeedbackVectorSlot slot, TypeofMode typeof_mode) {
AccumulatorResultScope accumulator_result(this);
ValueResultScope accumulator_result(this);
VisitVariableLoad(variable, slot, typeof_mode);
}
Register BytecodeGenerator::VisitVariableLoadForRegisterValue(
Variable* variable, FeedbackVectorSlot slot, TypeofMode typeof_mode) {
RegisterResultScope register_scope(this);
VisitVariableLoad(variable, slot, typeof_mode);
return register_scope.ResultRegister();
}
void BytecodeGenerator::BuildNamedSuperPropertyLoad(Register receiver,
Register home_object,
Register name) {
DCHECK(Register::AreContiguous(receiver, home_object, name));
builder()->CallRuntime(Runtime::kLoadFromSuper, receiver, 3);
}
void BytecodeGenerator::BuildKeyedSuperPropertyLoad(Register receiver,
Register home_object,
Register key) {
DCHECK(Register::AreContiguous(receiver, home_object, key));
builder()->CallRuntime(Runtime::kLoadKeyedFromSuper, receiver, 3);
}
void BytecodeGenerator::BuildNamedSuperPropertyStore(Register receiver,
Register home_object,
Register name,
Register value) {
DCHECK(Register::AreContiguous(receiver, home_object, name, value));
Runtime::FunctionId function_id = is_strict(language_mode())
? Runtime::kStoreToSuper_Strict
: Runtime::kStoreToSuper_Sloppy;
builder()->CallRuntime(function_id, receiver, 4);
}
void BytecodeGenerator::BuildKeyedSuperPropertyStore(Register receiver,
Register home_object,
Register key,
Register value) {
DCHECK(Register::AreContiguous(receiver, home_object, key, value));
Runtime::FunctionId function_id = is_strict(language_mode())
? Runtime::kStoreKeyedToSuper_Strict
: Runtime::kStoreKeyedToSuper_Sloppy;
builder()->CallRuntime(function_id, receiver, 4);
}
void BytecodeGenerator::BuildAbort(BailoutReason bailout_reason) {
RegisterAllocationScope register_scope(this);
Register reason = register_allocator()->NewRegister();
builder()
->LoadLiteral(Smi::FromInt(static_cast<int>(bailout_reason)))
.StoreAccumulatorInRegister(reason)
.CallRuntime(Runtime::kAbort, reason, 1);
.CallRuntime(Runtime::kAbort, reason);
}
void BytecodeGenerator::BuildThrowReferenceError(Handle<String> name) {
RegisterAllocationScope register_scope(this);
Register name_reg = register_allocator()->NewRegister();
builder()->LoadLiteral(name).StoreAccumulatorInRegister(name_reg).CallRuntime(
Runtime::kThrowReferenceError, name_reg, 1);
Runtime::kThrowReferenceError, name_reg);
}
void BytecodeGenerator::BuildThrowIfHole(Handle<String> name) {
......@@ -2166,7 +1941,7 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable,
if (mode != CONST || op == Token::INIT) {
builder()->StoreAccumulatorInRegister(destination);
} else if (variable->throw_on_const_assignment(language_mode())) {
builder()->CallRuntime(Runtime::kThrowConstAssignError, Register(), 0);
builder()->CallRuntime(Runtime::kThrowConstAssignError);
}
break;
}
......@@ -2201,7 +1976,7 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable,
if (mode != CONST || op == Token::INIT) {
builder()->StoreContextSlot(context_reg, variable->index(), depth);
} else if (variable->throw_on_const_assignment(language_mode())) {
builder()->CallRuntime(Runtime::kThrowConstAssignError, Register(), 0);
builder()->CallRuntime(Runtime::kThrowConstAssignError);
}
break;
}
......@@ -2213,7 +1988,7 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable,
DCHECK(IsDeclaredVariableMode(mode));
if (mode == CONST && op != Token::INIT) {
builder()->CallRuntime(Runtime::kThrowConstAssignError, Register(), 0);
builder()->CallRuntime(Runtime::kThrowConstAssignError);
break;
}
......@@ -2228,14 +2003,12 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable,
auto it = mod->regular_exports().find(variable->raw_name());
DCHECK(it != mod->regular_exports().end());
register_allocator()->PrepareForConsecutiveAllocations(2);
Register export_name = register_allocator()->NextConsecutiveRegister();
Register value = register_allocator()->NextConsecutiveRegister();
RegisterList args = register_allocator()->NewRegisterList(2);
builder()
->StoreAccumulatorInRegister(value)
->StoreAccumulatorInRegister(args[1])
.LoadLiteral(it->second->export_name->string())
.StoreAccumulatorInRegister(export_name)
.CallRuntime(Runtime::kStoreModuleExport, export_name, 2);
.StoreAccumulatorInRegister(args[0])
.CallRuntime(Runtime::kStoreModuleExport, args);
break;
}
}
......@@ -2243,7 +2016,8 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable,
void BytecodeGenerator::VisitAssignment(Assignment* expr) {
DCHECK(expr->target()->IsValidReferenceExpressionOrThis());
Register object, key, home_object, value;
Register object, key;
RegisterList super_property_args;
Handle<String> name;
// Left-hand side can only be a property, a global or a variable slot.
......@@ -2262,44 +2036,29 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) {
}
case KEYED_PROPERTY: {
object = VisitForRegisterValue(property->obj());
if (expr->is_compound()) {
// Use VisitForAccumulator and store to register so that the key is
// still in the accumulator for loading the old value below.
key = register_allocator()->NewRegister();
VisitForAccumulatorValue(property->key());
builder()->StoreAccumulatorInRegister(key);
} else {
key = VisitForRegisterValue(property->key());
}
key = VisitForRegisterValue(property->key());
break;
}
case NAMED_SUPER_PROPERTY: {
register_allocator()->PrepareForConsecutiveAllocations(4);
object = register_allocator()->NextConsecutiveRegister();
home_object = register_allocator()->NextConsecutiveRegister();
key = register_allocator()->NextConsecutiveRegister();
value = register_allocator()->NextConsecutiveRegister();
super_property_args = register_allocator()->NewRegisterList(4);
SuperPropertyReference* super_property =
property->obj()->AsSuperPropertyReference();
VisitForRegisterValue(super_property->this_var(), object);
VisitForRegisterValue(super_property->home_object(), home_object);
VisitForRegisterValue(super_property->this_var(), super_property_args[0]);
VisitForRegisterValue(super_property->home_object(),
super_property_args[1]);
builder()
->LoadLiteral(property->key()->AsLiteral()->AsPropertyName())
.StoreAccumulatorInRegister(key);
.StoreAccumulatorInRegister(super_property_args[2]);
break;
}
case KEYED_SUPER_PROPERTY: {
register_allocator()->PrepareForConsecutiveAllocations(4);
object = register_allocator()->NextConsecutiveRegister();
home_object = register_allocator()->NextConsecutiveRegister();
key = register_allocator()->NextConsecutiveRegister();
value = register_allocator()->NextConsecutiveRegister();
builder()->StoreAccumulatorInRegister(value);
super_property_args = register_allocator()->NewRegisterList(4);
SuperPropertyReference* super_property =
property->obj()->AsSuperPropertyReference();
VisitForRegisterValue(super_property->this_var(), object);
VisitForRegisterValue(super_property->home_object(), home_object);
VisitForRegisterValue(property->key(), key);
VisitForRegisterValue(super_property->this_var(), super_property_args[0]);
VisitForRegisterValue(super_property->home_object(),
super_property_args[1]);
VisitForRegisterValue(property->key(), super_property_args[2]);
break;
}
}
......@@ -2307,17 +2066,16 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) {
// Evaluate the value and potentially handle compound assignments by loading
// the left-hand side value and performing a binary operation.
if (expr->is_compound()) {
Register old_value;
Register old_value = register_allocator()->NewRegister();
switch (assign_type) {
case VARIABLE: {
VariableProxy* proxy = expr->target()->AsVariableProxy();
old_value = VisitVariableLoadForRegisterValue(
proxy->var(), proxy->VariableFeedbackSlot());
VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot());
builder()->StoreAccumulatorInRegister(old_value);
break;
}
case NAMED_PROPERTY: {
FeedbackVectorSlot slot = property->PropertyFeedbackSlot();
old_value = register_allocator()->NewRegister();
builder()
->LoadNamedProperty(object, name, feedback_index(slot))
.StoreAccumulatorInRegister(old_value);
......@@ -2327,22 +2085,23 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) {
// Key is already in accumulator at this point due to evaluating the
// LHS above.
FeedbackVectorSlot slot = property->PropertyFeedbackSlot();
old_value = register_allocator()->NewRegister();
builder()
->LoadKeyedProperty(object, feedback_index(slot))
.StoreAccumulatorInRegister(old_value);
break;
}
case NAMED_SUPER_PROPERTY: {
old_value = register_allocator()->NewRegister();
BuildNamedSuperPropertyLoad(object, home_object, key);
builder()->StoreAccumulatorInRegister(old_value);
builder()
->CallRuntime(Runtime::kLoadFromSuper,
super_property_args.Truncate(3))
.StoreAccumulatorInRegister(old_value);
break;
}
case KEYED_SUPER_PROPERTY: {
old_value = register_allocator()->NewRegister();
BuildKeyedSuperPropertyLoad(object, home_object, key);
builder()->StoreAccumulatorInRegister(old_value);
builder()
->CallRuntime(Runtime::kLoadKeyedFromSuper,
super_property_args.Truncate(3))
.StoreAccumulatorInRegister(old_value);
break;
}
}
......@@ -2375,17 +2134,18 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) {
language_mode());
break;
case NAMED_SUPER_PROPERTY: {
builder()->StoreAccumulatorInRegister(value);
BuildNamedSuperPropertyStore(object, home_object, key, value);
builder()
->StoreAccumulatorInRegister(super_property_args[3])
.CallRuntime(StoreToSuperRuntimeId(), super_property_args);
break;
}
case KEYED_SUPER_PROPERTY: {
builder()->StoreAccumulatorInRegister(value);
BuildKeyedSuperPropertyStore(object, home_object, key, value);
builder()
->StoreAccumulatorInRegister(super_property_args[3])
.CallRuntime(StoreKeyedToSuperRuntimeId(), super_property_args);
break;
}
}
execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::VisitYield(Yield* expr) {
......@@ -2415,12 +2175,12 @@ void BytecodeGenerator::VisitYield(Yield* expr) {
Register input = register_allocator()->NewRegister();
builder()
->CallRuntime(Runtime::kInlineGeneratorGetInputOrDebugPos, generator, 1)
->CallRuntime(Runtime::kInlineGeneratorGetInputOrDebugPos, generator)
.StoreAccumulatorInRegister(input);
Register resume_mode = register_allocator()->NewRegister();
builder()
->CallRuntime(Runtime::kInlineGeneratorGetResumeMode, generator, 1)
->CallRuntime(Runtime::kInlineGeneratorGetResumeMode, generator)
.StoreAccumulatorInRegister(resume_mode);
// Now dispatch on resume mode.
......@@ -2440,14 +2200,12 @@ void BytecodeGenerator::VisitYield(Yield* expr) {
builder()->Bind(&resume_with_return);
{
register_allocator()->PrepareForConsecutiveAllocations(2);
Register value = register_allocator()->NextConsecutiveRegister();
Register done = register_allocator()->NextConsecutiveRegister();
RegisterList args = register_allocator()->NewRegisterList(2);
builder()
->MoveRegister(input, value)
->MoveRegister(input, args[0])
.LoadTrue()
.StoreAccumulatorInRegister(done)
.CallRuntime(Runtime::kInlineCreateIterResultObject, value, 2);
.StoreAccumulatorInRegister(args[1])
.CallRuntime(Runtime::kInlineCreateIterResultObject, args);
execution_control()->ReturnAccumulator();
}
......@@ -2463,18 +2221,12 @@ void BytecodeGenerator::VisitYield(Yield* expr) {
builder()->Bind(&resume_with_next);
builder()->LoadAccumulatorWithRegister(input);
}
execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::VisitThrow(Throw* expr) {
VisitForAccumulatorValue(expr->exception());
builder()->SetExpressionPosition(expr);
builder()->Throw();
// Throw statements are modeled as expressions instead of statements. These
// are converted from assignment statements in Rewriter::ReWrite pass. An
// assignment statement expects a value in the accumulator. This is a hack to
// avoid DCHECK fails assert accumulator has been set.
execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) {
......@@ -2502,56 +2254,45 @@ void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) {
VisitKeyedSuperPropertyLoad(expr, Register::invalid_value());
break;
}
execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::VisitPropertyLoadForAccumulator(Register obj,
Property* expr) {
AccumulatorResultScope result_scope(this);
ValueResultScope result_scope(this);
VisitPropertyLoad(obj, expr);
}
void BytecodeGenerator::VisitNamedSuperPropertyLoad(Property* property,
Register opt_receiver_out) {
RegisterAllocationScope register_scope(this);
register_allocator()->PrepareForConsecutiveAllocations(3);
Register receiver, home_object, name;
receiver = register_allocator()->NextConsecutiveRegister();
home_object = register_allocator()->NextConsecutiveRegister();
name = register_allocator()->NextConsecutiveRegister();
SuperPropertyReference* super_property =
property->obj()->AsSuperPropertyReference();
VisitForRegisterValue(super_property->this_var(), receiver);
VisitForRegisterValue(super_property->home_object(), home_object);
RegisterList args = register_allocator()->NewRegisterList(3);
VisitForRegisterValue(super_property->this_var(), args[0]);
VisitForRegisterValue(super_property->home_object(), args[1]);
builder()
->LoadLiteral(property->key()->AsLiteral()->AsPropertyName())
.StoreAccumulatorInRegister(name);
BuildNamedSuperPropertyLoad(receiver, home_object, name);
.StoreAccumulatorInRegister(args[2])
.CallRuntime(Runtime::kLoadFromSuper, args);
if (opt_receiver_out.is_valid()) {
builder()->MoveRegister(receiver, opt_receiver_out);
builder()->MoveRegister(args[0], opt_receiver_out);
}
}
void BytecodeGenerator::VisitKeyedSuperPropertyLoad(Property* property,
Register opt_receiver_out) {
RegisterAllocationScope register_scope(this);
register_allocator()->PrepareForConsecutiveAllocations(3);
Register receiver, home_object, key;
receiver = register_allocator()->NextConsecutiveRegister();
home_object = register_allocator()->NextConsecutiveRegister();
key = register_allocator()->NextConsecutiveRegister();
SuperPropertyReference* super_property =
property->obj()->AsSuperPropertyReference();
VisitForRegisterValue(super_property->this_var(), receiver);
VisitForRegisterValue(super_property->home_object(), home_object);
VisitForRegisterValue(property->key(), key);
BuildKeyedSuperPropertyLoad(receiver, home_object, key);
RegisterList args = register_allocator()->NewRegisterList(3);
VisitForRegisterValue(super_property->this_var(), args[0]);
VisitForRegisterValue(super_property->home_object(), args[1]);
VisitForRegisterValue(property->key(), args[2]);
builder()->CallRuntime(Runtime::kLoadKeyedFromSuper, args);
if (opt_receiver_out.is_valid()) {
builder()->MoveRegister(receiver, opt_receiver_out);
builder()->MoveRegister(args[0], opt_receiver_out);
}
}
......@@ -2566,36 +2307,13 @@ void BytecodeGenerator::VisitProperty(Property* expr) {
}
}
Register BytecodeGenerator::VisitArguments(ZoneList<Expression*>* args) {
if (args->length() == 0) {
return Register();
}
// Visit arguments and place in a contiguous block of temporary
// registers. Return the first temporary register corresponding to
// the first argument.
//
// NB the caller may have already called
// PrepareForConsecutiveAllocations() with args->length() + N. The
// second call here will be a no-op provided there have been N or
// less calls to NextConsecutiveRegister(). Otherwise, the arguments
// here will be consecutive, but they will not be consecutive with
// earlier consecutive allocations made by the caller.
register_allocator()->PrepareForConsecutiveAllocations(args->length());
// Visit for first argument that goes into returned register
Register first_arg = register_allocator()->NextConsecutiveRegister();
VisitForAccumulatorValue(args->at(0));
builder()->StoreAccumulatorInRegister(first_arg);
// Visit remaining arguments
for (int i = 1; i < static_cast<int>(args->length()); i++) {
Register ith_arg = register_allocator()->NextConsecutiveRegister();
VisitForAccumulatorValue(args->at(i));
builder()->StoreAccumulatorInRegister(ith_arg);
DCHECK(ith_arg.index() - i == first_arg.index());
void BytecodeGenerator::VisitArguments(ZoneList<Expression*>* args,
RegisterList arg_regs,
size_t first_argument_register) {
// Visit arguments.
for (int i = 0; i < static_cast<int>(args->length()); i++) {
VisitForRegisterValue(args->at(i), arg_regs[first_argument_register + i]);
}
return first_arg;
}
void BytecodeGenerator::VisitCall(Call* expr) {
......@@ -2606,18 +2324,15 @@ void BytecodeGenerator::VisitCall(Call* expr) {
return VisitCallSuper(expr);
}
// Prepare the callee and the receiver to the function call. This depends on
// the semantics of the underlying call type.
Register callee = register_allocator()->NewRegister();
// The receiver and arguments need to be allocated consecutively for
// Call(). We allocate the callee and receiver consecutively for calls to
// %LoadLookupSlotForCall. Future optimizations could avoid this there are
// no arguments or the receiver and arguments are already consecutive.
ZoneList<Expression*>* args = expr->arguments();
register_allocator()->PrepareForConsecutiveAllocations(args->length() + 2);
Register callee = register_allocator()->NextConsecutiveRegister();
Register receiver = register_allocator()->NextConsecutiveRegister();
// Add an argument register for the receiver.
RegisterList args =
register_allocator()->NewRegisterList(expr->arguments()->length() + 1);
Register receiver = args[0];
// Prepare the callee and the receiver to the function call. This depends on
// the semantics of the underlying call type.
switch (call_type) {
case Call::NAMED_PROPERTY_CALL:
case Call::KEYED_PROPERTY_CALL: {
......@@ -2650,8 +2365,7 @@ void BytecodeGenerator::VisitCall(Call* expr) {
builder()
->LoadLiteral(variable->name())
.StoreAccumulatorInRegister(name)
.CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, name, 1,
callee);
.CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, name, callee);
break;
}
// Fall through.
......@@ -2659,8 +2373,7 @@ void BytecodeGenerator::VisitCall(Call* expr) {
}
case Call::OTHER_CALL: {
builder()->LoadUndefined().StoreAccumulatorInRegister(receiver);
VisitForAccumulatorValue(callee_expr);
builder()->StoreAccumulatorInRegister(callee);
VisitForRegisterValue(callee_expr, callee);
break;
}
case Call::NAMED_SUPER_PROPERTY_CALL: {
......@@ -2680,42 +2393,34 @@ void BytecodeGenerator::VisitCall(Call* expr) {
break;
}
// Evaluate all arguments to the function call and store in sequential
// Evaluate all arguments to the function call and store in sequential args
// registers.
Register arg = VisitArguments(args);
CHECK(args->length() == 0 || arg.index() == receiver.index() + 1);
VisitArguments(expr->arguments(), args, 1);
// Resolve callee for a potential direct eval call. This block will mutate the
// callee value.
if (call_type == Call::POSSIBLY_EVAL_CALL && args->length() > 0) {
if (call_type == Call::POSSIBLY_EVAL_CALL &&
expr->arguments()->length() > 0) {
RegisterAllocationScope inner_register_scope(this);
register_allocator()->PrepareForConsecutiveAllocations(6);
Register callee_for_eval = register_allocator()->NextConsecutiveRegister();
Register source = register_allocator()->NextConsecutiveRegister();
Register function = register_allocator()->NextConsecutiveRegister();
Register language = register_allocator()->NextConsecutiveRegister();
Register eval_scope_position =
register_allocator()->NextConsecutiveRegister();
Register eval_position = register_allocator()->NextConsecutiveRegister();
// Set up arguments for ResolvePossiblyDirectEval by copying callee, source
// strings and function closure, and loading language and
// position.
RegisterList runtime_call_args = register_allocator()->NewRegisterList(6);
builder()
->MoveRegister(callee, callee_for_eval)
.MoveRegister(arg, source)
.MoveRegister(Register::function_closure(), function)
->MoveRegister(callee, runtime_call_args[0])
.MoveRegister(args[1], runtime_call_args[1])
.MoveRegister(Register::function_closure(), runtime_call_args[2])
.LoadLiteral(Smi::FromInt(language_mode()))
.StoreAccumulatorInRegister(language)
.StoreAccumulatorInRegister(runtime_call_args[3])
.LoadLiteral(
Smi::FromInt(execution_context()->scope()->start_position()))
.StoreAccumulatorInRegister(eval_scope_position)
.StoreAccumulatorInRegister(runtime_call_args[4])
.LoadLiteral(Smi::FromInt(expr->position()))
.StoreAccumulatorInRegister(eval_position);
.StoreAccumulatorInRegister(runtime_call_args[5]);
// Call ResolvePossiblyDirectEval and modify the callee.
builder()
->CallRuntime(Runtime::kResolvePossiblyDirectEval, callee_for_eval, 6)
->CallRuntime(Runtime::kResolvePossiblyDirectEval, runtime_call_args)
.StoreAccumulatorInRegister(callee);
}
......@@ -2732,9 +2437,7 @@ void BytecodeGenerator::VisitCall(Call* expr) {
} else {
feedback_slot_index = feedback_index(expr->CallFeedbackICSlot());
}
builder()->Call(callee, receiver, 1 + args->length(), feedback_slot_index,
expr->tail_call_mode());
execution_result()->SetResultInAccumulator();
builder()->Call(callee, args, feedback_slot_index, expr->tail_call_mode());
}
void BytecodeGenerator::VisitCallSuper(Call* expr) {
......@@ -2742,17 +2445,15 @@ void BytecodeGenerator::VisitCallSuper(Call* expr) {
SuperCallReference* super = expr->expression()->AsSuperCallReference();
// Prepare the constructor to the super call.
Register this_function = register_allocator()->NewRegister();
VisitForAccumulatorValue(super->this_function_var());
builder()
->StoreAccumulatorInRegister(this_function)
.CallRuntime(Runtime::kInlineGetSuperConstructor, this_function, 1);
Register this_function = VisitForRegisterValue(super->this_function_var());
builder()->CallRuntime(Runtime::kInlineGetSuperConstructor, this_function);
Register constructor = this_function; // Re-use dead this_function register.
builder()->StoreAccumulatorInRegister(constructor);
ZoneList<Expression*>* args = expr->arguments();
Register first_arg = VisitArguments(args);
RegisterList args =
register_allocator()->NewRegisterList(expr->arguments()->length());
VisitArguments(expr->arguments(), args);
// The new target is loaded into the accumulator from the
// {new.target} variable.
......@@ -2766,52 +2467,45 @@ void BytecodeGenerator::VisitCallSuper(Call* expr) {
// Type feedback is not necessary for super constructor calls. The type
// information can be inferred in most cases. Slot id 0 indicates type
// feedback is not required.
builder()->New(constructor, first_arg, args->length(), 0);
execution_result()->SetResultInAccumulator();
builder()->New(constructor, args, 0);
}
void BytecodeGenerator::VisitCallNew(CallNew* expr) {
Register constructor = register_allocator()->NewRegister();
VisitForAccumulatorValue(expr->expression());
builder()->StoreAccumulatorInRegister(constructor);
ZoneList<Expression*>* args = expr->arguments();
Register first_arg = VisitArguments(args);
Register constructor = VisitForRegisterValue(expr->expression());
RegisterList args =
register_allocator()->NewRegisterList(expr->arguments()->length());
VisitArguments(expr->arguments(), args);
builder()->SetExpressionPosition(expr);
// The accumulator holds new target which is the same as the
// constructor for CallNew.
builder()
->LoadAccumulatorWithRegister(constructor)
.New(constructor, first_arg, args->length(),
feedback_index(expr->CallNewFeedbackSlot()));
execution_result()->SetResultInAccumulator();
.New(constructor, args, feedback_index(expr->CallNewFeedbackSlot()));
}
void BytecodeGenerator::VisitCallRuntime(CallRuntime* expr) {
ZoneList<Expression*>* args = expr->arguments();
if (expr->is_jsruntime()) {
// Allocate a register for the receiver and load it with undefined.
register_allocator()->PrepareForConsecutiveAllocations(1 + args->length());
Register receiver = register_allocator()->NextConsecutiveRegister();
RegisterList args =
register_allocator()->NewRegisterList(expr->arguments()->length() + 1);
Register receiver = args[0];
builder()->LoadUndefined().StoreAccumulatorInRegister(receiver);
Register first_arg = VisitArguments(args);
CHECK(args->length() == 0 || first_arg.index() == receiver.index() + 1);
builder()->CallJSRuntime(expr->context_index(), receiver,
1 + args->length());
VisitArguments(expr->arguments(), args, 1);
builder()->CallJSRuntime(expr->context_index(), args);
} else {
// Evaluate all arguments to the runtime call.
Register first_arg = VisitArguments(args);
RegisterList args =
register_allocator()->NewRegisterList(expr->arguments()->length());
VisitArguments(expr->arguments(), args);
Runtime::FunctionId function_id = expr->function()->function_id;
builder()->CallRuntime(function_id, first_arg, args->length());
builder()->CallRuntime(function_id, args);
}
execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::VisitVoid(UnaryOperation* expr) {
VisitForEffect(expr->expression());
builder()->LoadUndefined();
execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::VisitTypeOf(UnaryOperation* expr) {
......@@ -2825,7 +2519,6 @@ void BytecodeGenerator::VisitTypeOf(UnaryOperation* expr) {
VisitForAccumulatorValue(expr->expression());
}
builder()->TypeOf();
execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::VisitNot(UnaryOperation* expr) {
......@@ -2842,7 +2535,6 @@ void BytecodeGenerator::VisitNot(UnaryOperation* expr) {
} else {
VisitForAccumulatorValue(expr->expression());
builder()->LogicalNot();
execution_result()->SetResultInAccumulator();
}
}
......@@ -2917,7 +2609,7 @@ void BytecodeGenerator::VisitDelete(UnaryOperation* expr) {
builder()
->LoadLiteral(variable->name())
.StoreAccumulatorInRegister(name_reg)
.CallRuntime(Runtime::kDeleteLookupSlot, name_reg, 1);
.CallRuntime(Runtime::kDeleteLookupSlot, name_reg);
break;
}
default:
......@@ -2928,7 +2620,6 @@ void BytecodeGenerator::VisitDelete(UnaryOperation* expr) {
VisitForEffect(expr->expression());
builder()->LoadTrue();
}
execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::VisitCountOperation(CountOperation* expr) {
......@@ -2941,7 +2632,8 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) {
bool is_postfix = expr->is_postfix() && !execution_result()->IsEffect();
// Evaluate LHS expression and get old value.
Register object, home_object, key, old_value, value;
Register object, key, old_value;
RegisterList super_property_args;
Handle<String> name;
switch (assign_type) {
case VARIABLE: {
......@@ -2969,43 +2661,35 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) {
break;
}
case NAMED_SUPER_PROPERTY: {
register_allocator()->PrepareForConsecutiveAllocations(4);
object = register_allocator()->NextConsecutiveRegister();
home_object = register_allocator()->NextConsecutiveRegister();
key = register_allocator()->NextConsecutiveRegister();
value = register_allocator()->NextConsecutiveRegister();
super_property_args = register_allocator()->NewRegisterList(4);
RegisterList load_super_args = super_property_args.Truncate(3);
SuperPropertyReference* super_property =
property->obj()->AsSuperPropertyReference();
VisitForRegisterValue(super_property->this_var(), object);
VisitForRegisterValue(super_property->home_object(), home_object);
VisitForRegisterValue(super_property->this_var(), load_super_args[0]);
VisitForRegisterValue(super_property->home_object(), load_super_args[1]);
builder()
->LoadLiteral(property->key()->AsLiteral()->AsPropertyName())
.StoreAccumulatorInRegister(key);
BuildNamedSuperPropertyLoad(object, home_object, key);
.StoreAccumulatorInRegister(load_super_args[2])
.CallRuntime(Runtime::kLoadFromSuper, load_super_args);
break;
}
case KEYED_SUPER_PROPERTY: {
register_allocator()->PrepareForConsecutiveAllocations(4);
object = register_allocator()->NextConsecutiveRegister();
home_object = register_allocator()->NextConsecutiveRegister();
key = register_allocator()->NextConsecutiveRegister();
value = register_allocator()->NextConsecutiveRegister();
builder()->StoreAccumulatorInRegister(value);
super_property_args = register_allocator()->NewRegisterList(4);
RegisterList load_super_args = super_property_args.Truncate(3);
SuperPropertyReference* super_property =
property->obj()->AsSuperPropertyReference();
VisitForRegisterValue(super_property->this_var(), object);
VisitForRegisterValue(super_property->home_object(), home_object);
VisitForRegisterValue(property->key(), key);
BuildKeyedSuperPropertyLoad(object, home_object, key);
VisitForRegisterValue(super_property->this_var(), load_super_args[0]);
VisitForRegisterValue(super_property->home_object(), load_super_args[1]);
VisitForRegisterValue(property->key(), load_super_args[2]);
builder()->CallRuntime(Runtime::kLoadKeyedFromSuper, load_super_args);
break;
}
}
// Save result for postfix expressions.
if (is_postfix) {
old_value = register_allocator()->outer()->NewRegister();
// Convert old value into a number before saving it.
old_value = register_allocator()->NewRegister();
builder()->ConvertAccumulatorToNumber(old_value);
}
......@@ -3033,22 +2717,22 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) {
break;
}
case NAMED_SUPER_PROPERTY: {
builder()->StoreAccumulatorInRegister(value);
BuildNamedSuperPropertyStore(object, home_object, key, value);
builder()
->StoreAccumulatorInRegister(super_property_args[3])
.CallRuntime(StoreToSuperRuntimeId(), super_property_args);
break;
}
case KEYED_SUPER_PROPERTY: {
builder()->StoreAccumulatorInRegister(value);
BuildKeyedSuperPropertyStore(object, home_object, key, value);
builder()
->StoreAccumulatorInRegister(super_property_args[3])
.CallRuntime(StoreKeyedToSuperRuntimeId(), super_property_args);
break;
}
}
// Restore old value for postfix expressions.
if (is_postfix) {
execution_result()->SetResultInRegister(old_value);
} else {
execution_result()->SetResultInAccumulator();
builder()->LoadAccumulatorWithRegister(old_value);
}
}
......@@ -3075,7 +2759,6 @@ void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) {
builder()->SetExpressionPosition(expr);
FeedbackVectorSlot slot = expr->CompareOperationFeedbackSlot();
builder()->CompareOperation(expr->op(), lhs, feedback_index(slot));
execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) {
......@@ -3085,7 +2768,6 @@ void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) {
VisitForAccumulatorValue(expr->right());
FeedbackVectorSlot slot = expr->BinaryOperationFeedbackSlot();
builder()->BinaryOperation(expr->op(), lhs, feedback_index(slot));
execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::VisitSpread(Spread* expr) { UNREACHABLE(); }
......@@ -3095,7 +2777,7 @@ void BytecodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) {
}
void BytecodeGenerator::VisitThisFunction(ThisFunction* expr) {
execution_result()->SetResultInRegister(Register::function_closure());
builder()->LoadAccumulatorWithRegister(Register::function_closure());
}
void BytecodeGenerator::VisitSuperCallReference(SuperCallReference* expr) {
......@@ -3105,8 +2787,7 @@ void BytecodeGenerator::VisitSuperCallReference(SuperCallReference* expr) {
void BytecodeGenerator::VisitSuperPropertyReference(
SuperPropertyReference* expr) {
builder()->CallRuntime(Runtime::kThrowUnsupportedSuperError, Register(0), 0);
execution_result()->SetResultInAccumulator();
builder()->CallRuntime(Runtime::kThrowUnsupportedSuperError);
}
void BytecodeGenerator::VisitCommaExpression(BinaryOperation* binop) {
......@@ -3146,7 +2827,6 @@ void BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) {
VisitForAccumulatorValue(right);
builder()->Bind(&end_label);
}
execution_result()->SetResultInAccumulator();
}
}
......@@ -3182,7 +2862,6 @@ void BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) {
VisitForAccumulatorValue(right);
builder()->Bind(&end_label);
}
execution_result()->SetResultInAccumulator();
}
}
......@@ -3191,44 +2870,36 @@ void BytecodeGenerator::VisitRewritableExpression(RewritableExpression* expr) {
}
void BytecodeGenerator::BuildNewLocalActivationContext() {
AccumulatorResultScope accumulator_execution_result(this);
ValueResultScope value_execution_result(this);
Scope* scope = this->scope();
// Create the appropriate context.
if (scope->is_script_scope()) {
RegisterAllocationScope register_scope(this);
register_allocator()->PrepareForConsecutiveAllocations(2);
Register closure = register_allocator()->NextConsecutiveRegister();
Register scope_info = register_allocator()->NextConsecutiveRegister();
RegisterList args = register_allocator()->NewRegisterList(2);
builder()
->LoadAccumulatorWithRegister(Register::function_closure())
.StoreAccumulatorInRegister(closure)
.StoreAccumulatorInRegister(args[0])
.LoadLiteral(scope->scope_info())
.StoreAccumulatorInRegister(scope_info)
.CallRuntime(Runtime::kNewScriptContext, closure, 2);
.StoreAccumulatorInRegister(args[1])
.CallRuntime(Runtime::kNewScriptContext, args);
} else if (scope->is_module_scope()) {
// We don't need to do anything for the outer script scope.
DCHECK(scope->outer_scope()->is_script_scope());
RegisterAllocationScope register_scope(this);
register_allocator()->PrepareForConsecutiveAllocations(3);
Register module = register_allocator()->NextConsecutiveRegister();
Register closure = register_allocator()->NextConsecutiveRegister();
Register scope_info = register_allocator()->NextConsecutiveRegister();
// A JSFunction representing a module is called with the module object as
// its sole argument, which we pass on to PushModuleContext.
RegisterList args = register_allocator()->NewRegisterList(3);
builder()
->MoveRegister(builder()->Parameter(1), module)
->MoveRegister(builder()->Parameter(1), args[0])
.LoadAccumulatorWithRegister(Register::function_closure())
.StoreAccumulatorInRegister(closure)
.StoreAccumulatorInRegister(args[1])
.LoadLiteral(scope->scope_info())
.StoreAccumulatorInRegister(scope_info)
.CallRuntime(Runtime::kPushModuleContext, module, 3);
.StoreAccumulatorInRegister(args[2])
.CallRuntime(Runtime::kPushModuleContext, args);
} else {
int slot_count = scope->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
builder()->CreateFunctionContext(slot_count);
}
execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::BuildLocalActivationContextInitialization() {
......@@ -3260,28 +2931,26 @@ void BytecodeGenerator::BuildLocalActivationContextInitialization() {
}
void BytecodeGenerator::BuildNewLocalBlockContext(Scope* scope) {
AccumulatorResultScope accumulator_execution_result(this);
ValueResultScope value_execution_result(this);
DCHECK(scope->is_block_scope());
VisitFunctionClosureForContext();
builder()->CreateBlockContext(scope->scope_info());
execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::BuildNewLocalWithContext(Scope* scope) {
AccumulatorResultScope accumulator_execution_result(this);
ValueResultScope value_execution_result(this);
Register extension_object = register_allocator()->NewRegister();
builder()->ConvertAccumulatorToObject(extension_object);
VisitFunctionClosureForContext();
builder()->CreateWithContext(extension_object, scope->scope_info());
execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::BuildNewLocalCatchContext(Variable* variable,
Scope* scope) {
AccumulatorResultScope accumulator_execution_result(this);
ValueResultScope value_execution_result(this);
DCHECK(variable->IsContextSlot());
Register exception = register_allocator()->NewRegister();
......@@ -3289,17 +2958,14 @@ void BytecodeGenerator::BuildNewLocalCatchContext(Variable* variable,
VisitFunctionClosureForContext();
builder()->CreateCatchContext(exception, variable->name(),
scope->scope_info());
execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::VisitObjectLiteralAccessor(
Register home_object, ObjectLiteralProperty* property, Register value_out) {
// TODO(rmcilroy): Replace value_out with VisitForRegister();
if (property == nullptr) {
builder()->LoadNull().StoreAccumulatorInRegister(value_out);
} else {
VisitForAccumulatorValue(property->value());
builder()->StoreAccumulatorInRegister(value_out);
VisitForRegisterValue(property->value(), value_out);
VisitSetHomeObject(value_out, home_object, property);
}
}
......@@ -3367,7 +3033,7 @@ void BytecodeGenerator::VisitNewTargetVariable(Variable* variable) {
}
void BytecodeGenerator::VisitFunctionClosureForContext() {
AccumulatorResultScope accumulator_execution_result(this);
ValueResultScope value_execution_result(this);
DeclarationScope* closure_scope =
execution_context()->scope()->GetClosureScope();
if (closure_scope->is_script_scope()) {
......@@ -3390,12 +3056,11 @@ void BytecodeGenerator::VisitFunctionClosureForContext() {
closure_scope->is_module_scope());
builder()->LoadAccumulatorWithRegister(Register::function_closure());
}
execution_result()->SetResultInAccumulator();
}
// Visits the expression |expr| and places the result in the accumulator.
void BytecodeGenerator::VisitForAccumulatorValue(Expression* expr) {
AccumulatorResultScope accumulator_scope(this);
ValueResultScope accumulator_scope(this);
Visit(expr);
}
......@@ -3416,16 +3081,17 @@ void BytecodeGenerator::VisitForEffect(Expression* expr) {
// Visits the expression |expr| and returns the register containing
// the expression result.
Register BytecodeGenerator::VisitForRegisterValue(Expression* expr) {
RegisterResultScope register_scope(this);
Visit(expr);
return register_scope.ResultRegister();
VisitForAccumulatorValue(expr);
Register result = register_allocator()->NewRegister();
builder()->StoreAccumulatorInRegister(result);
return result;
}
// Visits the expression |expr| and stores the expression result in
// |destination|.
void BytecodeGenerator::VisitForRegisterValue(Expression* expr,
Register destination) {
AccumulatorResultScope register_scope(this);
ValueResultScope register_scope(this);
Visit(expr);
builder()->StoreAccumulatorInRegister(destination);
}
......@@ -3474,6 +3140,16 @@ int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const {
return TypeFeedbackVector::GetIndex(slot);
}
Runtime::FunctionId BytecodeGenerator::StoreToSuperRuntimeId() {
return is_strict(language_mode()) ? Runtime::kStoreToSuper_Strict
: Runtime::kStoreToSuper_Sloppy;
}
Runtime::FunctionId BytecodeGenerator::StoreKeyedToSuperRuntimeId() {
return is_strict(language_mode()) ? Runtime::kStoreKeyedToSuper_Strict
: Runtime::kStoreKeyedToSuper_Sloppy;
}
} // namespace interpreter
} // namespace internal
} // namespace v8
......@@ -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();
......
......@@ -12,199 +12,83 @@ namespace v8 {
namespace internal {
namespace interpreter {
class TemporaryRegisterAllocatorTest : public TestWithIsolateAndZone {
public:
TemporaryRegisterAllocatorTest() : allocator_(zone(), 0) {}
~TemporaryRegisterAllocatorTest() override {}
TemporaryRegisterAllocator* allocator() { return &allocator_; }
private:
TemporaryRegisterAllocator allocator_;
};
TEST_F(TemporaryRegisterAllocatorTest, FirstAllocation) {
CHECK_EQ(allocator()->allocation_count(), 0);
int reg0_index = allocator()->BorrowTemporaryRegister();
CHECK_EQ(reg0_index, 0);
CHECK_EQ(allocator()->allocation_count(), 1);
CHECK(allocator()->RegisterIsLive(Register(reg0_index)));
allocator()->ReturnTemporaryRegister(reg0_index);
CHECK(!allocator()->RegisterIsLive(Register(reg0_index)));
CHECK_EQ(allocator()->allocation_count(), 1);
CHECK(allocator()->first_temporary_register() == Register(0));
CHECK(allocator()->last_temporary_register() == Register(0));
}
TEST_F(TemporaryRegisterAllocatorTest, SimpleAllocations) {
for (int i = 0; i < 13; i++) {
int reg_index = allocator()->BorrowTemporaryRegister();
CHECK_EQ(reg_index, i);
CHECK_EQ(allocator()->allocation_count(), i + 1);
}
for (int i = 0; i < 13; i++) {
CHECK(allocator()->RegisterIsLive(Register(i)));
allocator()->ReturnTemporaryRegister(i);
CHECK(!allocator()->RegisterIsLive(Register(i)));
int reg_index = allocator()->BorrowTemporaryRegister();
CHECK_EQ(reg_index, i);
CHECK_EQ(allocator()->allocation_count(), 13);
}
for (int i = 0; i < 13; i++) {
CHECK(allocator()->RegisterIsLive(Register(i)));
allocator()->ReturnTemporaryRegister(i);
CHECK(!allocator()->RegisterIsLive(Register(i)));
}
}
TEST_F(TemporaryRegisterAllocatorTest, SimpleRangeAllocation) {
static const int kRunLength = 7;
int start = allocator()->PrepareForConsecutiveTemporaryRegisters(kRunLength);
CHECK(!allocator()->RegisterIsLive(Register(start)));
for (int i = 0; i < kRunLength; i++) {
CHECK(!allocator()->RegisterIsLive(Register(start + i)));
allocator()->BorrowConsecutiveTemporaryRegister(start + i);
CHECK(allocator()->RegisterIsLive(Register(start + i)));
}
}
TEST_F(TemporaryRegisterAllocatorTest, RangeAllocationAbuttingFree) {
static const int kFreeCount = 3;
static const int kRunLength = 6;
for (int i = 0; i < kFreeCount; i++) {
int to_free = allocator()->BorrowTemporaryRegister();
CHECK_EQ(to_free, i);
}
for (int i = 0; i < kFreeCount; i++) {
allocator()->ReturnTemporaryRegister(i);
}
int start = allocator()->PrepareForConsecutiveTemporaryRegisters(kRunLength);
CHECK(!allocator()->RegisterIsLive(Register(start)));
for (int i = 0; i < kRunLength; i++) {
CHECK(!allocator()->RegisterIsLive(Register(start + i)));
allocator()->BorrowConsecutiveTemporaryRegister(start + i);
CHECK(allocator()->RegisterIsLive(Register(start + i)));
}
}
TEST_F(TemporaryRegisterAllocatorTest, RangeAllocationAbuttingHole) {
static const int kPreAllocatedCount = 7;
static const int kPreAllocatedFreeCount = 6;
static const int kRunLength = 8;
for (int i = 0; i < kPreAllocatedCount; i++) {
int to_free = allocator()->BorrowTemporaryRegister();
CHECK_EQ(to_free, i);
}
for (int i = 0; i < kPreAllocatedFreeCount; i++) {
allocator()->ReturnTemporaryRegister(i);
}
int start = allocator()->PrepareForConsecutiveTemporaryRegisters(kRunLength);
CHECK(!allocator()->RegisterIsLive(Register(start)));
CHECK_EQ(start, kPreAllocatedCount);
for (int i = 0; i < kRunLength; i++) {
CHECK(!allocator()->RegisterIsLive(Register(start + i)));
allocator()->BorrowConsecutiveTemporaryRegister(start + i);
CHECK(allocator()->RegisterIsLive(Register(start + i)));
}
}
TEST_F(TemporaryRegisterAllocatorTest, RangeAllocationAvailableInTemporaries) {
static const int kNotRunLength = 13;
static const int kRunLength = 8;
// Allocate big batch
for (int i = 0; i < kNotRunLength * 2 + kRunLength; i++) {
int allocated = allocator()->BorrowTemporaryRegister();
CHECK_EQ(allocated, i);
}
// Free every other register either side of target.
for (int i = 0; i < kNotRunLength; i++) {
if ((i & 2) == 1) {
allocator()->ReturnTemporaryRegister(i);
allocator()->ReturnTemporaryRegister(kNotRunLength + kRunLength + i);
}
}
// Free all registers for target.
for (int i = kNotRunLength; i < kNotRunLength + kRunLength; i++) {
allocator()->ReturnTemporaryRegister(i);
}
int start = allocator()->PrepareForConsecutiveTemporaryRegisters(kRunLength);
CHECK_EQ(start, kNotRunLength);
for (int i = 0; i < kRunLength; i++) {
CHECK(!allocator()->RegisterIsLive(Register(start + i)));
allocator()->BorrowConsecutiveTemporaryRegister(start + i);
CHECK(allocator()->RegisterIsLive(Register(start + i)));
}
}
TEST_F(TemporaryRegisterAllocatorTest, NotInRange) {
for (int i = 0; i < 10; i++) {
int reg = allocator()->BorrowTemporaryRegisterNotInRange(2, 5);
CHECK(reg == i || (reg > 2 && reg == i + 4));
}
for (int i = 0; i < 10; i++) {
if (i < 2) {
allocator()->ReturnTemporaryRegister(i);
} else {
allocator()->ReturnTemporaryRegister(i + 4);
}
}
int reg0 = allocator()->BorrowTemporaryRegisterNotInRange(0, 3);
CHECK_EQ(reg0, 4);
int reg1 = allocator()->BorrowTemporaryRegisterNotInRange(3, 10);
CHECK_EQ(reg1, 2);
int reg2 = allocator()->BorrowTemporaryRegisterNotInRange(2, 6);
CHECK_EQ(reg2, 1);
allocator()->ReturnTemporaryRegister(reg0);
allocator()->ReturnTemporaryRegister(reg1);
allocator()->ReturnTemporaryRegister(reg2);
}
class BytecodeRegisterAllocatorTest : public TestWithIsolateAndZone {
public:
BytecodeRegisterAllocatorTest() {}
BytecodeRegisterAllocatorTest() : allocator_(0) {}
~BytecodeRegisterAllocatorTest() override {}
};
TEST_F(BytecodeRegisterAllocatorTest, TemporariesRecycled) {
BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0);
int first;
{
BytecodeRegisterAllocator allocator(zone(),
builder.temporary_register_allocator());
first = allocator.NewRegister().index();
allocator.NewRegister();
allocator.NewRegister();
allocator.NewRegister();
}
BytecodeRegisterAllocator* allocator() { return &allocator_; }
int second;
{
BytecodeRegisterAllocator allocator(zone(),
builder.temporary_register_allocator());
second = allocator.NewRegister().index();
}
private:
BytecodeRegisterAllocator allocator_;
};
CHECK_EQ(first, second);
TEST_F(BytecodeRegisterAllocatorTest, SimpleAllocations) {
CHECK_EQ(allocator()->maximum_register_count(), 0);
Register reg0 = allocator()->NewRegister();
CHECK_EQ(reg0.index(), 0);
CHECK_EQ(allocator()->maximum_register_count(), 1);
CHECK_EQ(allocator()->next_register_index(), 1);
CHECK(allocator()->RegisterIsLive(reg0));
allocator()->ReleaseRegisters(0);
CHECK(!allocator()->RegisterIsLive(reg0));
CHECK_EQ(allocator()->maximum_register_count(), 1);
CHECK_EQ(allocator()->next_register_index(), 0);
reg0 = allocator()->NewRegister();
Register reg1 = allocator()->NewRegister();
CHECK_EQ(reg0.index(), 0);
CHECK_EQ(reg1.index(), 1);
CHECK(allocator()->RegisterIsLive(reg0));
CHECK(allocator()->RegisterIsLive(reg1));
CHECK_EQ(allocator()->maximum_register_count(), 2);
CHECK_EQ(allocator()->next_register_index(), 2);
allocator()->ReleaseRegisters(1);
CHECK(allocator()->RegisterIsLive(reg0));
CHECK(!allocator()->RegisterIsLive(reg1));
CHECK_EQ(allocator()->maximum_register_count(), 2);
CHECK_EQ(allocator()->next_register_index(), 1);
}
TEST_F(BytecodeRegisterAllocatorTest, ConsecutiveRegisters) {
BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0);
BytecodeRegisterAllocator allocator(zone(),
builder.temporary_register_allocator());
allocator.PrepareForConsecutiveAllocations(4);
Register reg0 = allocator.NextConsecutiveRegister();
Register other = allocator.NewRegister();
Register reg1 = allocator.NextConsecutiveRegister();
Register reg2 = allocator.NextConsecutiveRegister();
Register reg3 = allocator.NextConsecutiveRegister();
USE(other);
CHECK(Register::AreContiguous(reg0, reg1, reg2, reg3));
TEST_F(BytecodeRegisterAllocatorTest, RegisterListAllocations) {
CHECK_EQ(allocator()->maximum_register_count(), 0);
RegisterList reg_list = allocator()->NewRegisterList(3);
CHECK_EQ(reg_list.first_register().index(), 0);
CHECK_EQ(reg_list.register_count(), 3);
CHECK_EQ(reg_list[0].index(), 0);
CHECK_EQ(reg_list[1].index(), 1);
CHECK_EQ(reg_list[2].index(), 2);
CHECK_EQ(allocator()->maximum_register_count(), 3);
CHECK_EQ(allocator()->next_register_index(), 3);
CHECK(allocator()->RegisterIsLive(reg_list[2]));
Register reg = allocator()->NewRegister();
RegisterList reg_list_2 = allocator()->NewRegisterList(2);
CHECK_EQ(reg.index(), 3);
CHECK_EQ(reg_list_2.first_register().index(), 4);
CHECK_EQ(reg_list_2.register_count(), 2);
CHECK_EQ(reg_list_2[0].index(), 4);
CHECK_EQ(reg_list_2[1].index(), 5);
CHECK_EQ(allocator()->maximum_register_count(), 6);
CHECK_EQ(allocator()->next_register_index(), 6);
CHECK(allocator()->RegisterIsLive(reg));
CHECK(allocator()->RegisterIsLive(reg_list_2[1]));
allocator()->ReleaseRegisters(reg.index());
CHECK(!allocator()->RegisterIsLive(reg));
CHECK(!allocator()->RegisterIsLive(reg_list_2[0]));
CHECK(!allocator()->RegisterIsLive(reg_list_2[1]));
CHECK(allocator()->RegisterIsLive(reg_list[2]));
CHECK_EQ(allocator()->maximum_register_count(), 6);
CHECK_EQ(allocator()->next_register_index(), 3);
RegisterList empty_reg_list = allocator()->NewRegisterList(0);
CHECK_EQ(empty_reg_list.first_register().index(), 0);
CHECK_EQ(empty_reg_list.register_count(), 0);
CHECK_EQ(allocator()->maximum_register_count(), 6);
CHECK_EQ(allocator()->next_register_index(), 3);
}
} // namespace interpreter
......
......@@ -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