[Interpreter] Ensure we always have an outer register allocation scope.

Split RegisterAllocationScope out of ExpressionResult and allocate one
for each statement. This ensures that we always have an outer register
allocation scope for statement code (used in CountOperation and
RegisterExecutionResult). Also refactored the register allocator code to
move it to it's own file and rename from TemporaryRegisterScope to
BytecodeRegisterAllocator.

BUG=v8:4280
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#33296}
This commit is contained in:
rmcilroy 2016-01-14 05:43:14 -08:00 committed by Commit bot
parent fd7f7a8f5a
commit ef21fb2de6
14 changed files with 376 additions and 255 deletions

View File

@ -1087,6 +1087,8 @@ source_set("v8_base") {
"src/interpreter/bytecode-array-iterator.h",
"src/interpreter/bytecode-generator.cc",
"src/interpreter/bytecode-generator.h",
"src/interpreter/bytecode-register-allocator.cc",
"src/interpreter/bytecode-register-allocator.h",
"src/interpreter/bytecode-traits.h",
"src/interpreter/constant-array-builder.cc",
"src/interpreter/constant-array-builder.h",

View File

@ -1603,63 +1603,6 @@ bool BytecodeArrayBuilder::FitsInReg16Operand(Register value) {
return kMinInt16 <= value.index() && value.index() <= kMaxInt16;
}
TemporaryRegisterScope::TemporaryRegisterScope(BytecodeArrayBuilder* builder)
: builder_(builder),
allocated_(builder->zone()),
next_consecutive_register_(-1),
next_consecutive_count_(-1) {}
TemporaryRegisterScope::~TemporaryRegisterScope() {
for (auto i = allocated_.rbegin(); i != allocated_.rend(); i++) {
builder_->ReturnTemporaryRegister(*i);
}
allocated_.clear();
}
Register TemporaryRegisterScope::NewRegister() {
int allocated = -1;
if (next_consecutive_count_ <= 0) {
allocated = builder_->BorrowTemporaryRegister();
} else {
allocated = builder_->BorrowTemporaryRegisterNotInRange(
next_consecutive_register_,
next_consecutive_register_ + next_consecutive_count_ - 1);
}
allocated_.push_back(allocated);
return Register(allocated);
}
bool TemporaryRegisterScope::RegisterIsAllocatedInThisScope(
Register reg) const {
for (auto i = allocated_.begin(); i != allocated_.end(); i++) {
if (*i == reg.index()) return true;
}
return false;
}
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
} // namespace internal
} // namespace v8

View File

@ -334,7 +334,8 @@ class BytecodeArrayBuilder final {
ZoneSet<int> free_temporaries_;
class PreviousBytecodeHelper;
friend class TemporaryRegisterScope;
friend class BytecodeRegisterAllocator;
DISALLOW_COPY_AND_ASSIGN(BytecodeArrayBuilder);
};
@ -379,38 +380,6 @@ class BytecodeLabel final {
friend class BytecodeArrayBuilder;
};
// 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();
bool RegisterIsAllocatedInThisScope(Register reg) const;
bool hasConsecutiveAllocations() const { return next_consecutive_count_ > 0; }
private:
void* operator new(size_t size);
void operator delete(void* p);
BytecodeArrayBuilder* builder_;
const TemporaryRegisterScope* outer_;
ZoneVector<int> allocated_;
int next_consecutive_register_;
int next_consecutive_count_;
DISALLOW_COPY_AND_ASSIGN(TemporaryRegisterScope);
};
} // namespace interpreter
} // namespace internal
} // namespace v8

View File

@ -6,6 +6,7 @@
#include "src/ast/scopes.h"
#include "src/compiler.h"
#include "src/interpreter/bytecode-register-allocator.h"
#include "src/interpreter/control-flow-builders.h"
#include "src/objects.h"
#include "src/parsing/parser.h"
@ -177,39 +178,24 @@ void BytecodeGenerator::ControlScope::PerformCommand(Command command,
}
// Scoped base class for determining where the result of an expression
// is stored.
class BytecodeGenerator::ExpressionResultScope {
class BytecodeGenerator::RegisterAllocationScope {
public:
ExpressionResultScope(BytecodeGenerator* generator, Expression::Context kind)
explicit RegisterAllocationScope(BytecodeGenerator* generator)
: generator_(generator),
kind_(kind),
outer_(generator->execution_result()),
allocator_(builder()),
result_identified_(false) {
generator_->set_execution_result(this);
outer_(generator->register_allocator()),
allocator_(builder()) {
generator_->set_register_allocator(this);
}
virtual ~ExpressionResultScope() {
generator_->set_execution_result(outer_);
DCHECK(result_identified());
virtual ~RegisterAllocationScope() {
generator_->set_register_allocator(outer_);
}
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() {
ExpressionResultScope* current_scope = generator()->execution_result();
RegisterAllocationScope* current_scope = generator()->register_allocator();
if ((current_scope == this) ||
(current_scope->outer() == this &&
!current_scope->allocator_.hasConsecutiveAllocations())) {
!current_scope->allocator_.HasConsecutiveAllocations())) {
// Regular case - Allocating registers in current or outer context.
// VisitForRegisterValue allocates register in outer context.
return allocator_.NewRegister();
@ -231,7 +217,53 @@ class BytecodeGenerator::ExpressionResultScope {
return allocator_.NextConsecutiveRegister();
}
bool RegisterIsAllocatedInThisScope(Register reg) const {
return allocator_.RegisterIsAllocatedInThisScope(reg);
}
RegisterAllocationScope* outer() const { return outer_; }
private:
BytecodeGenerator* generator() const { return generator_; }
BytecodeArrayBuilder* builder() const { return generator_->builder(); }
BytecodeGenerator* generator_;
RegisterAllocationScope* outer_;
BytecodeRegisterAllocator allocator_;
DISALLOW_COPY_AND_ASSIGN(RegisterAllocationScope);
};
// 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_(generator),
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;
protected:
ExpressionResultScope* outer() const { return outer_; }
BytecodeArrayBuilder* builder() const { return generator_->builder(); }
const RegisterAllocationScope* allocator() const { return &allocator_; }
void set_result_identified() {
DCHECK(!result_identified());
result_identified_ = true;
@ -239,13 +271,11 @@ class BytecodeGenerator::ExpressionResultScope {
bool result_identified() const { return result_identified_; }
const TemporaryRegisterScope* allocator() const { return &allocator_; }
private:
BytecodeGenerator* generator_;
Expression::Context kind_;
ExpressionResultScope* outer_;
TemporaryRegisterScope allocator_;
RegisterAllocationScope allocator_;
bool result_identified_;
DISALLOW_COPY_AND_ASSIGN(ExpressionResultScope);
@ -293,7 +323,7 @@ class BytecodeGenerator::RegisterResultScope final
: ExpressionResultScope(generator, Expression::kValue) {}
virtual void SetResultInAccumulator() {
result_register_ = outer()->NewRegister();
result_register_ = allocator()->outer()->NewRegister();
builder()->StoreAccumulatorInRegister(result_register_);
set_result_identified();
}
@ -322,7 +352,8 @@ BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone)
globals_(0, zone),
execution_control_(nullptr),
execution_context_(nullptr),
execution_result_(nullptr) {
execution_result_(nullptr),
register_allocator_(nullptr) {
InitializeAstVisitor(isolate);
}
@ -500,6 +531,7 @@ void BytecodeGenerator::VisitExportDeclaration(ExportDeclaration* decl) {
void BytecodeGenerator::VisitDeclarations(
ZoneList<Declaration*>* declarations) {
RegisterAllocationScope register_scope(this);
DCHECK(globals()->empty());
AstVisitor::VisitDeclarations(declarations);
if (globals()->empty()) return;
@ -511,12 +543,11 @@ void BytecodeGenerator::VisitDeclarations(
DeclareGlobalsNativeFlag::encode(info()->is_native()) |
DeclareGlobalsLanguageMode::encode(language_mode());
TemporaryRegisterScope temporary_register_scope(builder());
Register pairs = temporary_register_scope.NewRegister();
Register pairs = register_allocator()->NewRegister();
builder()->LoadLiteral(data);
builder()->StoreAccumulatorInRegister(pairs);
Register flags = temporary_register_scope.NewRegister();
Register flags = register_allocator()->NewRegister();
builder()->LoadLiteral(Smi::FromInt(encoded_flags));
builder()->StoreAccumulatorInRegister(flags);
DCHECK(flags.index() == pairs.index() + 1);
@ -526,8 +557,18 @@ void BytecodeGenerator::VisitDeclarations(
}
void BytecodeGenerator::VisitStatements(ZoneList<Statement*>* statements) {
for (int i = 0; i < statements->length(); i++) {
// Allocate an outer register allocations scope for the statement.
RegisterAllocationScope allocation_scope(this);
Statement* stmt = statements->at(i);
Visit(stmt);
if (stmt->IsJump()) break;
}
}
void BytecodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
EffectResultScope statement_result_scope(this);
VisitForEffect(stmt->expression());
}
@ -582,7 +623,6 @@ void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
void BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
EffectResultScope statement_result_scope(this);
VisitForAccumulatorValue(stmt->expression());
builder()->Return();
}
@ -596,7 +636,6 @@ void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) {
void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
// We need this scope because we visit for register values. We have to
// maintain a execution result scope where registers can be allocated.
EffectResultScope effect_results_scope(this);
ZoneList<CaseClause*>* clauses = stmt->cases();
SwitchBuilder switch_builder(builder(), clauses->length());
ControlScopeForBreakable scope(this, stmt, &switch_builder);
@ -735,8 +774,8 @@ void BytecodeGenerator::VisitForInAssignment(Expression* expr,
break;
}
case NAMED_PROPERTY: {
TemporaryRegisterScope temporary_register_scope(builder());
Register value = temporary_register_scope.NewRegister();
RegisterAllocationScope register_scope(this);
Register value = register_allocator()->NewRegister();
builder()->StoreAccumulatorInRegister(value);
Register object = VisitForRegisterValue(property->obj());
Handle<String> name = property->key()->AsLiteral()->AsPropertyName();
@ -746,8 +785,8 @@ void BytecodeGenerator::VisitForInAssignment(Expression* expr,
break;
}
case KEYED_PROPERTY: {
TemporaryRegisterScope temporary_register_scope(builder());
Register value = temporary_register_scope.NewRegister();
RegisterAllocationScope register_scope(this);
Register value = register_allocator()->NewRegister();
builder()->StoreAccumulatorInRegister(value);
Register object = VisitForRegisterValue(property->obj());
Register key = VisitForRegisterValue(property->key());
@ -764,7 +803,6 @@ void BytecodeGenerator::VisitForInAssignment(Expression* expr,
void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) {
EffectResultScope statement_result_scope(this);
if (stmt->subject()->IsNullLiteral() ||
stmt->subject()->IsUndefinedLiteral(isolate())) {
// ForIn generates lots of code, skip if it wouldn't produce any effects.
@ -779,17 +817,17 @@ void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) {
VisitForAccumulatorValue(stmt->subject());
builder()->JumpIfUndefined(&subject_undefined_label);
builder()->JumpIfNull(&subject_null_label);
Register receiver = execution_result()->NewRegister();
Register receiver = register_allocator()->NewRegister();
builder()->CastAccumulatorToJSObject();
builder()->JumpIfNull(&not_object_label);
builder()->StoreAccumulatorInRegister(receiver);
Register cache_type = execution_result()->NewRegister();
Register cache_array = execution_result()->NewRegister();
Register cache_length = execution_result()->NewRegister();
Register cache_type = register_allocator()->NewRegister();
Register cache_array = register_allocator()->NewRegister();
Register cache_length = register_allocator()->NewRegister();
builder()->ForInPrepare(cache_type, cache_array, cache_length);
// Set up loop counter
Register index = execution_result()->NewRegister();
Register index = register_allocator()->NewRegister();
builder()->LoadLiteral(Smi::FromInt(0));
builder()->StoreAccumulatorInRegister(index);
@ -915,7 +953,6 @@ void BytecodeGenerator::VisitLiteral(Literal* expr) {
void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
// Materialize a regular expression literal.
TemporaryRegisterScope temporary_register_scope(builder());
builder()->CreateRegExpLiteral(expr->pattern(), expr->literal_index(),
expr->flags());
execution_result()->SetResultInAccumulator();
@ -927,8 +964,6 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
builder()->CreateObjectLiteral(expr->constant_properties(),
expr->literal_index(),
expr->ComputeFlags(true));
TemporaryRegisterScope temporary_register_scope(builder());
Register literal;
// Store computed values into the literal.
@ -936,17 +971,17 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
int property_index = 0;
AccessorTable accessor_table(zone());
for (; property_index < expr->properties()->length(); property_index++) {
TemporaryRegisterScope inner_temporary_register_scope(builder());
ObjectLiteral::Property* property = expr->properties()->at(property_index);
if (property->is_computed_name()) break;
if (property->IsCompileTimeValue()) continue;
if (literal_in_accumulator) {
literal = temporary_register_scope.NewRegister();
literal = register_allocator()->NewRegister();
builder()->StoreAccumulatorInRegister(literal);
literal_in_accumulator = false;
}
RegisterAllocationScope inner_register_scope(this);
Literal* literal_key = property->key()->AsLiteral();
switch (property->kind()) {
case ObjectLiteral::Property::CONSTANT:
@ -967,16 +1002,13 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
VisitForEffect(property->value());
}
} else {
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();
register_allocator()->PrepareForConsecutiveAllocations(3);
Register key = register_allocator()->NextConsecutiveRegister();
Register value = register_allocator()->NextConsecutiveRegister();
Register language = register_allocator()->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.
// literal is allocated in outer register scope, whereas key, value,
// language are in another.
DCHECK(Register::AreContiguous(literal, key, value, language));
VisitForAccumulatorValue(property->key());
builder()->StoreAccumulatorInRegister(key);
@ -993,10 +1025,9 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
break;
}
case ObjectLiteral::Property::PROTOTYPE: {
inner_temporary_register_scope.PrepareForConsecutiveAllocations(1);
register_allocator()->PrepareForConsecutiveAllocations(1);
DCHECK(property->emit_store());
Register value =
inner_temporary_register_scope.NextConsecutiveRegister();
Register value = register_allocator()->NextConsecutiveRegister();
DCHECK(Register::AreContiguous(literal, value));
VisitForAccumulatorValue(property->value());
builder()->StoreAccumulatorInRegister(value).CallRuntime(
@ -1020,12 +1051,12 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
// corresponding getters and setters.
for (AccessorTable::Iterator it = accessor_table.begin();
it != accessor_table.end(); ++it) {
TemporaryRegisterScope inner_temporary_register_scope(builder());
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();
RegisterAllocationScope inner_register_scope(this);
register_allocator()->PrepareForConsecutiveAllocations(4);
Register name = register_allocator()->NextConsecutiveRegister();
Register getter = register_allocator()->NextConsecutiveRegister();
Register setter = register_allocator()->NextConsecutiveRegister();
Register attr = register_allocator()->NextConsecutiveRegister();
DCHECK(Register::AreContiguous(literal, name, getter, setter, attr));
VisitForAccumulatorValue(it->first);
builder()->StoreAccumulatorInRegister(name);
@ -1047,19 +1078,17 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
// compile them into a series of "SetOwnProperty" runtime calls. This will
// preserve insertion order.
for (; property_index < expr->properties()->length(); property_index++) {
ObjectLiteral::Property* property = expr->properties()->at(property_index);
if (literal_in_accumulator) {
temporary_register_scope.PrepareForConsecutiveAllocations(4);
literal = temporary_register_scope.NextConsecutiveRegister();
literal = register_allocator()->NewRegister();
builder()->StoreAccumulatorInRegister(literal);
literal_in_accumulator = false;
}
ObjectLiteral::Property* property = expr->properties()->at(property_index);
RegisterAllocationScope inner_register_scope(this);
if (property->kind() == ObjectLiteral::Property::PROTOTYPE) {
DCHECK(property->emit_store());
TemporaryRegisterScope inner_temporary_register_scope(builder());
Register value = inner_temporary_register_scope.NewRegister();
Register value = register_allocator()->NewRegister();
DCHECK(Register::AreContiguous(literal, value));
VisitForAccumulatorValue(property->value());
builder()->StoreAccumulatorInRegister(value).CallRuntime(
@ -1067,11 +1096,10 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
continue;
}
TemporaryRegisterScope inner_temporary_register_scope(builder());
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();
register_allocator()->PrepareForConsecutiveAllocations(3);
Register key = register_allocator()->NextConsecutiveRegister();
Register value = register_allocator()->NextConsecutiveRegister();
Register attr = register_allocator()->NextConsecutiveRegister();
DCHECK(Register::AreContiguous(literal, key, value, attr));
VisitForAccumulatorValue(property->key());
@ -1119,8 +1147,6 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
builder()->CreateArrayLiteral(expr->constant_elements(),
expr->literal_index(),
expr->ComputeFlags(true));
TemporaryRegisterScope temporary_register_scope(builder());
Register index, literal;
// Evaluate all the non-constant subexpressions and store them into the
@ -1136,8 +1162,8 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
}
if (literal_in_accumulator) {
index = temporary_register_scope.NewRegister();
literal = temporary_register_scope.NewRegister();
index = register_allocator()->NewRegister();
literal = register_allocator()->NewRegister();
builder()->StoreAccumulatorInRegister(literal);
literal_in_accumulator = false;
}
@ -1196,7 +1222,7 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable,
if (context) {
context_reg = context->reg();
} else {
context_reg = execution_result()->NewRegister();
context_reg = register_allocator()->NewRegister();
// Walk the context chain to find the context at the given depth.
// TODO(rmcilroy): Perform this work in a bytecode handler once we have
// a generic mechanism for performing jumps in interpreter.cc.
@ -1271,8 +1297,8 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable,
if (context) {
context_reg = context->reg();
} else {
Register value_temp = execution_result()->NewRegister();
context_reg = execution_result()->NewRegister();
Register value_temp = register_allocator()->NewRegister();
context_reg = register_allocator()->NewRegister();
// Walk the context chain to find the context at the given depth.
// TODO(rmcilroy): Perform this work in a bytecode handler once we have
// a generic mechanism for performing jumps in interpreter.cc.
@ -1324,7 +1350,7 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) {
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 = execution_result()->NewRegister();
key = register_allocator()->NewRegister();
VisitForAccumulatorValue(property->key());
builder()->StoreAccumulatorInRegister(key);
} else {
@ -1350,7 +1376,7 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) {
}
case NAMED_PROPERTY: {
FeedbackVectorSlot slot = property->PropertyFeedbackSlot();
old_value = execution_result()->NewRegister();
old_value = register_allocator()->NewRegister();
builder()
->LoadNamedProperty(object, name, feedback_index(slot),
language_mode())
@ -1361,7 +1387,7 @@ 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 = execution_result()->NewRegister();
old_value = register_allocator()->NewRegister();
builder()
->LoadKeyedProperty(object, feedback_index(slot), language_mode())
.StoreAccumulatorInRegister(old_value);
@ -1467,16 +1493,16 @@ Register BytecodeGenerator::VisitArguments(ZoneList<Expression*>* args) {
// 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());
register_allocator()->PrepareForConsecutiveAllocations(args->length());
// Visit for first argument that goes into returned register
Register first_arg = execution_result()->NextConsecutiveRegister();
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 = execution_result()->NextConsecutiveRegister();
Register ith_arg = register_allocator()->NextConsecutiveRegister();
VisitForAccumulatorValue(args->at(i));
builder()->StoreAccumulatorInRegister(ith_arg);
DCHECK(ith_arg.index() - i == first_arg.index());
@ -1497,9 +1523,9 @@ void BytecodeGenerator::VisitCall(Call* expr) {
// kLoadLookupSlot. 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() + 2);
Register callee = execution_result()->NextConsecutiveRegister();
Register receiver = execution_result()->NextConsecutiveRegister();
register_allocator()->PrepareForConsecutiveAllocations(args->length() + 2);
Register callee = register_allocator()->NextConsecutiveRegister();
Register receiver = register_allocator()->NextConsecutiveRegister();
switch (call_type) {
case Call::NAMED_PROPERTY_CALL:
@ -1524,10 +1550,10 @@ void BytecodeGenerator::VisitCall(Call* expr) {
case Call::LOOKUP_SLOT_CALL:
case Call::POSSIBLY_EVAL_CALL: {
if (callee_expr->AsVariableProxy()->var()->IsLookupSlot()) {
TemporaryRegisterScope temporary_register_scope(builder());
temporary_register_scope.PrepareForConsecutiveAllocations(2);
Register context = temporary_register_scope.NextConsecutiveRegister();
Register name = temporary_register_scope.NextConsecutiveRegister();
RegisterAllocationScope inner_register_scope(this);
register_allocator()->PrepareForConsecutiveAllocations(2);
Register context = register_allocator()->NextConsecutiveRegister();
Register name = register_allocator()->NextConsecutiveRegister();
// Call LoadLookupSlot to get the callee and receiver.
DCHECK(Register::AreContiguous(callee, receiver));
@ -1562,14 +1588,13 @@ void BytecodeGenerator::VisitCall(Call* expr) {
// 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) {
TemporaryRegisterScope temporary_register_scope(builder());
temporary_register_scope.PrepareForConsecutiveAllocations(5);
Register callee_for_eval =
temporary_register_scope.NextConsecutiveRegister();
Register source = temporary_register_scope.NextConsecutiveRegister();
Register function = temporary_register_scope.NextConsecutiveRegister();
Register language = temporary_register_scope.NextConsecutiveRegister();
Register position = temporary_register_scope.NextConsecutiveRegister();
RegisterAllocationScope inner_register_scope(this);
register_allocator()->PrepareForConsecutiveAllocations(5);
Register callee_for_eval = register_allocator()->NextConsecutiveRegister();
Register source = register_allocator()->NextConsecutiveRegister();
Register function = register_allocator()->NextConsecutiveRegister();
Register language = register_allocator()->NextConsecutiveRegister();
Register position = register_allocator()->NextConsecutiveRegister();
// Set up arguments for ResolvePossiblyDirectEval by copying callee, source
// strings and function closure, and loading language and
@ -1598,7 +1623,7 @@ void BytecodeGenerator::VisitCall(Call* expr) {
void BytecodeGenerator::VisitCallNew(CallNew* expr) {
Register constructor = execution_result()->NewRegister();
Register constructor = register_allocator()->NewRegister();
VisitForAccumulatorValue(expr->expression());
builder()->StoreAccumulatorInRegister(constructor);
@ -1614,8 +1639,8 @@ void BytecodeGenerator::VisitCallRuntime(CallRuntime* expr) {
Register receiver;
if (expr->is_jsruntime()) {
// Allocate a register for the receiver and load it with undefined.
execution_result()->PrepareForConsecutiveAllocations(args->length() + 1);
receiver = execution_result()->NextConsecutiveRegister();
register_allocator()->PrepareForConsecutiveAllocations(args->length() + 1);
receiver = register_allocator()->NextConsecutiveRegister();
builder()->LoadUndefined().StoreAccumulatorInRegister(receiver);
}
// Evaluate all arguments to the runtime call.
@ -1705,8 +1730,8 @@ void BytecodeGenerator::VisitDelete(UnaryOperation* expr) {
case VariableLocation::GLOBAL:
case VariableLocation::UNALLOCATED: {
// Global var, let, const or variables not explicitly declared.
Register native_context = execution_result()->NewRegister();
Register global_object = execution_result()->NewRegister();
Register native_context = register_allocator()->NewRegister();
Register global_object = register_allocator()->NewRegister();
builder()
->LoadContextSlot(execution_context()->reg(),
Context::NATIVE_CONTEXT_INDEX)
@ -1778,7 +1803,7 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) {
obj = VisitForRegisterValue(property->obj());
// Use visit for accumulator here since we need the key in the accumulator
// for the LoadKeyedProperty.
key = execution_result()->NewRegister();
key = register_allocator()->NewRegister();
VisitForAccumulatorValue(property->key());
builder()->StoreAccumulatorInRegister(key).LoadKeyedProperty(
obj, feedback_index(slot), language_mode());
@ -1796,7 +1821,7 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) {
// Save result for postfix expressions.
if (is_postfix) {
old_value = execution_result()->outer()->NewRegister();
old_value = register_allocator()->outer()->NewRegister();
builder()->StoreAccumulatorInRegister(old_value);
}
@ -1949,9 +1974,9 @@ void BytecodeGenerator::VisitNewLocalFunctionContext() {
// Allocate a new local context.
if (scope->is_script_scope()) {
TemporaryRegisterScope temporary_register_scope(builder());
Register closure = temporary_register_scope.NewRegister();
Register scope_info = temporary_register_scope.NewRegister();
RegisterAllocationScope register_scope(this);
Register closure = register_allocator()->NewRegister();
Register scope_info = register_allocator()->NewRegister();
DCHECK(Register::AreContiguous(closure, scope_info));
builder()
->LoadAccumulatorWithRegister(Register::function_closure())
@ -2001,10 +2026,9 @@ void BytecodeGenerator::VisitNewLocalBlockContext(Scope* scope) {
DCHECK(scope->is_block_scope());
// Allocate a new local block context.
TemporaryRegisterScope temporary_register_scope(builder());
temporary_register_scope.PrepareForConsecutiveAllocations(2);
Register scope_info = temporary_register_scope.NextConsecutiveRegister();
Register closure = temporary_register_scope.NextConsecutiveRegister();
register_allocator()->PrepareForConsecutiveAllocations(2);
Register scope_info = register_allocator()->NextConsecutiveRegister();
Register closure = register_allocator()->NextConsecutiveRegister();
builder()
->LoadLiteral(scope->GetScopeInfo(isolate()))
@ -2084,7 +2108,7 @@ void BytecodeGenerator::VisitFunctionClosureForContext() {
closure_scope->is_module_scope()) {
// Contexts nested in the native context have a canonical empty function as
// their closure, not the anonymous closure containing the global code.
Register native_context = execution_result()->NewRegister();
Register native_context = register_allocator()->NewRegister();
builder()
->LoadContextSlot(execution_context()->reg(),
Context::NATIVE_CONTEXT_INDEX)

View File

@ -23,8 +23,9 @@ class BytecodeGenerator final : public AstVisitor {
AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT
// Visiting function for declarations list is overridden.
// Visiting function for declarations list and statements are overridden.
void VisitDeclarations(ZoneList<Declaration*>* declarations) override;
void VisitStatements(ZoneList<Statement*>* statments) override;
private:
class ContextScope;
@ -35,6 +36,7 @@ class BytecodeGenerator final : public AstVisitor {
class EffectResultScope;
class AccumulatorResultScope;
class RegisterResultScope;
class RegisterAllocationScope;
void MakeBytecodeBody();
Register NextContextRegister() const;
@ -118,6 +120,13 @@ class BytecodeGenerator final : public AstVisitor {
execution_result_ = execution_result;
}
ExpressionResultScope* execution_result() const { return execution_result_; }
inline void set_register_allocator(
RegisterAllocationScope* register_allocator) {
register_allocator_ = register_allocator;
}
RegisterAllocationScope* register_allocator() const {
return register_allocator_;
}
ZoneVector<Handle<Object>>* globals() { return &globals_; }
inline LanguageMode language_mode() const;
@ -133,6 +142,7 @@ class BytecodeGenerator final : public AstVisitor {
ControlScope* execution_control_;
ContextScope* execution_context_;
ExpressionResultScope* execution_result_;
RegisterAllocationScope* register_allocator_;
};
} // namespace interpreter

View File

@ -0,0 +1,72 @@
// 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 {
BytecodeRegisterAllocator::BytecodeRegisterAllocator(
BytecodeArrayBuilder* builder)
: builder_(builder),
allocated_(builder->zone()),
next_consecutive_register_(-1),
next_consecutive_count_(-1) {}
BytecodeRegisterAllocator::~BytecodeRegisterAllocator() {
for (auto i = allocated_.rbegin(); i != allocated_.rend(); i++) {
builder_->ReturnTemporaryRegister(*i);
}
allocated_.clear();
}
Register BytecodeRegisterAllocator::NewRegister() {
int allocated = -1;
if (next_consecutive_count_ <= 0) {
allocated = builder_->BorrowTemporaryRegister();
} else {
allocated = builder_->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_ =
builder_->PrepareForConsecutiveTemporaryRegisters(count);
next_consecutive_count_ = static_cast<int>(count);
}
}
Register BytecodeRegisterAllocator::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
} // namespace internal
} // namespace v8

View File

@ -0,0 +1,49 @@
// 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.
#ifndef V8_INTERPRETER_BYTECODE_REGISTER_ALLOCATOR_H_
#define V8_INTERPRETER_BYTECODE_REGISTER_ALLOCATOR_H_
#include "src/zone-containers.h"
namespace v8 {
namespace internal {
namespace interpreter {
class BytecodeArrayBuilder;
class Register;
// A class than allows the instantiator to allocate temporary registers that are
// cleaned up when scope is closed.
class BytecodeRegisterAllocator {
public:
explicit BytecodeRegisterAllocator(BytecodeArrayBuilder* builder);
~BytecodeRegisterAllocator();
Register NewRegister();
void PrepareForConsecutiveAllocations(size_t count);
Register NextConsecutiveRegister();
bool RegisterIsAllocatedInThisScope(Register reg) const;
bool HasConsecutiveAllocations() const { return next_consecutive_count_ > 0; }
private:
void* operator new(size_t size);
void operator delete(void* p);
BytecodeArrayBuilder* builder_;
ZoneVector<int> allocated_;
int next_consecutive_register_;
int next_consecutive_count_;
DISALLOW_COPY_AND_ASSIGN(BytecodeRegisterAllocator);
};
} // namespace interpreter
} // namespace internal
} // namespace v8
#endif // V8_INTERPRETER_BYTECODE_REGISTER_ALLOCATOR_H_

View File

@ -5317,7 +5317,7 @@ TEST(ForIn) {
" if (x['a'] == 10) continue;\n"
" if (x['a'] == 20) break;\n"
"}",
9 * kPointerSize,
8 * kPointerSize,
1,
94,
{
@ -5344,17 +5344,17 @@ TEST(ForIn) {
B(Ldar), R(0), //
B(Star), R(6), //
B(LoadICSloppy), R(6), U8(2), U8(vector->GetIndex(slot2)), //
B(Star), R(8), //
B(Star), R(7), //
B(LdaSmi8), U8(10), //
B(TestEqual), R(8), //
B(TestEqual), R(7), //
B(JumpIfFalse), U8(4), //
B(Jump), U8(20), //
B(Ldar), R(0), //
B(Star), R(6), //
B(LoadICSloppy), R(6), U8(2), U8(vector->GetIndex(slot3)), //
B(Star), R(8), //
B(Star), R(7), //
B(LdaSmi8), U8(20), //
B(TestEqual), R(8), //
B(TestEqual), R(7), //
B(JumpIfFalse), U8(4), //
B(Jump), U8(8), //
B(ForInStep), R(5), //

View File

@ -2231,6 +2231,19 @@ TEST(InterpreterCountOperators) {
handle(Smi::FromInt(3), isolate)),
std::make_pair("var a = 1; (function() { a = 2 })(); return a--;",
handle(Smi::FromInt(2), isolate)),
std::make_pair("var i = 5; while(i--) {}; return i;",
handle(Smi::FromInt(-1), isolate)),
std::make_pair("var i = 1; if(i--) { return 1; } else { return 2; };",
handle(Smi::FromInt(1), isolate)),
std::make_pair("var i = -2; do {} while(i++) {}; return i;",
handle(Smi::FromInt(1), isolate)),
std::make_pair("var i = -1; for(; i++; ) {}; return i",
handle(Smi::FromInt(1), isolate)),
std::make_pair("var i = 20; switch(i++) {\n"
" case 20: return 1;\n"
" default: return 2;\n"
"}",
handle(Smi::FromInt(1), isolate)),
};
for (size_t i = 0; i < arraysize(count_ops); i++) {

View File

@ -765,7 +765,6 @@
'break': [SKIP],
'call-runtime-tail': [SKIP],
'compiler/compare-map-elim2': [SKIP],
'compiler/countoperation': [SKIP],
'compiler/deopt-inlined-smi': [SKIP],
'compiler/deopt-tonumber-compare': [SKIP],
'compiler/escape-analysis-arguments': [SKIP],
@ -782,8 +781,6 @@
'compiler/optimize_min': [SKIP],
'compiler/opt-next-call-turbo': [SKIP],
'compiler/osr-forof': [SKIP],
'compiler/osr-manual2': [SKIP],
'compiler/phi-representations': [SKIP],
'compiler/property-refs': [SKIP],
'compiler/regress-3786': [SKIP],
'compiler/regress-446647': [SKIP],
@ -851,7 +848,6 @@
'regress/regress-117409': [SKIP],
'regress/regress-1177809': [SKIP],
'regress/regress-119609': [SKIP],
'regress/regress-1209': [SKIP],
'regress/regress-123919': [SKIP],
'regress/regress-124594': [SKIP],
'regress/regress-125515': [SKIP],
@ -882,7 +878,6 @@
'regress/regress-2318': [SKIP],
'regress/regress-2339': [SKIP],
'regress/regress-2374': [SKIP],
'regress/regress-2444': [SKIP],
'regress/regress-2593': [SKIP],
'regress/regress-2618': [SKIP],
'regress/regress-263': [SKIP],
@ -890,7 +885,6 @@
'regress/regress-269': [SKIP],
'regress/regress-2790': [SKIP],
'regress/regress-2825': [SKIP],
'regress/regress-298269': [SKIP],
'regress/regress-3135': [SKIP],
'regress/regress-3138': [SKIP],
'regress/regress-318420': [SKIP],

View File

@ -6,6 +6,7 @@
#include "src/interpreter/bytecode-array-builder.h"
#include "src/interpreter/bytecode-array-iterator.h"
#include "src/interpreter/bytecode-register-allocator.h"
#include "test/unittests/test-utils.h"
namespace v8 {
@ -317,7 +318,7 @@ TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) {
builder.set_locals_count(locals);
builder.set_context_count(contexts);
TemporaryRegisterScope temporaries(&builder);
BytecodeRegisterAllocator temporaries(&builder);
for (int i = 0; i < temps; i++) {
builder.StoreAccumulatorInRegister(temporaries.NewRegister());
}
@ -332,32 +333,6 @@ TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) {
}
TEST_F(BytecodeArrayBuilderTest, TemporariesRecycled) {
BytecodeArrayBuilder builder(isolate(), zone());
builder.set_parameter_count(0);
builder.set_locals_count(0);
builder.set_context_count(0);
builder.Return();
int first;
{
TemporaryRegisterScope temporaries(&builder);
first = temporaries.NewRegister().index();
temporaries.NewRegister();
temporaries.NewRegister();
temporaries.NewRegister();
}
int second;
{
TemporaryRegisterScope temporaries(&builder);
second = temporaries.NewRegister().index();
}
CHECK_EQ(first, second);
}
TEST_F(BytecodeArrayBuilderTest, RegisterValues) {
int index = 1;
uint8_t operand = static_cast<uint8_t>(-index);
@ -391,15 +366,15 @@ TEST_F(BytecodeArrayBuilderTest, RegisterType) {
builder.set_locals_count(3);
builder.set_context_count(0);
TemporaryRegisterScope temporary_register_scope(&builder);
Register temp0 = temporary_register_scope.NewRegister();
BytecodeRegisterAllocator register_allocator(&builder);
Register temp0 = register_allocator.NewRegister();
Register param0(builder.Parameter(0));
Register param9(builder.Parameter(9));
Register temp1 = temporary_register_scope.NewRegister();
Register temp1 = register_allocator.NewRegister();
Register reg0(0);
Register reg1(1);
Register reg2(2);
Register temp2 = temporary_register_scope.NewRegister();
Register temp2 = register_allocator.NewRegister();
CHECK_EQ(builder.RegisterIsParameterOrLocal(temp0), false);
CHECK_EQ(builder.RegisterIsParameterOrLocal(temp1), false);
CHECK_EQ(builder.RegisterIsParameterOrLocal(temp2), false);

View File

@ -0,0 +1,67 @@
// Copyright 2014 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/v8.h"
#include "src/interpreter/bytecode-array-builder.h"
#include "src/interpreter/bytecode-register-allocator.h"
#include "test/unittests/test-utils.h"
namespace v8 {
namespace internal {
namespace interpreter {
class BytecodeRegisterAllocatorTest : public TestWithIsolateAndZone {
public:
BytecodeRegisterAllocatorTest() {}
~BytecodeRegisterAllocatorTest() override {}
};
TEST_F(BytecodeRegisterAllocatorTest, TemporariesRecycled) {
BytecodeArrayBuilder builder(isolate(), zone());
builder.set_parameter_count(0);
builder.set_locals_count(0);
builder.set_context_count(0);
int first;
{
BytecodeRegisterAllocator temporaries(&builder);
first = temporaries.NewRegister().index();
temporaries.NewRegister();
temporaries.NewRegister();
temporaries.NewRegister();
}
int second;
{
BytecodeRegisterAllocator temporaries(&builder);
second = temporaries.NewRegister().index();
}
CHECK_EQ(first, second);
}
TEST_F(BytecodeRegisterAllocatorTest, ConsecutiveRegisters) {
BytecodeArrayBuilder builder(isolate(), zone());
builder.set_parameter_count(0);
builder.set_locals_count(0);
builder.set_context_count(0);
BytecodeRegisterAllocator temporaries(&builder);
temporaries.PrepareForConsecutiveAllocations(4);
Register reg0 = temporaries.NextConsecutiveRegister();
Register other = temporaries.NewRegister();
Register reg1 = temporaries.NextConsecutiveRegister();
Register reg2 = temporaries.NextConsecutiveRegister();
Register reg3 = temporaries.NextConsecutiveRegister();
USE(other);
CHECK(Register::AreContiguous(reg0, reg1, reg2, reg3));
}
} // namespace interpreter
} // namespace internal
} // namespace v8

View File

@ -97,6 +97,7 @@
'interpreter/bytecodes-unittest.cc',
'interpreter/bytecode-array-builder-unittest.cc',
'interpreter/bytecode-array-iterator-unittest.cc',
'interpreter/bytecode-register-allocator-unittest.cc',
'interpreter/constant-array-builder-unittest.cc',
'libplatform/default-platform-unittest.cc',
'libplatform/task-queue-unittest.cc',

View File

@ -863,6 +863,8 @@
'../../src/interpreter/bytecode-array-builder.h',
'../../src/interpreter/bytecode-array-iterator.cc',
'../../src/interpreter/bytecode-array-iterator.h',
'../../src/interpreter/bytecode-register-allocator.cc',
'../../src/interpreter/bytecode-register-allocator.h',
'../../src/interpreter/bytecode-generator.cc',
'../../src/interpreter/bytecode-generator.h',
'../../src/interpreter/bytecode-traits.h',