diff options
Diffstat (limited to 'deps/v8/src/interpreter/bytecode-generator.cc')
-rw-r--r-- | deps/v8/src/interpreter/bytecode-generator.cc | 705 |
1 files changed, 359 insertions, 346 deletions
diff --git a/deps/v8/src/interpreter/bytecode-generator.cc b/deps/v8/src/interpreter/bytecode-generator.cc index 02061a7514..959e155149 100644 --- a/deps/v8/src/interpreter/bytecode-generator.cc +++ b/deps/v8/src/interpreter/bytecode-generator.cc @@ -4,12 +4,13 @@ #include "src/interpreter/bytecode-generator.h" +#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/parser.h" -#include "src/scopes.h" -#include "src/token.h" +#include "src/parsing/parser.h" +#include "src/parsing/token.h" namespace v8 { namespace internal { @@ -104,65 +105,65 @@ class BytecodeGenerator::ControlScope BASE_EMBEDDED { }; -// Scoped class for enabling 'break' and 'continue' in iteration -// constructs, e.g. do...while, while..., for... -class BytecodeGenerator::ControlScopeForIteration +// Scoped class for enabling break inside blocks and switch blocks. +class BytecodeGenerator::ControlScopeForBreakable final : public BytecodeGenerator::ControlScope { public: - ControlScopeForIteration(BytecodeGenerator* generator, - IterationStatement* statement, - LoopBuilder* loop_builder) + ControlScopeForBreakable(BytecodeGenerator* generator, + BreakableStatement* statement, + BreakableControlFlowBuilder* control_builder) : ControlScope(generator), statement_(statement), - loop_builder_(loop_builder) {} + control_builder_(control_builder) {} protected: virtual bool Execute(Command command, Statement* statement) { if (statement != statement_) return false; switch (command) { case CMD_BREAK: - loop_builder_->Break(); + control_builder_->Break(); return true; case CMD_CONTINUE: - loop_builder_->Continue(); - return true; + break; } return false; } private: Statement* statement_; - LoopBuilder* loop_builder_; + BreakableControlFlowBuilder* control_builder_; }; -// Scoped class for enabling 'break' in switch statements. -class BytecodeGenerator::ControlScopeForSwitch +// Scoped class for enabling 'break' and 'continue' in iteration +// constructs, e.g. do...while, while..., for... +class BytecodeGenerator::ControlScopeForIteration final : public BytecodeGenerator::ControlScope { public: - ControlScopeForSwitch(BytecodeGenerator* generator, - SwitchStatement* statement, - SwitchBuilder* switch_builder) + ControlScopeForIteration(BytecodeGenerator* generator, + IterationStatement* statement, + LoopBuilder* loop_builder) : ControlScope(generator), statement_(statement), - switch_builder_(switch_builder) {} + loop_builder_(loop_builder) {} protected: virtual bool Execute(Command command, Statement* statement) { if (statement != statement_) return false; switch (command) { case CMD_BREAK: - switch_builder_->Break(); + loop_builder_->Break(); return true; case CMD_CONTINUE: - break; + loop_builder_->Continue(); + return true; } return false; } private: Statement* statement_; - SwitchBuilder* switch_builder_; + LoopBuilder* loop_builder_; }; @@ -177,6 +178,63 @@ void BytecodeGenerator::ControlScope::PerformCommand(Command command, } +class BytecodeGenerator::RegisterAllocationScope { + public: + explicit RegisterAllocationScope(BytecodeGenerator* generator) + : generator_(generator), + outer_(generator->register_allocator()), + allocator_(builder()) { + generator_->set_register_allocator(this); + } + + virtual ~RegisterAllocationScope() { + generator_->set_register_allocator(outer_); + } + + Register NewRegister() { + RegisterAllocationScope* current_scope = generator()->register_allocator(); + if ((current_scope == this) || + (current_scope->outer() == this && + !current_scope->allocator_.HasConsecutiveAllocations())) { + // Regular case - Allocating registers in current or outer context. + // VisitForRegisterValue allocates register in outer context. + return allocator_.NewRegister(); + } else { + // If it is required to allocate a register other than current or outer + // scopes, allocate a new temporary register. It might be expensive to + // walk the full context chain and compute the list of consecutive + // reservations in the innerscopes. + UNIMPLEMENTED(); + return Register(-1); + } + } + + void PrepareForConsecutiveAllocations(size_t count) { + allocator_.PrepareForConsecutiveAllocations(count); + } + + Register NextConsecutiveRegister() { + 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 { @@ -185,7 +243,7 @@ class BytecodeGenerator::ExpressionResultScope { : generator_(generator), kind_(kind), outer_(generator->execution_result()), - allocator_(builder()), + allocator_(generator), result_identified_(false) { generator_->set_execution_result(this); } @@ -201,21 +259,11 @@ class BytecodeGenerator::ExpressionResultScope { virtual void SetResultInAccumulator() = 0; virtual void SetResultInRegister(Register reg) = 0; - BytecodeGenerator* generator() const { return generator_; } - BytecodeArrayBuilder* builder() const { return generator()->builder(); } + protected: ExpressionResultScope* outer() const { return outer_; } + BytecodeArrayBuilder* builder() const { return generator_->builder(); } + const RegisterAllocationScope* allocator() const { return &allocator_; } - 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; @@ -223,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); @@ -277,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(); } @@ -307,15 +353,11 @@ BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone) execution_control_(nullptr), execution_context_(nullptr), execution_result_(nullptr), - binary_expression_depth_(0), - binary_expression_hazard_set_(zone) { + register_allocator_(nullptr) { InitializeAstVisitor(isolate); } -BytecodeGenerator::~BytecodeGenerator() {} - - Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) { set_info(info); set_scope(info->scope()); @@ -348,6 +390,12 @@ void BytecodeGenerator::MakeBytecodeBody() { // Build the arguments object if it is used. VisitArgumentsObject(scope()->arguments()); + // TODO(mythria): Build rest arguments array if it is used. + int rest_index; + if (scope()->rest_parameter(&rest_index)) { + UNIMPLEMENTED(); + } + // Build assignment to {.this_function} variable if it is used. VisitThisFunctionVariable(scope()->this_function_var()); @@ -374,6 +422,9 @@ void BytecodeGenerator::MakeBytecodeBody() { void BytecodeGenerator::VisitBlock(Block* stmt) { + BlockBuilder block_builder(this->builder()); + ControlScopeForBreakable execution_control(this, stmt, &block_builder); + if (stmt->scope() == NULL) { // Visit statements in the same scope, no declarations. VisitStatements(stmt->statements()); @@ -389,6 +440,7 @@ void BytecodeGenerator::VisitBlock(Block* stmt) { VisitStatements(stmt->statements()); } } + if (stmt->labels() != nullptr) block_builder.EndBlock(); } @@ -479,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; @@ -490,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); @@ -505,9 +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) { - // TODO(rmcilroy): Replace this with a StatementResultScope when it exists. - EffectResultScope effect_scope(this); VisitForEffect(stmt->expression()); } @@ -519,14 +580,17 @@ void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) { void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) { BytecodeLabel else_label, end_label; if (stmt->condition()->ToBooleanIsTrue()) { - // Generate only then block. + // Generate then block unconditionally as always true. Visit(stmt->then_statement()); } else if (stmt->condition()->ToBooleanIsFalse()) { - // Generate only else block if it exists. + // Generate else block unconditionally if it exists. if (stmt->HasElseStatement()) { Visit(stmt->else_statement()); } } else { + // TODO(oth): If then statement is BreakStatement or + // ContinueStatement we can reduce number of generated + // jump/jump_ifs here. See BasicLoops test. VisitForAccumulatorValue(stmt->condition()); builder()->JumpIfFalse(&else_label); Visit(stmt->then_statement()); @@ -559,7 +623,6 @@ void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) { void BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { - EffectResultScope effect_scope(this); VisitForAccumulatorValue(stmt->expression()); builder()->Return(); } @@ -571,9 +634,11 @@ 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. ZoneList<CaseClause*>* clauses = stmt->cases(); SwitchBuilder switch_builder(builder(), clauses->length()); - ControlScopeForSwitch scope(this, stmt, &switch_builder); + ControlScopeForBreakable scope(this, stmt, &switch_builder); int default_index = -1; // Keep the switch value in a register until a case matches. @@ -627,96 +692,70 @@ void BytecodeGenerator::VisitCaseClause(CaseClause* clause) { void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { LoopBuilder loop_builder(builder()); ControlScopeForIteration execution_control(this, stmt, &loop_builder); - BytecodeLabel body_label, condition_label, done_label; - + loop_builder.LoopHeader(); if (stmt->cond()->ToBooleanIsFalse()) { Visit(stmt->body()); - // Bind condition_label and done_label for processing continue and break. - builder()->Bind(&condition_label); - builder()->Bind(&done_label); + loop_builder.Condition(); + } else if (stmt->cond()->ToBooleanIsTrue()) { + loop_builder.Condition(); + Visit(stmt->body()); + loop_builder.JumpToHeader(); } else { - builder()->Bind(&body_label); Visit(stmt->body()); - - builder()->Bind(&condition_label); - if (stmt->cond()->ToBooleanIsTrue()) { - builder()->Jump(&body_label); - } else { - VisitForAccumulatorValue(stmt->cond()); - builder()->JumpIfTrue(&body_label); - } - builder()->Bind(&done_label); + loop_builder.Condition(); + VisitForAccumulatorValue(stmt->cond()); + loop_builder.JumpToHeaderIfTrue(); } - loop_builder.SetBreakTarget(done_label); - loop_builder.SetContinueTarget(condition_label); + loop_builder.EndLoop(); } void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) { - LoopBuilder loop_builder(builder()); - ControlScopeForIteration execution_control(this, stmt, &loop_builder); - - BytecodeLabel body_label, condition_label, done_label; if (stmt->cond()->ToBooleanIsFalse()) { - // If the condition is false there is no need to generating the loop. + // If the condition is false there is no need to generate the loop. return; } + LoopBuilder loop_builder(builder()); + ControlScopeForIteration execution_control(this, stmt, &loop_builder); + loop_builder.LoopHeader(); + loop_builder.Condition(); if (!stmt->cond()->ToBooleanIsTrue()) { - builder()->Jump(&condition_label); - } - builder()->Bind(&body_label); - Visit(stmt->body()); - - builder()->Bind(&condition_label); - if (stmt->cond()->ToBooleanIsTrue()) { - builder()->Jump(&body_label); - } else { VisitForAccumulatorValue(stmt->cond()); - builder()->JumpIfTrue(&body_label); + loop_builder.BreakIfFalse(); } - builder()->Bind(&done_label); - - loop_builder.SetBreakTarget(done_label); - loop_builder.SetContinueTarget(condition_label); + Visit(stmt->body()); + loop_builder.JumpToHeader(); + loop_builder.EndLoop(); } void BytecodeGenerator::VisitForStatement(ForStatement* stmt) { - LoopBuilder loop_builder(builder()); - ControlScopeForIteration execution_control(this, stmt, &loop_builder); - if (stmt->init() != nullptr) { Visit(stmt->init()); } - if (stmt->cond() && stmt->cond()->ToBooleanIsFalse()) { // If the condition is known to be false there is no need to generate // body, next or condition blocks. Init block should be generated. return; } - BytecodeLabel body_label, condition_label, next_label, done_label; + LoopBuilder loop_builder(builder()); + ControlScopeForIteration execution_control(this, stmt, &loop_builder); + + loop_builder.LoopHeader(); + loop_builder.Condition(); if (stmt->cond() && !stmt->cond()->ToBooleanIsTrue()) { - builder()->Jump(&condition_label); + VisitForAccumulatorValue(stmt->cond()); + loop_builder.BreakIfFalse(); } - builder()->Bind(&body_label); Visit(stmt->body()); - builder()->Bind(&next_label); if (stmt->next() != nullptr) { + loop_builder.Next(); Visit(stmt->next()); } - if (stmt->cond() && !stmt->cond()->ToBooleanIsTrue()) { - builder()->Bind(&condition_label); - VisitForAccumulatorValue(stmt->cond()); - builder()->JumpIfTrue(&body_label); - } else { - builder()->Jump(&body_label); - } - builder()->Bind(&done_label); - - loop_builder.SetBreakTarget(done_label); - loop_builder.SetContinueTarget(next_label); + loop_builder.JumpToHeader(); + loop_builder.EndLoop(); } @@ -735,19 +774,19 @@ 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()); - size_t name_index = builder()->GetConstantPoolEntry( - property->key()->AsLiteral()->AsPropertyName()); - builder()->StoreNamedProperty(object, name_index, feedback_index(slot), + Handle<String> name = property->key()->AsLiteral()->AsPropertyName(); + builder()->LoadAccumulatorWithRegister(value); + builder()->StoreNamedProperty(object, name, feedback_index(slot), language_mode()); 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,12 +803,6 @@ void BytecodeGenerator::VisitForInAssignment(Expression* expr, void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) { - // TODO(oth): For now we need a parent scope for paths that end up - // in VisitLiteral which can allocate in the parent scope. A future - // CL in preparation will add a StatementResultScope that will - // remove the need for this EffectResultScope. - EffectResultScope result_scope(this); - if (stmt->subject()->IsNullLiteral() || stmt->subject()->IsUndefinedLiteral(isolate())) { // ForIn generates lots of code, skip if it wouldn't produce any effects. @@ -778,58 +811,43 @@ void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) { LoopBuilder loop_builder(builder()); ControlScopeForIteration control_scope(this, stmt, &loop_builder); + BytecodeLabel subject_null_label, subject_undefined_label, not_object_label; // Prepare the state for executing ForIn. VisitForAccumulatorValue(stmt->subject()); - loop_builder.BreakIfUndefined(); - loop_builder.BreakIfNull(); - - Register receiver = execution_result()->NewRegister(); + builder()->JumpIfUndefined(&subject_undefined_label); + builder()->JumpIfNull(&subject_null_label); + Register receiver = register_allocator()->NewRegister(); builder()->CastAccumulatorToJSObject(); + builder()->JumpIfNull(¬_object_label); builder()->StoreAccumulatorInRegister(receiver); - builder()->CallRuntime(Runtime::kGetPropertyNamesFast, receiver, 1); - builder()->ForInPrepare(receiver); - loop_builder.BreakIfUndefined(); + 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); - Register for_in_state = execution_result()->NewRegister(); - builder()->StoreAccumulatorInRegister(for_in_state); - - // The loop. - BytecodeLabel condition_label, break_label, continue_label; - Register index = receiver; // Re-using register as receiver no longer used. + // Set up loop counter + Register index = register_allocator()->NewRegister(); builder()->LoadLiteral(Smi::FromInt(0)); + builder()->StoreAccumulatorInRegister(index); - // Check loop termination (accumulator holds index). - builder() - ->Bind(&condition_label) - .StoreAccumulatorInRegister(index) - .ForInDone(for_in_state); + // The loop + loop_builder.LoopHeader(); + loop_builder.Condition(); + builder()->ForInDone(index, cache_length); loop_builder.BreakIfTrue(); - - // Get the next item. - builder()->ForInNext(for_in_state, index); - - // Start again if the item, currently in the accumulator, is undefined. + builder()->ForInNext(receiver, cache_type, cache_array, index); loop_builder.ContinueIfUndefined(); - - // Store the value in the each variable. VisitForInAssignment(stmt->each(), stmt->EachFeedbackSlot()); - // NB the user's loop variable will be assigned the value of each so - // even an empty body will have this assignment. Visit(stmt->body()); - - // Increment the index and start loop again. - builder() - ->Bind(&continue_label) - .LoadAccumulatorWithRegister(index) - .CountOperation(Token::Value::ADD, language_mode_strength()) - .Jump(&condition_label); - - // End of the loop. - builder()->Bind(&break_label); - - loop_builder.SetBreakTarget(break_label); - loop_builder.SetContinueTarget(continue_label); + loop_builder.Next(); + builder()->ForInStep(index); + builder()->StoreAccumulatorInRegister(index); + loop_builder.JumpToHeader(); + loop_builder.EndLoop(); + builder()->Bind(¬_object_label); + builder()->Bind(&subject_null_label); + builder()->Bind(&subject_undefined_label); } @@ -867,10 +885,8 @@ void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { Handle<SharedFunctionInfo> shared_info = Compiler::GetSharedFunctionInfo(expr, info()->script(), info()); CHECK(!shared_info.is_null()); // TODO(rmcilroy): Set stack overflow? - - builder() - ->LoadLiteral(shared_info) - .CreateClosure(expr->pretenure() ? TENURED : NOT_TENURED); + builder()->CreateClosure(shared_info, + expr->pretenure() ? TENURED : NOT_TENURED); execution_result()->SetResultInAccumulator(); } @@ -937,24 +953,17 @@ void BytecodeGenerator::VisitLiteral(Literal* expr) { void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { // Materialize a regular expression literal. - TemporaryRegisterScope temporary_register_scope(builder()); - Register flags = temporary_register_scope.NewRegister(); - builder() - ->LoadLiteral(expr->flags()) - .StoreAccumulatorInRegister(flags) - .LoadLiteral(expr->pattern()) - .CreateRegExpLiteral(expr->literal_index(), flags); + builder()->CreateRegExpLiteral(expr->pattern(), expr->literal_index(), + expr->flags()); execution_result()->SetResultInAccumulator(); } void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { // Deep-copy the literal boilerplate. - builder() - ->LoadLiteral(expr->constant_properties()) - .CreateObjectLiteral(expr->literal_index(), expr->ComputeFlags(true)); - - TemporaryRegisterScope temporary_register_scope(builder()); + builder()->CreateObjectLiteral(expr->constant_properties(), + expr->literal_index(), + expr->ComputeFlags(true)); Register literal; // Store computed values into the literal. @@ -962,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: @@ -985,26 +994,21 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { // contains computed properties with an uninitialized value. if (literal_key->value()->IsInternalizedString()) { if (property->emit_store()) { - size_t name_index = - builder()->GetConstantPoolEntry(literal_key->AsPropertyName()); VisitForAccumulatorValue(property->value()); - builder()->StoreNamedProperty(literal, name_index, - feedback_index(property->GetSlot(0)), - language_mode()); + builder()->StoreNamedProperty( + literal, literal_key->AsPropertyName(), + feedback_index(property->GetSlot(0)), language_mode()); } else { 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); @@ -1021,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( @@ -1048,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); @@ -1075,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( @@ -1095,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()); @@ -1144,11 +1144,9 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { // Deep-copy the literal boilerplate. - builder() - ->LoadLiteral(expr->constant_elements()) - .CreateArrayLiteral(expr->literal_index(), expr->ComputeFlags(true)); - - TemporaryRegisterScope temporary_register_scope(builder()); + builder()->CreateArrayLiteral(expr->constant_elements(), + expr->literal_index(), + expr->ComputeFlags(true)); Register index, literal; // Evaluate all the non-constant subexpressions and store them into the @@ -1164,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; } @@ -1198,21 +1196,22 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable, switch (variable->location()) { case VariableLocation::LOCAL: { Register source(Register(variable->index())); - execution_result()->SetResultInRegister(source); + builder()->LoadAccumulatorWithRegister(source); + execution_result()->SetResultInAccumulator(); 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); - execution_result()->SetResultInRegister(source); + builder()->LoadAccumulatorWithRegister(source); + execution_result()->SetResultInAccumulator(); break; } case VariableLocation::GLOBAL: case VariableLocation::UNALLOCATED: { - size_t name_index = builder()->GetConstantPoolEntry(variable->name()); - builder()->LoadGlobal(name_index, feedback_index(slot), language_mode(), - typeof_mode); + builder()->LoadGlobal(variable->name(), feedback_index(slot), + language_mode(), typeof_mode); execution_result()->SetResultInAccumulator(); break; } @@ -1223,10 +1222,12 @@ 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. + // TODO(mythria): Also update bytecode graph builder with correct depth + // when this changes. builder() ->LoadAccumulatorWithRegister(execution_context()->reg()) .StoreAccumulatorInRegister(context_reg); @@ -1242,8 +1243,11 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable, // let variables. break; } - case VariableLocation::LOOKUP: - UNIMPLEMENTED(); + case VariableLocation::LOOKUP: { + builder()->LoadLookupSlot(variable->name(), typeof_mode); + execution_result()->SetResultInAccumulator(); + break; + } } } @@ -1270,7 +1274,6 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable, // TODO(rmcilroy): support const mode initialization. Register destination(variable->index()); builder()->StoreAccumulatorInRegister(destination); - RecordStoreToRegister(destination); break; } case VariableLocation::PARAMETER: { @@ -1278,13 +1281,12 @@ 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: case VariableLocation::UNALLOCATED: { - size_t name_index = builder()->GetConstantPoolEntry(variable->name()); - builder()->StoreGlobal(name_index, feedback_index(slot), language_mode()); + builder()->StoreGlobal(variable->name(), feedback_index(slot), + language_mode()); break; } case VariableLocation::CONTEXT: { @@ -1295,11 +1297,13 @@ 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. + // TODO(mythria): Also update bytecode graph builder with correct depth + // when this changes. builder() ->StoreAccumulatorInRegister(value_temp) .LoadAccumulatorWithRegister(execution_context()->reg()) @@ -1314,8 +1318,10 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable, builder()->StoreContextSlot(context_reg, variable->index()); break; } - case VariableLocation::LOOKUP: - UNIMPLEMENTED(); + case VariableLocation::LOOKUP: { + builder()->StoreLookupSlot(variable->name(), language_mode()); + break; + } } } @@ -1323,7 +1329,7 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable, void BytecodeGenerator::VisitAssignment(Assignment* expr) { DCHECK(expr->target()->IsValidReferenceExpression()); Register object, key; - size_t name_index = kMaxUInt32; + Handle<String> name; // Left-hand side can only be a property, a global or a variable slot. Property* property = expr->target()->AsProperty(); @@ -1336,8 +1342,7 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) { break; case NAMED_PROPERTY: { object = VisitForRegisterValue(property->obj()); - name_index = builder()->GetConstantPoolEntry( - property->key()->AsLiteral()->AsPropertyName()); + name = property->key()->AsLiteral()->AsPropertyName(); break; } case KEYED_PROPERTY: { @@ -1345,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 { @@ -1371,9 +1376,9 @@ 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_index, feedback_index(slot), + ->LoadNamedProperty(object, name, feedback_index(slot), language_mode()) .StoreAccumulatorInRegister(old_value); break; @@ -1382,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); @@ -1411,7 +1416,7 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) { break; } case NAMED_PROPERTY: - builder()->StoreNamedProperty(object, name_index, feedback_index(slot), + builder()->StoreNamedProperty(object, name, feedback_index(slot), language_mode()); break; case KEYED_PROPERTY: @@ -1442,10 +1447,9 @@ void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) { case VARIABLE: UNREACHABLE(); case NAMED_PROPERTY: { - size_t name_index = builder()->GetConstantPoolEntry( - expr->key()->AsLiteral()->AsPropertyName()); - builder()->LoadNamedProperty(obj, name_index, feedback_index(slot), - language_mode()); + builder()->LoadNamedProperty(obj, + expr->key()->AsLiteral()->AsPropertyName(), + feedback_index(slot), language_mode()); break; } case KEYED_PROPERTY: { @@ -1489,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()); @@ -1513,14 +1517,15 @@ 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. - Register callee = execution_result()->NewRegister(); // The receiver and arguments need to be allocated consecutively for - // Call(). Future optimizations could avoid this there are no + // Call(). We allocate the callee and receiver consecutively for calls to + // 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() + 1); - 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: @@ -1542,6 +1547,27 @@ void BytecodeGenerator::VisitCall(Call* expr) { builder()->StoreAccumulatorInRegister(callee); break; } + case Call::LOOKUP_SLOT_CALL: + case Call::POSSIBLY_EVAL_CALL: { + if (callee_expr->AsVariableProxy()->var()->IsLookupSlot()) { + 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)); + Variable* variable = callee_expr->AsVariableProxy()->var(); + builder() + ->MoveRegister(Register::function_context(), context) + .LoadLiteral(variable->name()) + .StoreAccumulatorInRegister(name) + .CallRuntimeForPair(Runtime::kLoadLookupSlot, context, 2, callee); + break; + } + // Fall through. + DCHECK_EQ(call_type, Call::POSSIBLY_EVAL_CALL); + } case Call::OTHER_CALL: { builder()->LoadUndefined().StoreAccumulatorInRegister(receiver); VisitForAccumulatorValue(callee_expr); @@ -1550,9 +1576,7 @@ void BytecodeGenerator::VisitCall(Call* expr) { } case Call::NAMED_SUPER_PROPERTY_CALL: case Call::KEYED_SUPER_PROPERTY_CALL: - case Call::LOOKUP_SLOT_CALL: case Call::SUPER_CALL: - case Call::POSSIBLY_EVAL_CALL: UNIMPLEMENTED(); } @@ -1561,15 +1585,45 @@ void BytecodeGenerator::VisitCall(Call* expr) { Register arg = VisitArguments(args); CHECK(args->length() == 0 || arg.index() == receiver.index() + 1); - // TODO(rmcilroy): Deal with possible direct eval here? + // 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) { + 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 + // position. + builder() + ->MoveRegister(callee, callee_for_eval) + .MoveRegister(arg, source) + .MoveRegister(Register::function_closure(), function) + .LoadLiteral(Smi::FromInt(language_mode())) + .StoreAccumulatorInRegister(language) + .LoadLiteral( + Smi::FromInt(execution_context()->scope()->start_position())) + .StoreAccumulatorInRegister(position); + + // Call ResolvePossiblyDirectEval and modify the callee. + builder() + ->CallRuntime(Runtime::kResolvePossiblyDirectEval, callee_for_eval, 5) + .StoreAccumulatorInRegister(callee); + } + // TODO(rmcilroy): Use CallIC to allow call type feedback. - builder()->Call(callee, receiver, args->length()); + builder()->Call(callee, receiver, args->length(), + feedback_index(expr->CallFeedbackICSlot())); execution_result()->SetResultInAccumulator(); } void BytecodeGenerator::VisitCallNew(CallNew* expr) { - Register constructor = execution_result()->NewRegister(); + Register constructor = register_allocator()->NewRegister(); VisitForAccumulatorValue(expr->expression()); builder()->StoreAccumulatorInRegister(constructor); @@ -1585,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. @@ -1596,8 +1650,6 @@ void BytecodeGenerator::VisitCallRuntime(CallRuntime* expr) { DCHECK(args->length() == 0 || first_arg.index() == receiver.index() + 1); builder()->CallJSRuntime(expr->context_index(), receiver, args->length()); } else { - // TODO(rmcilroy): support multiple return values. - DCHECK_LE(expr->function()->result_size, 1); Runtime::FunctionId function_id = expr->function()->function_id; builder()->CallRuntime(function_id, first_arg, args->length()); } @@ -1678,10 +1730,13 @@ void BytecodeGenerator::VisitDelete(UnaryOperation* expr) { case VariableLocation::GLOBAL: case VariableLocation::UNALLOCATED: { // Global var, let, const or variables not explicitly declared. - Register global_object = execution_result()->NewRegister(); + Register native_context = register_allocator()->NewRegister(); + Register global_object = register_allocator()->NewRegister(); builder() ->LoadContextSlot(execution_context()->reg(), - Context::GLOBAL_OBJECT_INDEX) + Context::NATIVE_CONTEXT_INDEX) + .StoreAccumulatorInRegister(native_context) + .LoadContextSlot(native_context, Context::EXTENSION_INDEX) .StoreAccumulatorInRegister(global_object) .LoadLiteral(variable->name()) .Delete(global_object, language_mode()); @@ -1700,7 +1755,7 @@ void BytecodeGenerator::VisitDelete(UnaryOperation* expr) { break; } case VariableLocation::LOOKUP: { - UNIMPLEMENTED(); + builder()->LoadLiteral(variable->name()).DeleteLookupSlot(); break; } default: @@ -1727,7 +1782,7 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) { // Evaluate LHS expression and get old value. Register obj, key, old_value; - size_t name_index = kMaxUInt32; + Handle<String> name; switch (assign_type) { case VARIABLE: { VariableProxy* proxy = expr->expression()->AsVariableProxy(); @@ -1738,9 +1793,8 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) { case NAMED_PROPERTY: { FeedbackVectorSlot slot = property->PropertyFeedbackSlot(); obj = VisitForRegisterValue(property->obj()); - name_index = builder()->GetConstantPoolEntry( - property->key()->AsLiteral()->AsPropertyName()); - builder()->LoadNamedProperty(obj, name_index, feedback_index(slot), + name = property->key()->AsLiteral()->AsPropertyName(); + builder()->LoadNamedProperty(obj, name, feedback_index(slot), language_mode()); break; } @@ -1749,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()); @@ -1767,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); } @@ -1783,8 +1837,8 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) { break; } case NAMED_PROPERTY: { - builder()->StoreNamedProperty( - obj, name_index, feedback_index(feedback_slot), language_mode()); + builder()->StoreNamedProperty(obj, name, feedback_index(feedback_slot), + language_mode()); break; } case KEYED_PROPERTY: { @@ -1825,37 +1879,17 @@ void BytecodeGenerator::VisitBinaryOperation(BinaryOperation* binop) { void BytecodeGenerator::VisitCompareOperation(CompareOperation* 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()->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(); } @@ -1928,15 +1962,21 @@ void BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) { } +void BytecodeGenerator::VisitRewritableAssignmentExpression( + RewritableAssignmentExpression* expr) { + Visit(expr->expression()); +} + + void BytecodeGenerator::VisitNewLocalFunctionContext() { AccumulatorResultScope accumulator_execution_result(this); Scope* scope = this->scope(); // 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()) @@ -1956,7 +1996,12 @@ void BytecodeGenerator::VisitBuildLocalActivationContext() { Scope* scope = this->scope(); if (scope->has_this_declaration() && scope->receiver()->IsContextSlot()) { - UNIMPLEMENTED(); + Variable* variable = scope->receiver(); + Register receiver(builder()->Parameter(0)); + // Context variable (at bottom of the context chain). + DCHECK_EQ(0, scope->ContextChainLength(variable->scope())); + builder()->LoadAccumulatorWithRegister(receiver).StoreContextSlot( + execution_context()->reg(), variable->index()); } // Copy parameters into context if necessary. @@ -1981,10 +2026,10 @@ void BytecodeGenerator::VisitNewLocalBlockContext(Scope* scope) { DCHECK(scope->is_block_scope()); // Allocate a new local block context. - TemporaryRegisterScope temporary_register_scope(builder()); - Register scope_info = temporary_register_scope.NewRegister(); - Register closure = temporary_register_scope.NewRegister(); - DCHECK(Register::AreContiguous(scope_info, closure)); + register_allocator()->PrepareForConsecutiveAllocations(2); + Register scope_info = register_allocator()->NextConsecutiveRegister(); + Register closure = register_allocator()->NextConsecutiveRegister(); + builder() ->LoadLiteral(scope->GetScopeInfo(isolate())) .StoreAccumulatorInRegister(scope_info); @@ -2041,7 +2086,7 @@ void BytecodeGenerator::VisitThisFunctionVariable(Variable* variable) { // TODO(rmcilroy): Remove once we have tests which exercise this code path. UNIMPLEMENTED(); - // Store the closure we were called with in the this_function_var. + // Store the closure we were called with in the given variable. builder()->LoadAccumulatorWithRegister(Register::function_closure()); VisitVariableAssignment(variable, FeedbackVectorSlot::Invalid()); } @@ -2050,8 +2095,8 @@ void BytecodeGenerator::VisitThisFunctionVariable(Variable* variable) { void BytecodeGenerator::VisitNewTargetVariable(Variable* variable) { if (variable == nullptr) return; - // Store the closure we were called with in the this_function_var. - builder()->CallRuntime(Runtime::kGetOriginalConstructor, Register(), 0); + // Store the new target we were called with in the given variable. + builder()->LoadAccumulatorWithRegister(Register::new_target()); VisitVariableAssignment(variable, FeedbackVectorSlot::Invalid()); } @@ -2063,8 +2108,12 @@ 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. - // Pass a SMI sentinel and let the runtime look up the empty function. - builder()->LoadLiteral(Smi::FromInt(0)); + Register native_context = register_allocator()->NewRegister(); + builder() + ->LoadContextSlot(execution_context()->reg(), + Context::NATIVE_CONTEXT_INDEX) + .StoreAccumulatorInRegister(native_context) + .LoadContextSlot(native_context, Context::CLOSURE_INDEX); } else { DCHECK(closure_scope->is_function_scope()); builder()->LoadAccumulatorWithRegister(Register::function_closure()); @@ -2073,13 +2122,6 @@ 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); @@ -2103,35 +2145,6 @@ Register BytecodeGenerator::VisitForRegisterValue(Expression* expr) { } -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. |