Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/interpreter/bytecode-generator.h" | 5 #include "src/interpreter/bytecode-generator.h" |
| 6 | 6 |
| 7 #include <stack> | 7 #include <stack> |
| 8 | 8 |
| 9 #include "src/compiler.h" | 9 #include "src/compiler.h" |
| 10 #include "src/interpreter/control-flow-builders.h" | 10 #include "src/interpreter/control-flow-builders.h" |
| 11 #include "src/objects.h" | 11 #include "src/objects.h" |
| 12 #include "src/parser.h" | 12 #include "src/parser.h" |
| 13 #include "src/scopes.h" | 13 #include "src/scopes.h" |
| 14 #include "src/token.h" | 14 #include "src/token.h" |
| 15 | 15 |
| 16 namespace v8 { | 16 namespace v8 { |
| 17 namespace internal { | 17 namespace internal { |
| 18 namespace interpreter { | 18 namespace interpreter { |
| 19 | 19 |
| 20 | 20 |
| 21 // Scoped class tracking context objects created by the visitor. Represents | 21 // Scoped class tracking context objects created by the visitor. Represents |
| 22 // mutations of the context chain within the function body, allowing pushing and | 22 // mutations of the context chain within the function body, allowing pushing and |
| 23 // popping of the current {context_register} during visitation. | 23 // popping of the current {context_register} during visitation. |
| 24 class BytecodeGenerator::ContextScope BASE_EMBEDDED { | 24 class BytecodeGenerator::ContextScope BASE_EMBEDDED { |
| 25 public: | 25 public: |
| 26 explicit ContextScope(BytecodeGenerator* generator, | 26 ContextScope(BytecodeGenerator* generator, Scope* scope, |
| 27 bool is_function_context = false) | 27 bool is_function_context = false) |
| 28 : generator_(generator), | 28 : generator_(generator), |
| 29 outer_(generator_->current_context()), | 29 scope_(scope), |
| 30 outer_(generator_->execution_context()), | |
| 31 register_(generator_->NextContextRegister()), | |
| 32 depth_(0), | |
| 30 is_function_context_(is_function_context) { | 33 is_function_context_(is_function_context) { |
| 31 DCHECK(!is_function_context || | 34 if (outer_) { |
| 32 outer_.index() == Register::function_context().index()); | 35 depth_ = outer_->depth_ + 1; |
| 33 Register new_context_reg = NewContextRegister(); | 36 generator_->builder()->PushContext(register_); |
| 34 generator_->builder()->PushContext(new_context_reg); | 37 } |
| 35 generator_->set_current_context(new_context_reg); | 38 generator_->set_execution_context(this); |
| 36 } | 39 } |
| 37 | 40 |
| 38 ~ContextScope() { | 41 ~ContextScope() { |
| 39 if (!is_function_context_) { | 42 if (outer_ && !is_function_context_) { |
|
Michael Starzinger
2015/10/16 09:10:04
The semantics of the "is_function_context" flags a
rmcilroy
2015/10/16 11:19:04
Done, but named it should_pop_context.
Michael Starzinger
2015/10/16 13:29:05
Acknowledged. Works for me.
| |
| 40 generator_->builder()->PopContext(outer_); | 43 generator_->builder()->PopContext(outer_->reg()); |
| 41 } | 44 } |
| 42 generator_->set_current_context(outer_); | 45 generator_->set_execution_context(outer_); |
| 43 } | 46 } |
| 44 | 47 |
| 45 private: | 48 // Returns the execution context for the given |scope| if it is a function |
| 46 Register NewContextRegister() const { | 49 // local execution context, otherwise returns nullptr. |
| 47 if (outer_.index() == Register::function_context().index()) { | 50 ContextScope* Previous(Scope* scope) { |
| 48 return generator_->builder()->first_context_register(); | 51 int depth = scope_->ContextChainLength(scope); |
| 49 } else { | 52 if (depth > depth_) { |
| 50 DCHECK_LT(outer_.index(), | 53 return nullptr; |
| 51 generator_->builder()->last_context_register().index()); | |
| 52 return Register(outer_.index() + 1); | |
| 53 } | 54 } |
| 55 | |
| 56 ContextScope* previous = this; | |
| 57 for (int i = depth; i > 0; --i) { | |
| 58 previous = previous->outer_; | |
| 59 } | |
| 60 DCHECK_EQ(previous->scope_, scope); | |
| 61 return previous; | |
| 54 } | 62 } |
| 55 | 63 |
| 64 Scope* scope() const { return scope_; } | |
| 65 Register reg() const { return register_; } | |
| 66 | |
| 67 private: | |
| 56 BytecodeGenerator* generator_; | 68 BytecodeGenerator* generator_; |
| 57 Register outer_; | 69 Scope* scope_; |
| 70 ContextScope* outer_; | |
| 71 Register register_; | |
| 72 int depth_; | |
| 58 bool is_function_context_; | 73 bool is_function_context_; |
| 59 }; | 74 }; |
| 60 | 75 |
| 61 | 76 |
| 62 // Scoped class for tracking control statements entered by the | 77 // Scoped class for tracking control statements entered by the |
| 63 // visitor. The pattern derives AstGraphBuilder::ControlScope. | 78 // visitor. The pattern derives AstGraphBuilder::ControlScope. |
| 64 class BytecodeGenerator::ControlScope BASE_EMBEDDED { | 79 class BytecodeGenerator::ControlScope BASE_EMBEDDED { |
| 65 public: | 80 public: |
| 66 explicit ControlScope(BytecodeGenerator* generator) | 81 explicit ControlScope(BytecodeGenerator* generator) |
| 67 : generator_(generator), outer_(generator->control_scope()) { | 82 : generator_(generator), outer_(generator->execution_control()) { |
| 68 generator_->set_control_scope(this); | 83 generator_->set_execution_control(this); |
| 69 } | 84 } |
| 70 virtual ~ControlScope() { generator_->set_control_scope(outer()); } | 85 virtual ~ControlScope() { generator_->set_execution_control(outer()); } |
| 71 | 86 |
| 72 void Break(Statement* stmt) { PerformCommand(CMD_BREAK, stmt); } | 87 void Break(Statement* stmt) { PerformCommand(CMD_BREAK, stmt); } |
| 73 void Continue(Statement* stmt) { PerformCommand(CMD_CONTINUE, stmt); } | 88 void Continue(Statement* stmt) { PerformCommand(CMD_CONTINUE, stmt); } |
| 74 | 89 |
| 75 protected: | 90 protected: |
| 76 enum Command { CMD_BREAK, CMD_CONTINUE }; | 91 enum Command { CMD_BREAK, CMD_CONTINUE }; |
| 77 void PerformCommand(Command command, Statement* statement); | 92 void PerformCommand(Command command, Statement* statement); |
| 78 virtual bool Execute(Command command, Statement* statement) = 0; | 93 virtual bool Execute(Command command, Statement* statement) = 0; |
| 79 | 94 |
| 80 BytecodeGenerator* generator() const { return generator_; } | 95 BytecodeGenerator* generator() const { return generator_; } |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 131 } | 146 } |
| 132 | 147 |
| 133 | 148 |
| 134 BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone) | 149 BytecodeGenerator::BytecodeGenerator(Isolate* isolate, Zone* zone) |
| 135 : isolate_(isolate), | 150 : isolate_(isolate), |
| 136 zone_(zone), | 151 zone_(zone), |
| 137 builder_(isolate, zone), | 152 builder_(isolate, zone), |
| 138 info_(nullptr), | 153 info_(nullptr), |
| 139 scope_(nullptr), | 154 scope_(nullptr), |
| 140 globals_(0, zone), | 155 globals_(0, zone), |
| 141 control_scope_(nullptr), | 156 execution_control_(nullptr), |
| 142 current_context_(Register::function_context()) { | 157 execution_context_(nullptr) { |
| 143 InitializeAstVisitor(isolate); | 158 InitializeAstVisitor(isolate); |
| 144 } | 159 } |
| 145 | 160 |
| 146 | 161 |
| 147 BytecodeGenerator::~BytecodeGenerator() {} | 162 BytecodeGenerator::~BytecodeGenerator() {} |
| 148 | 163 |
| 149 | 164 |
| 150 Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) { | 165 Handle<BytecodeArray> BytecodeGenerator::MakeBytecode(CompilationInfo* info) { |
| 151 set_info(info); | 166 set_info(info); |
| 152 set_scope(info->scope()); | 167 set_scope(info->scope()); |
| 153 | 168 |
| 169 // Initialize the incoming context. | |
| 170 ContextScope incoming_context(this, scope(), true); | |
| 171 | |
| 154 builder()->set_parameter_count(info->num_parameters_including_this()); | 172 builder()->set_parameter_count(info->num_parameters_including_this()); |
| 155 builder()->set_locals_count(scope()->num_stack_slots()); | 173 builder()->set_locals_count(scope()->num_stack_slots()); |
| 156 builder()->set_context_count(scope()->MaxNestedContextChainLength()); | 174 builder()->set_context_count(scope()->MaxNestedContextChainLength()); |
| 157 | 175 |
| 158 // Build function context only if there are context allocated variables. | 176 // Build function context only if there are context allocated variables. |
| 159 if (scope()->NeedsContext()) { | 177 if (scope()->NeedsContext()) { |
| 160 // Push a new inner context scope for the function. | 178 // Push a new inner context scope for the function. |
| 161 VisitNewLocalFunctionContext(); | 179 VisitNewLocalFunctionContext(); |
| 162 ContextScope top_context(this, true); | 180 ContextScope local_function_context(this, scope(), true); |
| 163 MakeBytecodeBody(); | 181 MakeBytecodeBody(); |
| 164 } else { | 182 } else { |
| 165 MakeBytecodeBody(); | 183 MakeBytecodeBody(); |
| 166 } | 184 } |
| 167 | 185 |
| 168 set_scope(nullptr); | 186 set_scope(nullptr); |
| 169 set_info(nullptr); | 187 set_info(nullptr); |
| 170 return builder_.ToBytecodeArray(); | 188 return builder_.ToBytecodeArray(); |
| 171 } | 189 } |
| 172 | 190 |
| 173 | 191 |
| 174 void BytecodeGenerator::MakeBytecodeBody() { | 192 void BytecodeGenerator::MakeBytecodeBody() { |
| 175 // Visit declarations within the function scope. | 193 // Visit declarations within the function scope. |
| 176 VisitDeclarations(scope()->declarations()); | 194 VisitDeclarations(scope()->declarations()); |
| 177 | 195 |
| 178 // Visit statements in the function body. | 196 // Visit statements in the function body. |
| 179 VisitStatements(info()->literal()->body()); | 197 VisitStatements(info()->literal()->body()); |
| 180 } | 198 } |
| 181 | 199 |
| 182 | 200 |
| 183 void BytecodeGenerator::VisitBlock(Block* node) { | 201 void BytecodeGenerator::VisitBlock(Block* stmt) { |
| 184 builder()->EnterBlock(); | 202 builder()->EnterBlock(); |
| 185 if (node->scope() == NULL) { | 203 if (stmt->scope() == NULL) { |
| 186 // Visit statements in the same scope, no declarations. | 204 // Visit statements in the same scope, no declarations. |
| 187 VisitStatements(node->statements()); | 205 VisitStatements(stmt->statements()); |
| 188 } else { | 206 } else { |
| 189 // Visit declarations and statements in a block scope. | 207 // Visit declarations and statements in a block scope. |
| 190 if (node->scope()->ContextLocalCount() > 0) { | 208 if (stmt->scope()->NeedsContext()) { |
| 191 UNIMPLEMENTED(); | 209 VisitNewLocalBlockContext(stmt->scope()); |
| 210 ContextScope scope(this, stmt->scope()); | |
| 211 VisitDeclarations(stmt->scope()->declarations()); | |
| 212 VisitStatements(stmt->statements()); | |
| 192 } else { | 213 } else { |
| 193 VisitDeclarations(node->scope()->declarations()); | 214 VisitDeclarations(stmt->scope()->declarations()); |
| 194 VisitStatements(node->statements()); | 215 VisitStatements(stmt->statements()); |
| 195 } | 216 } |
| 196 } | 217 } |
| 197 builder()->LeaveBlock(); | 218 builder()->LeaveBlock(); |
| 198 } | 219 } |
| 199 | 220 |
| 200 | 221 |
| 201 void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) { | 222 void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) { |
| 202 Variable* variable = decl->proxy()->var(); | 223 Variable* variable = decl->proxy()->var(); |
| 203 VariableMode mode = decl->mode(); | 224 VariableMode mode = decl->mode(); |
| 204 bool hole_init = mode == CONST || mode == CONST_LEGACY || mode == LET; | 225 bool hole_init = mode == CONST || mode == CONST_LEGACY || mode == LET; |
|
oth
2015/10/16 09:30:43
A comment would be helpful explaining the purpose
rmcilroy
2015/10/16 11:19:04
Done.
| |
| 205 if (hole_init) { | |
| 206 UNIMPLEMENTED(); | |
| 207 } | |
| 208 switch (variable->location()) { | 226 switch (variable->location()) { |
| 209 case VariableLocation::GLOBAL: | 227 case VariableLocation::GLOBAL: |
| 210 case VariableLocation::UNALLOCATED: { | 228 case VariableLocation::UNALLOCATED: { |
| 211 Handle<Oddball> value = variable->binding_needs_init() | 229 Handle<Oddball> value = variable->binding_needs_init() |
| 212 ? isolate()->factory()->the_hole_value() | 230 ? isolate()->factory()->the_hole_value() |
| 213 : isolate()->factory()->undefined_value(); | 231 : isolate()->factory()->undefined_value(); |
| 214 globals()->push_back(variable->name()); | 232 globals()->push_back(variable->name()); |
| 215 globals()->push_back(value); | 233 globals()->push_back(value); |
| 216 break; | 234 break; |
| 217 } | 235 } |
| 236 case VariableLocation::LOCAL: | |
| 237 if (hole_init) { | |
| 238 Register destination(variable->index()); | |
| 239 builder()->LoadTheHole().StoreAccumulatorInRegister(destination); | |
| 240 } | |
| 241 break; | |
| 218 case VariableLocation::PARAMETER: | 242 case VariableLocation::PARAMETER: |
| 219 case VariableLocation::LOCAL: | 243 if (hole_init) { |
| 220 // Details stored in scope, i.e. variable index. | 244 // The parameter indices are shifted by 1 (receiver is variable |
| 245 // index -1 but is parameter index 0 in BytecodeArrayBuilder). | |
| 246 Register destination(builder()->Parameter(variable->index() + 1)); | |
| 247 builder()->LoadTheHole().StoreAccumulatorInRegister(destination); | |
| 248 } | |
| 221 break; | 249 break; |
| 222 case VariableLocation::CONTEXT: | 250 case VariableLocation::CONTEXT: |
| 251 if (hole_init) { | |
| 252 builder()->LoadTheHole().StoreContextSlot(execution_context()->reg(), | |
| 253 variable->index()); | |
| 254 } | |
| 255 break; | |
| 223 case VariableLocation::LOOKUP: | 256 case VariableLocation::LOOKUP: |
| 224 UNIMPLEMENTED(); | 257 UNIMPLEMENTED(); |
| 225 break; | 258 break; |
| 226 } | 259 } |
| 227 } | 260 } |
| 228 | 261 |
| 229 | 262 |
| 230 void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) { | 263 void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) { |
| 231 Variable* variable = decl->proxy()->var(); | 264 Variable* variable = decl->proxy()->var(); |
| 232 switch (variable->location()) { | 265 switch (variable->location()) { |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 319 } | 352 } |
| 320 | 353 |
| 321 | 354 |
| 322 void BytecodeGenerator::VisitSloppyBlockFunctionStatement( | 355 void BytecodeGenerator::VisitSloppyBlockFunctionStatement( |
| 323 SloppyBlockFunctionStatement* stmt) { | 356 SloppyBlockFunctionStatement* stmt) { |
| 324 Visit(stmt->statement()); | 357 Visit(stmt->statement()); |
| 325 } | 358 } |
| 326 | 359 |
| 327 | 360 |
| 328 void BytecodeGenerator::VisitContinueStatement(ContinueStatement* stmt) { | 361 void BytecodeGenerator::VisitContinueStatement(ContinueStatement* stmt) { |
| 329 control_scope()->Continue(stmt->target()); | 362 execution_control()->Continue(stmt->target()); |
| 330 } | 363 } |
| 331 | 364 |
| 332 | 365 |
| 333 void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) { | 366 void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) { |
| 334 control_scope()->Break(stmt->target()); | 367 execution_control()->Break(stmt->target()); |
| 335 } | 368 } |
| 336 | 369 |
| 337 | 370 |
| 338 void BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { | 371 void BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { |
| 339 Visit(stmt->expression()); | 372 Visit(stmt->expression()); |
| 340 builder()->Return(); | 373 builder()->Return(); |
| 341 } | 374 } |
| 342 | 375 |
| 343 | 376 |
| 344 void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) { | 377 void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) { |
| 345 UNIMPLEMENTED(); | 378 UNIMPLEMENTED(); |
| 346 } | 379 } |
| 347 | 380 |
| 348 | 381 |
| 349 void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { | 382 void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { |
| 350 UNIMPLEMENTED(); | 383 UNIMPLEMENTED(); |
| 351 } | 384 } |
| 352 | 385 |
| 353 | 386 |
| 354 void BytecodeGenerator::VisitCaseClause(CaseClause* clause) { UNIMPLEMENTED(); } | 387 void BytecodeGenerator::VisitCaseClause(CaseClause* clause) { UNIMPLEMENTED(); } |
| 355 | 388 |
| 356 | 389 |
| 357 void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { | 390 void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { |
| 358 LoopBuilder loop_builder(builder()); | 391 LoopBuilder loop_builder(builder()); |
| 359 ControlScopeForIteration control_scope(this, stmt, &loop_builder); | 392 ControlScopeForIteration execution_control(this, stmt, &loop_builder); |
| 360 | 393 |
| 361 BytecodeLabel body_label, condition_label, done_label; | 394 BytecodeLabel body_label, condition_label, done_label; |
| 362 builder()->Bind(&body_label); | 395 builder()->Bind(&body_label); |
| 363 Visit(stmt->body()); | 396 Visit(stmt->body()); |
| 364 builder()->Bind(&condition_label); | 397 builder()->Bind(&condition_label); |
| 365 Visit(stmt->cond()); | 398 Visit(stmt->cond()); |
| 366 builder()->JumpIfTrue(&body_label); | 399 builder()->JumpIfTrue(&body_label); |
| 367 builder()->Bind(&done_label); | 400 builder()->Bind(&done_label); |
| 368 | 401 |
| 369 loop_builder.SetBreakTarget(done_label); | 402 loop_builder.SetBreakTarget(done_label); |
| 370 loop_builder.SetContinueTarget(condition_label); | 403 loop_builder.SetContinueTarget(condition_label); |
| 371 } | 404 } |
| 372 | 405 |
| 373 | 406 |
| 374 void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) { | 407 void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) { |
| 375 LoopBuilder loop_builder(builder()); | 408 LoopBuilder loop_builder(builder()); |
| 376 ControlScopeForIteration control_scope(this, stmt, &loop_builder); | 409 ControlScopeForIteration execution_control(this, stmt, &loop_builder); |
| 377 | 410 |
| 378 BytecodeLabel body_label, condition_label, done_label; | 411 BytecodeLabel body_label, condition_label, done_label; |
| 379 builder()->Jump(&condition_label); | 412 builder()->Jump(&condition_label); |
| 380 builder()->Bind(&body_label); | 413 builder()->Bind(&body_label); |
| 381 Visit(stmt->body()); | 414 Visit(stmt->body()); |
| 382 builder()->Bind(&condition_label); | 415 builder()->Bind(&condition_label); |
| 383 Visit(stmt->cond()); | 416 Visit(stmt->cond()); |
| 384 builder()->JumpIfTrue(&body_label); | 417 builder()->JumpIfTrue(&body_label); |
| 385 builder()->Bind(&done_label); | 418 builder()->Bind(&done_label); |
| 386 | 419 |
| 387 loop_builder.SetBreakTarget(done_label); | 420 loop_builder.SetBreakTarget(done_label); |
| 388 loop_builder.SetContinueTarget(condition_label); | 421 loop_builder.SetContinueTarget(condition_label); |
| 389 } | 422 } |
| 390 | 423 |
| 391 | 424 |
| 392 void BytecodeGenerator::VisitForStatement(ForStatement* stmt) { | 425 void BytecodeGenerator::VisitForStatement(ForStatement* stmt) { |
| 393 LoopBuilder loop_builder(builder()); | 426 LoopBuilder loop_builder(builder()); |
| 394 ControlScopeForIteration control_scope(this, stmt, &loop_builder); | 427 ControlScopeForIteration execution_control(this, stmt, &loop_builder); |
| 395 | 428 |
| 396 if (stmt->init() != nullptr) { | 429 if (stmt->init() != nullptr) { |
| 397 Visit(stmt->init()); | 430 Visit(stmt->init()); |
| 398 } | 431 } |
| 399 | 432 |
| 400 BytecodeLabel body_label, condition_label, next_label, done_label; | 433 BytecodeLabel body_label, condition_label, next_label, done_label; |
| 401 if (stmt->cond() != nullptr) { | 434 if (stmt->cond() != nullptr) { |
| 402 builder()->Jump(&condition_label); | 435 builder()->Jump(&condition_label); |
| 403 } | 436 } |
| 404 builder()->Bind(&body_label); | 437 builder()->Bind(&body_label); |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 588 } | 621 } |
| 589 break; | 622 break; |
| 590 case ObjectLiteral::Property::SETTER: | 623 case ObjectLiteral::Property::SETTER: |
| 591 if (property->emit_store()) { | 624 if (property->emit_store()) { |
| 592 accessor_table.lookup(literal_key)->second->setter = property; | 625 accessor_table.lookup(literal_key)->second->setter = property; |
| 593 } | 626 } |
| 594 break; | 627 break; |
| 595 } | 628 } |
| 596 } | 629 } |
| 597 | 630 |
| 598 // Create nodes to define accessors, using only a single call to the runtime | 631 // Define accessors, using only a single call to the runtime for each pair of |
| 599 // for each pair of corresponding getters and setters. | 632 // corresponding getters and setters. |
| 600 for (AccessorTable::Iterator it = accessor_table.begin(); | 633 for (AccessorTable::Iterator it = accessor_table.begin(); |
| 601 it != accessor_table.end(); ++it) { | 634 it != accessor_table.end(); ++it) { |
| 602 TemporaryRegisterScope inner_temporary_register_scope(builder()); | 635 TemporaryRegisterScope inner_temporary_register_scope(builder()); |
| 603 Register name = inner_temporary_register_scope.NewRegister(); | 636 Register name = inner_temporary_register_scope.NewRegister(); |
| 604 Register getter = inner_temporary_register_scope.NewRegister(); | 637 Register getter = inner_temporary_register_scope.NewRegister(); |
| 605 Register setter = inner_temporary_register_scope.NewRegister(); | 638 Register setter = inner_temporary_register_scope.NewRegister(); |
| 606 Register attr = inner_temporary_register_scope.NewRegister(); | 639 Register attr = inner_temporary_register_scope.NewRegister(); |
| 607 DCHECK(Register::AreContiguous(literal, name, getter, setter, attr)); | 640 DCHECK(Register::AreContiguous(literal, name, getter, setter, attr)); |
| 608 Visit(it->first); | 641 Visit(it->first); |
| 609 builder()->StoreAccumulatorInRegister(name); | 642 builder()->StoreAccumulatorInRegister(name); |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 691 | 724 |
| 692 void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { | 725 void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
| 693 // Deep-copy the literal boilerplate. | 726 // Deep-copy the literal boilerplate. |
| 694 builder() | 727 builder() |
| 695 ->LoadLiteral(expr->constant_elements()) | 728 ->LoadLiteral(expr->constant_elements()) |
| 696 .CreateArrayLiteral(expr->literal_index(), expr->ComputeFlags(true)); | 729 .CreateArrayLiteral(expr->literal_index(), expr->ComputeFlags(true)); |
| 697 | 730 |
| 698 TemporaryRegisterScope temporary_register_scope(builder()); | 731 TemporaryRegisterScope temporary_register_scope(builder()); |
| 699 Register index, literal; | 732 Register index, literal; |
| 700 | 733 |
| 701 // Create nodes to evaluate all the non-constant subexpressions and to store | 734 // Evaluate all the non-constant subexpressions and to store them into the |
|
Michael Starzinger
2015/10/16 09:10:04
nit: Drop the "to" in this sentence.
rmcilroy
2015/10/16 11:19:04
Done.
| |
| 702 // them into the newly cloned array. | 735 // newly cloned array. |
| 703 bool literal_in_accumulator = true; | 736 bool literal_in_accumulator = true; |
| 704 for (int array_index = 0; array_index < expr->values()->length(); | 737 for (int array_index = 0; array_index < expr->values()->length(); |
| 705 array_index++) { | 738 array_index++) { |
| 706 Expression* subexpr = expr->values()->at(array_index); | 739 Expression* subexpr = expr->values()->at(array_index); |
| 707 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; | 740 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; |
| 708 if (subexpr->IsSpread()) { | 741 if (subexpr->IsSpread()) { |
| 709 // TODO(rmcilroy): Deal with spread expressions. | 742 // TODO(rmcilroy): Deal with spread expressions. |
| 710 UNIMPLEMENTED(); | 743 UNIMPLEMENTED(); |
| 711 } | 744 } |
| 712 | 745 |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 737 VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot()); | 770 VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot()); |
| 738 } | 771 } |
| 739 | 772 |
| 740 | 773 |
| 741 void BytecodeGenerator::VisitVariableLoad(Variable* variable, | 774 void BytecodeGenerator::VisitVariableLoad(Variable* variable, |
| 742 FeedbackVectorSlot slot) { | 775 FeedbackVectorSlot slot) { |
| 743 switch (variable->location()) { | 776 switch (variable->location()) { |
| 744 case VariableLocation::LOCAL: { | 777 case VariableLocation::LOCAL: { |
| 745 Register source(variable->index()); | 778 Register source(variable->index()); |
| 746 builder()->LoadAccumulatorWithRegister(source); | 779 builder()->LoadAccumulatorWithRegister(source); |
| 780 // TODO(rmcilroy): Perform check for uninitialized legacy const, const and | |
| 781 // let variables. | |
| 747 break; | 782 break; |
| 748 } | 783 } |
| 749 case VariableLocation::PARAMETER: { | 784 case VariableLocation::PARAMETER: { |
| 750 // The parameter indices are shifted by 1 (receiver is variable | 785 // The parameter indices are shifted by 1 (receiver is variable |
| 751 // index -1 but is parameter index 0 in BytecodeArrayBuilder). | 786 // index -1 but is parameter index 0 in BytecodeArrayBuilder). |
| 752 Register source(builder()->Parameter(variable->index() + 1)); | 787 Register source(builder()->Parameter(variable->index() + 1)); |
| 753 builder()->LoadAccumulatorWithRegister(source); | 788 builder()->LoadAccumulatorWithRegister(source); |
| 754 break; | 789 break; |
| 755 } | 790 } |
| 756 case VariableLocation::GLOBAL: { | 791 case VariableLocation::GLOBAL: { |
| 757 // Global var, const, or let variable. | 792 // Global var, const, or let variable. |
| 758 // TODO(rmcilroy): If context chain depth is short enough, do this using | 793 // TODO(rmcilroy): If context chain depth is short enough, do this using |
| 759 // a generic version of LoadGlobalViaContextStub rather than calling the | 794 // a generic version of LoadGlobalViaContextStub rather than calling the |
| 760 // runtime. | 795 // runtime. |
| 761 DCHECK(variable->IsStaticGlobalObjectProperty()); | 796 DCHECK(variable->IsStaticGlobalObjectProperty()); |
| 762 builder()->LoadGlobal(variable->index()); | 797 builder()->LoadGlobal(variable->index()); |
| 763 break; | 798 break; |
| 764 } | 799 } |
| 765 case VariableLocation::UNALLOCATED: { | 800 case VariableLocation::UNALLOCATED: { |
| 766 TemporaryRegisterScope temporary_register_scope(builder()); | 801 TemporaryRegisterScope temporary_register_scope(builder()); |
| 767 Register obj = temporary_register_scope.NewRegister(); | 802 Register obj = temporary_register_scope.NewRegister(); |
| 768 builder()->LoadContextSlot(current_context(), | 803 builder()->LoadContextSlot(execution_context()->reg(), |
| 769 Context::GLOBAL_OBJECT_INDEX); | 804 Context::GLOBAL_OBJECT_INDEX); |
| 770 builder()->StoreAccumulatorInRegister(obj); | 805 builder()->StoreAccumulatorInRegister(obj); |
| 771 builder()->LoadLiteral(variable->name()); | 806 builder()->LoadLiteral(variable->name()); |
| 772 builder()->LoadNamedProperty(obj, feedback_index(slot), language_mode()); | 807 builder()->LoadNamedProperty(obj, feedback_index(slot), language_mode()); |
| 773 break; | 808 break; |
| 774 } | 809 } |
| 775 case VariableLocation::CONTEXT: | 810 case VariableLocation::CONTEXT: { |
| 811 ContextScope* context = execution_context()->Previous(variable->scope()); | |
| 812 if (context) { | |
| 813 builder()->LoadContextSlot(context->reg(), variable->index()); | |
| 814 } else { | |
| 815 UNIMPLEMENTED(); | |
| 816 } | |
| 817 // TODO(rmcilroy): Perform check for uninitialized legacy const, const and | |
| 818 // let variables. | |
| 819 break; | |
| 820 } | |
| 776 case VariableLocation::LOOKUP: | 821 case VariableLocation::LOOKUP: |
| 777 UNIMPLEMENTED(); | 822 UNIMPLEMENTED(); |
| 778 } | 823 } |
| 779 } | 824 } |
| 780 | 825 |
| 781 | 826 |
| 782 void BytecodeGenerator::VisitVariableAssignment(Variable* variable, | 827 void BytecodeGenerator::VisitVariableAssignment(Variable* variable, |
| 783 FeedbackVectorSlot slot) { | 828 FeedbackVectorSlot slot) { |
| 784 switch (variable->location()) { | 829 switch (variable->location()) { |
| 785 case VariableLocation::LOCAL: { | 830 case VariableLocation::LOCAL: { |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 805 break; | 850 break; |
| 806 } | 851 } |
| 807 case VariableLocation::UNALLOCATED: { | 852 case VariableLocation::UNALLOCATED: { |
| 808 TemporaryRegisterScope temporary_register_scope(builder()); | 853 TemporaryRegisterScope temporary_register_scope(builder()); |
| 809 Register value = temporary_register_scope.NewRegister(); | 854 Register value = temporary_register_scope.NewRegister(); |
| 810 Register obj = temporary_register_scope.NewRegister(); | 855 Register obj = temporary_register_scope.NewRegister(); |
| 811 Register name = temporary_register_scope.NewRegister(); | 856 Register name = temporary_register_scope.NewRegister(); |
| 812 // TODO(rmcilroy): Investigate whether we can avoid having to stash the | 857 // TODO(rmcilroy): Investigate whether we can avoid having to stash the |
| 813 // value in a register. | 858 // value in a register. |
| 814 builder()->StoreAccumulatorInRegister(value); | 859 builder()->StoreAccumulatorInRegister(value); |
| 815 builder()->LoadContextSlot(current_context(), | 860 builder()->LoadContextSlot(execution_context()->reg(), |
| 816 Context::GLOBAL_OBJECT_INDEX); | 861 Context::GLOBAL_OBJECT_INDEX); |
| 817 builder()->StoreAccumulatorInRegister(obj); | 862 builder()->StoreAccumulatorInRegister(obj); |
| 818 builder()->LoadLiteral(variable->name()); | 863 builder()->LoadLiteral(variable->name()); |
| 819 builder()->StoreAccumulatorInRegister(name); | 864 builder()->StoreAccumulatorInRegister(name); |
| 820 builder()->LoadAccumulatorWithRegister(value); | 865 builder()->LoadAccumulatorWithRegister(value); |
| 821 builder()->StoreNamedProperty(obj, name, feedback_index(slot), | 866 builder()->StoreNamedProperty(obj, name, feedback_index(slot), |
| 822 language_mode()); | 867 language_mode()); |
| 823 break; | 868 break; |
| 824 } | 869 } |
| 825 case VariableLocation::CONTEXT: | 870 case VariableLocation::CONTEXT: { |
| 871 // TODO(rmcilroy): support const mode initialization. | |
| 872 ContextScope* context = execution_context()->Previous(variable->scope()); | |
| 873 if (context) { | |
| 874 builder()->StoreContextSlot(context->reg(), variable->index()); | |
| 875 } else { | |
| 876 UNIMPLEMENTED(); | |
| 877 } | |
| 878 break; | |
| 879 } | |
| 826 case VariableLocation::LOOKUP: | 880 case VariableLocation::LOOKUP: |
| 827 UNIMPLEMENTED(); | 881 UNIMPLEMENTED(); |
| 828 } | 882 } |
| 829 } | 883 } |
| 830 | 884 |
| 831 | 885 |
| 832 void BytecodeGenerator::VisitAssignment(Assignment* expr) { | 886 void BytecodeGenerator::VisitAssignment(Assignment* expr) { |
| 833 DCHECK(expr->target()->IsValidReferenceExpression()); | 887 DCHECK(expr->target()->IsValidReferenceExpression()); |
| 834 TemporaryRegisterScope temporary_register_scope(builder()); | 888 TemporaryRegisterScope temporary_register_scope(builder()); |
| 835 Register object, key; | 889 Register object, key; |
| (...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1150 int num_parameters = scope->num_parameters(); | 1204 int num_parameters = scope->num_parameters(); |
| 1151 for (int i = 0; i < num_parameters; i++) { | 1205 for (int i = 0; i < num_parameters; i++) { |
| 1152 Variable* variable = scope->parameter(i); | 1206 Variable* variable = scope->parameter(i); |
| 1153 if (variable->IsContextSlot()) { | 1207 if (variable->IsContextSlot()) { |
| 1154 UNIMPLEMENTED(); | 1208 UNIMPLEMENTED(); |
| 1155 } | 1209 } |
| 1156 } | 1210 } |
| 1157 } | 1211 } |
| 1158 | 1212 |
| 1159 | 1213 |
| 1214 void BytecodeGenerator::VisitNewLocalBlockContext(Scope* scope) { | |
| 1215 DCHECK(scope->is_block_scope()); | |
| 1216 | |
| 1217 // Allocate a new local block context. | |
| 1218 TemporaryRegisterScope temporary_register_scope(builder()); | |
| 1219 Register scope_info = temporary_register_scope.NewRegister(); | |
| 1220 Register closure = temporary_register_scope.NewRegister(); | |
| 1221 DCHECK(Register::AreContiguous(scope_info, closure)); | |
| 1222 builder() | |
| 1223 ->LoadLiteral(scope->GetScopeInfo(isolate())) | |
| 1224 .StoreAccumulatorInRegister(scope_info) | |
| 1225 .LoadAccumulatorWithRegister(Register::function_closure()) | |
|
Michael Starzinger
2015/10/16 09:10:04
For script (or any other top level code) the passe
rmcilroy
2015/10/16 11:19:04
Ahh I never spotted this, thanks for the hint. I'v
Michael Starzinger
2015/10/16 13:29:06
Acknowledged.
| |
| 1226 .StoreAccumulatorInRegister(closure) | |
| 1227 .CallRuntime(Runtime::kPushBlockContext, scope_info, 2); | |
| 1228 } | |
| 1229 | |
| 1230 | |
| 1160 void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* binop) { | 1231 void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* binop) { |
| 1161 Token::Value op = binop->op(); | 1232 Token::Value op = binop->op(); |
| 1162 Expression* left = binop->left(); | 1233 Expression* left = binop->left(); |
| 1163 Expression* right = binop->right(); | 1234 Expression* right = binop->right(); |
| 1164 | 1235 |
| 1165 TemporaryRegisterScope temporary_register_scope(builder()); | 1236 TemporaryRegisterScope temporary_register_scope(builder()); |
| 1166 Register temporary = temporary_register_scope.NewRegister(); | 1237 Register temporary = temporary_register_scope.NewRegister(); |
| 1167 | 1238 |
| 1168 Visit(left); | 1239 Visit(left); |
| 1169 builder()->StoreAccumulatorInRegister(temporary); | 1240 builder()->StoreAccumulatorInRegister(temporary); |
| 1170 Visit(right); | 1241 Visit(right); |
| 1171 builder()->BinaryOperation(op, temporary, language_mode_strength()); | 1242 builder()->BinaryOperation(op, temporary, language_mode_strength()); |
| 1172 } | 1243 } |
| 1173 | 1244 |
| 1174 | 1245 |
| 1175 void BytecodeGenerator::VisitObjectLiteralAccessor( | |
| 1176 Register home_object, ObjectLiteralProperty* property, Register value_out) { | |
| 1177 // TODO(rmcilroy): Replace value_out with VisitForRegister(); | |
| 1178 if (property == nullptr) { | |
| 1179 builder()->LoadNull().StoreAccumulatorInRegister(value_out); | |
| 1180 } else { | |
| 1181 Visit(property->value()); | |
| 1182 builder()->StoreAccumulatorInRegister(value_out); | |
| 1183 VisitSetHomeObject(value_out, home_object, property); | |
| 1184 } | |
| 1185 } | |
| 1186 | |
| 1187 | |
| 1188 void BytecodeGenerator::VisitSetHomeObject(Register value, Register home_object, | |
| 1189 ObjectLiteralProperty* property, | |
| 1190 int slot_number) { | |
| 1191 Expression* expr = property->value(); | |
| 1192 if (!FunctionLiteral::NeedsHomeObject(expr)) return; | |
| 1193 | |
| 1194 // TODO(rmcilroy): Remove UNIMPLEMENTED once we have tests for setting the | |
| 1195 // home object. | |
| 1196 UNIMPLEMENTED(); | |
| 1197 | |
| 1198 TemporaryRegisterScope temporary_register_scope(builder()); | |
| 1199 Register name = temporary_register_scope.NewRegister(); | |
| 1200 isolate()->factory()->home_object_symbol(); | |
| 1201 builder() | |
| 1202 ->LoadLiteral(isolate()->factory()->home_object_symbol()) | |
| 1203 .StoreAccumulatorInRegister(name) | |
| 1204 .StoreNamedProperty(home_object, name, | |
| 1205 feedback_index(property->GetSlot(slot_number)), | |
| 1206 language_mode()); | |
| 1207 } | |
| 1208 | |
| 1209 | |
| 1210 void BytecodeGenerator::VisitCommaExpression(BinaryOperation* binop) { | 1246 void BytecodeGenerator::VisitCommaExpression(BinaryOperation* binop) { |
| 1211 Expression* left = binop->left(); | 1247 Expression* left = binop->left(); |
| 1212 Expression* right = binop->right(); | 1248 Expression* right = binop->right(); |
| 1213 | 1249 |
| 1214 Visit(left); | 1250 Visit(left); |
| 1215 Visit(right); | 1251 Visit(right); |
| 1216 } | 1252 } |
| 1217 | 1253 |
| 1218 | 1254 |
| 1219 void BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) { | 1255 void BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) { |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 1247 BytecodeLabel end_label; | 1283 BytecodeLabel end_label; |
| 1248 | 1284 |
| 1249 Visit(left); | 1285 Visit(left); |
| 1250 builder()->JumpIfToBooleanFalse(&end_label); | 1286 builder()->JumpIfToBooleanFalse(&end_label); |
| 1251 Visit(right); | 1287 Visit(right); |
| 1252 builder()->Bind(&end_label); | 1288 builder()->Bind(&end_label); |
| 1253 } | 1289 } |
| 1254 } | 1290 } |
| 1255 | 1291 |
| 1256 | 1292 |
| 1293 void BytecodeGenerator::VisitObjectLiteralAccessor( | |
| 1294 Register home_object, ObjectLiteralProperty* property, Register value_out) { | |
| 1295 // TODO(rmcilroy): Replace value_out with VisitForRegister(); | |
| 1296 if (property == nullptr) { | |
| 1297 builder()->LoadNull().StoreAccumulatorInRegister(value_out); | |
| 1298 } else { | |
| 1299 Visit(property->value()); | |
| 1300 builder()->StoreAccumulatorInRegister(value_out); | |
| 1301 VisitSetHomeObject(value_out, home_object, property); | |
| 1302 } | |
| 1303 } | |
| 1304 | |
| 1305 | |
| 1306 void BytecodeGenerator::VisitSetHomeObject(Register value, Register home_object, | |
| 1307 ObjectLiteralProperty* property, | |
| 1308 int slot_number) { | |
| 1309 Expression* expr = property->value(); | |
| 1310 if (!FunctionLiteral::NeedsHomeObject(expr)) return; | |
| 1311 | |
| 1312 // TODO(rmcilroy): Remove UNIMPLEMENTED once we have tests for setting the | |
| 1313 // home object. | |
| 1314 UNIMPLEMENTED(); | |
| 1315 | |
| 1316 TemporaryRegisterScope temporary_register_scope(builder()); | |
| 1317 Register name = temporary_register_scope.NewRegister(); | |
| 1318 isolate()->factory()->home_object_symbol(); | |
| 1319 builder() | |
| 1320 ->LoadLiteral(isolate()->factory()->home_object_symbol()) | |
| 1321 .StoreAccumulatorInRegister(name) | |
| 1322 .StoreNamedProperty(home_object, name, | |
| 1323 feedback_index(property->GetSlot(slot_number)), | |
| 1324 language_mode()); | |
| 1325 } | |
| 1326 | |
| 1327 | |
| 1328 Register BytecodeGenerator::NextContextRegister() const { | |
| 1329 if (execution_context() == nullptr) { | |
| 1330 return Register::function_context(); | |
| 1331 } | |
| 1332 Register previous = execution_context()->reg(); | |
| 1333 if (previous == Register::function_context()) { | |
|
oth
2015/10/16 09:30:43
Comments here explaining the logic for the returne
rmcilroy
2015/10/16 11:19:04
Done.
| |
| 1334 return builder_.first_context_register(); | |
| 1335 } else { | |
| 1336 DCHECK_LT(previous.index(), builder_.last_context_register().index()); | |
| 1337 return Register(previous.index() + 1); | |
| 1338 } | |
| 1339 } | |
| 1340 | |
| 1341 | |
| 1257 LanguageMode BytecodeGenerator::language_mode() const { | 1342 LanguageMode BytecodeGenerator::language_mode() const { |
| 1258 return info()->language_mode(); | 1343 return info()->language_mode(); |
| 1259 } | 1344 } |
| 1260 | 1345 |
| 1261 | 1346 |
| 1262 Strength BytecodeGenerator::language_mode_strength() const { | 1347 Strength BytecodeGenerator::language_mode_strength() const { |
| 1263 return strength(language_mode()); | 1348 return strength(language_mode()); |
| 1264 } | 1349 } |
| 1265 | 1350 |
| 1266 | 1351 |
| 1267 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { | 1352 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { |
| 1268 return info()->feedback_vector()->GetIndex(slot); | 1353 return info()->feedback_vector()->GetIndex(slot); |
| 1269 } | 1354 } |
| 1270 | 1355 |
| 1271 } // namespace interpreter | 1356 } // namespace interpreter |
| 1272 } // namespace internal | 1357 } // namespace internal |
| 1273 } // namespace v8 | 1358 } // namespace v8 |
| OLD | NEW |