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 should_pop_context = true) |
28 : generator_(generator), | 28 : generator_(generator), |
29 outer_(generator_->current_context()), | 29 scope_(scope), |
30 is_function_context_(is_function_context) { | 30 outer_(generator_->execution_context()), |
31 DCHECK(!is_function_context || | 31 register_(generator_->NextContextRegister()), |
32 outer_.index() == Register::function_context().index()); | 32 depth_(0), |
33 Register new_context_reg = NewContextRegister(); | 33 should_pop_context_(should_pop_context) { |
34 generator_->builder()->PushContext(new_context_reg); | 34 if (outer_) { |
35 generator_->set_current_context(new_context_reg); | 35 depth_ = outer_->depth_ + 1; |
36 generator_->builder()->PushContext(register_); | |
37 } | |
38 generator_->set_execution_context(this); | |
36 } | 39 } |
37 | 40 |
38 ~ContextScope() { | 41 ~ContextScope() { |
39 if (!is_function_context_) { | 42 if (should_pop_context_) { |
Michael Starzinger
2015/10/16 13:29:06
nit: Let's be defensive and keep checking "outer_
rmcilroy
2015/10/16 14:11:35
Ok, done.
| |
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_; |
58 bool is_function_context_; | 70 ContextScope* outer_; |
71 Register register_; | |
72 int depth_; | |
73 bool should_pop_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(), false); | |
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(), false); |
181 VisitBuildLocalActivationContext(); | |
163 MakeBytecodeBody(); | 182 MakeBytecodeBody(); |
164 } else { | 183 } else { |
165 MakeBytecodeBody(); | 184 MakeBytecodeBody(); |
166 } | 185 } |
167 | 186 |
168 set_scope(nullptr); | 187 set_scope(nullptr); |
169 set_info(nullptr); | 188 set_info(nullptr); |
170 return builder_.ToBytecodeArray(); | 189 return builder_.ToBytecodeArray(); |
171 } | 190 } |
172 | 191 |
173 | 192 |
174 void BytecodeGenerator::MakeBytecodeBody() { | 193 void BytecodeGenerator::MakeBytecodeBody() { |
175 // Visit declarations within the function scope. | 194 // Visit declarations within the function scope. |
176 VisitDeclarations(scope()->declarations()); | 195 VisitDeclarations(scope()->declarations()); |
177 | 196 |
178 // Visit statements in the function body. | 197 // Visit statements in the function body. |
179 VisitStatements(info()->literal()->body()); | 198 VisitStatements(info()->literal()->body()); |
180 } | 199 } |
181 | 200 |
182 | 201 |
183 void BytecodeGenerator::VisitBlock(Block* node) { | 202 void BytecodeGenerator::VisitBlock(Block* stmt) { |
184 builder()->EnterBlock(); | 203 builder()->EnterBlock(); |
185 if (node->scope() == NULL) { | 204 if (stmt->scope() == NULL) { |
186 // Visit statements in the same scope, no declarations. | 205 // Visit statements in the same scope, no declarations. |
187 VisitStatements(node->statements()); | 206 VisitStatements(stmt->statements()); |
188 } else { | 207 } else { |
189 // Visit declarations and statements in a block scope. | 208 // Visit declarations and statements in a block scope. |
190 if (node->scope()->ContextLocalCount() > 0) { | 209 if (stmt->scope()->NeedsContext()) { |
191 UNIMPLEMENTED(); | 210 VisitNewLocalBlockContext(stmt->scope()); |
211 ContextScope scope(this, stmt->scope()); | |
212 VisitDeclarations(stmt->scope()->declarations()); | |
213 VisitStatements(stmt->statements()); | |
192 } else { | 214 } else { |
193 VisitDeclarations(node->scope()->declarations()); | 215 VisitDeclarations(stmt->scope()->declarations()); |
194 VisitStatements(node->statements()); | 216 VisitStatements(stmt->statements()); |
195 } | 217 } |
196 } | 218 } |
197 builder()->LeaveBlock(); | 219 builder()->LeaveBlock(); |
198 } | 220 } |
199 | 221 |
200 | 222 |
201 void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) { | 223 void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) { |
202 Variable* variable = decl->proxy()->var(); | 224 Variable* variable = decl->proxy()->var(); |
203 VariableMode mode = decl->mode(); | 225 VariableMode mode = decl->mode(); |
226 // Const and let variables are initialized with the hole so that we can | |
227 // check that they are only assigned once. | |
204 bool hole_init = mode == CONST || mode == CONST_LEGACY || mode == LET; | 228 bool hole_init = mode == CONST || mode == CONST_LEGACY || mode == LET; |
205 if (hole_init) { | |
206 UNIMPLEMENTED(); | |
207 } | |
208 switch (variable->location()) { | 229 switch (variable->location()) { |
209 case VariableLocation::GLOBAL: | 230 case VariableLocation::GLOBAL: |
210 case VariableLocation::UNALLOCATED: { | 231 case VariableLocation::UNALLOCATED: { |
211 Handle<Oddball> value = variable->binding_needs_init() | 232 Handle<Oddball> value = variable->binding_needs_init() |
212 ? isolate()->factory()->the_hole_value() | 233 ? isolate()->factory()->the_hole_value() |
213 : isolate()->factory()->undefined_value(); | 234 : isolate()->factory()->undefined_value(); |
214 globals()->push_back(variable->name()); | 235 globals()->push_back(variable->name()); |
215 globals()->push_back(value); | 236 globals()->push_back(value); |
216 break; | 237 break; |
217 } | 238 } |
239 case VariableLocation::LOCAL: | |
240 if (hole_init) { | |
241 Register destination(variable->index()); | |
242 builder()->LoadTheHole().StoreAccumulatorInRegister(destination); | |
243 } | |
244 break; | |
218 case VariableLocation::PARAMETER: | 245 case VariableLocation::PARAMETER: |
219 case VariableLocation::LOCAL: | 246 if (hole_init) { |
220 // Details stored in scope, i.e. variable index. | 247 // The parameter indices are shifted by 1 (receiver is variable |
248 // index -1 but is parameter index 0 in BytecodeArrayBuilder). | |
249 Register destination(builder()->Parameter(variable->index() + 1)); | |
250 builder()->LoadTheHole().StoreAccumulatorInRegister(destination); | |
251 } | |
221 break; | 252 break; |
222 case VariableLocation::CONTEXT: | 253 case VariableLocation::CONTEXT: |
254 if (hole_init) { | |
255 builder()->LoadTheHole().StoreContextSlot(execution_context()->reg(), | |
256 variable->index()); | |
257 } | |
258 break; | |
223 case VariableLocation::LOOKUP: | 259 case VariableLocation::LOOKUP: |
224 UNIMPLEMENTED(); | 260 UNIMPLEMENTED(); |
225 break; | 261 break; |
226 } | 262 } |
227 } | 263 } |
228 | 264 |
229 | 265 |
230 void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) { | 266 void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) { |
231 Variable* variable = decl->proxy()->var(); | 267 Variable* variable = decl->proxy()->var(); |
232 switch (variable->location()) { | 268 switch (variable->location()) { |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
319 } | 355 } |
320 | 356 |
321 | 357 |
322 void BytecodeGenerator::VisitSloppyBlockFunctionStatement( | 358 void BytecodeGenerator::VisitSloppyBlockFunctionStatement( |
323 SloppyBlockFunctionStatement* stmt) { | 359 SloppyBlockFunctionStatement* stmt) { |
324 Visit(stmt->statement()); | 360 Visit(stmt->statement()); |
325 } | 361 } |
326 | 362 |
327 | 363 |
328 void BytecodeGenerator::VisitContinueStatement(ContinueStatement* stmt) { | 364 void BytecodeGenerator::VisitContinueStatement(ContinueStatement* stmt) { |
329 control_scope()->Continue(stmt->target()); | 365 execution_control()->Continue(stmt->target()); |
330 } | 366 } |
331 | 367 |
332 | 368 |
333 void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) { | 369 void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) { |
334 control_scope()->Break(stmt->target()); | 370 execution_control()->Break(stmt->target()); |
335 } | 371 } |
336 | 372 |
337 | 373 |
338 void BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { | 374 void BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) { |
339 Visit(stmt->expression()); | 375 Visit(stmt->expression()); |
340 builder()->Return(); | 376 builder()->Return(); |
341 } | 377 } |
342 | 378 |
343 | 379 |
344 void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) { | 380 void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) { |
345 UNIMPLEMENTED(); | 381 UNIMPLEMENTED(); |
346 } | 382 } |
347 | 383 |
348 | 384 |
349 void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { | 385 void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { |
350 UNIMPLEMENTED(); | 386 UNIMPLEMENTED(); |
351 } | 387 } |
352 | 388 |
353 | 389 |
354 void BytecodeGenerator::VisitCaseClause(CaseClause* clause) { UNIMPLEMENTED(); } | 390 void BytecodeGenerator::VisitCaseClause(CaseClause* clause) { UNIMPLEMENTED(); } |
355 | 391 |
356 | 392 |
357 void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { | 393 void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) { |
358 LoopBuilder loop_builder(builder()); | 394 LoopBuilder loop_builder(builder()); |
359 ControlScopeForIteration control_scope(this, stmt, &loop_builder); | 395 ControlScopeForIteration execution_control(this, stmt, &loop_builder); |
360 | 396 |
361 BytecodeLabel body_label, condition_label, done_label; | 397 BytecodeLabel body_label, condition_label, done_label; |
362 builder()->Bind(&body_label); | 398 builder()->Bind(&body_label); |
363 Visit(stmt->body()); | 399 Visit(stmt->body()); |
364 builder()->Bind(&condition_label); | 400 builder()->Bind(&condition_label); |
365 Visit(stmt->cond()); | 401 Visit(stmt->cond()); |
366 builder()->JumpIfTrue(&body_label); | 402 builder()->JumpIfTrue(&body_label); |
367 builder()->Bind(&done_label); | 403 builder()->Bind(&done_label); |
368 | 404 |
369 loop_builder.SetBreakTarget(done_label); | 405 loop_builder.SetBreakTarget(done_label); |
370 loop_builder.SetContinueTarget(condition_label); | 406 loop_builder.SetContinueTarget(condition_label); |
371 } | 407 } |
372 | 408 |
373 | 409 |
374 void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) { | 410 void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) { |
375 LoopBuilder loop_builder(builder()); | 411 LoopBuilder loop_builder(builder()); |
376 ControlScopeForIteration control_scope(this, stmt, &loop_builder); | 412 ControlScopeForIteration execution_control(this, stmt, &loop_builder); |
377 | 413 |
378 BytecodeLabel body_label, condition_label, done_label; | 414 BytecodeLabel body_label, condition_label, done_label; |
379 builder()->Jump(&condition_label); | 415 builder()->Jump(&condition_label); |
380 builder()->Bind(&body_label); | 416 builder()->Bind(&body_label); |
381 Visit(stmt->body()); | 417 Visit(stmt->body()); |
382 builder()->Bind(&condition_label); | 418 builder()->Bind(&condition_label); |
383 Visit(stmt->cond()); | 419 Visit(stmt->cond()); |
384 builder()->JumpIfTrue(&body_label); | 420 builder()->JumpIfTrue(&body_label); |
385 builder()->Bind(&done_label); | 421 builder()->Bind(&done_label); |
386 | 422 |
387 loop_builder.SetBreakTarget(done_label); | 423 loop_builder.SetBreakTarget(done_label); |
388 loop_builder.SetContinueTarget(condition_label); | 424 loop_builder.SetContinueTarget(condition_label); |
389 } | 425 } |
390 | 426 |
391 | 427 |
392 void BytecodeGenerator::VisitForStatement(ForStatement* stmt) { | 428 void BytecodeGenerator::VisitForStatement(ForStatement* stmt) { |
393 LoopBuilder loop_builder(builder()); | 429 LoopBuilder loop_builder(builder()); |
394 ControlScopeForIteration control_scope(this, stmt, &loop_builder); | 430 ControlScopeForIteration execution_control(this, stmt, &loop_builder); |
395 | 431 |
396 if (stmt->init() != nullptr) { | 432 if (stmt->init() != nullptr) { |
397 Visit(stmt->init()); | 433 Visit(stmt->init()); |
398 } | 434 } |
399 | 435 |
400 BytecodeLabel body_label, condition_label, next_label, done_label; | 436 BytecodeLabel body_label, condition_label, next_label, done_label; |
401 if (stmt->cond() != nullptr) { | 437 if (stmt->cond() != nullptr) { |
402 builder()->Jump(&condition_label); | 438 builder()->Jump(&condition_label); |
403 } | 439 } |
404 builder()->Bind(&body_label); | 440 builder()->Bind(&body_label); |
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
588 } | 624 } |
589 break; | 625 break; |
590 case ObjectLiteral::Property::SETTER: | 626 case ObjectLiteral::Property::SETTER: |
591 if (property->emit_store()) { | 627 if (property->emit_store()) { |
592 accessor_table.lookup(literal_key)->second->setter = property; | 628 accessor_table.lookup(literal_key)->second->setter = property; |
593 } | 629 } |
594 break; | 630 break; |
595 } | 631 } |
596 } | 632 } |
597 | 633 |
598 // Create nodes to define accessors, using only a single call to the runtime | 634 // Define accessors, using only a single call to the runtime for each pair of |
599 // for each pair of corresponding getters and setters. | 635 // corresponding getters and setters. |
600 for (AccessorTable::Iterator it = accessor_table.begin(); | 636 for (AccessorTable::Iterator it = accessor_table.begin(); |
601 it != accessor_table.end(); ++it) { | 637 it != accessor_table.end(); ++it) { |
602 TemporaryRegisterScope inner_temporary_register_scope(builder()); | 638 TemporaryRegisterScope inner_temporary_register_scope(builder()); |
603 Register name = inner_temporary_register_scope.NewRegister(); | 639 Register name = inner_temporary_register_scope.NewRegister(); |
604 Register getter = inner_temporary_register_scope.NewRegister(); | 640 Register getter = inner_temporary_register_scope.NewRegister(); |
605 Register setter = inner_temporary_register_scope.NewRegister(); | 641 Register setter = inner_temporary_register_scope.NewRegister(); |
606 Register attr = inner_temporary_register_scope.NewRegister(); | 642 Register attr = inner_temporary_register_scope.NewRegister(); |
607 DCHECK(Register::AreContiguous(literal, name, getter, setter, attr)); | 643 DCHECK(Register::AreContiguous(literal, name, getter, setter, attr)); |
608 Visit(it->first); | 644 Visit(it->first); |
609 builder()->StoreAccumulatorInRegister(name); | 645 builder()->StoreAccumulatorInRegister(name); |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
691 | 727 |
692 void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { | 728 void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { |
693 // Deep-copy the literal boilerplate. | 729 // Deep-copy the literal boilerplate. |
694 builder() | 730 builder() |
695 ->LoadLiteral(expr->constant_elements()) | 731 ->LoadLiteral(expr->constant_elements()) |
696 .CreateArrayLiteral(expr->literal_index(), expr->ComputeFlags(true)); | 732 .CreateArrayLiteral(expr->literal_index(), expr->ComputeFlags(true)); |
697 | 733 |
698 TemporaryRegisterScope temporary_register_scope(builder()); | 734 TemporaryRegisterScope temporary_register_scope(builder()); |
699 Register index, literal; | 735 Register index, literal; |
700 | 736 |
701 // Create nodes to evaluate all the non-constant subexpressions and to store | 737 // Evaluate all the non-constant subexpressions and store them into the |
702 // them into the newly cloned array. | 738 // newly cloned array. |
703 bool literal_in_accumulator = true; | 739 bool literal_in_accumulator = true; |
704 for (int array_index = 0; array_index < expr->values()->length(); | 740 for (int array_index = 0; array_index < expr->values()->length(); |
705 array_index++) { | 741 array_index++) { |
706 Expression* subexpr = expr->values()->at(array_index); | 742 Expression* subexpr = expr->values()->at(array_index); |
707 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; | 743 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; |
708 if (subexpr->IsSpread()) { | 744 if (subexpr->IsSpread()) { |
709 // TODO(rmcilroy): Deal with spread expressions. | 745 // TODO(rmcilroy): Deal with spread expressions. |
710 UNIMPLEMENTED(); | 746 UNIMPLEMENTED(); |
711 } | 747 } |
712 | 748 |
(...skipping 24 matching lines...) Expand all Loading... | |
737 VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot()); | 773 VisitVariableLoad(proxy->var(), proxy->VariableFeedbackSlot()); |
738 } | 774 } |
739 | 775 |
740 | 776 |
741 void BytecodeGenerator::VisitVariableLoad(Variable* variable, | 777 void BytecodeGenerator::VisitVariableLoad(Variable* variable, |
742 FeedbackVectorSlot slot) { | 778 FeedbackVectorSlot slot) { |
743 switch (variable->location()) { | 779 switch (variable->location()) { |
744 case VariableLocation::LOCAL: { | 780 case VariableLocation::LOCAL: { |
745 Register source(variable->index()); | 781 Register source(variable->index()); |
746 builder()->LoadAccumulatorWithRegister(source); | 782 builder()->LoadAccumulatorWithRegister(source); |
783 // TODO(rmcilroy): Perform check for uninitialized legacy const, const and | |
784 // let variables. | |
747 break; | 785 break; |
748 } | 786 } |
749 case VariableLocation::PARAMETER: { | 787 case VariableLocation::PARAMETER: { |
750 // The parameter indices are shifted by 1 (receiver is variable | 788 // The parameter indices are shifted by 1 (receiver is variable |
751 // index -1 but is parameter index 0 in BytecodeArrayBuilder). | 789 // index -1 but is parameter index 0 in BytecodeArrayBuilder). |
752 Register source(builder()->Parameter(variable->index() + 1)); | 790 Register source(builder()->Parameter(variable->index() + 1)); |
753 builder()->LoadAccumulatorWithRegister(source); | 791 builder()->LoadAccumulatorWithRegister(source); |
754 break; | 792 break; |
755 } | 793 } |
756 case VariableLocation::GLOBAL: { | 794 case VariableLocation::GLOBAL: { |
757 // Global var, const, or let variable. | 795 // Global var, const, or let variable. |
758 // TODO(rmcilroy): If context chain depth is short enough, do this using | 796 // TODO(rmcilroy): If context chain depth is short enough, do this using |
759 // a generic version of LoadGlobalViaContextStub rather than calling the | 797 // a generic version of LoadGlobalViaContextStub rather than calling the |
760 // runtime. | 798 // runtime. |
761 DCHECK(variable->IsStaticGlobalObjectProperty()); | 799 DCHECK(variable->IsStaticGlobalObjectProperty()); |
762 builder()->LoadGlobal(variable->index()); | 800 builder()->LoadGlobal(variable->index()); |
763 break; | 801 break; |
764 } | 802 } |
765 case VariableLocation::UNALLOCATED: { | 803 case VariableLocation::UNALLOCATED: { |
766 TemporaryRegisterScope temporary_register_scope(builder()); | 804 TemporaryRegisterScope temporary_register_scope(builder()); |
767 Register obj = temporary_register_scope.NewRegister(); | 805 Register obj = temporary_register_scope.NewRegister(); |
768 builder()->LoadContextSlot(current_context(), | 806 builder()->LoadContextSlot(execution_context()->reg(), |
769 Context::GLOBAL_OBJECT_INDEX); | 807 Context::GLOBAL_OBJECT_INDEX); |
770 builder()->StoreAccumulatorInRegister(obj); | 808 builder()->StoreAccumulatorInRegister(obj); |
771 builder()->LoadLiteral(variable->name()); | 809 builder()->LoadLiteral(variable->name()); |
772 builder()->LoadNamedProperty(obj, feedback_index(slot), language_mode()); | 810 builder()->LoadNamedProperty(obj, feedback_index(slot), language_mode()); |
773 break; | 811 break; |
774 } | 812 } |
775 case VariableLocation::CONTEXT: | 813 case VariableLocation::CONTEXT: { |
814 ContextScope* context = execution_context()->Previous(variable->scope()); | |
815 if (context) { | |
816 builder()->LoadContextSlot(context->reg(), variable->index()); | |
817 } else { | |
818 UNIMPLEMENTED(); | |
819 } | |
820 // TODO(rmcilroy): Perform check for uninitialized legacy const, const and | |
821 // let variables. | |
822 break; | |
823 } | |
776 case VariableLocation::LOOKUP: | 824 case VariableLocation::LOOKUP: |
777 UNIMPLEMENTED(); | 825 UNIMPLEMENTED(); |
778 } | 826 } |
779 } | 827 } |
780 | 828 |
781 | 829 |
782 void BytecodeGenerator::VisitVariableAssignment(Variable* variable, | 830 void BytecodeGenerator::VisitVariableAssignment(Variable* variable, |
783 FeedbackVectorSlot slot) { | 831 FeedbackVectorSlot slot) { |
784 switch (variable->location()) { | 832 switch (variable->location()) { |
785 case VariableLocation::LOCAL: { | 833 case VariableLocation::LOCAL: { |
(...skipping 19 matching lines...) Expand all Loading... | |
805 break; | 853 break; |
806 } | 854 } |
807 case VariableLocation::UNALLOCATED: { | 855 case VariableLocation::UNALLOCATED: { |
808 TemporaryRegisterScope temporary_register_scope(builder()); | 856 TemporaryRegisterScope temporary_register_scope(builder()); |
809 Register value = temporary_register_scope.NewRegister(); | 857 Register value = temporary_register_scope.NewRegister(); |
810 Register obj = temporary_register_scope.NewRegister(); | 858 Register obj = temporary_register_scope.NewRegister(); |
811 Register name = temporary_register_scope.NewRegister(); | 859 Register name = temporary_register_scope.NewRegister(); |
812 // TODO(rmcilroy): Investigate whether we can avoid having to stash the | 860 // TODO(rmcilroy): Investigate whether we can avoid having to stash the |
813 // value in a register. | 861 // value in a register. |
814 builder()->StoreAccumulatorInRegister(value); | 862 builder()->StoreAccumulatorInRegister(value); |
815 builder()->LoadContextSlot(current_context(), | 863 builder()->LoadContextSlot(execution_context()->reg(), |
816 Context::GLOBAL_OBJECT_INDEX); | 864 Context::GLOBAL_OBJECT_INDEX); |
817 builder()->StoreAccumulatorInRegister(obj); | 865 builder()->StoreAccumulatorInRegister(obj); |
818 builder()->LoadLiteral(variable->name()); | 866 builder()->LoadLiteral(variable->name()); |
819 builder()->StoreAccumulatorInRegister(name); | 867 builder()->StoreAccumulatorInRegister(name); |
820 builder()->LoadAccumulatorWithRegister(value); | 868 builder()->LoadAccumulatorWithRegister(value); |
821 builder()->StoreNamedProperty(obj, name, feedback_index(slot), | 869 builder()->StoreNamedProperty(obj, name, feedback_index(slot), |
822 language_mode()); | 870 language_mode()); |
823 break; | 871 break; |
824 } | 872 } |
825 case VariableLocation::CONTEXT: | 873 case VariableLocation::CONTEXT: { |
874 // TODO(rmcilroy): support const mode initialization. | |
875 ContextScope* context = execution_context()->Previous(variable->scope()); | |
876 if (context) { | |
877 builder()->StoreContextSlot(context->reg(), variable->index()); | |
878 } else { | |
879 UNIMPLEMENTED(); | |
880 } | |
881 break; | |
882 } | |
826 case VariableLocation::LOOKUP: | 883 case VariableLocation::LOOKUP: |
827 UNIMPLEMENTED(); | 884 UNIMPLEMENTED(); |
828 } | 885 } |
829 } | 886 } |
830 | 887 |
831 | 888 |
832 void BytecodeGenerator::VisitAssignment(Assignment* expr) { | 889 void BytecodeGenerator::VisitAssignment(Assignment* expr) { |
833 DCHECK(expr->target()->IsValidReferenceExpression()); | 890 DCHECK(expr->target()->IsValidReferenceExpression()); |
834 TemporaryRegisterScope temporary_register_scope(builder()); | 891 TemporaryRegisterScope temporary_register_scope(builder()); |
835 Register object, key; | 892 Register object, key; |
(...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1134 builder() | 1191 builder() |
1135 ->LoadAccumulatorWithRegister(Register::function_closure()) | 1192 ->LoadAccumulatorWithRegister(Register::function_closure()) |
1136 .StoreAccumulatorInRegister(closure) | 1193 .StoreAccumulatorInRegister(closure) |
1137 .LoadLiteral(scope->GetScopeInfo(isolate())) | 1194 .LoadLiteral(scope->GetScopeInfo(isolate())) |
1138 .StoreAccumulatorInRegister(scope_info) | 1195 .StoreAccumulatorInRegister(scope_info) |
1139 .CallRuntime(Runtime::kNewScriptContext, closure, 2); | 1196 .CallRuntime(Runtime::kNewScriptContext, closure, 2); |
1140 } else { | 1197 } else { |
1141 builder()->CallRuntime(Runtime::kNewFunctionContext, | 1198 builder()->CallRuntime(Runtime::kNewFunctionContext, |
1142 Register::function_closure(), 1); | 1199 Register::function_closure(), 1); |
1143 } | 1200 } |
1201 } | |
1202 | |
1203 | |
1204 void BytecodeGenerator::VisitBuildLocalActivationContext() { | |
1205 Scope* scope = this->scope(); | |
1144 | 1206 |
1145 if (scope->has_this_declaration() && scope->receiver()->IsContextSlot()) { | 1207 if (scope->has_this_declaration() && scope->receiver()->IsContextSlot()) { |
1146 UNIMPLEMENTED(); | 1208 UNIMPLEMENTED(); |
1147 } | 1209 } |
1148 | 1210 |
1149 // Copy parameters into context if necessary. | 1211 // Copy parameters into context if necessary. |
1150 int num_parameters = scope->num_parameters(); | 1212 int num_parameters = scope->num_parameters(); |
1151 for (int i = 0; i < num_parameters; i++) { | 1213 for (int i = 0; i < num_parameters; i++) { |
1152 Variable* variable = scope->parameter(i); | 1214 Variable* variable = scope->parameter(i); |
1153 if (variable->IsContextSlot()) { | 1215 if (!variable->IsContextSlot()) continue; |
1154 UNIMPLEMENTED(); | 1216 |
1155 } | 1217 // The parameter indices are shifted by 1 (receiver is variable |
1218 // index -1 but is parameter index 0 in BytecodeArrayBuilder). | |
1219 Register parameter(builder()->Parameter(i + 1)); | |
1220 // Context variable (at bottom of the context chain). | |
1221 DCHECK_EQ(0, scope->ContextChainLength(variable->scope())); | |
1222 builder()->LoadAccumulatorWithRegister(parameter) | |
1223 .StoreContextSlot(execution_context()->reg(), variable->index()); | |
1156 } | 1224 } |
1157 } | 1225 } |
1158 | 1226 |
1159 | 1227 |
1228 void BytecodeGenerator::VisitNewLocalBlockContext(Scope* scope) { | |
1229 DCHECK(scope->is_block_scope()); | |
1230 | |
1231 // Allocate a new local block context. | |
1232 TemporaryRegisterScope temporary_register_scope(builder()); | |
1233 Register scope_info = temporary_register_scope.NewRegister(); | |
1234 Register closure = temporary_register_scope.NewRegister(); | |
1235 DCHECK(Register::AreContiguous(scope_info, closure)); | |
1236 builder() | |
1237 ->LoadLiteral(scope->GetScopeInfo(isolate())) | |
1238 .StoreAccumulatorInRegister(scope_info); | |
1239 VisitFunctionClosureForContext(); | |
1240 builder() | |
1241 ->StoreAccumulatorInRegister(closure) | |
1242 .CallRuntime(Runtime::kPushBlockContext, scope_info, 2); | |
1243 } | |
1244 | |
1245 | |
1160 void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* binop) { | 1246 void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* binop) { |
1161 Token::Value op = binop->op(); | 1247 Token::Value op = binop->op(); |
1162 Expression* left = binop->left(); | 1248 Expression* left = binop->left(); |
1163 Expression* right = binop->right(); | 1249 Expression* right = binop->right(); |
1164 | 1250 |
1165 TemporaryRegisterScope temporary_register_scope(builder()); | 1251 TemporaryRegisterScope temporary_register_scope(builder()); |
1166 Register temporary = temporary_register_scope.NewRegister(); | 1252 Register temporary = temporary_register_scope.NewRegister(); |
1167 | 1253 |
1168 Visit(left); | 1254 Visit(left); |
1169 builder()->StoreAccumulatorInRegister(temporary); | 1255 builder()->StoreAccumulatorInRegister(temporary); |
1170 Visit(right); | 1256 Visit(right); |
1171 builder()->BinaryOperation(op, temporary, language_mode_strength()); | 1257 builder()->BinaryOperation(op, temporary, language_mode_strength()); |
1172 } | 1258 } |
1173 | 1259 |
1174 | 1260 |
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) { | 1261 void BytecodeGenerator::VisitCommaExpression(BinaryOperation* binop) { |
1211 Expression* left = binop->left(); | 1262 Expression* left = binop->left(); |
1212 Expression* right = binop->right(); | 1263 Expression* right = binop->right(); |
1213 | 1264 |
1214 Visit(left); | 1265 Visit(left); |
1215 Visit(right); | 1266 Visit(right); |
1216 } | 1267 } |
1217 | 1268 |
1218 | 1269 |
1219 void BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) { | 1270 void BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) { |
(...skipping 27 matching lines...) Expand all Loading... | |
1247 BytecodeLabel end_label; | 1298 BytecodeLabel end_label; |
1248 | 1299 |
1249 Visit(left); | 1300 Visit(left); |
1250 builder()->JumpIfToBooleanFalse(&end_label); | 1301 builder()->JumpIfToBooleanFalse(&end_label); |
1251 Visit(right); | 1302 Visit(right); |
1252 builder()->Bind(&end_label); | 1303 builder()->Bind(&end_label); |
1253 } | 1304 } |
1254 } | 1305 } |
1255 | 1306 |
1256 | 1307 |
1308 void BytecodeGenerator::VisitObjectLiteralAccessor( | |
1309 Register home_object, ObjectLiteralProperty* property, Register value_out) { | |
1310 // TODO(rmcilroy): Replace value_out with VisitForRegister(); | |
1311 if (property == nullptr) { | |
1312 builder()->LoadNull().StoreAccumulatorInRegister(value_out); | |
1313 } else { | |
1314 Visit(property->value()); | |
1315 builder()->StoreAccumulatorInRegister(value_out); | |
1316 VisitSetHomeObject(value_out, home_object, property); | |
1317 } | |
1318 } | |
1319 | |
1320 | |
1321 void BytecodeGenerator::VisitSetHomeObject(Register value, Register home_object, | |
1322 ObjectLiteralProperty* property, | |
1323 int slot_number) { | |
1324 Expression* expr = property->value(); | |
1325 if (!FunctionLiteral::NeedsHomeObject(expr)) return; | |
1326 | |
1327 // TODO(rmcilroy): Remove UNIMPLEMENTED once we have tests for setting the | |
1328 // home object. | |
1329 UNIMPLEMENTED(); | |
1330 | |
1331 TemporaryRegisterScope temporary_register_scope(builder()); | |
1332 Register name = temporary_register_scope.NewRegister(); | |
1333 isolate()->factory()->home_object_symbol(); | |
1334 builder() | |
1335 ->LoadLiteral(isolate()->factory()->home_object_symbol()) | |
1336 .StoreAccumulatorInRegister(name) | |
1337 .StoreNamedProperty(home_object, name, | |
1338 feedback_index(property->GetSlot(slot_number)), | |
1339 language_mode()); | |
1340 } | |
1341 | |
1342 | |
1343 void BytecodeGenerator::VisitFunctionClosureForContext() { | |
1344 Scope* closure_scope = execution_context()->scope()->ClosureScope(); | |
1345 if (closure_scope->is_script_scope() || | |
1346 closure_scope->is_module_scope()) { | |
1347 // Contexts nested in the native context have a canonical empty function as | |
1348 // their closure, not the anonymous closure containing the global code. | |
1349 // Pass a SMI sentinel and let the runtime look up the empty function. | |
1350 builder()->LoadLiteral(Smi::FromInt(0)); | |
1351 } else { | |
1352 DCHECK(closure_scope->is_function_scope()); | |
1353 builder()->LoadAccumulatorWithRegister(Register::function_closure()); | |
1354 } | |
1355 } | |
1356 | |
1357 | |
1358 Register BytecodeGenerator::NextContextRegister() const { | |
1359 if (execution_context() == nullptr) { | |
1360 // Return the incoming function context for the outermost execution context. | |
1361 return Register::function_context(); | |
1362 } | |
1363 Register previous = execution_context()->reg(); | |
1364 if (previous == Register::function_context()) { | |
1365 // If the previous context was the incoming function context, then the next | |
1366 // context register is the first local context register. | |
1367 return builder_.first_context_register(); | |
1368 } else { | |
1369 // Otherwise use the next local context register. | |
1370 DCHECK_LT(previous.index(), builder_.last_context_register().index()); | |
1371 return Register(previous.index() + 1); | |
1372 } | |
1373 } | |
1374 | |
1375 | |
1257 LanguageMode BytecodeGenerator::language_mode() const { | 1376 LanguageMode BytecodeGenerator::language_mode() const { |
1258 return info()->language_mode(); | 1377 return info()->language_mode(); |
1259 } | 1378 } |
1260 | 1379 |
1261 | 1380 |
1262 Strength BytecodeGenerator::language_mode_strength() const { | 1381 Strength BytecodeGenerator::language_mode_strength() const { |
1263 return strength(language_mode()); | 1382 return strength(language_mode()); |
1264 } | 1383 } |
1265 | 1384 |
1266 | 1385 |
1267 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { | 1386 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const { |
1268 return info()->feedback_vector()->GetIndex(slot); | 1387 return info()->feedback_vector()->GetIndex(slot); |
1269 } | 1388 } |
1270 | 1389 |
1271 } // namespace interpreter | 1390 } // namespace interpreter |
1272 } // namespace internal | 1391 } // namespace internal |
1273 } // namespace v8 | 1392 } // namespace v8 |
OLD | NEW |