diff --git a/src/compiler/bytecode-graph-builder.cc b/src/compiler/bytecode-graph-builder.cc index a0bf78b9a1..456e393f76 100644 --- a/src/compiler/bytecode-graph-builder.cc +++ b/src/compiler/bytecode-graph-builder.cc @@ -273,6 +273,12 @@ void BytecodeGraphBuilder::VisitLdaContextSlot( } +void BytecodeGraphBuilder::VisitStaContextSlot( + const interpreter::BytecodeArrayIterator& iterator) { + UNIMPLEMENTED(); +} + + void BytecodeGraphBuilder::VisitLoadICSloppy( const interpreter::BytecodeArrayIterator& iterator) { UNIMPLEMENTED(); diff --git a/src/compiler/interpreter-assembler.cc b/src/compiler/interpreter-assembler.cc index 47c24a4cee..9173fedc27 100644 --- a/src/compiler/interpreter-assembler.cc +++ b/src/compiler/interpreter-assembler.cc @@ -305,6 +305,15 @@ Node* InterpreterAssembler::LoadContextSlot(Node* context, Node* slot_index) { } +Node* InterpreterAssembler::StoreContextSlot(Node* context, Node* slot_index, + Node* value) { + Node* offset = + IntPtrAdd(WordShl(slot_index, kPointerSizeLog2), + Int32Constant(Context::kHeaderSize - kHeapObjectTag)); + return raw_assembler_->Store(kMachAnyTagged, context, offset, value); +} + + Node* InterpreterAssembler::LoadTypeFeedbackVector() { Node* function = raw_assembler_->Load( kMachAnyTagged, RegisterFileRawPointer(), diff --git a/src/compiler/interpreter-assembler.h b/src/compiler/interpreter-assembler.h index e49f9e919d..db1e004400 100644 --- a/src/compiler/interpreter-assembler.h +++ b/src/compiler/interpreter-assembler.h @@ -97,6 +97,8 @@ class InterpreterAssembler { // Load |slot_index| from |context|. Node* LoadContextSlot(Node* context, Node* slot_index); + // Stores |value| into |slot_index| of |context|. + Node* StoreContextSlot(Node* context, Node* slot_index, Node* value); // Load the TypeFeedbackVector for the current function. Node* LoadTypeFeedbackVector(); diff --git a/src/interpreter/bytecode-array-builder.cc b/src/interpreter/bytecode-array-builder.cc index f3aa4f017d..8e52ecd7fd 100644 --- a/src/interpreter/bytecode-array-builder.cc +++ b/src/interpreter/bytecode-array-builder.cc @@ -32,17 +32,11 @@ void BytecodeArrayBuilder::set_locals_count(int number_of_locals) { } -int BytecodeArrayBuilder::locals_count() const { return local_register_count_; } - - void BytecodeArrayBuilder::set_parameter_count(int number_of_parameters) { parameter_count_ = number_of_parameters; } -int BytecodeArrayBuilder::parameter_count() const { return parameter_count_; } - - void BytecodeArrayBuilder::set_context_count(int number_of_contexts) { context_register_count_ = number_of_contexts; DCHECK_GE(local_register_count_, 0); @@ -64,20 +58,17 @@ Register BytecodeArrayBuilder::last_context_register() const { Register BytecodeArrayBuilder::Parameter(int parameter_index) const { DCHECK_GE(parameter_index, 0); - DCHECK_LT(parameter_index, parameter_count_); - return Register::FromParameterIndex(parameter_index, parameter_count_); + return Register::FromParameterIndex(parameter_index, parameter_count()); } Handle BytecodeArrayBuilder::ToBytecodeArray() { DCHECK_EQ(bytecode_generated_, false); - DCHECK_GE(parameter_count_, 0); - DCHECK_GE(local_register_count_, 0); EnsureReturn(); int bytecode_size = static_cast(bytecodes_.size()); - int register_count = local_register_count_ + temporary_register_count_; + int register_count = fixed_register_count() + temporary_register_count_; int frame_size = register_count * kPointerSize; Factory* factory = isolate_->factory(); @@ -90,7 +81,7 @@ Handle BytecodeArrayBuilder::ToBytecodeArray() { Handle output = factory->NewBytecodeArray(bytecode_size, &bytecodes_.front(), frame_size, - parameter_count_, constant_pool); + parameter_count(), constant_pool); bytecode_generated_ = true; return output; } @@ -289,6 +280,19 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::LoadContextSlot(Register context, } +BytecodeArrayBuilder& BytecodeArrayBuilder::StoreContextSlot(Register context, + int slot_index) { + DCHECK(slot_index >= 0); + if (FitsInIdx8Operand(slot_index)) { + Output(Bytecode::kStaContextSlot, context.ToOperand(), + static_cast(slot_index)); + } else { + UNIMPLEMENTED(); + } + return *this; +} + + BytecodeArrayBuilder& BytecodeArrayBuilder::LoadNamedProperty( Register object, int feedback_slot, LanguageMode language_mode) { Bytecode bytecode = BytecodeForLoadIC(language_mode); @@ -638,9 +642,8 @@ size_t BytecodeArrayBuilder::GetConstantPoolEntry(Handle object) { int BytecodeArrayBuilder::BorrowTemporaryRegister() { - DCHECK_GE(local_register_count_, 0); int temporary_reg_index = temporary_register_next_++; - int count = temporary_register_next_ - local_register_count_; + int count = temporary_register_next_ - fixed_register_count(); if (count > temporary_register_count_) { temporary_register_count_ = count; } @@ -671,8 +674,8 @@ bool BytecodeArrayBuilder::OperandIsValid(Bytecode bytecode, int operand_index, if (reg.is_function_context() || reg.is_function_closure()) { return true; } else if (reg.is_parameter()) { - int parameter_index = reg.ToParameterIndex(parameter_count_); - return parameter_index >= 0 && parameter_index < parameter_count_; + int parameter_index = reg.ToParameterIndex(parameter_count()); + return parameter_index >= 0 && parameter_index < parameter_count(); } else { return (reg.index() >= 0 && reg.index() < temporary_register_next_); } diff --git a/src/interpreter/bytecode-array-builder.h b/src/interpreter/bytecode-array-builder.h index a4831a45b4..079327d99b 100644 --- a/src/interpreter/bytecode-array-builder.h +++ b/src/interpreter/bytecode-array-builder.h @@ -30,19 +30,31 @@ class BytecodeArrayBuilder { // Set number of parameters expected by function. void set_parameter_count(int number_of_params); - int parameter_count() const; + int parameter_count() const { + DCHECK_GE(parameter_count_, 0); + return parameter_count_; + } // Set number of locals required for bytecode array. void set_locals_count(int number_of_locals); - int locals_count() const; + int locals_count() const { + DCHECK_GE(local_register_count_, 0); + return local_register_count_; + } // Set number of contexts required for bytecode array. void set_context_count(int number_of_contexts); - int context_count() const; + int context_count() const { + DCHECK_GE(context_register_count_, 0); + return context_register_count_; + } Register first_context_register() const; Register last_context_register() const; + // Returns the number of fixed (non-temporary) registers. + int fixed_register_count() const { return context_count() + locals_count(); } + Register Parameter(int parameter_index) const; // Constant loads to the accumulator. @@ -61,6 +73,9 @@ class BytecodeArrayBuilder { // Load the object at |slot_index| in |context| into the accumulator. BytecodeArrayBuilder& LoadContextSlot(Register context, int slot_index); + // Stores the object in the accumulator into |slot_index| of |context|. + BytecodeArrayBuilder& StoreContextSlot(Register context, int slot_index); + // Register-accumulator transfers. BytecodeArrayBuilder& LoadAccumulatorWithRegister(Register reg); BytecodeArrayBuilder& StoreAccumulatorInRegister(Register reg); diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc index 34c2425d87..b051bd9bbb 100644 --- a/src/interpreter/bytecode-generator.cc +++ b/src/interpreter/bytecode-generator.cc @@ -23,39 +23,54 @@ namespace interpreter { // popping of the current {context_register} during visitation. class BytecodeGenerator::ContextScope BASE_EMBEDDED { public: - explicit ContextScope(BytecodeGenerator* generator, - bool is_function_context = false) + ContextScope(BytecodeGenerator* generator, Scope* scope, + bool should_pop_context = true) : generator_(generator), - outer_(generator_->current_context()), - is_function_context_(is_function_context) { - DCHECK(!is_function_context || - outer_.index() == Register::function_context().index()); - Register new_context_reg = NewContextRegister(); - generator_->builder()->PushContext(new_context_reg); - generator_->set_current_context(new_context_reg); + scope_(scope), + outer_(generator_->execution_context()), + register_(generator_->NextContextRegister()), + depth_(0), + should_pop_context_(should_pop_context) { + if (outer_) { + depth_ = outer_->depth_ + 1; + generator_->builder()->PushContext(register_); + } + generator_->set_execution_context(this); } ~ContextScope() { - if (!is_function_context_) { - generator_->builder()->PopContext(outer_); + if (outer_ && should_pop_context_) { + generator_->builder()->PopContext(outer_->reg()); } - generator_->set_current_context(outer_); + generator_->set_execution_context(outer_); } + // Returns the execution context for the given |scope| if it is a function + // local execution context, otherwise returns nullptr. + ContextScope* Previous(Scope* scope) { + int depth = scope_->ContextChainLength(scope); + if (depth > depth_) { + return nullptr; + } + + ContextScope* previous = this; + for (int i = depth; i > 0; --i) { + previous = previous->outer_; + } + DCHECK_EQ(previous->scope_, scope); + return previous; + } + + Scope* scope() const { return scope_; } + Register reg() const { return register_; } + private: - Register NewContextRegister() const { - if (outer_.index() == Register::function_context().index()) { - return generator_->builder()->first_context_register(); - } else { - DCHECK_LT(outer_.index(), - generator_->builder()->last_context_register().index()); - return Register(outer_.index() + 1); - } - } - BytecodeGenerator* generator_; - Register outer_; - bool is_function_context_; + Scope* scope_; + ContextScope* outer_; + Register register_; + int depth_; + bool should_pop_context_; }; @@ -64,10 +79,10 @@ class BytecodeGenerator::ContextScope BASE_EMBEDDED { class BytecodeGenerator::ControlScope BASE_EMBEDDED { public: explicit ControlScope(BytecodeGenerator* generator) - : generator_(generator), outer_(generator->control_scope()) { - generator_->set_control_scope(this); + : generator_(generator), outer_(generator->execution_control()) { + generator_->set_execution_control(this); } - virtual ~ControlScope() { generator_->set_control_scope(outer()); } + virtual ~ControlScope() { generator_->set_execution_control(outer()); } void Break(Statement* stmt) { PerformCommand(CMD_BREAK, stmt); } void Continue(Statement* stmt) { PerformCommand(CMD_CONTINUE, stmt); } @@ -138,8 +153,8 @@ BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone) info_(nullptr), scope_(nullptr), globals_(0, zone), - control_scope_(nullptr), - current_context_(Register::function_context()) { + execution_control_(nullptr), + execution_context_(nullptr) { InitializeAstVisitor(isolate); } @@ -151,6 +166,9 @@ Handle BytecodeGenerator::MakeBytecode(CompilationInfo* info) { set_info(info); set_scope(info->scope()); + // Initialize the incoming context. + ContextScope incoming_context(this, scope(), false); + builder()->set_parameter_count(info->num_parameters_including_this()); builder()->set_locals_count(scope()->num_stack_slots()); builder()->set_context_count(scope()->MaxNestedContextChainLength()); @@ -159,7 +177,8 @@ Handle BytecodeGenerator::MakeBytecode(CompilationInfo* info) { if (scope()->NeedsContext()) { // Push a new inner context scope for the function. VisitNewLocalFunctionContext(); - ContextScope top_context(this, true); + ContextScope local_function_context(this, scope(), false); + VisitBuildLocalActivationContext(); MakeBytecodeBody(); } else { MakeBytecodeBody(); @@ -180,18 +199,21 @@ void BytecodeGenerator::MakeBytecodeBody() { } -void BytecodeGenerator::VisitBlock(Block* node) { +void BytecodeGenerator::VisitBlock(Block* stmt) { builder()->EnterBlock(); - if (node->scope() == NULL) { + if (stmt->scope() == NULL) { // Visit statements in the same scope, no declarations. - VisitStatements(node->statements()); + VisitStatements(stmt->statements()); } else { // Visit declarations and statements in a block scope. - if (node->scope()->ContextLocalCount() > 0) { - UNIMPLEMENTED(); + if (stmt->scope()->NeedsContext()) { + VisitNewLocalBlockContext(stmt->scope()); + ContextScope scope(this, stmt->scope()); + VisitDeclarations(stmt->scope()->declarations()); + VisitStatements(stmt->statements()); } else { - VisitDeclarations(node->scope()->declarations()); - VisitStatements(node->statements()); + VisitDeclarations(stmt->scope()->declarations()); + VisitStatements(stmt->statements()); } } builder()->LeaveBlock(); @@ -201,10 +223,9 @@ void BytecodeGenerator::VisitBlock(Block* node) { void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) { Variable* variable = decl->proxy()->var(); VariableMode mode = decl->mode(); + // Const and let variables are initialized with the hole so that we can + // check that they are only assigned once. bool hole_init = mode == CONST || mode == CONST_LEGACY || mode == LET; - if (hole_init) { - UNIMPLEMENTED(); - } switch (variable->location()) { case VariableLocation::GLOBAL: case VariableLocation::UNALLOCATED: { @@ -215,11 +236,26 @@ void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) { globals()->push_back(value); break; } - case VariableLocation::PARAMETER: case VariableLocation::LOCAL: - // Details stored in scope, i.e. variable index. + if (hole_init) { + Register destination(variable->index()); + builder()->LoadTheHole().StoreAccumulatorInRegister(destination); + } + break; + case VariableLocation::PARAMETER: + if (hole_init) { + // The parameter indices are shifted by 1 (receiver is variable + // index -1 but is parameter index 0 in BytecodeArrayBuilder). + Register destination(builder()->Parameter(variable->index() + 1)); + builder()->LoadTheHole().StoreAccumulatorInRegister(destination); + } break; case VariableLocation::CONTEXT: + if (hole_init) { + builder()->LoadTheHole().StoreContextSlot(execution_context()->reg(), + variable->index()); + } + break; case VariableLocation::LOOKUP: UNIMPLEMENTED(); break; @@ -326,12 +362,12 @@ void BytecodeGenerator::VisitSloppyBlockFunctionStatement( void BytecodeGenerator::VisitContinueStatement(ContinueStatement* stmt) { - control_scope()->Continue(stmt->target()); + execution_control()->Continue(stmt->target()); } void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) { - control_scope()->Break(stmt->target()); + execution_control()->Break(stmt->target()); } @@ -356,7 +392,7 @@ void BytecodeGenerator::VisitCaseClause(CaseClause* clause) { UNIMPLEMENTED(); } void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { LoopBuilder loop_builder(builder()); - ControlScopeForIteration control_scope(this, stmt, &loop_builder); + ControlScopeForIteration execution_control(this, stmt, &loop_builder); BytecodeLabel body_label, condition_label, done_label; builder()->Bind(&body_label); @@ -373,7 +409,7 @@ void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) { LoopBuilder loop_builder(builder()); - ControlScopeForIteration control_scope(this, stmt, &loop_builder); + ControlScopeForIteration execution_control(this, stmt, &loop_builder); BytecodeLabel body_label, condition_label, done_label; builder()->Jump(&condition_label); @@ -391,7 +427,7 @@ void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) { void BytecodeGenerator::VisitForStatement(ForStatement* stmt) { LoopBuilder loop_builder(builder()); - ControlScopeForIteration control_scope(this, stmt, &loop_builder); + ControlScopeForIteration execution_control(this, stmt, &loop_builder); if (stmt->init() != nullptr) { Visit(stmt->init()); @@ -595,8 +631,8 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { } } - // Create nodes to define accessors, using only a single call to the runtime - // for each pair of corresponding getters and setters. + // Define accessors, using only a single call to the runtime for each pair of + // corresponding getters and setters. for (AccessorTable::Iterator it = accessor_table.begin(); it != accessor_table.end(); ++it) { TemporaryRegisterScope inner_temporary_register_scope(builder()); @@ -698,8 +734,8 @@ void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { TemporaryRegisterScope temporary_register_scope(builder()); Register index, literal; - // Create nodes to evaluate all the non-constant subexpressions and to store - // them into the newly cloned array. + // Evaluate all the non-constant subexpressions and store them into the + // newly cloned array. bool literal_in_accumulator = true; for (int array_index = 0; array_index < expr->values()->length(); array_index++) { @@ -744,6 +780,8 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable, case VariableLocation::LOCAL: { Register source(variable->index()); builder()->LoadAccumulatorWithRegister(source); + // TODO(rmcilroy): Perform check for uninitialized legacy const, const and + // let variables. break; } case VariableLocation::PARAMETER: { @@ -765,14 +803,24 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable, case VariableLocation::UNALLOCATED: { TemporaryRegisterScope temporary_register_scope(builder()); Register obj = temporary_register_scope.NewRegister(); - builder()->LoadContextSlot(current_context(), + builder()->LoadContextSlot(execution_context()->reg(), Context::GLOBAL_OBJECT_INDEX); builder()->StoreAccumulatorInRegister(obj); builder()->LoadLiteral(variable->name()); builder()->LoadNamedProperty(obj, feedback_index(slot), language_mode()); break; } - case VariableLocation::CONTEXT: + case VariableLocation::CONTEXT: { + ContextScope* context = execution_context()->Previous(variable->scope()); + if (context) { + builder()->LoadContextSlot(context->reg(), variable->index()); + } else { + UNIMPLEMENTED(); + } + // TODO(rmcilroy): Perform check for uninitialized legacy const, const and + // let variables. + break; + } case VariableLocation::LOOKUP: UNIMPLEMENTED(); } @@ -812,7 +860,7 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable, // TODO(rmcilroy): Investigate whether we can avoid having to stash the // value in a register. builder()->StoreAccumulatorInRegister(value); - builder()->LoadContextSlot(current_context(), + builder()->LoadContextSlot(execution_context()->reg(), Context::GLOBAL_OBJECT_INDEX); builder()->StoreAccumulatorInRegister(obj); builder()->LoadLiteral(variable->name()); @@ -822,7 +870,16 @@ void BytecodeGenerator::VisitVariableAssignment(Variable* variable, language_mode()); break; } - case VariableLocation::CONTEXT: + case VariableLocation::CONTEXT: { + // TODO(rmcilroy): support const mode initialization. + ContextScope* context = execution_context()->Previous(variable->scope()); + if (context) { + builder()->StoreContextSlot(context->reg(), variable->index()); + } else { + UNIMPLEMENTED(); + } + break; + } case VariableLocation::LOOKUP: UNIMPLEMENTED(); } @@ -1172,6 +1229,11 @@ void BytecodeGenerator::VisitNewLocalFunctionContext() { builder()->CallRuntime(Runtime::kNewFunctionContext, Register::function_closure(), 1); } +} + + +void BytecodeGenerator::VisitBuildLocalActivationContext() { + Scope* scope = this->scope(); if (scope->has_this_declaration() && scope->receiver()->IsContextSlot()) { UNIMPLEMENTED(); @@ -1181,13 +1243,37 @@ void BytecodeGenerator::VisitNewLocalFunctionContext() { int num_parameters = scope->num_parameters(); for (int i = 0; i < num_parameters; i++) { Variable* variable = scope->parameter(i); - if (variable->IsContextSlot()) { - UNIMPLEMENTED(); - } + if (!variable->IsContextSlot()) continue; + + // The parameter indices are shifted by 1 (receiver is variable + // index -1 but is parameter index 0 in BytecodeArrayBuilder). + Register parameter(builder()->Parameter(i + 1)); + // Context variable (at bottom of the context chain). + DCHECK_EQ(0, scope->ContextChainLength(variable->scope())); + builder()->LoadAccumulatorWithRegister(parameter) + .StoreContextSlot(execution_context()->reg(), variable->index()); } } +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)); + builder() + ->LoadLiteral(scope->GetScopeInfo(isolate())) + .StoreAccumulatorInRegister(scope_info); + VisitFunctionClosureForContext(); + builder() + ->StoreAccumulatorInRegister(closure) + .CallRuntime(Runtime::kPushBlockContext, scope_info, 2); +} + + void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* binop) { Token::Value op = binop->op(); Expression* left = binop->left(); @@ -1203,41 +1289,6 @@ void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* binop) { } -void BytecodeGenerator::VisitObjectLiteralAccessor( - Register home_object, ObjectLiteralProperty* property, Register value_out) { - // TODO(rmcilroy): Replace value_out with VisitForRegister(); - if (property == nullptr) { - builder()->LoadNull().StoreAccumulatorInRegister(value_out); - } else { - Visit(property->value()); - builder()->StoreAccumulatorInRegister(value_out); - VisitSetHomeObject(value_out, home_object, property); - } -} - - -void BytecodeGenerator::VisitSetHomeObject(Register value, Register home_object, - ObjectLiteralProperty* property, - int slot_number) { - Expression* expr = property->value(); - if (!FunctionLiteral::NeedsHomeObject(expr)) return; - - // TODO(rmcilroy): Remove UNIMPLEMENTED once we have tests for setting the - // home object. - UNIMPLEMENTED(); - - TemporaryRegisterScope temporary_register_scope(builder()); - Register name = temporary_register_scope.NewRegister(); - isolate()->factory()->home_object_symbol(); - builder() - ->LoadLiteral(isolate()->factory()->home_object_symbol()) - .StoreAccumulatorInRegister(name) - .StoreNamedProperty(home_object, name, - feedback_index(property->GetSlot(slot_number)), - language_mode()); -} - - void BytecodeGenerator::VisitCommaExpression(BinaryOperation* binop) { Expression* left = binop->left(); Expression* right = binop->right(); @@ -1285,6 +1336,74 @@ void BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) { } +void BytecodeGenerator::VisitObjectLiteralAccessor( + Register home_object, ObjectLiteralProperty* property, Register value_out) { + // TODO(rmcilroy): Replace value_out with VisitForRegister(); + if (property == nullptr) { + builder()->LoadNull().StoreAccumulatorInRegister(value_out); + } else { + Visit(property->value()); + builder()->StoreAccumulatorInRegister(value_out); + VisitSetHomeObject(value_out, home_object, property); + } +} + + +void BytecodeGenerator::VisitSetHomeObject(Register value, Register home_object, + ObjectLiteralProperty* property, + int slot_number) { + Expression* expr = property->value(); + if (!FunctionLiteral::NeedsHomeObject(expr)) return; + + // TODO(rmcilroy): Remove UNIMPLEMENTED once we have tests for setting the + // home object. + UNIMPLEMENTED(); + + TemporaryRegisterScope temporary_register_scope(builder()); + Register name = temporary_register_scope.NewRegister(); + isolate()->factory()->home_object_symbol(); + builder() + ->LoadLiteral(isolate()->factory()->home_object_symbol()) + .StoreAccumulatorInRegister(name) + .StoreNamedProperty(home_object, name, + feedback_index(property->GetSlot(slot_number)), + language_mode()); +} + + +void BytecodeGenerator::VisitFunctionClosureForContext() { + Scope* closure_scope = execution_context()->scope()->ClosureScope(); + if (closure_scope->is_script_scope() || + 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)); + } else { + DCHECK(closure_scope->is_function_scope()); + builder()->LoadAccumulatorWithRegister(Register::function_closure()); + } +} + + +Register BytecodeGenerator::NextContextRegister() const { + if (execution_context() == nullptr) { + // Return the incoming function context for the outermost execution context. + return Register::function_context(); + } + Register previous = execution_context()->reg(); + if (previous == Register::function_context()) { + // If the previous context was the incoming function context, then the next + // context register is the first local context register. + return builder_.first_context_register(); + } else { + // Otherwise use the next local context register. + DCHECK_LT(previous.index(), builder_.last_context_register().index()); + return Register(previous.index() + 1); + } +} + + LanguageMode BytecodeGenerator::language_mode() const { return info()->language_mode(); } diff --git a/src/interpreter/bytecode-generator.h b/src/interpreter/bytecode-generator.h index cc596fc1e5..e79ff787e9 100644 --- a/src/interpreter/bytecode-generator.h +++ b/src/interpreter/bytecode-generator.h @@ -33,6 +33,7 @@ class BytecodeGenerator : public AstVisitor { class ControlScopeForIteration; void MakeBytecodeBody(); + Register NextContextRegister() const; DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); @@ -46,6 +47,9 @@ class BytecodeGenerator : public AstVisitor { void VisitVariableLoad(Variable* variable, FeedbackVectorSlot slot); void VisitVariableAssignment(Variable* variable, FeedbackVectorSlot slot); void VisitNewLocalFunctionContext(); + void VisitBuildLocalActivationContext(); + void VisitNewLocalBlockContext(Scope* scope); + void VisitFunctionClosureForContext(); void VisitSetHomeObject(Register value, Register home_object, ObjectLiteralProperty* property, int slot_number = 0); void VisitObjectLiteralAccessor(Register home_object, @@ -67,11 +71,13 @@ class BytecodeGenerator : public AstVisitor { inline CompilationInfo* info() const { return info_; } inline void set_info(CompilationInfo* info) { info_ = info; } - inline ControlScope* control_scope() const { return control_scope_; } - inline void set_control_scope(ControlScope* scope) { control_scope_ = scope; } - inline Register current_context() const { return current_context_; } - inline void set_current_context(Register context) { - current_context_ = context; + inline ControlScope* execution_control() const { return execution_control_; } + inline void set_execution_control(ControlScope* scope) { + execution_control_ = scope; + } + inline ContextScope* execution_context() const { return execution_context_; } + inline void set_execution_context(ContextScope* context) { + execution_context_ = context; } ZoneVector>* globals() { return &globals_; } @@ -85,9 +91,8 @@ class BytecodeGenerator : public AstVisitor { CompilationInfo* info_; Scope* scope_; ZoneVector> globals_; - ControlScope* control_scope_; - - Register current_context_; + ControlScope* execution_control_; + ContextScope* execution_context_; }; } // namespace interpreter diff --git a/src/interpreter/bytecodes.h b/src/interpreter/bytecodes.h index 8aeb489e24..76aab42463 100644 --- a/src/interpreter/bytecodes.h +++ b/src/interpreter/bytecodes.h @@ -49,7 +49,10 @@ namespace interpreter { V(StaGlobalStrict, OperandType::kIdx8) \ \ /* Context operations */ \ + V(PushContext, OperandType::kReg8) \ + V(PopContext, OperandType::kReg8) \ V(LdaContextSlot, OperandType::kReg8, OperandType::kIdx8) \ + V(StaContextSlot, OperandType::kReg8, OperandType::kIdx8) \ \ /* Register-accumulator transfers */ \ V(Ldar, OperandType::kReg8) \ @@ -69,10 +72,6 @@ namespace interpreter { V(KeyedStoreICStrict, OperandType::kReg8, OperandType::kReg8, \ OperandType::kIdx8) \ \ - /* Context operations */ \ - V(PushContext, OperandType::kReg8) \ - V(PopContext, OperandType::kReg8) \ - \ /* Binary Operators */ \ V(Add, OperandType::kReg8) \ V(Sub, OperandType::kReg8) \ @@ -210,6 +209,9 @@ class Register { Register reg4 = Register(), Register reg5 = Register()); + bool operator==(const Register& o) const { return o.index() == index(); } + bool operator!=(const Register& o) const { return o.index() != index(); } + private: static const int kIllegalIndex = kMaxInt; diff --git a/src/interpreter/interpreter.cc b/src/interpreter/interpreter.cc index 3335e2108e..2b3171f31f 100644 --- a/src/interpreter/interpreter.cc +++ b/src/interpreter/interpreter.cc @@ -235,6 +235,19 @@ void Interpreter::DoLdaContextSlot(compiler::InterpreterAssembler* assembler) { } +// StaContextSlot +// +// Stores the object in the accumulator into |slot_index| of |context|. +void Interpreter::DoStaContextSlot(compiler::InterpreterAssembler* assembler) { + Node* value = __ GetAccumulator(); + Node* reg_index = __ BytecodeOperandReg8(0); + Node* context = __ LoadRegister(reg_index); + Node* slot_index = __ BytecodeOperandIdx8(1); + __ StoreContextSlot(context, slot_index, value); + __ Dispatch(); +} + + void Interpreter::DoPropertyLoadIC(Callable ic, compiler::InterpreterAssembler* assembler) { Node* code_target = __ HeapConstant(ic.code()); diff --git a/test/cctest/interpreter/test-bytecode-generator.cc b/test/cctest/interpreter/test-bytecode-generator.cc index a6d9b2785a..3614c11111 100644 --- a/test/cctest/interpreter/test-bytecode-generator.cc +++ b/test/cctest/interpreter/test-bytecode-generator.cc @@ -134,14 +134,12 @@ static void CheckBytecodeArrayEqual(struct ExpectedSnippet expected, CHECK_EQ(actual->frame_size(), expected.frame_size); CHECK_EQ(actual->parameter_count(), expected.parameter_count); CHECK_EQ(actual->length(), expected.bytecode_length); - if (expected.constant_count != -1) { - if (expected.constant_count == 0) { - CHECK_EQ(actual->constant_pool(), CcTest::heap()->empty_fixed_array()); - } else { - CHECK_EQ(actual->constant_pool()->length(), expected.constant_count); - for (int i = 0; i < expected.constant_count; i++) { - CheckConstant(expected.constants[i], actual->constant_pool()->get(i)); - } + if (expected.constant_count == 0) { + CHECK_EQ(actual->constant_pool(), CcTest::heap()->empty_fixed_array()); + } else { + CHECK_EQ(actual->constant_pool()->length(), expected.constant_count); + for (int i = 0; i < expected.constant_count; i++) { + CheckConstant(expected.constants[i], actual->constant_pool()->get(i)); } } @@ -1504,7 +1502,7 @@ TEST(DeclareGlobals) { InitializedHandleScope handle_scope; BytecodeGeneratorHelper helper; - ExpectedSnippet snippets[] = { + ExpectedSnippet snippets[] = { {"var a = 1;", 5 * kPointerSize, 1, @@ -1532,7 +1530,10 @@ TEST(DeclareGlobals) { B(LdaUndefined), // B(Return) // }, - -1}, + 3, + {InstanceType::FIXED_ARRAY_TYPE, + InstanceType::FIXED_ARRAY_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, {"function f() {}", 3 * kPointerSize, 1, @@ -1552,7 +1553,8 @@ TEST(DeclareGlobals) { B(LdaUndefined), // B(Return) // }, - -1}, + 2, + {InstanceType::FIXED_ARRAY_TYPE, InstanceType::FIXED_ARRAY_TYPE}}, {"var a = 1;\na=2;", 5 * kPointerSize, 1, @@ -1583,7 +1585,10 @@ TEST(DeclareGlobals) { B(Ldar), R(0), // B(Return) // }, - -1}, + 3, + {InstanceType::FIXED_ARRAY_TYPE, + InstanceType::FIXED_ARRAY_TYPE, + InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE}}, {"function f() {}\nf();", 4 * kPointerSize, 1, @@ -1609,7 +1614,8 @@ TEST(DeclareGlobals) { B(Ldar), R(0), // B(Return) // }, - -1}, + 2, + {InstanceType::FIXED_ARRAY_TYPE, InstanceType::FIXED_ARRAY_TYPE}}, }; for (size_t i = 0; i < arraysize(snippets); i++) { @@ -1778,8 +1784,7 @@ TEST(BasicLoops) { B(Star), R(0), // B(Ldar), R(0), // B(Star), R(1), // - B(LdaSmi8), // - U8(1), // + B(LdaSmi8), U8(1), // B(TestEqual), R(1), // B(JumpIfFalse), U8(4), // B(Jump), U8(14), // @@ -2617,7 +2622,7 @@ TEST(TryCatch) { // TODO(rmcilroy): modify tests when we have real try catch support. ExpectedSnippet snippets[] = { {"try { return 1; } catch(e) { return 2; }", - 0, + 1 * kPointerSize, 1, 5, { @@ -2659,7 +2664,7 @@ TEST(TryFinally) { }, 0}, {"var a = 1; try { a = 2; } catch(e) { a = 20 } finally { a = 3; }", - 1 * kPointerSize, + 2 * kPointerSize, 1, 14, { @@ -2748,6 +2753,211 @@ TEST(CallNew) { } } + +TEST(ContextVariables) { + InitializedHandleScope handle_scope; + BytecodeGeneratorHelper helper; + + int closure = Register::function_closure().index(); + int first_context_slot = Context::MIN_CONTEXT_SLOTS; + ExpectedSnippet snippets[] = { + {"var a; return function() { a = 1; };", + 1 * kPointerSize, + 1, + 12, + { + B(CallRuntime), U16(Runtime::kNewFunctionContext), // + R(closure), U8(1), // + B(PushContext), R(0), // + B(LdaConstant), U8(0), // + B(CreateClosure), U8(0), // + B(Return), // + }, + 1, + {InstanceType::SHARED_FUNCTION_INFO_TYPE}}, + {"var a = 1; return function() { a = 2; };", + 1 * kPointerSize, + 1, + 17, + { + B(CallRuntime), U16(Runtime::kNewFunctionContext), // + R(closure), U8(1), // + B(PushContext), R(0), // + B(LdaSmi8), U8(1), // + B(StaContextSlot), R(0), U8(first_context_slot), // + B(LdaConstant), U8(0), // + B(CreateClosure), U8(0), // + B(Return), // + }, + 1, + {InstanceType::SHARED_FUNCTION_INFO_TYPE}}, + {"var a = 1; var b = 2; return function() { a = 2; b = 3 };", + 1 * kPointerSize, + 1, + 22, + { + B(CallRuntime), U16(Runtime::kNewFunctionContext), // + R(closure), U8(1), // + B(PushContext), R(0), // + B(LdaSmi8), U8(1), // + B(StaContextSlot), R(0), U8(first_context_slot), // + B(LdaSmi8), U8(2), // + B(StaContextSlot), R(0), U8(first_context_slot + 1), // + B(LdaConstant), U8(0), // + B(CreateClosure), U8(0), // + B(Return), // + }, + 1, + {InstanceType::SHARED_FUNCTION_INFO_TYPE}}, + {"var a; (function() { a = 2; })(); return a;", + 3 * kPointerSize, + 1, + 24, + { + B(CallRuntime), U16(Runtime::kNewFunctionContext), // + R(closure), U8(1), // + B(PushContext), R(0), // + B(LdaUndefined), // + B(Star), R(2), // + B(LdaConstant), U8(0), // + B(CreateClosure), U8(0), // + B(Star), R(1), // + B(Call), R(1), R(2), U8(0), // + B(LdaContextSlot), R(0), U8(first_context_slot), // + B(Return), // + }, + 1, + {InstanceType::SHARED_FUNCTION_INFO_TYPE}}, + {"'use strict'; let a = 1; { let b = 2; return function() { a + b; }; }", + 4 * kPointerSize, + 1, + 51, + { + B(CallRuntime), U16(Runtime::kNewFunctionContext), // + R(closure), U8(1), // + B(PushContext), R(0), // + B(LdaTheHole), // + B(StaContextSlot), R(0), U8(first_context_slot), // + B(LdaConstant), U8(0), // + B(LdaSmi8), U8(1), // + B(StaContextSlot), R(0), U8(first_context_slot), // + B(LdaConstant), U8(1), // + B(Star), R(2), // + B(Ldar), R(closure), // + B(Star), R(3), // + B(CallRuntime), U16(Runtime::kPushBlockContext), R(2), U8(2), // + B(PushContext), R(1), // + B(LdaTheHole), // + B(StaContextSlot), R(1), U8(first_context_slot), // + B(LdaSmi8), U8(2), // + B(StaContextSlot), R(1), U8(first_context_slot), // + B(LdaConstant), U8(2), // + B(CreateClosure), U8(0), // + B(Return), // + // TODO(rmcilroy): Dead code after this point due to return in nested + // block - investigate eliminating this. + B(PopContext), R(0), + B(LdaUndefined), // + B(Return), // + }, + 3, + {InstanceType::ONE_BYTE_INTERNALIZED_STRING_TYPE, + InstanceType::FIXED_ARRAY_TYPE, + InstanceType::SHARED_FUNCTION_INFO_TYPE}}, + }; + + for (size_t i = 0; i < arraysize(snippets); i++) { + Handle bytecode_array = + helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet); + CheckBytecodeArrayEqual(snippets[i], bytecode_array); + } +} + + +TEST(ContextParameters) { + InitializedHandleScope handle_scope; + BytecodeGeneratorHelper helper; + + int closure = Register::function_closure().index(); + int first_context_slot = Context::MIN_CONTEXT_SLOTS; + ExpectedSnippet snippets[] = { + {"function f(arg1) { return function() { arg1 = 2; }; }", + 1 * kPointerSize, + 2, + 17, + { + B(CallRuntime), U16(Runtime::kNewFunctionContext), // + R(closure), U8(1), // + B(PushContext), R(0), // + B(Ldar), R(helper.kLastParamIndex), // + B(StaContextSlot), R(0), U8(first_context_slot), // + B(LdaConstant), U8(0), // + B(CreateClosure), U8(0), // + B(Return), // + }, + 1, + {InstanceType::SHARED_FUNCTION_INFO_TYPE}}, + {"function f(arg1) { var a = function() { arg1 = 2; }; return arg1; }", + 2 * kPointerSize, + 2, + 22, + { + B(CallRuntime), U16(Runtime::kNewFunctionContext), // + R(closure), U8(1), // + B(PushContext), R(1), // + B(Ldar), R(helper.kLastParamIndex), // + B(StaContextSlot), R(1), U8(first_context_slot), // + B(LdaConstant), U8(0), // + B(CreateClosure), U8(0), // + B(Star), R(0), // + B(LdaContextSlot), R(1), U8(first_context_slot), // + B(Return), // + }, + 1, + {InstanceType::SHARED_FUNCTION_INFO_TYPE}}, + {"function f(a1, a2, a3, a4) { return function() { a1 = a3; }; }", + 1 * kPointerSize, + 5, + 22, + { + B(CallRuntime), U16(Runtime::kNewFunctionContext), // + R(closure), U8(1), // + B(PushContext), R(0), // + B(Ldar), R(helper.kLastParamIndex - 3), // + B(StaContextSlot), R(0), U8(first_context_slot + 1), // + B(Ldar), R(helper.kLastParamIndex -1), // + B(StaContextSlot), R(0), U8(first_context_slot), // + B(LdaConstant), U8(0), // + B(CreateClosure), U8(0), // + B(Return), // + }, + 1, + {InstanceType::SHARED_FUNCTION_INFO_TYPE}}, + {"function f() { var self = this; return function() { self = 2; }; }", + 1 * kPointerSize, + 1, + 17, + { + B(CallRuntime), U16(Runtime::kNewFunctionContext), // + R(closure), U8(1), // + B(PushContext), R(0), // + B(Ldar), R(helper.kLastParamIndex), // + B(StaContextSlot), R(0), U8(first_context_slot), // + B(LdaConstant), U8(0), // + B(CreateClosure), U8(0), // + B(Return), // + }, + 1, + {InstanceType::SHARED_FUNCTION_INFO_TYPE}}, + }; + + for (size_t i = 0; i < arraysize(snippets); i++) { + Handle bytecode_array = + helper.MakeBytecodeForFunction(snippets[i].code_snippet); + CheckBytecodeArrayEqual(snippets[i], bytecode_array); + } +} + } // namespace interpreter } // namespace internal } // namespace v8 diff --git a/test/cctest/interpreter/test-interpreter.cc b/test/cctest/interpreter/test-interpreter.cc index cc265e2ba6..6e933b9b47 100644 --- a/test/cctest/interpreter/test-interpreter.cc +++ b/test/cctest/interpreter/test-interpreter.cc @@ -172,6 +172,7 @@ TEST(InterpreterReturn) { BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); builder.set_locals_count(0); + builder.set_context_count(0); builder.set_parameter_count(1); builder.Return(); Handle bytecode_array = builder.ToBytecodeArray(); @@ -190,6 +191,7 @@ TEST(InterpreterLoadUndefined) { BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); builder.set_locals_count(0); + builder.set_context_count(0); builder.set_parameter_count(1); builder.LoadUndefined().Return(); Handle bytecode_array = builder.ToBytecodeArray(); @@ -207,6 +209,7 @@ TEST(InterpreterLoadNull) { BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); builder.set_locals_count(0); + builder.set_context_count(0); builder.set_parameter_count(1); builder.LoadNull().Return(); Handle bytecode_array = builder.ToBytecodeArray(); @@ -225,6 +228,7 @@ TEST(InterpreterLoadTheHole) { BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); builder.set_locals_count(0); + builder.set_context_count(0); builder.set_parameter_count(1); builder.LoadTheHole().Return(); Handle bytecode_array = builder.ToBytecodeArray(); @@ -242,6 +246,7 @@ TEST(InterpreterLoadTrue) { BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); builder.set_locals_count(0); + builder.set_context_count(0); builder.set_parameter_count(1); builder.LoadTrue().Return(); Handle bytecode_array = builder.ToBytecodeArray(); @@ -259,6 +264,7 @@ TEST(InterpreterLoadFalse) { BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); builder.set_locals_count(0); + builder.set_context_count(0); builder.set_parameter_count(1); builder.LoadFalse().Return(); Handle bytecode_array = builder.ToBytecodeArray(); @@ -278,6 +284,7 @@ TEST(InterpreterLoadLiteral) { for (int i = -128; i < 128; i++) { BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); builder.set_locals_count(0); + builder.set_context_count(0); builder.set_parameter_count(1); builder.LoadLiteral(Smi::FromInt(i)).Return(); Handle bytecode_array = builder.ToBytecodeArray(); @@ -292,6 +299,7 @@ TEST(InterpreterLoadLiteral) { { BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); builder.set_locals_count(0); + builder.set_context_count(0); builder.set_parameter_count(1); builder.LoadLiteral(Smi::FromInt(0x12345678)).Return(); Handle bytecode_array = builder.ToBytecodeArray(); @@ -306,6 +314,7 @@ TEST(InterpreterLoadLiteral) { { BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); builder.set_locals_count(0); + builder.set_context_count(0); builder.set_parameter_count(1); builder.LoadLiteral(factory->NewHeapNumber(-2.1e19)).Return(); Handle bytecode_array = builder.ToBytecodeArray(); @@ -320,6 +329,7 @@ TEST(InterpreterLoadLiteral) { { BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); builder.set_locals_count(0); + builder.set_context_count(0); builder.set_parameter_count(1); Handle string = factory->NewStringFromAsciiChecked("String"); builder.LoadLiteral(string).Return(); @@ -339,6 +349,7 @@ TEST(InterpreterLoadStoreRegisters) { for (int i = 0; i <= Register::kMaxRegisterIndex; i++) { BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); builder.set_locals_count(i + 1); + builder.set_context_count(0); builder.set_parameter_count(1); Register reg(i); builder.LoadTrue() @@ -424,6 +435,7 @@ TEST(InterpreterShiftOpsSmi) { BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); builder.set_locals_count(1); + builder.set_context_count(0); builder.set_parameter_count(1); Register reg(0); int lhs = lhs_inputs[l]; @@ -458,6 +470,7 @@ TEST(InterpreterBinaryOpsSmi) { BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); builder.set_locals_count(1); + builder.set_context_count(0); builder.set_parameter_count(1); Register reg(0); int lhs = lhs_inputs[l]; @@ -493,6 +506,7 @@ TEST(InterpreterBinaryOpsHeapNumber) { BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); builder.set_locals_count(1); + builder.set_context_count(0); builder.set_parameter_count(1); Register reg(0); double lhs = lhs_inputs[l]; @@ -551,6 +565,7 @@ TEST(InterpreterStringAdd) { for (size_t i = 0; i < arraysize(test_cases); i++) { BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); builder.set_locals_count(1); + builder.set_context_count(0); builder.set_parameter_count(1); Register reg(0); builder.LoadLiteral(test_cases[i].lhs) @@ -572,6 +587,7 @@ TEST(InterpreterParameter1) { HandleAndZoneScope handles; BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); builder.set_locals_count(0); + builder.set_context_count(0); builder.set_parameter_count(1); builder.LoadAccumulatorWithRegister(builder.Parameter(0)).Return(); Handle bytecode_array = builder.ToBytecodeArray(); @@ -595,6 +611,7 @@ TEST(InterpreterParameter8) { HandleAndZoneScope handles; BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); builder.set_locals_count(0); + builder.set_context_count(0); builder.set_parameter_count(8); builder.LoadAccumulatorWithRegister(builder.Parameter(0)) .BinaryOperation(Token::Value::ADD, builder.Parameter(1), Strength::WEAK) @@ -631,6 +648,7 @@ TEST(InterpreterParameter1Assign) { HandleAndZoneScope handles; BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); builder.set_locals_count(0); + builder.set_context_count(0); builder.set_parameter_count(1); builder.LoadLiteral(Smi::FromInt(5)) .StoreAccumulatorInRegister(builder.Parameter(0)) @@ -760,6 +778,7 @@ TEST(InterpreterLoadNamedProperty) { BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); builder.set_locals_count(0); + builder.set_context_count(0); builder.set_parameter_count(1); builder.LoadLiteral(name) .LoadNamedProperty(builder.Parameter(0), vector->GetIndex(slot), @@ -816,6 +835,7 @@ TEST(InterpreterLoadKeyedProperty) { BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); builder.set_locals_count(1); + builder.set_context_count(0); builder.set_parameter_count(1); builder.LoadLiteral(key) .LoadKeyedProperty(builder.Parameter(0), vector->GetIndex(slot), @@ -860,6 +880,7 @@ TEST(InterpreterStoreNamedProperty) { BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); builder.set_locals_count(1); + builder.set_context_count(0); builder.set_parameter_count(1); builder.LoadLiteral(name) .StoreAccumulatorInRegister(Register(0)) @@ -922,6 +943,7 @@ TEST(InterpreterStoreKeyedProperty) { BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); builder.set_locals_count(1); + builder.set_context_count(0); builder.set_parameter_count(1); builder.LoadLiteral(name) .StoreAccumulatorInRegister(Register(0)) @@ -974,6 +996,7 @@ TEST(InterpreterCall) { { BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); builder.set_locals_count(1); + builder.set_context_count(0); builder.set_parameter_count(1); builder.LoadLiteral(name) .LoadNamedProperty(builder.Parameter(0), slot_index, i::SLOPPY) @@ -995,6 +1018,7 @@ TEST(InterpreterCall) { { BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); builder.set_locals_count(1); + builder.set_context_count(0); builder.set_parameter_count(1); builder.LoadLiteral(name) .LoadNamedProperty(builder.Parameter(0), slot_index, i::SLOPPY) @@ -1019,6 +1043,7 @@ TEST(InterpreterCall) { { BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); builder.set_locals_count(4); + builder.set_context_count(0); builder.set_parameter_count(1); builder.LoadLiteral(name) .LoadNamedProperty(builder.Parameter(0), slot_index, i::SLOPPY) @@ -1048,6 +1073,7 @@ TEST(InterpreterCall) { { BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); builder.set_locals_count(12); + builder.set_context_count(0); builder.set_parameter_count(1); builder.LoadLiteral(name) .LoadNamedProperty(builder.Parameter(0), slot_index, i::SLOPPY) @@ -1121,6 +1147,7 @@ TEST(InterpreterJumps) { HandleAndZoneScope handles; BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); builder.set_locals_count(2); + builder.set_context_count(0); builder.set_parameter_count(0); Register reg(0), scratch(1); BytecodeLabel label[3]; @@ -1149,6 +1176,7 @@ TEST(InterpreterConditionalJumps) { HandleAndZoneScope handles; BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); builder.set_locals_count(2); + builder.set_context_count(0); builder.set_parameter_count(0); Register reg(0), scratch(1); BytecodeLabel label[2]; @@ -1237,6 +1265,7 @@ TEST(InterpreterSmiComparisons) { handles.main_zone()); Register r0(0); builder.set_locals_count(1); + builder.set_context_count(0); builder.set_parameter_count(0); builder.LoadLiteral(Smi::FromInt(inputs[i])) .StoreAccumulatorInRegister(r0) @@ -1275,6 +1304,7 @@ TEST(InterpreterHeapNumberComparisons) { handles.main_zone()); Register r0(0); builder.set_locals_count(1); + builder.set_context_count(0); builder.set_parameter_count(0); builder.LoadLiteral(factory->NewHeapNumber(inputs[i])) .StoreAccumulatorInRegister(r0) @@ -1310,6 +1340,7 @@ TEST(InterpreterStringComparisons) { handles.main_zone()); Register r0(0); builder.set_locals_count(1); + builder.set_context_count(0); builder.set_parameter_count(0); builder.LoadLiteral(factory->NewStringFromAsciiChecked(lhs)) .StoreAccumulatorInRegister(r0) @@ -1356,6 +1387,7 @@ TEST(InterpreterMixedComparisons) { handles.main_zone()); Register r0(0); builder.set_locals_count(1); + builder.set_context_count(0); builder.set_parameter_count(0); if (pass == 0) { // Comparison with HeapNumber on the lhs and String on the rhs @@ -1400,6 +1432,7 @@ TEST(InterpreterInstanceOf) { BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); Register r0(0); builder.set_locals_count(1); + builder.set_context_count(0); builder.set_parameter_count(0); builder.LoadLiteral(cases[i]); builder.StoreAccumulatorInRegister(r0) @@ -1430,6 +1463,7 @@ TEST(InterpreterTestIn) { BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); Register r0(0); builder.set_locals_count(1); + builder.set_context_count(0); builder.set_parameter_count(0); builder.LoadLiteral(factory->NewStringFromAsciiChecked(properties[i])) .StoreAccumulatorInRegister(r0) @@ -1454,6 +1488,7 @@ TEST(InterpreterUnaryNot) { BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); Register r0(0); builder.set_locals_count(0); + builder.set_context_count(0); builder.set_parameter_count(0); builder.EnterBlock(); builder.LoadFalse(); @@ -1517,6 +1552,7 @@ TEST(InterpreterToBoolean) { BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); Register r0(0); builder.set_locals_count(0); + builder.set_context_count(0); builder.set_parameter_count(0); builder.EnterBlock(); LoadAny(&builder, factory, object_type_tuples[i].first); @@ -1554,6 +1590,7 @@ TEST(InterpreterUnaryNotNonBoolean) { BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); Register r0(0); builder.set_locals_count(0); + builder.set_context_count(0); builder.set_parameter_count(0); builder.EnterBlock(); LoadAny(&builder, factory, object_type_tuples[i].first); @@ -1589,6 +1626,7 @@ TEST(InterpreterTypeOf) { BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); Register r0(0); builder.set_locals_count(0); + builder.set_context_count(0); builder.set_parameter_count(0); builder.EnterBlock(); LoadAny(&builder, factory, object_type_tuples[i].first); @@ -1610,6 +1648,7 @@ TEST(InterpreterCallRuntime) { BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); builder.set_locals_count(2); + builder.set_context_count(0); builder.set_parameter_count(1); builder.LoadLiteral(Smi::FromInt(15)) .StoreAccumulatorInRegister(Register(0)) @@ -1787,6 +1826,67 @@ TEST(InterpreterConstructWithArguments) { } +TEST(InterpreterContextVariables) { + HandleAndZoneScope handles; + i::Isolate* isolate = handles.main_isolate(); + + std::pair> context_vars[5] = { + std::make_pair("var a; (function() { a = 1; })(); return a;", + Handle(Smi::FromInt(1), isolate)), + std::make_pair("var a = 10; (function() { a; })(); return a;", + Handle(Smi::FromInt(10), isolate)), + std::make_pair("var a = 20; var b = 30;\n" + "return (function() { return a + b; })();", + Handle(Smi::FromInt(50), isolate)), + std::make_pair("'use strict'; let a = 1;\n" + "{ let b = 2; return (function() { return a + b; })(); }", + Handle(Smi::FromInt(3), isolate)), + std::make_pair("'use strict'; let a = 10;\n" + "{ let b = 20; var c = function() { [a, b] };\n" + " return a + b; }", + Handle(Smi::FromInt(30), isolate)), + }; + + for (size_t i = 0; i < arraysize(context_vars); i++) { + std::string source(InterpreterTester::SourceForBody(context_vars[i].first)); + InterpreterTester tester(handles.main_isolate(), source.c_str()); + auto callable = tester.GetCallable<>(); + + Handle return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*context_vars[i].second)); + } +} + + +TEST(InterpreterContextParameters) { + HandleAndZoneScope handles; + i::Isolate* isolate = handles.main_isolate(); + + std::pair> context_params[3] = { + std::make_pair("return (function() { return arg1; })();", + Handle(Smi::FromInt(1), isolate)), + std::make_pair("(function() { arg1 = 4; })(); return arg1;", + Handle(Smi::FromInt(4), isolate)), + std::make_pair("(function() { arg3 = arg2 - arg1; })(); return arg3;", + Handle(Smi::FromInt(1), isolate)), + }; + + for (size_t i = 0; i < arraysize(context_params); i++) { + std::string source = "function " + InterpreterTester::function_name() + + "(arg1, arg2, arg3) {" + context_params[i].first + "}"; + InterpreterTester tester(handles.main_isolate(), source.c_str()); + auto callable = + tester.GetCallable, Handle, Handle>(); + + Handle a1 = Handle(Smi::FromInt(1), isolate); + Handle a2 = Handle(Smi::FromInt(2), isolate); + Handle a3 = Handle(Smi::FromInt(3), isolate); + Handle return_value = callable(a1, a2, a3).ToHandleChecked(); + CHECK(return_value->SameValue(*context_params[i].second)); + } +} + + TEST(InterpreterComma) { HandleAndZoneScope handles; i::Isolate* isolate = handles.main_isolate(); diff --git a/test/unittests/compiler/bytecode-graph-builder-unittest.cc b/test/unittests/compiler/bytecode-graph-builder-unittest.cc index 036e7b48cc..27ff4ca359 100644 --- a/test/unittests/compiler/bytecode-graph-builder-unittest.cc +++ b/test/unittests/compiler/bytecode-graph-builder-unittest.cc @@ -98,6 +98,7 @@ Matcher BytecodeGraphBuilderTest::IsTrueConstant() { TEST_F(BytecodeGraphBuilderTest, ReturnUndefined) { array_builder()->set_locals_count(0); + array_builder()->set_context_count(0); array_builder()->set_parameter_count(1); array_builder()->LoadUndefined().Return(); @@ -113,6 +114,7 @@ TEST_F(BytecodeGraphBuilderTest, ReturnUndefined) { TEST_F(BytecodeGraphBuilderTest, ReturnNull) { array_builder()->set_locals_count(0); + array_builder()->set_context_count(0); array_builder()->set_parameter_count(1); array_builder()->LoadNull().Return(); @@ -126,6 +128,7 @@ TEST_F(BytecodeGraphBuilderTest, ReturnNull) { TEST_F(BytecodeGraphBuilderTest, ReturnTheHole) { array_builder()->set_locals_count(0); + array_builder()->set_context_count(0); array_builder()->set_parameter_count(1); array_builder()->LoadTheHole().Return(); @@ -141,6 +144,7 @@ TEST_F(BytecodeGraphBuilderTest, ReturnTheHole) { TEST_F(BytecodeGraphBuilderTest, ReturnTrue) { array_builder()->set_locals_count(0); + array_builder()->set_context_count(0); array_builder()->set_parameter_count(1); array_builder()->LoadTrue().Return(); @@ -156,6 +160,7 @@ TEST_F(BytecodeGraphBuilderTest, ReturnTrue) { TEST_F(BytecodeGraphBuilderTest, ReturnFalse) { array_builder()->set_locals_count(0); + array_builder()->set_context_count(0); array_builder()->set_parameter_count(1); array_builder()->LoadFalse().Return(); @@ -172,6 +177,7 @@ TEST_F(BytecodeGraphBuilderTest, ReturnFalse) { TEST_F(BytecodeGraphBuilderTest, ReturnInt8) { static const int kValue = 3; array_builder()->set_locals_count(0); + array_builder()->set_context_count(0); array_builder()->set_parameter_count(1); array_builder()->LoadLiteral(Smi::FromInt(kValue)).Return(); @@ -188,6 +194,7 @@ TEST_F(BytecodeGraphBuilderTest, ReturnInt8) { TEST_F(BytecodeGraphBuilderTest, ReturnDouble) { const double kValue = 0.123456789; array_builder()->set_locals_count(0); + array_builder()->set_context_count(0); array_builder()->set_parameter_count(1); array_builder()->LoadLiteral(factory()->NewHeapNumber(kValue)); array_builder()->Return(); @@ -204,6 +211,7 @@ TEST_F(BytecodeGraphBuilderTest, ReturnDouble) { TEST_F(BytecodeGraphBuilderTest, SimpleExpressionWithParameters) { array_builder()->set_locals_count(1); + array_builder()->set_context_count(0); array_builder()->set_parameter_count(3); array_builder() ->LoadAccumulatorWithRegister(array_builder()->Parameter(1)) @@ -227,6 +235,7 @@ TEST_F(BytecodeGraphBuilderTest, SimpleExpressionWithRegister) { static const int kLeft = -655371; static const int kRight = +2000000; array_builder()->set_locals_count(1); + array_builder()->set_context_count(0); array_builder()->set_parameter_count(1); array_builder() ->LoadLiteral(Smi::FromInt(kLeft)) diff --git a/test/unittests/compiler/interpreter-assembler-unittest.cc b/test/unittests/compiler/interpreter-assembler-unittest.cc index 0fab029d56..3363033005 100644 --- a/test/unittests/compiler/interpreter-assembler-unittest.cc +++ b/test/unittests/compiler/interpreter-assembler-unittest.cc @@ -486,6 +486,24 @@ TARGET_TEST_F(InterpreterAssemblerTest, LoadContextSlot) { } +TARGET_TEST_F(InterpreterAssemblerTest, StoreContextSlot) { + TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { + InterpreterAssemblerForTest m(this, bytecode); + Node* context = m.Int32Constant(1); + Node* slot_index = m.Int32Constant(22); + Node* value = m.Int32Constant(100); + Node* store_context_slot = m.StoreContextSlot(context, slot_index, value); + + Matcher offset = + IsIntPtrAdd(IsWordShl(slot_index, IsInt32Constant(kPointerSizeLog2)), + IsInt32Constant(Context::kHeaderSize - kHeapObjectTag)); + EXPECT_THAT(store_context_slot, + m.IsStore(StoreRepresentation(kMachAnyTagged, kNoWriteBarrier), + context, offset, value)); + } +} + + TARGET_TEST_F(InterpreterAssemblerTest, LoadObjectField) { TRACED_FOREACH(interpreter::Bytecode, bytecode, kBytecodes) { InterpreterAssemblerForTest m(this, bytecode); diff --git a/test/unittests/interpreter/bytecode-array-builder-unittest.cc b/test/unittests/interpreter/bytecode-array-builder-unittest.cc index a7f5067681..2654923b55 100644 --- a/test/unittests/interpreter/bytecode-array-builder-unittest.cc +++ b/test/unittests/interpreter/bytecode-array-builder-unittest.cc @@ -23,8 +23,11 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { BytecodeArrayBuilder builder(isolate(), zone()); builder.set_locals_count(1); + builder.set_context_count(1); builder.set_parameter_count(0); CHECK_EQ(builder.locals_count(), 1); + CHECK_EQ(builder.context_count(), 1); + CHECK_EQ(builder.fixed_register_count(), 2); // Emit constant loads. builder.LoadLiteral(Smi::FromInt(0)) @@ -49,6 +52,7 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { builder.PushContext(reg); builder.PopContext(reg); builder.LoadContextSlot(reg, 1); + builder.StoreContextSlot(reg, 1); // Emit load / store property operations. builder.LoadNamedProperty(reg, 0, LanguageMode::SLOPPY) @@ -134,7 +138,8 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { // Generate BytecodeArray. Handle the_array = builder.ToBytecodeArray(); - CHECK_EQ(the_array->frame_size(), builder.locals_count() * kPointerSize); + CHECK_EQ(the_array->frame_size(), + builder.fixed_register_count() * kPointerSize); // Build scorecard of bytecodes encountered in the BytecodeArray. std::vector scorecard(Bytecodes::ToByte(Bytecode::kLast) + 1); @@ -161,20 +166,23 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) { TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) { for (int locals = 0; locals < 5; locals++) { - for (int temps = 0; temps < 3; temps++) { - BytecodeArrayBuilder builder(isolate(), zone()); - builder.set_parameter_count(0); - builder.set_locals_count(locals); - builder.Return(); + for (int contexts = 0; contexts < 4; contexts++) { + for (int temps = 0; temps < 3; temps++) { + BytecodeArrayBuilder builder(isolate(), zone()); + builder.set_parameter_count(0); + builder.set_locals_count(locals); + builder.set_context_count(contexts); + builder.Return(); - TemporaryRegisterScope temporaries(&builder); - for (int i = 0; i < temps; i++) { - temporaries.NewRegister(); + TemporaryRegisterScope temporaries(&builder); + for (int i = 0; i < temps; i++) { + temporaries.NewRegister(); + } + + Handle the_array = builder.ToBytecodeArray(); + int total_registers = locals + contexts + temps; + CHECK_EQ(the_array->frame_size(), total_registers * kPointerSize); } - - Handle the_array = builder.ToBytecodeArray(); - int total_registers = locals + temps; - CHECK_EQ(the_array->frame_size(), total_registers * kPointerSize); } } } @@ -184,6 +192,7 @@ 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; @@ -224,6 +233,7 @@ TEST_F(BytecodeArrayBuilderTest, Parameters) { BytecodeArrayBuilder builder(isolate(), zone()); builder.set_parameter_count(10); builder.set_locals_count(0); + builder.set_context_count(0); Register param0(builder.Parameter(0)); Register param9(builder.Parameter(9)); @@ -235,6 +245,7 @@ TEST_F(BytecodeArrayBuilderTest, Constants) { BytecodeArrayBuilder builder(isolate(), zone()); builder.set_parameter_count(0); builder.set_locals_count(0); + builder.set_context_count(0); Factory* factory = isolate()->factory(); Handle heap_num_1 = factory->NewHeapNumber(3.14); @@ -260,6 +271,7 @@ TEST_F(BytecodeArrayBuilderTest, ForwardJumps) { BytecodeArrayBuilder builder(isolate(), zone()); builder.set_parameter_count(0); builder.set_locals_count(0); + builder.set_context_count(0); BytecodeLabel far0, far1, far2; BytecodeLabel near0, near1, near2; @@ -328,6 +340,7 @@ TEST_F(BytecodeArrayBuilderTest, BackwardJumps) { BytecodeArrayBuilder builder(isolate(), zone()); builder.set_parameter_count(0); builder.set_locals_count(0); + builder.set_context_count(0); BytecodeLabel label0, label1, label2; builder.Bind(&label0) @@ -379,6 +392,7 @@ TEST_F(BytecodeArrayBuilderTest, LabelReuse) { BytecodeArrayBuilder builder(isolate(), zone()); builder.set_parameter_count(0); builder.set_locals_count(0); + builder.set_context_count(0); // Labels can only have 1 forward reference, but // can be referred to mulitple times once bound. @@ -409,6 +423,7 @@ TEST_F(BytecodeArrayBuilderTest, LabelAddressReuse) { BytecodeArrayBuilder builder(isolate(), zone()); builder.set_parameter_count(0); builder.set_locals_count(0); + builder.set_context_count(0); for (int i = 0; i < kRepeats; i++) { BytecodeLabel label; @@ -440,6 +455,7 @@ TEST_F(BytecodeArrayBuilderTest, ToBoolean) { BytecodeArrayBuilder builder(isolate(), zone()); builder.set_parameter_count(0); builder.set_locals_count(0); + builder.set_context_count(0); // Check ToBoolean emitted at start of block. builder.EnterBlock().CastAccumulatorToBoolean(); diff --git a/test/unittests/interpreter/bytecode-array-iterator-unittest.cc b/test/unittests/interpreter/bytecode-array-iterator-unittest.cc index 9ed325f92f..e8a49579d7 100644 --- a/test/unittests/interpreter/bytecode-array-iterator-unittest.cc +++ b/test/unittests/interpreter/bytecode-array-iterator-unittest.cc @@ -25,6 +25,7 @@ TEST_F(BytecodeArrayIteratorTest, IteratesBytecodeArray) { BytecodeArrayBuilder builder(isolate(), zone()); builder.set_parameter_count(3); builder.set_locals_count(2); + builder.set_context_count(0); Factory* factory = isolate()->factory(); Handle heap_num_0 = factory->NewHeapNumber(2.718);