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 |