Commit 339e0c80 authored by oth's avatar oth Committed by Commit bot

[Interpreter] Reduce temporary register usage in generated bytecode.

This change adds new flavors of Visit() methods for obtaining
expression results:

- VisitForAccumulatorValue() which places result in the accumulator.
- VisitForRegisterValue() which places the result in a register.
- VisitForEffect() which evaluates the expression and discards the result.

The targets of these calls place the expression result with
result_scope()->SetResultInRegister() or
result_scope()->SetResultInAccumulator().

By being smarter about result locations, there's less temporary
register usage. However, we now have a hazard with assignments
in binary expressions that didn't exist before. This change detects and
DCHECK's when a hazard is detected. A follow on CL will address this.

There are consequential changes to test-bytecode-generator.cc and
this change also adds new bytecode macros A(x, n) and THIS(n) for
register file entries for arguments and this.

BUG=v8:4280
LOG=NO

Review URL: https://codereview.chromium.org/1392933002

Cr-Commit-Position: refs/heads/master@{#31445}
parent 14ba9c3d
......@@ -22,13 +22,12 @@ BytecodeArrayBuilder::BytecodeArrayBuilder(Isolate* isolate, Zone* zone)
local_register_count_(-1),
context_register_count_(-1),
temporary_register_count_(0),
temporary_register_next_(0) {}
free_temporaries_(zone) {}
void BytecodeArrayBuilder::set_locals_count(int number_of_locals) {
local_register_count_ = number_of_locals;
DCHECK_LE(context_register_count_, 0);
temporary_register_next_ = local_register_count_;
}
......@@ -40,7 +39,6 @@ void BytecodeArrayBuilder::set_parameter_count(int number_of_parameters) {
void BytecodeArrayBuilder::set_context_count(int number_of_contexts) {
context_register_count_ = number_of_contexts;
DCHECK_GE(local_register_count_, 0);
temporary_register_next_ = local_register_count_ + context_register_count_;
}
......@@ -56,12 +54,35 @@ Register BytecodeArrayBuilder::last_context_register() const {
}
Register BytecodeArrayBuilder::first_temporary_register() const {
DCHECK_GT(temporary_register_count_, 0);
return Register(fixed_register_count());
}
Register BytecodeArrayBuilder::last_temporary_register() const {
DCHECK_GT(temporary_register_count_, 0);
return Register(fixed_register_count() + temporary_register_count_ - 1);
}
Register BytecodeArrayBuilder::Parameter(int parameter_index) const {
DCHECK_GE(parameter_index, 0);
return Register::FromParameterIndex(parameter_index, parameter_count());
}
bool BytecodeArrayBuilder::RegisterIsParameterOrLocal(Register reg) const {
return reg.is_parameter() || reg.index() < locals_count();
}
bool BytecodeArrayBuilder::RegisterIsTemporary(Register reg) const {
return temporary_register_count_ > 0 && first_temporary_register() <= reg &&
reg <= last_temporary_register();
}
Handle<BytecodeArray> BytecodeArrayBuilder::ToBytecodeArray() {
DCHECK_EQ(bytecode_generated_, false);
......@@ -607,6 +628,7 @@ void BytecodeArrayBuilder::EnsureReturn() {
}
}
BytecodeArrayBuilder& BytecodeArrayBuilder::Call(Register callable,
Register receiver,
size_t arg_count) {
......@@ -661,18 +683,74 @@ size_t BytecodeArrayBuilder::GetConstantPoolEntry(Handle<Object> object) {
int BytecodeArrayBuilder::BorrowTemporaryRegister() {
int temporary_reg_index = temporary_register_next_++;
int count = temporary_register_next_ - fixed_register_count();
if (count > temporary_register_count_) {
temporary_register_count_ = count;
if (free_temporaries_.empty()) {
temporary_register_count_ += 1;
return last_temporary_register().index();
} else {
auto pos = free_temporaries_.begin();
int retval = *pos;
free_temporaries_.erase(pos);
return retval;
}
return temporary_reg_index;
}
void BytecodeArrayBuilder::BorrowConsecutiveTemporaryRegister(int reg_index) {
DCHECK(free_temporaries_.find(reg_index) != free_temporaries_.end());
free_temporaries_.erase(reg_index);
}
void BytecodeArrayBuilder::ReturnTemporaryRegister(int reg_index) {
DCHECK_EQ(reg_index, temporary_register_next_ - 1);
temporary_register_next_ = reg_index;
DCHECK(free_temporaries_.find(reg_index) == free_temporaries_.end());
free_temporaries_.insert(reg_index);
}
int BytecodeArrayBuilder::PrepareForConsecutiveTemporaryRegisters(
size_t count) {
if (count == 0) {
return -1;
}
// 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++) {
if (*run_end != *start + static_cast<int>(run_length)) {
start = run_end;
run_length = 0;
}
if (++run_length == count) {
return *start;
}
}
// Continue run if possible across existing last temporary.
if (temporary_register_count_ > 0 &&
(start == free_temporaries_.end() ||
*start + static_cast<int>(run_length) !=
last_temporary_register().index() + 1)) {
run_length = 0;
}
// Ensure enough registers for run.
while (run_length++ < count) {
temporary_register_count_++;
free_temporaries_.insert(last_temporary_register().index());
}
return last_temporary_register().index() - static_cast<int>(count) + 1;
}
bool BytecodeArrayBuilder::TemporaryRegisterIsLive(Register reg) const {
if (temporary_register_count_ > 0) {
DCHECK(reg.index() >= first_temporary_register().index() &&
reg.index() <= last_temporary_register().index());
return free_temporaries_.find(reg.index()) == free_temporaries_.end();
} else {
return false;
}
}
......@@ -693,10 +771,12 @@ bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index,
if (reg.is_function_context() || reg.is_function_closure()) {
return true;
} else if (reg.is_parameter()) {
int parameter_index = reg.ToParameterIndex(parameter_count());
return parameter_index >= 0 && parameter_index < parameter_count();
int parameter_index = reg.ToParameterIndex(parameter_count_);
return parameter_index >= 0 && parameter_index < parameter_count_;
} else if (reg.index() < fixed_register_count()) {
return true;
} else {
return (reg.index() >= 0 && reg.index() < temporary_register_next_);
return TemporaryRegisterIsLive(reg);
}
}
}
......@@ -880,20 +960,43 @@ bool BytecodeArrayBuilder::FitsInIdx16Operand(int value) {
TemporaryRegisterScope::TemporaryRegisterScope(BytecodeArrayBuilder* builder)
: builder_(builder), count_(0), last_register_index_(-1) {}
: builder_(builder),
allocated_(builder->zone()),
next_consecutive_register_(-1),
next_consecutive_count_(-1) {}
TemporaryRegisterScope::~TemporaryRegisterScope() {
while (count_-- != 0) {
builder_->ReturnTemporaryRegister(last_register_index_--);
for (auto i = allocated_.rbegin(); i != allocated_.rend(); i++) {
builder_->ReturnTemporaryRegister(*i);
}
allocated_.clear();
}
Register TemporaryRegisterScope::NewRegister() {
count_++;
last_register_index_ = builder_->BorrowTemporaryRegister();
return Register(last_register_index_);
int allocated = builder_->BorrowTemporaryRegister();
allocated_.push_back(allocated);
return Register(allocated);
}
void TemporaryRegisterScope::PrepareForConsecutiveAllocations(size_t count) {
if (static_cast<int>(count) > next_consecutive_count_) {
next_consecutive_register_ =
builder_->PrepareForConsecutiveTemporaryRegisters(count);
next_consecutive_count_ = static_cast<int>(count);
}
}
Register TemporaryRegisterScope::NextConsecutiveRegister() {
DCHECK_GE(next_consecutive_register_, 0);
DCHECK_GT(next_consecutive_count_, 0);
builder_->BorrowConsecutiveTemporaryRegister(next_consecutive_register_);
allocated_.push_back(next_consecutive_register_);
next_consecutive_count_--;
return Register(next_consecutive_register_++);
}
} // namespace interpreter
......
......@@ -28,14 +28,14 @@ class BytecodeArrayBuilder {
BytecodeArrayBuilder(Isolate* isolate, Zone* zone);
Handle<BytecodeArray> ToBytecodeArray();
// Set number of parameters expected by function.
// Set the number of parameters expected by function.
void set_parameter_count(int number_of_params);
int parameter_count() const {
DCHECK_GE(parameter_count_, 0);
return parameter_count_;
}
// Set number of locals required for bytecode array.
// Set the number of locals required for bytecode array.
void set_locals_count(int number_of_locals);
int locals_count() const {
DCHECK_GE(local_register_count_, 0);
......@@ -57,7 +57,14 @@ class BytecodeArrayBuilder {
Register Parameter(int parameter_index) const;
// Constant loads to the accumulator.
// Return true if the register |reg| represents a parameter or a
// local.
bool RegisterIsParameterOrLocal(Register reg) const;
// Return true if the register |reg| represents a temporary register.
bool RegisterIsTemporary(Register reg) const;
// Constant loads to accumulator.
BytecodeArrayBuilder& LoadLiteral(v8::internal::Smi* value);
BytecodeArrayBuilder& LoadLiteral(Handle<Object> object);
BytecodeArrayBuilder& LoadUndefined();
......@@ -66,7 +73,7 @@ class BytecodeArrayBuilder {
BytecodeArrayBuilder& LoadTrue();
BytecodeArrayBuilder& LoadFalse();
// Global loads to accumulator and stores from the accumulator.
// Global loads to the accumulator and stores from the accumulator.
BytecodeArrayBuilder& LoadGlobal(int slot_index);
BytecodeArrayBuilder& StoreGlobal(int slot_index, LanguageMode language_mode);
......@@ -140,7 +147,7 @@ class BytecodeArrayBuilder {
BytecodeArrayBuilder& CompareOperation(Token::Value op, Register reg,
Strength strength);
// Casts
// Casts.
BytecodeArrayBuilder& CastAccumulatorToBoolean();
BytecodeArrayBuilder& CastAccumulatorToName();
......@@ -207,9 +214,14 @@ class BytecodeArrayBuilder {
size_t GetConstantPoolEntry(Handle<Object> object);
// Scope helpers used by TemporaryRegisterScope
int BorrowTemporaryRegister();
void ReturnTemporaryRegister(int reg_index);
int PrepareForConsecutiveTemporaryRegisters(size_t count);
void BorrowConsecutiveTemporaryRegister(int reg_index);
bool TemporaryRegisterIsLive(Register reg) const;
Register first_temporary_register() const;
Register last_temporary_register() const;
Isolate* isolate_;
Zone* zone_;
......@@ -226,10 +238,11 @@ class BytecodeArrayBuilder {
int local_register_count_;
int context_register_count_;
int temporary_register_count_;
int temporary_register_next_;
ZoneSet<int> free_temporaries_;
friend class TemporaryRegisterScope;
DISALLOW_IMPLICIT_CONSTRUCTORS(BytecodeArrayBuilder);
DISALLOW_COPY_AND_ASSIGN(BytecodeArrayBuilder);
};
......@@ -273,19 +286,26 @@ class BytecodeLabel final {
// A stack-allocated class than allows the instantiator to allocate
// temporary registers that are cleaned up when scope is closed.
// TODO(oth): Deprecate TemporaryRegisterScope use. Code should be
// using result scopes as far as possible.
class TemporaryRegisterScope {
public:
explicit TemporaryRegisterScope(BytecodeArrayBuilder* builder);
~TemporaryRegisterScope();
Register NewRegister();
void PrepareForConsecutiveAllocations(size_t count);
Register NextConsecutiveRegister();
private:
void* operator new(size_t size);
void operator delete(void* p);
BytecodeArrayBuilder* builder_;
int count_;
int last_register_index_;
const TemporaryRegisterScope* outer_;
ZoneVector<int> allocated_;
int next_consecutive_register_;
int next_consecutive_count_;
DISALLOW_COPY_AND_ASSIGN(TemporaryRegisterScope);
};
......
......@@ -4,8 +4,6 @@
#include "src/interpreter/bytecode-generator.h"
#include <stack>
#include "src/compiler.h"
#include "src/interpreter/control-flow-builders.h"
#include "src/objects.h"
......@@ -146,6 +144,123 @@ void BytecodeGenerator::ControlScope::PerformCommand(Command command,
}
// Scoped base class for determining where the result of an expression
// is stored.
class BytecodeGenerator::ExpressionResultScope {
public:
ExpressionResultScope(BytecodeGenerator* generator, Expression::Context kind)
: generator_(generator),
kind_(kind),
outer_(generator->execution_result()),
allocator_(builder()),
result_identified_(false) {
generator_->set_execution_result(this);
}
virtual ~ExpressionResultScope() {
generator_->set_execution_result(outer_);
DCHECK(result_identified());
}
bool IsEffect() const { return kind_ == Expression::kEffect; }
bool IsValue() const { return kind_ == Expression::kValue; }
virtual void SetResultInAccumulator() = 0;
virtual void SetResultInRegister(Register reg) = 0;
BytecodeGenerator* generator() const { return generator_; }
BytecodeArrayBuilder* builder() const { return generator()->builder(); }
ExpressionResultScope* outer() const { return outer_; }
Register NewRegister() { return allocator_.NewRegister(); }
void PrepareForConsecutiveAllocations(size_t count) {
allocator_.PrepareForConsecutiveAllocations(count);
}
Register NextConsecutiveRegister() {
return allocator_.NextConsecutiveRegister();
}
protected:
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_;
TemporaryRegisterScope allocator_;
bool result_identified_;
DISALLOW_COPY_AND_ASSIGN(ExpressionResultScope);
};
// Scoped class used when the result of the current expression is not
// expected to produce a result.
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) {}
};
// 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 {
public:
explicit AccumulatorResultScope(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_ = outer()->NewRegister();
builder()->StoreAccumulatorInRegister(result_register_);
set_result_identified();
}
virtual void SetResultInRegister(Register reg) {
DCHECK(builder()->RegisterIsParameterOrLocal(reg) ||
builder()->RegisterIsTemporary(reg));
result_register_ = reg;
set_result_identified();
}
Register ResultRegister() const { return result_register_; }
private:
Register result_register_;
};
BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone)
: isolate_(isolate),
zone_(zone),
......@@ -154,7 +269,10 @@ BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone)
scope_(nullptr),
globals_(0, zone),
execution_control_(nullptr),
execution_context_(nullptr) {
execution_context_(nullptr),
execution_result_(nullptr),
binary_expression_depth_(0),
binary_expression_hazard_set_(zone) {
InitializeAstVisitor(isolate);
}
......@@ -324,12 +442,11 @@ void BytecodeGenerator::VisitDeclarations(
void BytecodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
Visit(stmt->expression());
VisitForEffect(stmt->expression());
}
void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
// TODO(oth): For control-flow it could be useful to signal empty paths here.
}
......@@ -340,7 +457,7 @@ void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) {
BytecodeLabel else_label, end_label;
Visit(stmt->condition());
VisitForAccumulatorValue(stmt->condition());
builder()->CastAccumulatorToBoolean();
builder()->JumpIfFalse(&else_label);
Visit(stmt->then_statement());
......@@ -372,7 +489,7 @@ void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
void BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
Visit(stmt->expression());
VisitForAccumulatorValue(stmt->expression());
builder()->Return();
}
......@@ -398,7 +515,7 @@ void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
builder()->Bind(&body_label);
Visit(stmt->body());
builder()->Bind(&condition_label);
Visit(stmt->cond());
VisitForAccumulatorValue(stmt->cond());
builder()->JumpIfTrue(&body_label);
builder()->Bind(&done_label);
......@@ -416,7 +533,7 @@ void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
builder()->Bind(&body_label);
Visit(stmt->body());
builder()->Bind(&condition_label);
Visit(stmt->cond());
VisitForAccumulatorValue(stmt->cond());
builder()->JumpIfTrue(&body_label);
builder()->Bind(&done_label);
......@@ -445,7 +562,7 @@ void BytecodeGenerator::VisitForStatement(ForStatement* stmt) {
}
if (stmt->cond()) {
builder()->Bind(&condition_label);
Visit(stmt->cond());
VisitForAccumulatorValue(stmt->cond());
builder()->JumpIfTrue(&body_label);
} else {
builder()->Jump(&body_label);
......@@ -500,6 +617,7 @@ void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
builder()
->LoadLiteral(shared_info)
.CreateClosure(expr->pretenure() ? TENURED : NOT_TENURED);
execution_result()->SetResultInAccumulator();
}
......@@ -523,21 +641,24 @@ void BytecodeGenerator::VisitConditional(Conditional* expr) { UNIMPLEMENTED(); }
void BytecodeGenerator::VisitLiteral(Literal* expr) {
Handle<Object> value = expr->value();
if (value->IsSmi()) {
builder()->LoadLiteral(Smi::cast(*value));
} else if (value->IsUndefined()) {
builder()->LoadUndefined();
} else if (value->IsTrue()) {
builder()->LoadTrue();
} else if (value->IsFalse()) {
builder()->LoadFalse();
} else if (value->IsNull()) {
builder()->LoadNull();
} else if (value->IsTheHole()) {
builder()->LoadTheHole();
} else {
builder()->LoadLiteral(value);
if (!execution_result()->IsEffect()) {
Handle<Object> value = expr->value();
if (value->IsSmi()) {
builder()->LoadLiteral(Smi::cast(*value));
} else if (value->IsUndefined()) {
builder()->LoadUndefined();
} else if (value->IsTrue()) {
builder()->LoadTrue();
} else if (value->IsFalse()) {
builder()->LoadFalse();
} else if (value->IsNull()) {
builder()->LoadNull();
} else if (value->IsTheHole()) {
builder()->LoadTheHole();
} else {
builder()->LoadLiteral(value);
}
execution_result()->SetResultInAccumulator();
}
}
......@@ -551,6 +672,7 @@ void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
.StoreAccumulatorInRegister(flags)
.LoadLiteral(expr->pattern())
.CreateRegExpLiteral(expr->literal_index(), flags);
execution_result()->SetResultInAccumulator();
}
......@@ -595,21 +717,28 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
builder()
->LoadLiteral(literal_key->AsPropertyName())
.StoreAccumulatorInRegister(name);
Visit(property->value());
VisitForAccumulatorValue(property->value());
builder()->StoreNamedProperty(literal, name,
feedback_index(property->GetSlot(0)),
language_mode());
} else {
Visit(property->value());
VisitForEffect(property->value());
}
} else {
Register key = inner_temporary_register_scope.NewRegister();
Register value = inner_temporary_register_scope.NewRegister();
Register language = inner_temporary_register_scope.NewRegister();
inner_temporary_register_scope.PrepareForConsecutiveAllocations(3);
Register key =
inner_temporary_register_scope.NextConsecutiveRegister();
Register value =
inner_temporary_register_scope.NextConsecutiveRegister();
Register language =
inner_temporary_register_scope.NextConsecutiveRegister();
// TODO(oth): This is problematic - can't assume contiguous here.
// literal is allocated in temporary_register_scope, whereas
// key, value, language are in another.
DCHECK(Register::AreContiguous(literal, key, value, language));
Visit(property->key());
VisitForAccumulatorValue(property->key());
builder()->StoreAccumulatorInRegister(key);
Visit(property->value());
VisitForAccumulatorValue(property->value());
builder()->StoreAccumulatorInRegister(value);
if (property->emit_store()) {
builder()
......@@ -622,10 +751,12 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
break;
}
case ObjectLiteral::Property::PROTOTYPE: {
inner_temporary_register_scope.PrepareForConsecutiveAllocations(1);
DCHECK(property->emit_store());
Register value = inner_temporary_register_scope.NewRegister();
Register value =
inner_temporary_register_scope.NextConsecutiveRegister();
DCHECK(Register::AreContiguous(literal, value));
Visit(property->value());
VisitForAccumulatorValue(property->value());
builder()->StoreAccumulatorInRegister(value).CallRuntime(
Runtime::kInternalSetPrototype, literal, 2);
break;
......@@ -648,12 +779,13 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
for (AccessorTable::Iterator it = accessor_table.begin();
it != accessor_table.end(); ++it) {
TemporaryRegisterScope inner_temporary_register_scope(builder());
Register name = inner_temporary_register_scope.NewRegister();
Register getter = inner_temporary_register_scope.NewRegister();
Register setter = inner_temporary_register_scope.NewRegister();
Register attr = inner_temporary_register_scope.NewRegister();
inner_temporary_register_scope.PrepareForConsecutiveAllocations(4);
Register name = inner_temporary_register_scope.NextConsecutiveRegister();
Register getter = inner_temporary_register_scope.NextConsecutiveRegister();
Register setter = inner_temporary_register_scope.NextConsecutiveRegister();
Register attr = inner_temporary_register_scope.NextConsecutiveRegister();
DCHECK(Register::AreContiguous(literal, name, getter, setter, attr));
Visit(it->first);
VisitForAccumulatorValue(it->first);
builder()->StoreAccumulatorInRegister(name);
VisitObjectLiteralAccessor(literal, it->second->getter, getter);
VisitObjectLiteralAccessor(literal, it->second->setter, setter);
......@@ -676,7 +808,8 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
ObjectLiteral::Property* property = expr->properties()->at(property_index);
if (literal_in_accumulator) {
literal = temporary_register_scope.NewRegister();
temporary_register_scope.PrepareForConsecutiveAllocations(4);
literal = temporary_register_scope.NextConsecutiveRegister();
builder()->StoreAccumulatorInRegister(literal);
literal_in_accumulator = false;
}
......@@ -686,21 +819,22 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
TemporaryRegisterScope inner_temporary_register_scope(builder());
Register value = inner_temporary_register_scope.NewRegister();
DCHECK(Register::AreContiguous(literal, value));
Visit(property->value());
VisitForAccumulatorValue(property->value());
builder()->StoreAccumulatorInRegister(value).CallRuntime(
Runtime::kInternalSetPrototype, literal, 2);
continue;
}
TemporaryRegisterScope inner_temporary_register_scope(builder());
Register key = inner_temporary_register_scope.NewRegister();
Register value = inner_temporary_register_scope.NewRegister();
Register attr = inner_temporary_register_scope.NewRegister();
inner_temporary_register_scope.PrepareForConsecutiveAllocations(3);
Register key = inner_temporary_register_scope.NextConsecutiveRegister();
Register value = inner_temporary_register_scope.NextConsecutiveRegister();
Register attr = inner_temporary_register_scope.NextConsecutiveRegister();
DCHECK(Register::AreContiguous(literal, key, value, attr));
Visit(property->key());
VisitForAccumulatorValue(property->key());
builder()->CastAccumulatorToName().StoreAccumulatorInRegister(key);
Visit(property->value());
VisitForAccumulatorValue(property->value());
builder()->StoreAccumulatorInRegister(value);
VisitSetHomeObject(value, literal, property);
builder()->LoadLiteral(Smi::FromInt(NONE)).StoreAccumulatorInRegister(attr);
......@@ -734,6 +868,7 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
// Restore literal array into accumulator.
builder()->LoadAccumulatorWithRegister(literal);
}
execution_result()->SetResultInAccumulator();
}
......@@ -765,11 +900,11 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
literal_in_accumulator = false;
}
FeedbackVectorSlot slot = expr->LiteralFeedbackSlot();
builder()
->LoadLiteral(Smi::FromInt(array_index))
.StoreAccumulatorInRegister(index);
Visit(subexpr);
FeedbackVectorSlot slot = expr->LiteralFeedbackSlot();
VisitForAccumulatorValue(subexpr);
builder()->StoreKeyedProperty(literal, index, feedback_index(slot),
language_mode());
}
......@@ -778,6 +913,7 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
// Restore literal array into accumulator.
builder()->LoadAccumulatorWithRegister(literal);
}
execution_result()->SetResultInAccumulator();
}
......@@ -790,17 +926,15 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable,
FeedbackVectorSlot slot) {
switch (variable->location()) {
case VariableLocation::LOCAL: {
Register source(variable->index());
builder()->LoadAccumulatorWithRegister(source);
// TODO(rmcilroy): Perform check for uninitialized legacy const, const and
// let variables.
Register source(Register(variable->index()));
execution_result()->SetResultInRegister(source);
break;
}
case VariableLocation::PARAMETER: {
// The parameter indices are shifted by 1 (receiver is variable
// index -1 but is parameter index 0 in BytecodeArrayBuilder).
Register source(builder()->Parameter(variable->index() + 1));
builder()->LoadAccumulatorWithRegister(source);
Register source = builder()->Parameter(variable->index() + 1);
execution_result()->SetResultInRegister(source);
break;
}
case VariableLocation::GLOBAL: {
......@@ -810,6 +944,7 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable,
// runtime.
DCHECK(variable->IsStaticGlobalObjectProperty());
builder()->LoadGlobal(variable->index());
execution_result()->SetResultInAccumulator();
break;
}
case VariableLocation::UNALLOCATED: {
......@@ -820,12 +955,14 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable,
builder()->StoreAccumulatorInRegister(obj);
builder()->LoadLiteral(variable->name());
builder()->LoadNamedProperty(obj, feedback_index(slot), language_mode());
execution_result()->SetResultInAccumulator();
break;
}
case VariableLocation::CONTEXT: {
ContextScope* context = execution_context()->Previous(variable->scope());
if (context) {
builder()->LoadContextSlot(context->reg(), variable->index());
execution_result()->SetResultInAccumulator();
} else {
UNIMPLEMENTED();
}
......@@ -846,6 +983,7 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable,
// TODO(rmcilroy): support const mode initialization.
Register destination(variable->index());
builder()->StoreAccumulatorInRegister(destination);
RecordStoreToRegister(destination);
break;
}
case VariableLocation::PARAMETER: {
......@@ -853,6 +991,7 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable,
// index -1 but is parameter index 0 in BytecodeArrayBuilder).
Register destination(builder()->Parameter(variable->index() + 1));
builder()->StoreAccumulatorInRegister(destination);
RecordStoreToRegister(destination);
break;
}
case VariableLocation::GLOBAL: {
......@@ -865,10 +1004,10 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable,
break;
}
case VariableLocation::UNALLOCATED: {
TemporaryRegisterScope temporary_register_scope(builder());
Register value = temporary_register_scope.NewRegister();
Register obj = temporary_register_scope.NewRegister();
Register name = temporary_register_scope.NewRegister();
Register value = execution_result()->NewRegister();
Register obj = execution_result()->NewRegister();
Register name = execution_result()->NewRegister();
// TODO(rmcilroy): Investigate whether we can avoid having to stash the
// value in a register.
builder()->StoreAccumulatorInRegister(value);
......@@ -900,7 +1039,6 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable,
void BytecodeGenerator::VisitAssignment(Assignment* expr) {
DCHECK(expr->target()->IsValidReferenceExpression());
TemporaryRegisterScope temporary_register_scope(builder());
Register object, key;
// Left-hand side can only be a property, a global or a variable slot.
......@@ -912,22 +1050,18 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) {
case VARIABLE:
// Nothing to do to evaluate variable assignment LHS.
break;
case NAMED_PROPERTY:
object = temporary_register_scope.NewRegister();
key = temporary_register_scope.NewRegister();
Visit(property->obj());
builder()->StoreAccumulatorInRegister(object);
case NAMED_PROPERTY: {
object = VisitForRegisterValue(property->obj());
key = execution_result()->NewRegister();
builder()->LoadLiteral(property->key()->AsLiteral()->AsPropertyName());
builder()->StoreAccumulatorInRegister(key);
break;
case KEYED_PROPERTY:
object = temporary_register_scope.NewRegister();
key = temporary_register_scope.NewRegister();
Visit(property->obj());
builder()->StoreAccumulatorInRegister(object);
Visit(property->key());
builder()->StoreAccumulatorInRegister(key);
}
case KEYED_PROPERTY: {
object = VisitForRegisterValue(property->obj());
key = VisitForRegisterValue(property->key());
break;
}
case NAMED_SUPER_PROPERTY:
case KEYED_SUPER_PROPERTY:
UNIMPLEMENTED();
......@@ -938,13 +1072,15 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) {
if (expr->is_compound()) {
UNIMPLEMENTED();
} else {
Visit(expr->value());
VisitForAccumulatorValue(expr->value());
}
// Store the value.
FeedbackVectorSlot slot = expr->AssignmentSlot();
switch (assign_type) {
case VARIABLE: {
// TODO(oth): The VisitVariableAssignment() call is hard to reason about.
// Is the value in the accumulator safe? Yes, but scary.
Variable* variable = expr->target()->AsVariableProxy()->var();
VisitVariableAssignment(variable, slot);
break;
......@@ -961,6 +1097,7 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) {
case KEYED_SUPER_PROPERTY:
UNIMPLEMENTED();
}
execution_result()->SetResultInAccumulator();
}
......@@ -968,8 +1105,7 @@ void BytecodeGenerator::VisitYield(Yield* expr) { UNIMPLEMENTED(); }
void BytecodeGenerator::VisitThrow(Throw* expr) {
TemporaryRegisterScope temporary_register_scope(builder());
Visit(expr->exception());
VisitForAccumulatorValue(expr->exception());
builder()->Throw();
}
......@@ -986,7 +1122,7 @@ void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) {
break;
}
case KEYED_PROPERTY: {
Visit(expr->key());
VisitForAccumulatorValue(expr->key());
builder()->LoadKeyedProperty(obj, feedback_index(slot), language_mode());
break;
}
......@@ -994,33 +1130,41 @@ void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) {
case KEYED_SUPER_PROPERTY:
UNIMPLEMENTED();
}
execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::VisitProperty(Property* expr) {
TemporaryRegisterScope temporary_register_scope(builder());
Register obj = temporary_register_scope.NewRegister();
Visit(expr->obj());
builder()->StoreAccumulatorInRegister(obj);
Register obj = VisitForRegisterValue(expr->obj());
VisitPropertyLoad(obj, expr);
}
Register BytecodeGenerator::VisitArguments(
ZoneList<Expression*>* args, TemporaryRegisterScope* register_scope) {
// Visit arguments and place in a contiguous block of temporary registers.
// Return the first temporary register corresponding to the first argument.
DCHECK_GT(args->length(), 0);
Register first_arg = register_scope->NewRegister();
Visit(args->at(0));
Register BytecodeGenerator::VisitArguments(ZoneList<Expression*>* args) {
// 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.
execution_result()->PrepareForConsecutiveAllocations(args->length());
// Visit for first argument that goes into returned register
Register first_arg = execution_result()->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_scope->NewRegister();
Visit(args->at(i));
Register ith_arg = execution_result()->NextConsecutiveRegister();
VisitForAccumulatorValue(args->at(i));
builder()->StoreAccumulatorInRegister(ith_arg);
DCHECK(ith_arg.index() - i == first_arg.index());
}
return first_arg;
}
......@@ -1031,9 +1175,14 @@ void BytecodeGenerator::VisitCall(Call* expr) {
// Prepare the callee and the receiver to the function call. This depends on
// the semantics of the underlying call type.
TemporaryRegisterScope temporary_register_scope(builder());
Register callee = temporary_register_scope.NewRegister();
Register receiver = temporary_register_scope.NewRegister();
Register callee = execution_result()->NewRegister();
// The receiver and arguments need to be allocated consecutively for
// Call(). Future optimizations could avoid this there are no
// arguments or the receiver and arguments are already consecutive.
ZoneList<Expression*>* args = expr->arguments();
execution_result()->PrepareForConsecutiveAllocations(args->length() + 1);
Register receiver = execution_result()->NextConsecutiveRegister();
switch (call_type) {
case Call::PROPERTY_CALL: {
......@@ -1041,8 +1190,11 @@ void BytecodeGenerator::VisitCall(Call* expr) {
if (property->IsSuperAccess()) {
UNIMPLEMENTED();
}
Visit(property->obj());
VisitForAccumulatorValue(property->obj());
builder()->StoreAccumulatorInRegister(receiver);
// Need a result scope here to keep our consecutive
// temporaries.
AccumulatorResultScope accumulator_execution_result(this);
// Perform a property load of the callee.
VisitPropertyLoad(receiver, property);
builder()->StoreAccumulatorInRegister(callee);
......@@ -1053,13 +1205,16 @@ void BytecodeGenerator::VisitCall(Call* expr) {
builder()->LoadUndefined().StoreAccumulatorInRegister(receiver);
// Load callee as a global variable.
VariableProxy* proxy = callee_expr->AsVariableProxy();
// Result scope for VisitVariableLoad to avoid using our temporaries
// and double setting the result in our result_scope() and.
AccumulatorResultScope accumulator_execution_result(this);
VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot());
builder()->StoreAccumulatorInRegister(callee);
break;
}
case Call::OTHER_CALL: {
builder()->LoadUndefined().StoreAccumulatorInRegister(receiver);
Visit(callee_expr);
VisitForAccumulatorValue(callee_expr);
builder()->StoreAccumulatorInRegister(callee);
break;
}
......@@ -1071,26 +1226,26 @@ void BytecodeGenerator::VisitCall(Call* expr) {
// Evaluate all arguments to the function call and store in sequential
// registers.
ZoneList<Expression*>* args = expr->arguments();
if (args->length() > 0) {
Register first_arg = VisitArguments(args, &temporary_register_scope);
CHECK_EQ(first_arg.index(), receiver.index() + 1);
Register arg = VisitArguments(args);
CHECK(arg.index() == receiver.index() + 1);
}
// TODO(rmcilroy): Deal with possible direct eval here?
// TODO(rmcilroy): Use CallIC to allow call type feedback.
builder()->Call(callee, receiver, args->length());
execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::VisitCallNew(CallNew* expr) {
TemporaryRegisterScope temporary_register_scope(builder());
Register constructor = temporary_register_scope.NewRegister();
Visit(expr->expression());
Register constructor = execution_result()->NewRegister();
VisitForAccumulatorValue(expr->expression());
builder()->StoreAccumulatorInRegister(constructor);
ZoneList<Expression*>* args = expr->arguments();
if (args->length() > 0) {
Register first_arg = VisitArguments(args, &temporary_register_scope);
Register first_arg = VisitArguments(args);
builder()->New(constructor, first_arg, args->length());
} else {
// The second argument here will be ignored as there are zero
......@@ -1098,6 +1253,7 @@ void BytecodeGenerator::VisitCallNew(CallNew* expr) {
// allocating a temporary just to fill the operands.
builder()->New(constructor, constructor, 0);
}
execution_result()->SetResultInAccumulator();
}
......@@ -1106,41 +1262,44 @@ void BytecodeGenerator::VisitCallRuntime(CallRuntime* expr) {
UNIMPLEMENTED();
}
// Evaluate all arguments to the runtime call.
TemporaryRegisterScope temporary_register_scope(&builder_);
// TODO(rmcilroy): support multiple return values.
DCHECK_LE(expr->function()->result_size, 1);
Runtime::FunctionId function_id = expr->function()->function_id;
// Evaluate all arguments to the runtime call.
ZoneList<Expression*>* args = expr->arguments();
Register first_arg;
if (args->length() > 0) {
first_arg = VisitArguments(args, &temporary_register_scope);
first_arg = VisitArguments(args);
} else {
// Allocation here is just to fullfil the requirement that there
// is a register operand for the start of the arguments though
// there are zero when this is generated.
first_arg = temporary_register_scope.NewRegister();
first_arg = execution_result()->NewRegister();
}
builder()->CallRuntime(function_id, first_arg, args->length());
execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::VisitVoid(UnaryOperation* expr) {
Visit(expr->expression());
VisitForEffect(expr->expression());
builder()->LoadUndefined();
execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::VisitTypeOf(UnaryOperation* expr) {
Visit(expr->expression());
VisitForAccumulatorValue(expr->expression());
builder()->TypeOf();
execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::VisitNot(UnaryOperation* expr) {
Visit(expr->expression());
VisitForAccumulatorValue(expr->expression());
builder()->LogicalNot();
execution_result()->SetResultInAccumulator();
}
......@@ -1188,17 +1347,38 @@ void BytecodeGenerator::VisitBinaryOperation(BinaryOperation* binop) {
void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) {
Token::Value op = expr->op();
Expression* left = expr->left();
Expression* right = expr->right();
TemporaryRegisterScope temporary_register_scope(builder());
Register temporary = temporary_register_scope.NewRegister();
Visit(left);
builder()->StoreAccumulatorInRegister(temporary);
Visit(right);
builder()->CompareOperation(op, temporary, language_mode_strength());
// TODO(oth): Remove PrepareForBinaryExpression/CompleteBinaryExpression
// once we have StatementScope that tracks hazardous loads/stores.
PrepareForBinaryExpression();
Register lhs = VisitForRegisterValue(expr->left());
if (builder()->RegisterIsParameterOrLocal(lhs)) {
// Result was returned in an existing local or parameter. See if
// it needs to be moved to a temporary.
// TODO(oth) LoadFromAliasedRegister call into VisitVariableLoad().
lhs = LoadFromAliasedRegister(lhs);
}
VisitForAccumulatorValue(expr->right());
builder()->CompareOperation(expr->op(), lhs, language_mode_strength());
CompleteBinaryExpression();
execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) {
// TODO(oth): Remove PrepareForBinaryExpression/CompleteBinaryExpression
// once we have StatementScope that tracks hazardous loads/stores.
PrepareForBinaryExpression();
Register lhs = VisitForRegisterValue(expr->left());
if (builder()->RegisterIsParameterOrLocal(lhs)) {
// Result was returned in an existing local or parameter. See if
// it needs to be moved to a temporary.
// TODO(oth) LoadFromAliasedRegister call into VisitVariableLoad().
lhs = LoadFromAliasedRegister(lhs);
}
VisitForAccumulatorValue(expr->right());
builder()->BinaryOperation(expr->op(), lhs, language_mode_strength());
CompleteBinaryExpression();
execution_result()->SetResultInAccumulator();
}
......@@ -1290,27 +1470,9 @@ void BytecodeGenerator::VisitNewLocalBlockContext(Scope* scope) {
}
void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* binop) {
Token::Value op = binop->op();
Expression* left = binop->left();
Expression* right = binop->right();
TemporaryRegisterScope temporary_register_scope(builder());
Register temporary = temporary_register_scope.NewRegister();
Visit(left);
builder()->StoreAccumulatorInRegister(temporary);
Visit(right);
builder()->BinaryOperation(op, temporary, language_mode_strength());
}
void BytecodeGenerator::VisitCommaExpression(BinaryOperation* binop) {
Expression* left = binop->left();
Expression* right = binop->right();
Visit(left);
Visit(right);
VisitForEffect(binop->left());
Visit(binop->right());
}
......@@ -1321,15 +1483,15 @@ void BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) {
// Short-circuit evaluation- If it is known that left is always true,
// no need to visit right
if (left->ToBooleanIsTrue()) {
Visit(left);
VisitForAccumulatorValue(left);
} else {
BytecodeLabel end_label;
Visit(left);
VisitForAccumulatorValue(left);
builder()->JumpIfToBooleanTrue(&end_label);
Visit(right);
VisitForAccumulatorValue(right);
builder()->Bind(&end_label);
}
execution_result()->SetResultInAccumulator();
}
......@@ -1340,15 +1502,15 @@ void BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) {
// Short-circuit evaluation- If it is known that left is always false,
// no need to visit right
if (left->ToBooleanIsFalse()) {
Visit(left);
VisitForAccumulatorValue(left);
} else {
BytecodeLabel end_label;
Visit(left);
VisitForAccumulatorValue(left);
builder()->JumpIfToBooleanFalse(&end_label);
Visit(right);
VisitForAccumulatorValue(right);
builder()->Bind(&end_label);
}
execution_result()->SetResultInAccumulator();
}
......@@ -1358,7 +1520,7 @@ void BytecodeGenerator::VisitObjectLiteralAccessor(
if (property == nullptr) {
builder()->LoadNull().StoreAccumulatorInRegister(value_out);
} else {
Visit(property->value());
VisitForAccumulatorValue(property->value());
builder()->StoreAccumulatorInRegister(value_out);
VisitSetHomeObject(value_out, home_object, property);
}
......@@ -1402,6 +1564,65 @@ void BytecodeGenerator::VisitFunctionClosureForContext() {
}
void BytecodeGenerator::PrepareForBinaryExpression() {
if (binary_expression_depth_++ == 0) {
binary_expression_hazard_set_.clear();
}
}
// Visits the expression |expr| and places the result in the accumulator.
void BytecodeGenerator::VisitForAccumulatorValue(Expression* expr) {
AccumulatorResultScope accumulator_scope(this);
Visit(expr);
}
// Visits the expression |expr| and discards the result.
void BytecodeGenerator::VisitForEffect(Expression* expr) {
EffectResultScope effect_scope(this);
Visit(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();
}
Register BytecodeGenerator::LoadFromAliasedRegister(Register reg) {
// TODO(oth): Follow on CL to load from re-map here.
DCHECK(builder()->RegisterIsParameterOrLocal(reg));
if (binary_expression_depth_ > 0) {
binary_expression_hazard_set_.insert(reg.index());
}
return reg;
}
void BytecodeGenerator::RecordStoreToRegister(Register reg) {
DCHECK(builder()->RegisterIsParameterOrLocal(reg));
if (binary_expression_depth_ > 0) {
// TODO(oth): a store to a register that's be loaded needs to be
// remapped.
DCHECK(binary_expression_hazard_set_.find(reg.index()) ==
binary_expression_hazard_set_.end());
}
}
void BytecodeGenerator::CompleteBinaryExpression() {
DCHECK(binary_expression_depth_ > 0);
binary_expression_depth_ -= 1;
// TODO(oth): spill remapped registers into origins.
// TODO(oth): make statement/top-level.
}
Register BytecodeGenerator::NextContextRegister() const {
if (execution_context() == nullptr) {
// Return the incoming function context for the outermost execution context.
......
......@@ -31,14 +31,17 @@ class BytecodeGenerator : public AstVisitor {
class ContextScope;
class ControlScope;
class ControlScopeForIteration;
class ExpressionResultScope;
class EffectResultScope;
class AccumulatorResultScope;
class RegisterResultScope;
void MakeBytecodeBody();
Register NextContextRegister() const;
DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
Register VisitArguments(ZoneList<Expression*>* arguments,
TemporaryRegisterScope* caller_scope);
Register VisitArguments(ZoneList<Expression*>* arguments);
void VisitArithmeticExpression(BinaryOperation* binop);
void VisitCommaExpression(BinaryOperation* binop);
void VisitLogicalOrExpression(BinaryOperation* binop);
......@@ -61,6 +64,20 @@ class BytecodeGenerator : public AstVisitor {
void VisitTypeOf(UnaryOperation* expr);
void VisitNot(UnaryOperation* expr);
// Visitors for obtaining expression result in the accumulator, in a
// register, or just getting the effect.
void VisitForAccumulatorValue(Expression* expression);
MUST_USE_RESULT Register VisitForRegisterValue(Expression* expression);
void VisitForEffect(Expression* node);
// Methods marking the start and end of binary expressions.
void PrepareForBinaryExpression();
void CompleteBinaryExpression();
// Methods for tracking and remapping register.
void RecordStoreToRegister(Register reg);
Register LoadFromAliasedRegister(Register reg);
inline BytecodeArrayBuilder* builder() { return &builder_; }
inline Isolate* isolate() const { return isolate_; }
......@@ -79,6 +96,10 @@ class BytecodeGenerator : public AstVisitor {
inline void set_execution_context(ContextScope* context) {
execution_context_ = context;
}
inline void set_execution_result(ExpressionResultScope* execution_result) {
execution_result_ = execution_result;
}
ExpressionResultScope* execution_result() const { return execution_result_; }
ZoneVector<Handle<Object>>* globals() { return &globals_; }
inline LanguageMode language_mode() const;
......@@ -93,6 +114,10 @@ class BytecodeGenerator : public AstVisitor {
ZoneVector<Handle<Object>> globals_;
ControlScope* execution_control_;
ContextScope* execution_context_;
ExpressionResultScope* execution_result_;
int binary_expression_depth_;
ZoneSet<int> binary_expression_hazard_set_;
};
} // namespace interpreter
......
......@@ -211,8 +211,18 @@ class Register {
Register reg4 = Register(),
Register reg5 = Register());
bool operator==(const Register& o) const { return o.index() == index(); }
bool operator!=(const Register& o) const { return o.index() != index(); }
bool operator==(const Register& other) const {
return index() == other.index();
}
bool operator!=(const Register& other) const {
return index() != other.index();
}
bool operator<(const Register& other) const {
return index() < other.index();
}
bool operator<=(const Register& other) const {
return index() <= other.index();
}
private:
static const int kIllegalIndex = kMaxInt;
......
......@@ -75,6 +75,8 @@ class BytecodeGeneratorHelper {
#define B(x) static_cast<uint8_t>(Bytecode::k##x)
#define U8(x) static_cast<uint8_t>((x) & 0xff)
#define R(x) static_cast<uint8_t>(-(x) & 0xff)
#define A(x, n) R(helper.kLastParamIndex - (n) + 1 + (x))
#define THIS(n) A(0, n)
#define _ static_cast<uint8_t>(0x5a)
#if defined(V8_TARGET_LITTLE_ENDIAN)
#define U16(x) static_cast<uint8_t>((x) & 0xff), \
......@@ -128,7 +130,7 @@ static void CheckConstant(InstanceType expected, Object* actual) {
template <typename T>
static void CheckBytecodeArrayEqual(struct ExpectedSnippet<T> expected,
static void CheckBytecodeArrayEqual(const ExpectedSnippet<T>& expected,
Handle<BytecodeArray> actual,
bool has_unknown = false) {
CHECK_EQ(expected.frame_size, actual->frame_size());
......@@ -240,144 +242,121 @@ TEST(PrimitiveExpressions) {
B(Return)},
0},
{"var x = 0; return x + 3;",
2 * kPointerSize,
kPointerSize,
1,
12,
8,
{B(LdaZero), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(3), //
B(Add), R(1), //
B(Add), R(0), //
B(Return)},
0},
{"var x = 0; return x - 3;",
2 * kPointerSize,
kPointerSize,
1,
12,
8,
{B(LdaZero), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(3), //
B(Sub), R(1), //
B(Sub), R(0), //
B(Return)},
0},
{"var x = 4; return x * 3;",
2 * kPointerSize,
kPointerSize,
1,
13,
9,
{B(LdaSmi8), U8(4), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(3), //
B(Mul), R(1), //
B(Mul), R(0), //
B(Return)},
0},
{"var x = 4; return x / 3;",
2 * kPointerSize,
kPointerSize,
1,
13,
9,
{B(LdaSmi8), U8(4), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(3), //
B(Div), R(1), //
B(Div), R(0), //
B(Return)},
0},
{"var x = 4; return x % 3;",
2 * kPointerSize,
kPointerSize,
1,
13,
9,
{B(LdaSmi8), U8(4), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(3), //
B(Mod), R(1), //
B(Mod), R(0), //
B(Return)},
0},
{"var x = 1; return x | 2;",
2 * kPointerSize,
kPointerSize,
1,
13,
9,
{B(LdaSmi8), U8(1), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(2), //
B(BitwiseOr), R(1), //
B(BitwiseOr), R(0), //
B(Return)},
0},
{"var x = 1; return x ^ 2;",
2 * kPointerSize,
kPointerSize,
1,
13,
9,
{B(LdaSmi8), U8(1), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(2), //
B(BitwiseXor), R(1), //
B(BitwiseXor), R(0), //
B(Return)},
0},
{"var x = 1; return x & 2;",
2 * kPointerSize,
kPointerSize,
1,
13,
9,
{B(LdaSmi8), U8(1), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(2), //
B(BitwiseAnd), R(1), //
B(BitwiseAnd), R(0), //
B(Return)},
0},
{"var x = 10; return x << 3;",
2 * kPointerSize,
kPointerSize,
1,
13,
9,
{B(LdaSmi8), U8(10), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(3), //
B(ShiftLeft), R(1), //
B(ShiftLeft), R(0), //
B(Return)},
0},
{"var x = 10; return x >> 3;",
2 * kPointerSize,
kPointerSize,
1,
13,
9,
{B(LdaSmi8), U8(10), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(3), //
B(ShiftRight), R(1), //
B(ShiftRight), R(0), //
B(Return)},
0},
{"var x = 10; return x >>> 3;",
2 * kPointerSize,
kPointerSize,
1,
13,
9,
{B(LdaSmi8), U8(10), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(3), //
B(ShiftRightLogical), R(1), //
B(ShiftRightLogical), R(0), //
B(Return)},
0},
{"var x = 0; return (x, 3);",
1 * kPointerSize,
kPointerSize,
1,
8,
6,
{B(LdaZero), //
B(Star), R(0), //
B(Ldar), R(0), //
B(LdaSmi8), U8(3), //
B(Return)},
0}};
......@@ -418,8 +397,36 @@ TEST(LogicalExpressions) {
B(LdaSmi8), U8(3), //
B(Return)},
0},
{"var x = 0; return x || (1, 2, 3);",
1 * kPointerSize,
1,
10,
{B(LdaZero), //
B(Star), R(0), //
B(Ldar), R(0), //
B(JumpIfToBooleanTrue), U8(4), //
B(LdaSmi8), U8(3), //
B(Return)},
0},
{"var a = 2, b = 3, c = 4; return a || (a, b, a, b, c = 5, 3);",
3 * kPointerSize,
1,
23,
{B(LdaSmi8), U8(2), //
B(Star), R(0), //
B(LdaSmi8), U8(3), //
B(Star), R(1), //
B(LdaSmi8), U8(4), //
B(Star), R(2), //
B(Ldar), R(0), //
B(JumpIfToBooleanTrue), U8(8), //
B(LdaSmi8), U8(5), //
B(Star), R(2), //
B(LdaSmi8), U8(3), //
B(Return)},
0},
{"var x = 1; var a = 2, b = 3; return x || ("
#define X "a, b, a, b, "
#define X "a = 1, b = 2, "
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
#undef X
"3);",
......@@ -434,7 +441,7 @@ TEST(LogicalExpressions) {
B(Star), R(2), //
B(Ldar), R(0), //
B(JumpIfToBooleanTrueConstant), U8(0), //
#define X B(Ldar), R(1), B(Ldar), R(2), B(Ldar), R(1), B(Ldar), R(2),
#define X B(LdaSmi8), U8(1), B(Star), R(1), B(LdaSmi8), U8(2), B(Star), R(2),
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
#undef X
B(LdaSmi8), U8(3), //
......@@ -442,7 +449,7 @@ TEST(LogicalExpressions) {
1,
{268, 0, 0, 0}},
{"var x = 0; var a = 2, b = 3; return x && ("
#define X "a, b, a, b, "
#define X "a = 1, b = 2, "
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
#undef X
"3);",
......@@ -457,10 +464,10 @@ TEST(LogicalExpressions) {
B(Star), R(2), //
B(Ldar), R(0), //
B(JumpIfToBooleanFalseConstant), U8(0), //
#define X B(Ldar), R(1), B(Ldar), R(2), B(Ldar), R(1), B(Ldar), R(2),
#define X B(LdaSmi8), U8(1), B(Star), R(1), B(LdaSmi8), U8(2), B(Star), R(2),
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X
#undef X
B(LdaSmi8), U8(3), //
B(LdaSmi8), U8(3), //
B(Return)},
1,
{268, 0, 0, 0}},
......@@ -468,14 +475,14 @@ TEST(LogicalExpressions) {
0 * kPointerSize,
1,
2,
{B(LdaZero), //
{B(LdaZero), //
B(Return)},
0},
{"return 1 || 3;",
0 * kPointerSize,
1,
3,
{B(LdaSmi8), U8(1), //
{B(LdaSmi8), U8(1), //
B(Return)},
0},
{"var x = 1; return x && 3 || 0, 1;",
......@@ -507,27 +514,51 @@ TEST(Parameters) {
ExpectedSnippet<int> snippets[] = {
{"function f() { return this; }",
0, 1, 3, {B(Ldar), R(helper.kLastParamIndex), B(Return)}, 0},
0,
1,
3,
{B(Ldar), THIS(1), B(Return)},
0},
{"function f(arg1) { return arg1; }",
0, 2, 3, {B(Ldar), R(helper.kLastParamIndex), B(Return)}, 0},
0,
2,
3,
{B(Ldar), A(1, 2), B(Return)},
0},
{"function f(arg1) { return this; }",
0, 2, 3, {B(Ldar), R(helper.kLastParamIndex - 1), B(Return)}, 0},
0,
2,
3,
{B(Ldar), THIS(2), B(Return)},
0},
{"function f(arg1, arg2, arg3, arg4, arg5, arg6, arg7) { return arg4; }",
0, 8, 3, {B(Ldar), R(helper.kLastParamIndex - 3), B(Return)}, 0},
0,
8,
3,
{B(Ldar), A(4, 8), B(Return)},
0},
{"function f(arg1, arg2, arg3, arg4, arg5, arg6, arg7) { return this; }",
0, 8, 3, {B(Ldar), R(helper.kLastParamIndex - 7), B(Return)}, 0},
0,
8,
3,
{B(Ldar), THIS(8), B(Return)},
0},
{"function f(arg1) { arg1 = 1; }",
0, 2, 6,
{B(LdaSmi8), U8(1), //
B(Star), R(helper.kLastParamIndex), //
B(LdaUndefined), //
0,
2,
6,
{B(LdaSmi8), U8(1), //
B(Star), A(1, 2), //
B(LdaUndefined), //
B(Return)},
0},
{"function f(arg1, arg2, arg3, arg4) { arg2 = 1; }",
0, 5, 6,
{B(LdaSmi8), U8(1), //
B(Star), R(helper.kLastParamIndex - 2), //
B(LdaUndefined), //
0,
5,
6,
{B(LdaSmi8), U8(1), //
B(Star), A(2, 5), //
B(LdaUndefined), //
B(Return)},
0},
};
......@@ -697,107 +728,85 @@ TEST(PropertyLoads) {
ExpectedSnippet<const char*> snippets[] = {
{"function f(a) { return a.name; }\nf({name : \"test\"})",
1 * kPointerSize,
0,
2,
10,
6,
{
B(Ldar), R(helper.kLastParamIndex), //
B(Star), R(0), //
B(LdaConstant), U8(0), //
B(LoadICSloppy), R(0), U8(vector->GetIndex(slot1)), //
B(Return) //
B(LdaConstant), U8(0), //
B(LoadICSloppy), A(1, 2), U8(vector->GetIndex(slot1)), //
B(Return), //
},
1,
{"name"}},
{"function f(a) { return a[\"key\"]; }\nf({key : \"test\"})",
1 * kPointerSize,
0,
2,
10,
6,
{
B(Ldar), R(helper.kLastParamIndex), //
B(Star), R(0), //
B(LdaConstant), U8(0), //
B(LoadICSloppy), R(0), U8(vector->GetIndex(slot1)), //
B(Return) //
B(LdaConstant), U8(0), //
B(LoadICSloppy), A(1, 2), U8(vector->GetIndex(slot1)), //
B(Return) //
},
1,
{"key"}},
{"function f(a) { return a[100]; }\nf({100 : \"test\"})",
1 * kPointerSize,
0,
2,
10,
6,
{
B(Ldar), R(helper.kLastParamIndex), //
B(Star), R(0), //
B(LdaSmi8), U8(100), //
B(KeyedLoadICSloppy), R(0), U8(vector->GetIndex(slot1)), //
B(Return) //
B(LdaSmi8), U8(100), //
B(KeyedLoadICSloppy), A(1, 2), U8(vector->GetIndex(slot1)), //
B(Return) //
},
0},
{"function f(a, b) { return a[b]; }\nf({arg : \"test\"}, \"arg\")",
1 * kPointerSize,
0,
3,
10,
6,
{
B(Ldar), R(helper.kLastParamIndex - 1), //
B(Star), R(0), //
B(Ldar), R(helper.kLastParamIndex), //
B(KeyedLoadICSloppy), R(0), U8(vector->GetIndex(slot1)), //
B(Return) //
B(Ldar), A(1, 2), //
B(KeyedLoadICSloppy), A(1, 3), U8(vector->GetIndex(slot1)), //
B(Return) //
},
0},
{"function f(a) { var b = a.name; return a[-124]; }\n"
"f({\"-124\" : \"test\", name : 123 })",
2 * kPointerSize,
kPointerSize,
2,
21,
13,
{
B(Ldar), R(helper.kLastParamIndex), //
B(Star), R(1), //
B(LdaConstant), U8(0), //
B(LoadICSloppy), R(1), U8(vector->GetIndex(slot1)), //
B(Star), R(0), //
B(Ldar), R(helper.kLastParamIndex), //
B(Star), R(1), //
B(LdaSmi8), U8(-124), //
B(KeyedLoadICSloppy), R(1), U8(vector->GetIndex(slot2)), //
B(Return) //
B(LdaConstant), U8(0), //
B(LoadICSloppy), A(1, 2), U8(vector->GetIndex(slot1)), //
B(Star), R(0), //
B(LdaSmi8), U8(-124), //
B(KeyedLoadICSloppy), A(1, 2), U8(vector->GetIndex(slot2)), //
B(Return), //
},
1,
{"name"}},
{"function f(a) { \"use strict\"; return a.name; }\nf({name : \"test\"})",
1 * kPointerSize,
0,
2,
12,
6,
{
// TODO(rmcilroy) Avoid unnecessary LdaConstant for "use strict"
// expression, or any other unused literal expression.
B(LdaConstant), U8(0), //
B(Ldar), R(helper.kLastParamIndex), //
B(Star), R(0), //
B(LdaConstant), U8(1), //
B(LoadICStrict), R(0), U8(vector->GetIndex(slot1)), //
B(Return) //
B(LdaConstant), U8(0), //
B(LoadICStrict), A(1, 2), U8(vector->GetIndex(slot1)), //
B(Return), //
},
2,
{"use strict", "name"}},
1,
{"name"}},
{"function f(a, b) { \"use strict\"; return a[b]; }\n"
"f({arg : \"test\"}, \"arg\")",
1 * kPointerSize,
0,
3,
12,
6,
{
// TODO(rmcilroy) Avoid unnecessary LdaConstant for "use strict"
// expression, or any other unused literal expression.
B(LdaConstant), U8(0), //
B(Ldar), R(helper.kLastParamIndex - 1), //
B(Star), R(0), //
B(Ldar), R(helper.kLastParamIndex), //
B(KeyedLoadICStrict), R(0), U8(vector->GetIndex(slot1)), //
B(Return) //
B(Ldar), A(2, 3), //
B(KeyedLoadICStrict), A(1, 3), U8(vector->GetIndex(slot1)), //
B(Return), //
},
1,
{"use strict"}}};
0,
}};
for (size_t i = 0; i < arraysize(snippets); i++) {
Handle<BytecodeArray> bytecode_array =
helper.MakeBytecode(snippets[i].code_snippet, helper.kFunctionName);
......@@ -820,129 +829,106 @@ TEST(PropertyStores) {
ExpectedSnippet<const char*> snippets[] = {
{"function f(a) { a.name = \"val\"; }\nf({name : \"test\"})",
2 * kPointerSize,
kPointerSize,
2,
16,
12,
{
B(Ldar), R(helper.kLastParamIndex), //
B(Star), R(0), //
B(LdaConstant), U8(0), //
B(Star), R(1), //
B(LdaConstant), U8(1), //
B(StoreICSloppy), R(0), R(1), U8(vector->GetIndex(slot1)), //
B(LdaUndefined), //
B(Return) //
B(LdaConstant), U8(0), //
B(Star), R(0), //
B(LdaConstant), U8(1), //
B(StoreICSloppy), A(1, 2), R(0), U8(vector->GetIndex(slot1)), //
B(LdaUndefined), //
B(Return), //
},
2,
{"name", "val"}},
{"function f(a) { a[\"key\"] = \"val\"; }\nf({key : \"test\"})",
2 * kPointerSize,
kPointerSize,
2,
16,
12,
{
B(Ldar), R(helper.kLastParamIndex), //
B(Star), R(0), //
B(LdaConstant), U8(0), //
B(Star), R(1), //
B(LdaConstant), U8(1), //
B(StoreICSloppy), R(0), R(1), U8(vector->GetIndex(slot1)), //
B(LdaUndefined), //
B(Return) //
B(LdaConstant), U8(0), //
B(Star), R(0), //
B(LdaConstant), U8(1), //
B(StoreICSloppy), A(1, 2), R(0), U8(vector->GetIndex(slot1)), //
B(LdaUndefined), //
B(Return), //
},
2,
{"key", "val"}},
{"function f(a) { a[100] = \"val\"; }\nf({100 : \"test\"})",
2 * kPointerSize,
kPointerSize,
2,
16,
12,
{
B(Ldar), R(helper.kLastParamIndex), //
B(Star), R(0), //
B(LdaSmi8), U8(100), //
B(Star), R(1), //
B(LdaConstant), U8(0), //
B(KeyedStoreICSloppy), R(0), R(1), U8(vector->GetIndex(slot1)), //
B(LdaUndefined), //
B(Return) //
B(LdaSmi8), U8(100), //
B(Star), R(0), //
B(LdaConstant), U8(0), //
B(KeyedStoreICSloppy), //
A(1, 2), R(0), U8(vector->GetIndex(slot1)), //
B(LdaUndefined), //
B(Return), //
},
1,
{"val"}},
{"function f(a, b) { a[b] = \"val\"; }\nf({arg : \"test\"}, \"arg\")",
2 * kPointerSize,
0,
3,
16,
8,
{
B(Ldar), R(helper.kLastParamIndex - 1), //
B(Star), R(0), //
B(Ldar), R(helper.kLastParamIndex), //
B(Star), R(1), //
B(LdaConstant), U8(0), //
B(KeyedStoreICSloppy), R(0), R(1), U8(vector->GetIndex(slot1)), //
B(LdaUndefined), //
B(Return) //
B(LdaConstant), U8(0), //
B(KeyedStoreICSloppy), //
A(1, 3), A(2, 3), U8(vector->GetIndex(slot1)), //
B(LdaUndefined), //
B(Return), //
},
1,
{"val"}},
{"function f(a) { a.name = a[-124]; }\n"
"f({\"-124\" : \"test\", name : 123 })",
3 * kPointerSize,
kPointerSize,
2,
23,
15,
{
B(Ldar), R(helper.kLastParamIndex), //
B(Star), R(0), //
B(LdaConstant), U8(0), //
B(Star), R(1), //
B(Ldar), R(helper.kLastParamIndex), //
B(Star), R(2), //
B(LdaSmi8), U8(-124), //
B(KeyedLoadICSloppy), R(2), U8(vector->GetIndex(slot1)), //
B(StoreICSloppy), R(0), R(1), U8(vector->GetIndex(slot2)), //
B(LdaUndefined), //
B(Return) //
B(LdaConstant), U8(0), //
B(Star), R(0), //
B(LdaSmi8), U8(-124), //
B(KeyedLoadICSloppy), A(1, 2), U8(vector->GetIndex(slot1)), //
B(StoreICSloppy), A(1, 2), R(0), U8(vector->GetIndex(slot2)), //
B(LdaUndefined), //
B(Return), //
},
1,
{"name"}},
{"function f(a) { \"use strict\"; a.name = \"val\"; }\n"
"f({name : \"test\"})",
2 * kPointerSize,
kPointerSize,
2,
18,
12,
{
// TODO(rmcilroy) Avoid unnecessary LdaConstant for "use strict"
// expression, or any other unused literal expression.
B(LdaConstant), U8(0), //
B(Ldar), R(helper.kLastParamIndex), //
B(Star), R(0), //
B(LdaConstant), U8(1), //
B(Star), R(1), //
B(LdaConstant), U8(2), //
B(StoreICStrict), R(0), R(1), U8(vector->GetIndex(slot1)), //
B(LdaUndefined), //
B(Return) //
B(LdaConstant), U8(0), //
B(Star), R(0), //
B(LdaConstant), U8(1), //
B(StoreICStrict), A(1, 2), R(0), U8(vector->GetIndex(slot1)), //
B(LdaUndefined), //
B(Return), //
},
3,
{"use strict", "name", "val"}},
2,
{"name", "val"}},
{"function f(a, b) { \"use strict\"; a[b] = \"val\"; }\n"
"f({arg : \"test\"}, \"arg\")",
2 * kPointerSize,
0,
3,
18,
8,
{
// TODO(rmcilroy) Avoid unnecessary LdaConstant for "use strict"
// expression, or any other unused literal expression.
B(LdaConstant), U8(0), //
B(Ldar), R(helper.kLastParamIndex - 1), //
B(Star), R(0), //
B(Ldar), R(helper.kLastParamIndex), //
B(Star), R(1), //
B(LdaConstant), U8(1), //
B(KeyedStoreICStrict), R(0), R(1), U8(vector->GetIndex(slot1)), //
B(LdaUndefined), //
B(Return) //
B(LdaConstant), U8(0), //
B(KeyedStoreICStrict), A(1, 3), A(2, 3), //
U8(vector->GetIndex(slot1)), //
B(LdaUndefined), //
B(Return), //
},
2,
{"use strict", "val"}}};
1,
{"val"}}};
for (size_t i = 0; i < arraysize(snippets); i++) {
Handle<BytecodeArray> bytecode_array =
helper.MakeBytecode(snippets[i].code_snippet, helper.kFunctionName);
......@@ -973,13 +959,13 @@ TEST(PropertyCall) {
2,
16,
{
B(Ldar), R(helper.kLastParamIndex), //
B(Ldar), A(1, 2), //
B(Star), R(1), //
B(LdaConstant), U8(0), //
B(LoadICSloppy), R(1), U8(vector->GetIndex(slot2)), //
B(Star), R(0), //
B(Call), R(0), R(1), U8(0), //
B(Return) //
B(Return), //
},
1,
{"func"}},
......@@ -988,14 +974,14 @@ TEST(PropertyCall) {
4,
24,
{
B(Ldar), R(helper.kLastParamIndex - 2), //
B(Ldar), A(1, 4), //
B(Star), R(1), //
B(LdaConstant), U8(0), //
B(LoadICSloppy), R(1), U8(vector->GetIndex(slot2)), //
B(Star), R(0), //
B(Ldar), R(helper.kLastParamIndex - 1), //
B(Ldar), A(2, 4), //
B(Star), R(2), //
B(Ldar), R(helper.kLastParamIndex), //
B(Ldar), A(3, 4), //
B(Star), R(3), //
B(Call), R(0), R(1), U8(2), //
B(Return) //
......@@ -1005,19 +991,17 @@ TEST(PropertyCall) {
{"function f(a, b) { return a.func(b + b, b); }\nf(" FUNC_ARG ", 1)",
4 * kPointerSize,
3,
30,
26,
{
B(Ldar), R(helper.kLastParamIndex - 1), //
B(Ldar), A(1, 3), //
B(Star), R(1), //
B(LdaConstant), U8(0), //
B(LoadICSloppy), R(1), U8(vector->GetIndex(slot2)), //
B(Star), R(0), //
B(Ldar), R(helper.kLastParamIndex), //
B(Star), R(3), //
B(Ldar), R(helper.kLastParamIndex), //
B(Add), R(3), //
B(Ldar), A(2, 3), //
B(Add), A(2, 3), //
B(Star), R(2), //
B(Ldar), R(helper.kLastParamIndex), //
B(Ldar), A(2, 3), //
B(Star), R(3), //
B(Call), R(0), R(1), U8(2), //
B(Return), //
......@@ -1300,7 +1284,7 @@ TEST(CallRuntime) {
2,
10,
{
B(Ldar), R(helper.kLastParamIndex), //
B(Ldar), A(1, 2), //
B(Star), R(0), //
B(CallRuntime), U16(Runtime::kIsArray), R(0), U8(1), //
B(Return) //
......@@ -1387,39 +1371,35 @@ TEST(IfConditions) {
{unused, unused, unused, unused, unused, unused}},
{"function f(a) { if (a <= 0) { return 200; } else { return -200; } }"
"f(99);",
kPointerSize,
0,
2,
19,
{B(Ldar), R(helper.kLastParamIndex), //
B(Star), R(0), //
B(LdaZero), //
B(TestLessThanOrEqual), R(0), //
B(JumpIfFalse), U8(7), //
B(LdaConstant), U8(0), //
B(Return), //
B(Jump), U8(5), //
B(LdaConstant), U8(1), //
B(Return), //
B(LdaUndefined), //
B(Return)}, //
15,
{B(LdaZero), //
B(TestLessThanOrEqual), A(1, 2), //
B(JumpIfFalse), U8(7), //
B(LdaConstant), U8(0), //
B(Return), //
B(Jump), U8(5), //
B(LdaConstant), U8(1), //
B(Return), //
B(LdaUndefined), //
B(Return)}, //
2,
{helper.factory()->NewNumberFromInt(200),
helper.factory()->NewNumberFromInt(-200), unused, unused, unused,
unused}},
{"function f(a, b) { if (a in b) { return 200; } }"
"f('prop', { prop: 'yes'});",
kPointerSize,
0,
3,
15,
{B(Ldar), R(helper.kLastParamIndex - 1), //
B(Star), R(0), //
B(Ldar), R(helper.kLastParamIndex), //
B(TestIn), R(0), //
B(JumpIfFalse), U8(5), //
B(LdaConstant), U8(0), //
B(Return), //
B(LdaUndefined), //
B(Return)}, //
11,
{B(Ldar), A(2, 3), //
B(TestIn), A(1, 3), //
B(JumpIfFalse), U8(5), //
B(LdaConstant), U8(0), //
B(Return), //
B(LdaUndefined), //
B(Return)}, //
1,
{helper.factory()->NewNumberFromInt(200), unused, unused, unused, unused,
unused}},
......@@ -1428,34 +1408,34 @@ TEST(IfConditions) {
X X X X X X X X X X X X X X X X X X X X X X X X
#undef X
" return 200; } else { return -200; } } f(0.001)",
3 * kPointerSize,
2 * kPointerSize,
2,
218,
{B(LdaZero), //
B(Star), R(0), //
B(LdaZero), //
B(Star), R(1), //
B(Ldar), R(0), //
B(Star), R(2), //
B(LdaConstant), U8(0), //
B(TestEqualStrict), R(2), //
B(JumpIfFalseConstant), U8(2), //
#define X B(Ldar), R(0), B(Star), R(1), B(Ldar), R(1), B(Star), R(0),
X X X X X X X X X X X X X X X X X X X X X X X X
214,
{
#define X B(Ldar), R(0), B(Star), R(1), B(Ldar), R(1), B(Star), R(0)
B(LdaZero), //
B(Star), R(0), //
B(LdaZero), //
B(Star), R(1), //
B(LdaConstant), U8(0), //
B(TestEqualStrict), R(0), //
B(JumpIfFalseConstant), U8(2), //
X, X, X, X, X, X, X, X, X, X, //
X, X, X, X, X, X, X, X, X, X, //
X, X, X, X, //
B(LdaConstant), U8(1), //
B(Return), //
B(Jump), U8(5), //
B(LdaConstant), U8(3), //
B(Return), //
B(LdaUndefined), //
B(Return)}, //
#undef X
B(LdaConstant), U8(1), //
B(Return), //
B(Jump), U8(5), //
B(LdaConstant), U8(3), //
B(Return), //
B(LdaUndefined), //
B(Return)}, //
4,
{helper.factory()->NewHeapNumber(0.01),
helper.factory()->NewNumberFromInt(200),
helper.factory()->NewNumberFromInt(199),
helper.factory()->NewNumberFromInt(-200),
unused, unused}},
helper.factory()->NewNumberFromInt(-200), unused, unused}},
{"function f(a, b) {\n"
" if (a == b) { return 1; }\n"
" if (a === b) { return 1; }\n"
......@@ -1465,22 +1445,18 @@ TEST(IfConditions) {
" if (a >= b) { return 1; }\n"
" if (a in b) { return 1; }\n"
" if (a instanceof b) { return 1; }\n"
" /* if (a != b) { return 1; } */" // TODO(oth) Ast visitor yields
" /* if (a !== b) { return 1; } */" // UNARY NOT, rather than !=/!==.
" return 0;\n"
"} f(1, 1);",
kPointerSize,
0,
3,
106,
74,
{
#define IF_CONDITION_RETURN(condition) \
B(Ldar), R(helper.kLastParamIndex - 1), \
B(Star), R(0), \
B(Ldar), R(helper.kLastParamIndex), \
B(condition), R(0), \
B(JumpIfFalse), U8(5), \
B(LdaSmi8), U8(1), \
B(Return),
B(Ldar), A(2, 3), \
B(condition), A(1, 3), \
B(JumpIfFalse), U8(5), \
B(LdaSmi8), U8(1), \
B(Return),
IF_CONDITION_RETURN(TestEqual) //
IF_CONDITION_RETURN(TestEqualStrict) //
IF_CONDITION_RETURN(TestLessThan) //
......@@ -1489,9 +1465,9 @@ TEST(IfConditions) {
IF_CONDITION_RETURN(TestGreaterThanOrEqual) //
IF_CONDITION_RETURN(TestIn) //
IF_CONDITION_RETURN(TestInstanceOf) //
B(LdaZero), //
B(Return)}, //
#undef IF_CONDITION_RETURN
B(LdaZero), //
B(Return)}, //
0,
{unused, unused, unused, unused, unused, unused}},
};
......@@ -1653,31 +1629,29 @@ TEST(DeclareGlobals2) {
1,
45,
{
B(Ldar), R(Register::function_closure().index()), //
B(Star), R(2), //
B(LdaConstant), U8(0), //
B(Star), R(3), //
B(CallRuntime), U16(Runtime::kNewScriptContext), R(2), U8(2), //
B(PushContext), R(1), //
B(LdaConstant), U8(1), //
B(Star), R(2), //
B(LdaZero), //
B(Star), R(3), //
B(CallRuntime), U16(Runtime::kDeclareGlobals), R(2), U8(2), //
B(LdaConstant), U8(2), //
B(Star), R(2), //
B(LdaZero), //
B(Star), R(3), //
B(LdaSmi8), U8(1), //
B(Star), R(4), //
B(CallRuntime), U16(Runtime::kInitializeVarGlobal), R(2), //
U8(3), //
B(LdaUndefined), //
B(Return) //
B(Ldar), R(Register::function_closure().index()), //
B(Star), R(2), //
B(LdaConstant), U8(0), //
B(Star), R(3), //
B(CallRuntime), U16(Runtime::kNewScriptContext), R(2), U8(2), //
B(PushContext), R(1), //
B(LdaConstant), U8(1), //
B(Star), R(2), //
B(LdaZero), //
B(Star), R(3), //
B(CallRuntime), U16(Runtime::kDeclareGlobals), R(2), U8(2), //
B(LdaConstant), U8(2), //
B(Star), R(2), //
B(LdaZero), //
B(Star), R(3), //
B(LdaSmi8), U8(1), //
B(Star), R(4), //
B(CallRuntime), U16(Runtime::kInitializeVarGlobal), R(2), U8(3), //
B(LdaUndefined), //
B(Return), //
},
3,
{InstanceType::FIXED_ARRAY_TYPE,
InstanceType::FIXED_ARRAY_TYPE,
{InstanceType::FIXED_ARRAY_TYPE, InstanceType::FIXED_ARRAY_TYPE,
InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}},
{"function f() {}",
3 * kPointerSize,
......@@ -1731,8 +1705,7 @@ TEST(DeclareGlobals2) {
B(Return) //
},
3,
{InstanceType::FIXED_ARRAY_TYPE,
InstanceType::FIXED_ARRAY_TYPE,
{InstanceType::FIXED_ARRAY_TYPE, InstanceType::FIXED_ARRAY_TYPE,
InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}},
{"function f() {}\nf();",
4 * kPointerSize,
......@@ -1779,34 +1752,28 @@ TEST(BasicLoops) {
{"var x = 0;"
"var y = 1;"
"while (x < 10) {"
" y = y * 10;"
" y = y * 12;"
" x = x + 1;"
"}"
"return y;",
3 * kPointerSize,
2 * kPointerSize,
1,
42,
30,
{
B(LdaZero), //
B(Star), R(0), //
B(LdaSmi8), U8(1), //
B(Star), R(1), //
B(Jump), U8(22), //
B(Ldar), R(1), //
B(Star), R(2), //
B(LdaSmi8), U8(10), //
B(Mul), R(2), //
B(Jump), U8(14), //
B(LdaSmi8), U8(12), //
B(Mul), R(1), //
B(Star), R(1), //
B(Ldar), R(0), //
B(Star), R(2), //
B(LdaSmi8), U8(1), //
B(Add), R(2), //
B(Add), R(0), //
B(Star), R(0), //
B(Ldar), R(0), //
B(Star), R(2), //
B(LdaSmi8), U8(10), //
B(TestLessThan), R(2), //
B(JumpIfTrue), U8(-28), //
B(TestLessThan), R(0), //
B(JumpIfTrue), U8(-16), //
B(Ldar), R(1), //
B(Return), //
},
......@@ -1821,52 +1788,40 @@ TEST(BasicLoops) {
" i = i + 1;"
"}"
"return i;",
2 * kPointerSize,
1 * kPointerSize,
1,
80,
56,
{
B(LdaZero), //
B(Star), R(0), //
B(Jump), U8(71), //
B(Ldar), R(0), //
B(Star), R(1), //
B(Jump), U8(47), //
B(LdaZero), //
B(TestLessThan), R(1), //
B(TestLessThan), R(0), //
B(JumpIfFalse), U8(4), //
B(Jump), U8(60), //
B(Ldar), R(0), //
B(Star), R(1), //
B(Jump), U8(40), //
B(LdaSmi8), U8(3), //
B(TestEqual), R(1), //
B(TestEqual), R(0), //
B(JumpIfFalse), U8(4), //
B(Jump), U8(51), //
B(Ldar), R(0), //
B(Star), R(1), //
B(Jump), U8(35), //
B(LdaSmi8), U8(4), //
B(TestEqual), R(1), //
B(TestEqual), R(0), //
B(JumpIfFalse), U8(4), //
B(Jump), U8(39), //
B(Ldar), R(0), //
B(Star), R(1), //
B(Jump), U8(27), //
B(LdaSmi8), U8(10), //
B(TestEqual), R(1), //
B(TestEqual), R(0), //
B(JumpIfFalse), U8(4), //
B(Jump), U8(24), //
B(Ldar), R(0), //
B(Star), R(1), //
B(Jump), U8(16), //
B(LdaSmi8), U8(5), //
B(TestEqual), R(1), //
B(TestEqual), R(0), //
B(JumpIfFalse), U8(4), //
B(Jump), U8(15), //
B(Ldar), R(0), //
B(Star), R(1), //
B(Jump), U8(11), //
B(LdaSmi8), U8(1), //
B(Add), R(1), //
B(Add), R(0), //
B(Star), R(0), //
B(LdaTrue), //
B(JumpIfTrue), U8(-70), //
B(JumpIfTrue), U8(-46), //
B(Ldar), R(0), //
B(Return) //
B(Return), //
},
0},
{"var x = 0; var y = 1;"
......@@ -1877,43 +1832,33 @@ TEST(BasicLoops) {
" x = x + 1;"
"} while (x < 10);"
"return y;",
3 * kPointerSize,
2 * kPointerSize,
1,
64,
44,
{
B(LdaZero), //
B(Star), R(0), //
B(LdaSmi8), U8(1), //
B(Star), R(1), //
B(Ldar), R(1), //
B(Star), R(2), //
B(LdaSmi8), U8(10), //
B(Mul), R(2), //
B(Mul), R(1), //
B(Star), R(1), //
B(Ldar), R(0), //
B(Star), R(2), //
B(LdaSmi8), U8(5), //
B(TestEqual), R(2), //
B(TestEqual), R(0), //
B(JumpIfFalse), U8(4), //
B(Jump), U8(34), //
B(Ldar), R(0), //
B(Star), R(2), //
B(Jump), U8(22), //
B(LdaSmi8), U8(6), //
B(TestEqual), R(2), //
B(TestEqual), R(0), //
B(JumpIfFalse), U8(4), //
B(Jump), U8(12), //
B(Ldar), R(0), //
B(Star), R(2), //
B(Jump), U8(8), //
B(LdaSmi8), U8(1), //
B(Add), R(2), //
B(Add), R(0), //
B(Star), R(0), //
B(Ldar), R(0), //
B(Star), R(2), //
B(LdaSmi8), U8(10), //
B(TestLessThan), R(2), //
B(JumpIfTrue), U8(-52), //
B(TestLessThan), R(0), //
B(JumpIfTrue), U8(-32), //
B(Ldar), R(1), //
B(Return) //
B(Return), //
},
0},
{"var x = 0; "
......@@ -1921,24 +1866,20 @@ TEST(BasicLoops) {
" if (x == 1) break;"
" x = x + 1;"
"}",
2 * kPointerSize,
1 * kPointerSize,
1,
29,
21,
{
B(LdaZero), //
B(Star), R(0), //
B(Ldar), R(0), //
B(Star), R(1), //
B(LdaSmi8), U8(1), //
B(TestEqual), R(1), //
B(TestEqual), R(0), //
B(JumpIfFalse), U8(4), //
B(Jump), U8(14), //
B(Ldar), R(0), //
B(Star), R(1), //
B(Jump), U8(10), //
B(LdaSmi8), U8(1), //
B(Add), R(1), //
B(Add), R(0), //
B(Star), R(0), //
B(Jump), U8(-22), //
B(Jump), U8(-14), //
B(LdaUndefined), //
B(Return), //
},
......@@ -1948,31 +1889,25 @@ TEST(BasicLoops) {
" u = u + 1;"
" continue;"
"}",
3 * kPointerSize,
2 * kPointerSize,
1,
42,
30,
{
B(LdaZero), //
B(Star), R(0), //
B(LdaZero), //
B(Star), R(1), //
B(Jump), U8(24), //
B(Ldar), R(0), //
B(Star), R(2), //
B(Jump), U8(16), //
B(LdaSmi8), U8(1), //
B(Add), R(2), //
B(Add), R(0), //
B(Star), R(0), //
B(Jump), U8(2), //
B(Ldar), R(1), //
B(Star), R(2), //
B(LdaSmi8), U8(1), //
B(Add), R(2), //
B(Add), R(1), //
B(Star), R(1), //
B(Ldar), R(1), //
B(Star), R(2), //
B(LdaSmi8), U8(100), //
B(TestLessThan), R(2), //
B(JumpIfTrue), U8(-30), //
B(TestLessThan), R(1), //
B(JumpIfTrue), U8(-18), //
B(LdaUndefined), //
B(Return), //
},
......@@ -1987,38 +1922,30 @@ TEST(BasicLoops) {
" break;"
"}"
"return i;",
2 * kPointerSize,
1 * kPointerSize,
1,
57,
41,
{
B(LdaZero), //
B(Star), R(0), //
B(Jump), U8(48), //
B(Jump), U8(24), //
B(Ldar), R(0), //
B(Star), R(1), //
B(Jump), U8(32), //
B(Jump), U8(16), //
B(LdaSmi8), U8(2), //
B(TestEqual), R(1), //
B(TestEqual), R(0), //
B(JumpIfFalse), U8(4), //
B(Jump), U8(22), //
B(Ldar), R(0), //
B(Star), R(1), //
B(Jump), U8(14), //
B(LdaSmi8), U8(1), //
B(Add), R(1), //
B(Add), R(0), //
B(Star), R(0), //
B(Ldar), R(0), //
B(Star), R(1), //
B(LdaSmi8), U8(3), //
B(TestLessThan), R(1), //
B(JumpIfTrue), U8(-30), //
B(Ldar), R(0), //
B(Star), R(1), //
B(TestLessThan), R(0), //
B(JumpIfTrue), U8(-18), //
B(LdaSmi8), U8(1), //
B(Add), R(1), //
B(Add), R(0), //
B(Star), R(0), //
B(Jump), U8(5), //
B(LdaTrue), //
B(JumpIfTrue), U8(-47), //
B(JumpIfTrue), U8(-31), //
B(Ldar), R(0), //
B(Return), //
},
......@@ -2043,24 +1970,20 @@ TEST(UnaryOperators) {
" x = x + 10;"
"}"
"return x;",
2 * kPointerSize,
kPointerSize,
1,
29,
21,
{
B(LdaZero), //
B(Star), R(0), //
B(Jump), U8(12), //
B(Ldar), R(0), //
B(Star), R(1), //
B(Jump), U8(8), //
B(LdaSmi8), U8(10), //
B(Add), R(1), //
B(Add), R(0), //
B(Star), R(0), //
B(Ldar), R(0), //
B(Star), R(1), //
B(LdaSmi8), U8(10), //
B(TestEqual), R(1), //
B(TestEqual), R(0), //
B(LogicalNot), //
B(JumpIfTrue), U8(-19), //
B(JumpIfTrue), U8(-11), //
B(Ldar), R(0), //
B(Return), //
},
......@@ -2070,36 +1993,32 @@ TEST(UnaryOperators) {
" x = !x;"
"} while(x == false);"
"return x;",
2 * kPointerSize,
kPointerSize,
1,
20,
16,
{
B(LdaFalse), //
B(Star), R(0), //
B(Ldar), R(0), //
B(LogicalNot), //
B(Star), R(0), //
B(Ldar), R(0), //
B(Star), R(1), //
B(LdaFalse), //
B(TestEqual), R(1), //
B(JumpIfTrue), U8(-12), //
B(Ldar), R(0), //
B(Return), //
B(LdaFalse), //
B(Star), R(0), //
B(Ldar), R(0), //
B(LogicalNot), //
B(Star), R(0), //
B(LdaFalse), //
B(TestEqual), R(0), //
B(JumpIfTrue), U8(-8), //
B(Ldar), R(0), //
B(Return), //
},
0},
{"var x = 101;"
"return void(x * 3);",
2 * kPointerSize,
kPointerSize,
1,
14,
10,
{
B(LdaSmi8), U8(101), //
B(Star), R(0), //
B(Ldar), R(0), //
B(Star), R(1), //
B(LdaSmi8), U8(3), //
B(Mul), R(1), //
B(Mul), R(0), //
B(LdaUndefined), //
B(Return), //
},
......@@ -2107,16 +2026,14 @@ TEST(UnaryOperators) {
{"var x = 1234;"
"var y = void (x * x - 1);"
"return y;",
4 * kPointerSize,
3 * kPointerSize,
1,
24,
20,
{
B(LdaConstant), U8(0), //
B(Star), R(0), //
B(Ldar), R(0), //
B(Star), R(3), //
B(Ldar), R(0), //
B(Mul), R(3), //
B(Mul), R(0), //
B(Star), R(2), //
B(LdaSmi8), U8(1), //
B(Sub), R(2), //
......@@ -2129,13 +2046,13 @@ TEST(UnaryOperators) {
{1234}},
{"var x = 13;"
"return typeof(x);",
1 * kPointerSize,
kPointerSize,
1,
8,
{
B(LdaSmi8), U8(13), //
B(Star), R(0), //
B(Ldar), R(0), //
B(Star), R(0), // TODO(oth): Ldar R(X) following Star R(X)
B(Ldar), R(0), // could be culled in bytecode array builder.
B(TypeOf), //
B(Return), //
},
......@@ -2306,9 +2223,9 @@ TEST(ArrayLiterals) {
1,
{InstanceType::FIXED_ARRAY_TYPE}},
{"var a = 1; return [ a, a + 1 ];",
4 * kPointerSize,
3 * kPointerSize,
1,
39,
35,
{
B(LdaSmi8), U8(1), //
B(Star), R(0), //
......@@ -2321,13 +2238,11 @@ TEST(ArrayLiterals) {
B(KeyedStoreICSloppy), R(2), R(1), U8(vector->GetIndex(slot1)), //
B(LdaSmi8), U8(1), //
B(Star), R(1), //
B(Ldar), R(0), //
B(Star), R(3), //
B(LdaSmi8), U8(1), //
B(Add), R(3), //
B(Add), R(0), //
B(KeyedStoreICSloppy), R(2), R(1), U8(vector->GetIndex(slot1)), //
B(Ldar), R(2), //
B(Return) //
B(Return), //
},
1,
{InstanceType::FIXED_ARRAY_TYPE}},
......@@ -2343,9 +2258,9 @@ TEST(ArrayLiterals) {
1,
{InstanceType::FIXED_ARRAY_TYPE}},
{"var a = 1; return [ [ a, 2 ], [ a + 2 ] ];",
6 * kPointerSize,
5 * kPointerSize,
1,
71,
67,
{
B(LdaSmi8), U8(1), //
B(Star), R(0), //
......@@ -2370,10 +2285,8 @@ TEST(ArrayLiterals) {
B(Star), R(4), //
B(LdaZero), //
B(Star), R(3), //
B(Ldar), R(0), //
B(Star), R(5), //
B(LdaSmi8), U8(2), //
B(Add), R(5), //
B(Add), R(0), //
B(KeyedStoreICSloppy), R(4), R(3), U8(vector->GetIndex(slot2)), //
B(Ldar), R(4), //
B(KeyedStoreICSloppy), R(2), R(1), U8(vector->GetIndex(slot3)), //
......@@ -2446,22 +2359,19 @@ TEST(ObjectLiterals) {
{InstanceType::FIXED_ARRAY_TYPE,
InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}},
{"var a = 1; return { val: a, val: a + 1 };",
4 * kPointerSize,
3 * kPointerSize,
1,
32,
26,
{
B(LdaSmi8), U8(1), //
B(Star), R(0), //
B(LdaConstant), U8(0), //
B(CreateObjectLiteral), U8(0), U8(deep_elements_flags), //
B(Star), R(1), //
B(Ldar), R(0), //
B(LdaConstant), U8(1), //
B(Star), R(2), //
B(Ldar), R(0), //
B(Star), R(3), //
B(LdaSmi8), U8(1), //
B(Add), R(3), //
B(Add), R(0), //
B(StoreICSloppy), R(1), R(2), U8(3), //
B(Ldar), R(1), //
B(Return), //
......@@ -2738,7 +2648,7 @@ TEST(ObjectLiterals) {
B(LdaZero), //
B(Star), R(4), //
B(CallRuntime), U16(Runtime::kDefineGetterPropertyUnchecked), //
R(1), U8(4), //
R(1), U8(4), //
B(LdaConstant), U8(3), //
B(ToName), //
B(Star), R(2), //
......@@ -2748,7 +2658,7 @@ TEST(ObjectLiterals) {
B(LdaZero), //
B(Star), R(4), //
B(CallRuntime), U16(Runtime::kDefineSetterPropertyUnchecked), //
R(1), U8(4), //
R(1), U8(4), //
B(Ldar), R(1), //
B(Return), //
},
......@@ -2870,7 +2780,7 @@ TEST(TopLevelObjectLiterals2) {
B(Star), R(4), //
B(CallRuntime), U16(Runtime::kInitializeVarGlobal), R(2), U8(3), //
B(LdaUndefined), //
B(Return), //
B(Return),
},
6,
{InstanceType::FIXED_ARRAY_TYPE,
......@@ -2896,7 +2806,7 @@ TEST(TryCatch) {
// TODO(rmcilroy): modify tests when we have real try catch support.
ExpectedSnippet<int> snippets[] = {
{"try { return 1; } catch(e) { return 2; }",
1 * kPointerSize,
kPointerSize,
1,
5,
{
......@@ -2923,7 +2833,7 @@ TEST(TryFinally) {
// TODO(rmcilroy): modify tests when we have real try finally support.
ExpectedSnippet<int> snippets[] = {
{"var a = 1; try { a = 2; } finally { a = 3; }",
1 * kPointerSize,
kPointerSize,
1,
14,
{
......@@ -3253,17 +3163,16 @@ TEST(ContextVariables) {
{"'use strict'; let a = 1; { let b = 2; return function() { a + b; }; }",
4 * kPointerSize,
1,
51,
49,
{
B(CallRuntime), U16(Runtime::kNewFunctionContext), //
R(closure), U8(1), //
B(PushContext), R(0), //
B(LdaTheHole), //
B(StaContextSlot), R(0), U8(first_context_slot), //
B(LdaConstant), U8(0), //
B(LdaSmi8), U8(1), //
B(StaContextSlot), R(0), U8(first_context_slot), //
B(LdaConstant), U8(1), //
B(LdaConstant), U8(0), //
B(Star), R(2), //
B(Ldar), R(closure), //
B(Star), R(3), //
......@@ -3273,7 +3182,7 @@ TEST(ContextVariables) {
B(StaContextSlot), R(1), U8(first_context_slot), //
B(LdaSmi8), U8(2), //
B(StaContextSlot), R(1), U8(first_context_slot), //
B(LdaConstant), U8(2), //
B(LdaConstant), U8(1), //
B(CreateClosure), U8(0), //
B(Return), //
// TODO(rmcilroy): Dead code after this point due to return in nested
......@@ -3282,9 +3191,8 @@ TEST(ContextVariables) {
B(LdaUndefined), //
B(Return), //
},
3,
{InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE,
InstanceType::FIXED_ARRAY_TYPE,
2,
{InstanceType::FIXED_ARRAY_TYPE,
InstanceType::SHARED_FUNCTION_INFO_TYPE}},
};
......
......@@ -178,12 +178,12 @@ TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) {
builder.set_parameter_count(0);
builder.set_locals_count(locals);
builder.set_context_count(contexts);
builder.Return();
TemporaryRegisterScope temporaries(&builder);
for (int i = 0; i < temps; i++) {
temporaries.NewRegister();
builder.StoreAccumulatorInRegister(temporaries.NewRegister());
}
builder.Return();
Handle<BytecodeArray> the_array = builder.ToBytecodeArray();
int total_registers = locals + contexts + temps;
......@@ -247,6 +247,32 @@ TEST_F(BytecodeArrayBuilderTest, Parameters) {
}
TEST_F(BytecodeArrayBuilderTest, RegisterType) {
BytecodeArrayBuilder builder(isolate(), zone());
builder.set_parameter_count(10);
builder.set_locals_count(3);
builder.set_context_count(0);
TemporaryRegisterScope temporary_register_scope(&builder);
Register temp0 = temporary_register_scope.NewRegister();
Register param0(builder.Parameter(0));
Register param9(builder.Parameter(9));
Register temp1 = temporary_register_scope.NewRegister();
Register reg0(0);
Register reg1(1);
Register reg2(2);
Register temp2 = temporary_register_scope.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) {
BytecodeArrayBuilder builder(isolate(), zone());
builder.set_parameter_count(0);
......
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