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
3 // found in the LICENSE file.
4
5 #include "src/interpreter/bytecode-generator.h"
6
7 #include "src/ast/compile-time-value.h"
8 #include "src/ast/scopes.h"
9 #include "src/code-stubs.h"
10 #include "src/compilation-info.h"
11 #include "src/compiler.h"
12 #include "src/interpreter/bytecode-flags.h"
13 #include "src/interpreter/bytecode-label.h"
14 #include "src/interpreter/bytecode-register-allocator.h"
15 #include "src/interpreter/control-flow-builders.h"
16 #include "src/objects.h"
17 #include "src/parsing/parse-info.h"
18 #include "src/parsing/token.h"
19
20 namespace v8 {
21 namespace internal {
22 namespace interpreter {
23
24 // Scoped class tracking context objects created by the visitor. Represents
25 // mutations of the context chain within the function body, allowing pushing and
26 // popping of the current {context_register} during visitation.
27 class BytecodeGenerator::ContextScope BASE_EMBEDDED {
28 public:
ContextScope(BytecodeGenerator * generator,Scope * scope,bool should_pop_context=true)29 ContextScope(BytecodeGenerator* generator, Scope* scope,
30 bool should_pop_context = true)
31 : generator_(generator),
32 scope_(scope),
33 outer_(generator_->execution_context()),
34 register_(Register::current_context()),
35 depth_(0),
36 should_pop_context_(should_pop_context) {
37 if (outer_) {
38 depth_ = outer_->depth_ + 1;
39
40 // Push the outer context into a new context register.
41 Register outer_context_reg(builder()->first_context_register().index() +
42 outer_->depth_);
43 outer_->set_register(outer_context_reg);
44 generator_->builder()->PushContext(outer_context_reg);
45 }
46 generator_->set_execution_context(this);
47 }
48
~ContextScope()49 ~ContextScope() {
50 if (outer_ && should_pop_context_) {
51 DCHECK_EQ(register_.index(), Register::current_context().index());
52 generator_->builder()->PopContext(outer_->reg());
53 outer_->set_register(register_);
54 }
55 generator_->set_execution_context(outer_);
56 }
57
58 // Returns the depth of the given |scope| for the current execution context.
ContextChainDepth(Scope * scope)59 int ContextChainDepth(Scope* scope) {
60 return scope_->ContextChainLength(scope);
61 }
62
63 // Returns the execution context at |depth| in the current context chain if it
64 // is a function local execution context, otherwise returns nullptr.
Previous(int depth)65 ContextScope* Previous(int depth) {
66 if (depth > depth_) {
67 return nullptr;
68 }
69
70 ContextScope* previous = this;
71 for (int i = depth; i > 0; --i) {
72 previous = previous->outer_;
73 }
74 return previous;
75 }
76
scope() const77 Scope* scope() const { return scope_; }
reg() const78 Register reg() const { return register_; }
ShouldPopContext()79 bool ShouldPopContext() { return should_pop_context_; }
80
81 private:
builder() const82 const BytecodeArrayBuilder* builder() const { return generator_->builder(); }
83
set_register(Register reg)84 void set_register(Register reg) { register_ = reg; }
85
86 BytecodeGenerator* generator_;
87 Scope* scope_;
88 ContextScope* outer_;
89 Register register_;
90 int depth_;
91 bool should_pop_context_;
92 };
93
94 // Scoped class for tracking control statements entered by the
95 // visitor. The pattern derives AstGraphBuilder::ControlScope.
96 class BytecodeGenerator::ControlScope BASE_EMBEDDED {
97 public:
ControlScope(BytecodeGenerator * generator)98 explicit ControlScope(BytecodeGenerator* generator)
99 : generator_(generator), outer_(generator->execution_control()),
100 context_(generator->execution_context()) {
101 generator_->set_execution_control(this);
102 }
~ControlScope()103 virtual ~ControlScope() { generator_->set_execution_control(outer()); }
104
Break(Statement * stmt)105 void Break(Statement* stmt) { PerformCommand(CMD_BREAK, stmt); }
Continue(Statement * stmt)106 void Continue(Statement* stmt) { PerformCommand(CMD_CONTINUE, stmt); }
ReturnAccumulator()107 void ReturnAccumulator() { PerformCommand(CMD_RETURN, nullptr); }
ReThrowAccumulator()108 void ReThrowAccumulator() { PerformCommand(CMD_RETHROW, nullptr); }
109
110 class DeferredCommands;
111
112 protected:
113 enum Command { CMD_BREAK, CMD_CONTINUE, CMD_RETURN, CMD_RETHROW };
114 void PerformCommand(Command command, Statement* statement);
115 virtual bool Execute(Command command, Statement* statement) = 0;
116
generator() const117 BytecodeGenerator* generator() const { return generator_; }
outer() const118 ControlScope* outer() const { return outer_; }
context() const119 ContextScope* context() const { return context_; }
120
121 private:
122 BytecodeGenerator* generator_;
123 ControlScope* outer_;
124 ContextScope* context_;
125
126 DISALLOW_COPY_AND_ASSIGN(ControlScope);
127 };
128
129 // Helper class for a try-finally control scope. It can record intercepted
130 // control-flow commands that cause entry into a finally-block, and re-apply
131 // them after again leaving that block. Special tokens are used to identify
132 // paths going through the finally-block to dispatch after leaving the block.
133 class BytecodeGenerator::ControlScope::DeferredCommands final {
134 public:
DeferredCommands(BytecodeGenerator * generator,Register token_register,Register result_register)135 DeferredCommands(BytecodeGenerator* generator, Register token_register,
136 Register result_register)
137 : generator_(generator),
138 deferred_(generator->zone()),
139 token_register_(token_register),
140 result_register_(result_register) {}
141
142 // One recorded control-flow command.
143 struct Entry {
144 Command command; // The command type being applied on this path.
145 Statement* statement; // The target statement for the command or {nullptr}.
146 int token; // A token identifying this particular path.
147 };
148
149 // Records a control-flow command while entering the finally-block. This also
150 // generates a new dispatch token that identifies one particular path. This
151 // expects the result to be in the accumulator.
RecordCommand(Command command,Statement * statement)152 void RecordCommand(Command command, Statement* statement) {
153 int token = static_cast<int>(deferred_.size());
154 deferred_.push_back({command, statement, token});
155
156 builder()->StoreAccumulatorInRegister(result_register_);
157 builder()->LoadLiteral(Smi::FromInt(token));
158 builder()->StoreAccumulatorInRegister(token_register_);
159 }
160
161 // Records the dispatch token to be used to identify the re-throw path when
162 // the finally-block has been entered through the exception handler. This
163 // expects the exception to be in the accumulator.
RecordHandlerReThrowPath()164 void RecordHandlerReThrowPath() {
165 // The accumulator contains the exception object.
166 RecordCommand(CMD_RETHROW, nullptr);
167 }
168
169 // Records the dispatch token to be used to identify the implicit fall-through
170 // path at the end of a try-block into the corresponding finally-block.
RecordFallThroughPath()171 void RecordFallThroughPath() {
172 builder()->LoadLiteral(Smi::FromInt(-1));
173 builder()->StoreAccumulatorInRegister(token_register_);
174 }
175
176 // Applies all recorded control-flow commands after the finally-block again.
177 // This generates a dynamic dispatch on the token from the entry point.
ApplyDeferredCommands()178 void ApplyDeferredCommands() {
179 // The fall-through path is covered by the default case, hence +1 here.
180 SwitchBuilder dispatch(builder(), static_cast<int>(deferred_.size() + 1));
181 for (size_t i = 0; i < deferred_.size(); ++i) {
182 Entry& entry = deferred_[i];
183 builder()->LoadLiteral(Smi::FromInt(entry.token));
184 builder()->CompareOperation(Token::EQ_STRICT, token_register_);
185 dispatch.Case(static_cast<int>(i));
186 }
187 dispatch.DefaultAt(static_cast<int>(deferred_.size()));
188 for (size_t i = 0; i < deferred_.size(); ++i) {
189 Entry& entry = deferred_[i];
190 dispatch.SetCaseTarget(static_cast<int>(i));
191 builder()->LoadAccumulatorWithRegister(result_register_);
192 execution_control()->PerformCommand(entry.command, entry.statement);
193 }
194 dispatch.SetCaseTarget(static_cast<int>(deferred_.size()));
195 }
196
builder()197 BytecodeArrayBuilder* builder() { return generator_->builder(); }
execution_control()198 ControlScope* execution_control() { return generator_->execution_control(); }
199
200 private:
201 BytecodeGenerator* generator_;
202 ZoneVector<Entry> deferred_;
203 Register token_register_;
204 Register result_register_;
205 };
206
207 // Scoped class for dealing with control flow reaching the function level.
208 class BytecodeGenerator::ControlScopeForTopLevel final
209 : public BytecodeGenerator::ControlScope {
210 public:
ControlScopeForTopLevel(BytecodeGenerator * generator)211 explicit ControlScopeForTopLevel(BytecodeGenerator* generator)
212 : ControlScope(generator) {}
213
214 protected:
Execute(Command command,Statement * statement)215 bool Execute(Command command, Statement* statement) override {
216 switch (command) {
217 case CMD_BREAK: // We should never see break/continue in top-level.
218 case CMD_CONTINUE:
219 UNREACHABLE();
220 case CMD_RETURN:
221 generator()->BuildReturn();
222 return true;
223 case CMD_RETHROW:
224 generator()->BuildReThrow();
225 return true;
226 }
227 return false;
228 }
229 };
230
231 // Scoped class for enabling break inside blocks and switch blocks.
232 class BytecodeGenerator::ControlScopeForBreakable final
233 : public BytecodeGenerator::ControlScope {
234 public:
ControlScopeForBreakable(BytecodeGenerator * generator,BreakableStatement * statement,BreakableControlFlowBuilder * control_builder)235 ControlScopeForBreakable(BytecodeGenerator* generator,
236 BreakableStatement* statement,
237 BreakableControlFlowBuilder* control_builder)
238 : ControlScope(generator),
239 statement_(statement),
240 control_builder_(control_builder) {}
241
242 protected:
Execute(Command command,Statement * statement)243 bool Execute(Command command, Statement* statement) override {
244 if (statement != statement_) return false;
245 switch (command) {
246 case CMD_BREAK:
247 control_builder_->Break();
248 return true;
249 case CMD_CONTINUE:
250 case CMD_RETURN:
251 case CMD_RETHROW:
252 break;
253 }
254 return false;
255 }
256
257 private:
258 Statement* statement_;
259 BreakableControlFlowBuilder* control_builder_;
260 };
261
262 // Scoped class for enabling 'break' and 'continue' in iteration
263 // constructs, e.g. do...while, while..., for...
264 class BytecodeGenerator::ControlScopeForIteration final
265 : public BytecodeGenerator::ControlScope {
266 public:
ControlScopeForIteration(BytecodeGenerator * generator,IterationStatement * statement,LoopBuilder * loop_builder)267 ControlScopeForIteration(BytecodeGenerator* generator,
268 IterationStatement* statement,
269 LoopBuilder* loop_builder)
270 : ControlScope(generator),
271 statement_(statement),
272 loop_builder_(loop_builder) {
273 generator->loop_depth_++;
274 }
~ControlScopeForIteration()275 ~ControlScopeForIteration() { generator()->loop_depth_--; }
276
277 protected:
Execute(Command command,Statement * statement)278 bool Execute(Command command, Statement* statement) override {
279 if (statement != statement_) return false;
280 switch (command) {
281 case CMD_BREAK:
282 loop_builder_->Break();
283 return true;
284 case CMD_CONTINUE:
285 loop_builder_->Continue();
286 return true;
287 case CMD_RETURN:
288 case CMD_RETHROW:
289 break;
290 }
291 return false;
292 }
293
294 private:
295 Statement* statement_;
296 LoopBuilder* loop_builder_;
297 };
298
299 // Scoped class for enabling 'throw' in try-catch constructs.
300 class BytecodeGenerator::ControlScopeForTryCatch final
301 : public BytecodeGenerator::ControlScope {
302 public:
ControlScopeForTryCatch(BytecodeGenerator * generator,TryCatchBuilder * try_catch_builder)303 ControlScopeForTryCatch(BytecodeGenerator* generator,
304 TryCatchBuilder* try_catch_builder)
305 : ControlScope(generator) {}
306
307 protected:
Execute(Command command,Statement * statement)308 bool Execute(Command command, Statement* statement) override {
309 switch (command) {
310 case CMD_BREAK:
311 case CMD_CONTINUE:
312 case CMD_RETURN:
313 break;
314 case CMD_RETHROW:
315 generator()->BuildReThrow();
316 return true;
317 }
318 return false;
319 }
320 };
321
322 // Scoped class for enabling control flow through try-finally constructs.
323 class BytecodeGenerator::ControlScopeForTryFinally final
324 : public BytecodeGenerator::ControlScope {
325 public:
ControlScopeForTryFinally(BytecodeGenerator * generator,TryFinallyBuilder * try_finally_builder,DeferredCommands * commands)326 ControlScopeForTryFinally(BytecodeGenerator* generator,
327 TryFinallyBuilder* try_finally_builder,
328 DeferredCommands* commands)
329 : ControlScope(generator),
330 try_finally_builder_(try_finally_builder),
331 commands_(commands) {}
332
333 protected:
Execute(Command command,Statement * statement)334 bool Execute(Command command, Statement* statement) override {
335 switch (command) {
336 case CMD_BREAK:
337 case CMD_CONTINUE:
338 case CMD_RETURN:
339 case CMD_RETHROW:
340 commands_->RecordCommand(command, statement);
341 try_finally_builder_->LeaveTry();
342 return true;
343 }
344 return false;
345 }
346
347 private:
348 TryFinallyBuilder* try_finally_builder_;
349 DeferredCommands* commands_;
350 };
351
PerformCommand(Command command,Statement * statement)352 void BytecodeGenerator::ControlScope::PerformCommand(Command command,
353 Statement* statement) {
354 ControlScope* current = this;
355 ContextScope* context = generator()->execution_context();
356 // Pop context to the expected depth but do not pop the outermost context.
357 if (context != current->context() && context->ShouldPopContext()) {
358 generator()->builder()->PopContext(current->context()->reg());
359 }
360 do {
361 if (current->Execute(command, statement)) {
362 return;
363 }
364 current = current->outer();
365 if (current->context() != context && context->ShouldPopContext()) {
366 // Pop context to the expected depth.
367 // TODO(rmcilroy): Only emit a single context pop.
368 generator()->builder()->PopContext(current->context()->reg());
369 }
370 } while (current != nullptr);
371 UNREACHABLE();
372 }
373
374 class BytecodeGenerator::RegisterAllocationScope {
375 public:
RegisterAllocationScope(BytecodeGenerator * generator)376 explicit RegisterAllocationScope(BytecodeGenerator* generator)
377 : generator_(generator),
378 outer_next_register_index_(
379 generator->register_allocator()->next_register_index()) {}
380
~RegisterAllocationScope()381 virtual ~RegisterAllocationScope() {
382 generator_->register_allocator()->ReleaseRegisters(
383 outer_next_register_index_);
384 }
385
386 private:
387 BytecodeGenerator* generator_;
388 int outer_next_register_index_;
389
390 DISALLOW_COPY_AND_ASSIGN(RegisterAllocationScope);
391 };
392
393 // Scoped base class for determining how the result of an expression will be
394 // used.
395 class BytecodeGenerator::ExpressionResultScope {
396 public:
ExpressionResultScope(BytecodeGenerator * generator,Expression::Context kind)397 ExpressionResultScope(BytecodeGenerator* generator, Expression::Context kind)
398 : generator_(generator),
399 kind_(kind),
400 outer_(generator->execution_result()),
401 allocator_(generator) {
402 generator_->set_execution_result(this);
403 }
404
~ExpressionResultScope()405 virtual ~ExpressionResultScope() {
406 generator_->set_execution_result(outer_);
407 }
408
IsEffect() const409 bool IsEffect() const { return kind_ == Expression::kEffect; }
IsValue() const410 bool IsValue() const { return kind_ == Expression::kValue; }
IsTest() const411 bool IsTest() const { return kind_ == Expression::kTest; }
412
AsTest()413 TestResultScope* AsTest() {
414 DCHECK(IsTest());
415 return reinterpret_cast<TestResultScope*>(this);
416 }
417
418 private:
419 BytecodeGenerator* generator_;
420 Expression::Context kind_;
421 ExpressionResultScope* outer_;
422 RegisterAllocationScope allocator_;
423
424 DISALLOW_COPY_AND_ASSIGN(ExpressionResultScope);
425 };
426
427 // Scoped class used when the result of the current expression is not
428 // expected to produce a result.
429 class BytecodeGenerator::EffectResultScope final
430 : public ExpressionResultScope {
431 public:
EffectResultScope(BytecodeGenerator * generator)432 explicit EffectResultScope(BytecodeGenerator* generator)
433 : ExpressionResultScope(generator, Expression::kEffect) {}
434 };
435
436 // Scoped class used when the result of the current expression to be
437 // evaluated should go into the interpreter's accumulator.
438 class BytecodeGenerator::ValueResultScope final : public ExpressionResultScope {
439 public:
ValueResultScope(BytecodeGenerator * generator)440 explicit ValueResultScope(BytecodeGenerator* generator)
441 : ExpressionResultScope(generator, Expression::kValue) {}
442 };
443
444 // Scoped class used when the result of the current expression to be
445 // evaluated is only tested with jumps to two branches.
446 class BytecodeGenerator::TestResultScope final : public ExpressionResultScope {
447 public:
TestResultScope(BytecodeGenerator * generator,BytecodeLabels * then_labels,BytecodeLabels * else_labels,TestFallthrough fallthrough)448 TestResultScope(BytecodeGenerator* generator, BytecodeLabels* then_labels,
449 BytecodeLabels* else_labels, TestFallthrough fallthrough)
450 : ExpressionResultScope(generator, Expression::kTest),
451 then_labels_(then_labels),
452 else_labels_(else_labels),
453 fallthrough_(fallthrough),
454 result_consumed_by_test_(false) {}
455
456 // Used when code special cases for TestResultScope and consumes any
457 // possible value by testing and jumping to a then/else label.
SetResultConsumedByTest()458 void SetResultConsumedByTest() {
459 result_consumed_by_test_ = true;
460 }
461
ResultConsumedByTest()462 bool ResultConsumedByTest() { return result_consumed_by_test_; }
463
NewThenLabel()464 BytecodeLabel* NewThenLabel() { return then_labels_->New(); }
NewElseLabel()465 BytecodeLabel* NewElseLabel() { return else_labels_->New(); }
466
then_labels() const467 BytecodeLabels* then_labels() const { return then_labels_; }
else_labels() const468 BytecodeLabels* else_labels() const { return else_labels_; }
469
fallthrough() const470 TestFallthrough fallthrough() const { return fallthrough_; }
inverted_fallthrough() const471 TestFallthrough inverted_fallthrough() const {
472 switch (fallthrough_) {
473 case TestFallthrough::kThen:
474 return TestFallthrough::kElse;
475 case TestFallthrough::kElse:
476 return TestFallthrough::kThen;
477 default:
478 return TestFallthrough::kNone;
479 }
480 }
481
482 private:
483 BytecodeLabels* then_labels_;
484 BytecodeLabels* else_labels_;
485 TestFallthrough fallthrough_;
486 bool result_consumed_by_test_;
487
488 DISALLOW_COPY_AND_ASSIGN(TestResultScope);
489 };
490
491 // Used to build a list of global declaration initial value pairs.
492 class BytecodeGenerator::GlobalDeclarationsBuilder final : public ZoneObject {
493 public:
GlobalDeclarationsBuilder(Zone * zone)494 explicit GlobalDeclarationsBuilder(Zone* zone)
495 : declarations_(0, zone),
496 constant_pool_entry_(0),
497 has_constant_pool_entry_(false) {}
498
AddFunctionDeclaration(FeedbackVectorSlot slot,FunctionLiteral * func)499 void AddFunctionDeclaration(FeedbackVectorSlot slot, FunctionLiteral* func) {
500 DCHECK(!slot.IsInvalid());
501 declarations_.push_back(std::make_pair(slot, func));
502 }
503
AddUndefinedDeclaration(FeedbackVectorSlot slot)504 void AddUndefinedDeclaration(FeedbackVectorSlot slot) {
505 DCHECK(!slot.IsInvalid());
506 declarations_.push_back(std::make_pair(slot, nullptr));
507 }
508
AllocateDeclarationPairs(CompilationInfo * info)509 Handle<FixedArray> AllocateDeclarationPairs(CompilationInfo* info) {
510 DCHECK(has_constant_pool_entry_);
511 int array_index = 0;
512 Handle<FixedArray> pairs = info->isolate()->factory()->NewFixedArray(
513 static_cast<int>(declarations_.size() * 2), TENURED);
514 for (std::pair<FeedbackVectorSlot, FunctionLiteral*> declaration :
515 declarations_) {
516 FunctionLiteral* func = declaration.second;
517 Handle<Object> initial_value;
518 if (func == nullptr) {
519 initial_value = info->isolate()->factory()->undefined_value();
520 } else {
521 initial_value =
522 Compiler::GetSharedFunctionInfo(func, info->script(), info);
523 }
524
525 // Return a null handle if any initial values can't be created. Caller
526 // will set stack overflow.
527 if (initial_value.is_null()) return Handle<FixedArray>();
528
529 pairs->set(array_index++, Smi::FromInt(declaration.first.ToInt()));
530 pairs->set(array_index++, *initial_value);
531 }
532 return pairs;
533 }
534
constant_pool_entry()535 size_t constant_pool_entry() {
536 DCHECK(has_constant_pool_entry_);
537 return constant_pool_entry_;
538 }
539
set_constant_pool_entry(size_t constant_pool_entry)540 void set_constant_pool_entry(size_t constant_pool_entry) {
541 DCHECK(!empty());
542 DCHECK(!has_constant_pool_entry_);
543 constant_pool_entry_ = constant_pool_entry;
544 has_constant_pool_entry_ = true;
545 }
546
empty()547 bool empty() { return declarations_.empty(); }
548
549 private:
550 ZoneVector<std::pair<FeedbackVectorSlot, FunctionLiteral*>> declarations_;
551 size_t constant_pool_entry_;
552 bool has_constant_pool_entry_;
553 };
554
BytecodeGenerator(CompilationInfo * info)555 BytecodeGenerator::BytecodeGenerator(CompilationInfo* info)
556 : zone_(info->zone()),
557 builder_(new (zone()) BytecodeArrayBuilder(
558 info->isolate(), info->zone(), info->num_parameters_including_this(),
559 info->scope()->MaxNestedContextChainLength(),
560 info->scope()->num_stack_slots(), info->literal(),
561 info->SourcePositionRecordingMode())),
562 info_(info),
563 scope_(info->scope()),
564 globals_builder_(new (zone()) GlobalDeclarationsBuilder(info->zone())),
565 global_declarations_(0, info->zone()),
566 function_literals_(0, info->zone()),
567 native_function_literals_(0, info->zone()),
568 execution_control_(nullptr),
569 execution_context_(nullptr),
570 execution_result_(nullptr),
571 generator_resume_points_(info->literal()->yield_count(), info->zone()),
572 generator_state_(),
573 loop_depth_(0),
574 home_object_symbol_(info->isolate()->factory()->home_object_symbol()),
575 empty_fixed_array_(info->isolate()->factory()->empty_fixed_array()) {
576 AstValueFactory* ast_value_factory = info->parse_info()->ast_value_factory();
577 const AstRawString* prototype_string = ast_value_factory->prototype_string();
578 ast_value_factory->Internalize(info->isolate());
579 prototype_string_ = prototype_string->string();
580 }
581
FinalizeBytecode(Isolate * isolate)582 Handle<BytecodeArray> BytecodeGenerator::FinalizeBytecode(Isolate* isolate) {
583 AllocateDeferredConstants();
584 if (HasStackOverflow()) return Handle<BytecodeArray>();
585 return builder()->ToBytecodeArray(isolate);
586 }
587
AllocateDeferredConstants()588 void BytecodeGenerator::AllocateDeferredConstants() {
589 // Build global declaration pair arrays.
590 for (GlobalDeclarationsBuilder* globals_builder : global_declarations_) {
591 Handle<FixedArray> declarations =
592 globals_builder->AllocateDeclarationPairs(info());
593 if (declarations.is_null()) return SetStackOverflow();
594 builder()->InsertConstantPoolEntryAt(globals_builder->constant_pool_entry(),
595 declarations);
596 }
597
598 // Find or build shared function infos.
599 for (std::pair<FunctionLiteral*, size_t> literal : function_literals_) {
600 FunctionLiteral* expr = literal.first;
601 Handle<SharedFunctionInfo> shared_info =
602 Compiler::GetSharedFunctionInfo(expr, info()->script(), info());
603 if (shared_info.is_null()) return SetStackOverflow();
604 builder()->InsertConstantPoolEntryAt(literal.second, shared_info);
605 }
606
607 // Find or build shared function infos for the native function templates.
608 for (std::pair<NativeFunctionLiteral*, size_t> literal :
609 native_function_literals_) {
610 NativeFunctionLiteral* expr = literal.first;
611 Handle<SharedFunctionInfo> shared_info =
612 Compiler::GetSharedFunctionInfoForNative(expr->extension(),
613 expr->name());
614 if (shared_info.is_null()) return SetStackOverflow();
615 builder()->InsertConstantPoolEntryAt(literal.second, shared_info);
616 }
617 }
618
GenerateBytecode(uintptr_t stack_limit)619 void BytecodeGenerator::GenerateBytecode(uintptr_t stack_limit) {
620 DisallowHeapAllocation no_allocation;
621 DisallowHandleAllocation no_handles;
622 DisallowHandleDereference no_deref;
623
624 InitializeAstVisitor(stack_limit);
625
626 // Initialize the incoming context.
627 ContextScope incoming_context(this, scope(), false);
628
629 // Initialize control scope.
630 ControlScopeForTopLevel control(this);
631
632 RegisterAllocationScope register_scope(this);
633
634 if (IsResumableFunction(info()->literal()->kind())) {
635 generator_state_ = register_allocator()->NewRegister();
636 VisitGeneratorPrologue();
637 }
638
639 if (scope()->NeedsContext()) {
640 // Push a new inner context scope for the function.
641 BuildNewLocalActivationContext();
642 ContextScope local_function_context(this, scope(), false);
643 BuildLocalActivationContextInitialization();
644 GenerateBytecodeBody();
645 } else {
646 GenerateBytecodeBody();
647 }
648
649 // In generator functions, we may not have visited every yield in the AST
650 // since we skip some obviously dead code. Hence the generated bytecode may
651 // contain jumps to unbound labels (resume points that will never be used).
652 // We bind these now.
653 for (auto& label : generator_resume_points_) {
654 if (!label.is_bound()) builder()->Bind(&label);
655 }
656
657 // Emit an implicit return instruction in case control flow can fall off the
658 // end of the function without an explicit return being present on all paths.
659 if (builder()->RequiresImplicitReturn()) {
660 builder()->LoadUndefined();
661 BuildReturn();
662 }
663 DCHECK(!builder()->RequiresImplicitReturn());
664 }
665
GenerateBytecodeBody()666 void BytecodeGenerator::GenerateBytecodeBody() {
667 // Build the arguments object if it is used.
668 VisitArgumentsObject(scope()->arguments());
669
670 // Build rest arguments array if it is used.
671 Variable* rest_parameter = scope()->rest_parameter();
672 VisitRestArgumentsArray(rest_parameter);
673
674 // Build assignment to {.this_function} variable if it is used.
675 VisitThisFunctionVariable(scope()->this_function_var());
676
677 // Build assignment to {new.target} variable if it is used.
678 VisitNewTargetVariable(scope()->new_target_var());
679
680 // Emit tracing call if requested to do so.
681 if (FLAG_trace) builder()->CallRuntime(Runtime::kTraceEnter);
682
683 // Visit declarations within the function scope.
684 VisitDeclarations(scope()->declarations());
685
686 // Emit initializing assignments for module namespace imports (if any).
687 VisitModuleNamespaceImports();
688
689 // Perform a stack-check before the body.
690 builder()->StackCheck(info()->literal()->start_position());
691
692 // Visit statements in the function body.
693 VisitStatements(info()->literal()->body());
694 }
695
BuildIndexedJump(Register index,size_t start_index,size_t size,ZoneVector<BytecodeLabel> & targets)696 void BytecodeGenerator::BuildIndexedJump(Register index, size_t start_index,
697 size_t size,
698 ZoneVector<BytecodeLabel>& targets) {
699 // TODO(neis): Optimize this by using a proper jump table.
700 DCHECK_LE(start_index + size, targets.size());
701 for (size_t i = start_index; i < start_index + size; i++) {
702 builder()
703 ->LoadLiteral(Smi::FromInt(static_cast<int>(i)))
704 .CompareOperation(Token::Value::EQ_STRICT, index)
705 .JumpIfTrue(&(targets[i]));
706 }
707 BuildAbort(BailoutReason::kInvalidJumpTableIndex);
708 }
709
VisitIterationHeader(IterationStatement * stmt,LoopBuilder * loop_builder)710 void BytecodeGenerator::VisitIterationHeader(IterationStatement* stmt,
711 LoopBuilder* loop_builder) {
712 // Recall that stmt->yield_count() is always zero inside ordinary
713 // (i.e. non-generator) functions.
714
715 // Collect all labels for generator resume points within the loop (if any) so
716 // that they can be bound to the loop header below. Also create fresh labels
717 // for these resume points, to be used inside the loop.
718 ZoneVector<BytecodeLabel> resume_points_in_loop(zone());
719 size_t first_yield = stmt->first_yield_id();
720 DCHECK_LE(first_yield + stmt->yield_count(), generator_resume_points_.size());
721 for (size_t id = first_yield; id < first_yield + stmt->yield_count(); id++) {
722 auto& label = generator_resume_points_[id];
723 resume_points_in_loop.push_back(label);
724 generator_resume_points_[id] = BytecodeLabel();
725 }
726
727 loop_builder->LoopHeader(&resume_points_in_loop);
728
729 if (stmt->yield_count() > 0) {
730 // If we are not resuming, fall through to loop body.
731 // If we are resuming, perform state dispatch.
732 BytecodeLabel not_resuming;
733 builder()
734 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting))
735 .CompareOperation(Token::Value::EQ, generator_state_)
736 .JumpIfTrue(¬_resuming);
737 BuildIndexedJump(generator_state_, first_yield,
738 stmt->yield_count(), generator_resume_points_);
739 builder()->Bind(¬_resuming);
740 }
741 }
742
VisitGeneratorPrologue()743 void BytecodeGenerator::VisitGeneratorPrologue() {
744 // The generator resume trampoline abuses the new.target register both to
745 // indicate that this is a resume call and to pass in the generator object.
746 // In ordinary calls, new.target is always undefined because generator
747 // functions are non-constructable.
748 Register generator_object = Register::new_target();
749 BytecodeLabel regular_call;
750 builder()
751 ->LoadAccumulatorWithRegister(generator_object)
752 .JumpIfUndefined(®ular_call);
753
754 // This is a resume call. Restore registers and perform state dispatch.
755 // (The current context has already been restored by the trampoline.)
756 builder()
757 ->ResumeGenerator(generator_object)
758 .StoreAccumulatorInRegister(generator_state_);
759 BuildIndexedJump(generator_state_, 0, generator_resume_points_.size(),
760 generator_resume_points_);
761
762 builder()
763 ->Bind(®ular_call)
764 .LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting))
765 .StoreAccumulatorInRegister(generator_state_);
766 // This is a regular call. Fall through to the ordinary function prologue,
767 // after which we will run into the generator object creation and other extra
768 // code inserted by the parser.
769 }
770
VisitBlock(Block * stmt)771 void BytecodeGenerator::VisitBlock(Block* stmt) {
772 // Visit declarations and statements.
773 if (stmt->scope() != nullptr && stmt->scope()->NeedsContext()) {
774 BuildNewLocalBlockContext(stmt->scope());
775 ContextScope scope(this, stmt->scope());
776 VisitBlockDeclarationsAndStatements(stmt);
777 } else {
778 VisitBlockDeclarationsAndStatements(stmt);
779 }
780 }
781
VisitBlockDeclarationsAndStatements(Block * stmt)782 void BytecodeGenerator::VisitBlockDeclarationsAndStatements(Block* stmt) {
783 BlockBuilder block_builder(builder());
784 ControlScopeForBreakable execution_control(this, stmt, &block_builder);
785 if (stmt->scope() != nullptr) {
786 VisitDeclarations(stmt->scope()->declarations());
787 }
788 VisitStatements(stmt->statements());
789 if (stmt->labels() != nullptr) block_builder.EndBlock();
790 }
791
VisitVariableDeclaration(VariableDeclaration * decl)792 void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) {
793 Variable* variable = decl->proxy()->var();
794 switch (variable->location()) {
795 case VariableLocation::UNALLOCATED: {
796 DCHECK(!variable->binding_needs_init());
797 FeedbackVectorSlot slot = decl->proxy()->VariableFeedbackSlot();
798 globals_builder()->AddUndefinedDeclaration(slot);
799 break;
800 }
801 case VariableLocation::LOCAL:
802 if (variable->binding_needs_init()) {
803 Register destination(variable->index());
804 builder()->LoadTheHole().StoreAccumulatorInRegister(destination);
805 }
806 break;
807 case VariableLocation::PARAMETER:
808 if (variable->binding_needs_init()) {
809 // The parameter indices are shifted by 1 (receiver is variable
810 // index -1 but is parameter index 0 in BytecodeArrayBuilder).
811 Register destination(builder()->Parameter(variable->index() + 1));
812 builder()->LoadTheHole().StoreAccumulatorInRegister(destination);
813 }
814 break;
815 case VariableLocation::CONTEXT:
816 if (variable->binding_needs_init()) {
817 DCHECK_EQ(0, execution_context()->ContextChainDepth(variable->scope()));
818 builder()->LoadTheHole().StoreContextSlot(execution_context()->reg(),
819 variable->index(), 0);
820 }
821 break;
822 case VariableLocation::LOOKUP: {
823 DCHECK_EQ(VAR, variable->mode());
824 DCHECK(!variable->binding_needs_init());
825
826 Register name = register_allocator()->NewRegister();
827
828 builder()
829 ->LoadLiteral(variable->name())
830 .StoreAccumulatorInRegister(name)
831 .CallRuntime(Runtime::kDeclareEvalVar, name);
832 break;
833 }
834 case VariableLocation::MODULE:
835 if (variable->IsExport() && variable->binding_needs_init()) {
836 builder()->LoadTheHole();
837 BuildVariableAssignment(variable, Token::INIT,
838 FeedbackVectorSlot::Invalid(),
839 HoleCheckMode::kElided);
840 }
841 // Nothing to do for imports.
842 break;
843 }
844 }
845
VisitFunctionDeclaration(FunctionDeclaration * decl)846 void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) {
847 Variable* variable = decl->proxy()->var();
848 DCHECK(variable->mode() == LET || variable->mode() == VAR);
849 switch (variable->location()) {
850 case VariableLocation::UNALLOCATED: {
851 FeedbackVectorSlot slot = decl->proxy()->VariableFeedbackSlot();
852 globals_builder()->AddFunctionDeclaration(slot, decl->fun());
853 break;
854 }
855 case VariableLocation::PARAMETER:
856 case VariableLocation::LOCAL: {
857 VisitForAccumulatorValue(decl->fun());
858 BuildVariableAssignment(variable, Token::INIT,
859 FeedbackVectorSlot::Invalid(),
860 HoleCheckMode::kElided);
861 break;
862 }
863 case VariableLocation::CONTEXT: {
864 DCHECK_EQ(0, execution_context()->ContextChainDepth(variable->scope()));
865 VisitForAccumulatorValue(decl->fun());
866 builder()->StoreContextSlot(execution_context()->reg(), variable->index(),
867 0);
868 break;
869 }
870 case VariableLocation::LOOKUP: {
871 RegisterList args = register_allocator()->NewRegisterList(2);
872 builder()
873 ->LoadLiteral(variable->name())
874 .StoreAccumulatorInRegister(args[0]);
875 VisitForAccumulatorValue(decl->fun());
876 builder()->StoreAccumulatorInRegister(args[1]).CallRuntime(
877 Runtime::kDeclareEvalFunction, args);
878 break;
879 }
880 case VariableLocation::MODULE:
881 DCHECK_EQ(variable->mode(), LET);
882 DCHECK(variable->IsExport());
883 VisitForAccumulatorValue(decl->fun());
884 BuildVariableAssignment(variable, Token::INIT,
885 FeedbackVectorSlot::Invalid(),
886 HoleCheckMode::kElided);
887 break;
888 }
889 }
890
VisitModuleNamespaceImports()891 void BytecodeGenerator::VisitModuleNamespaceImports() {
892 if (!scope()->is_module_scope()) return;
893
894 RegisterAllocationScope register_scope(this);
895 Register module_request = register_allocator()->NewRegister();
896
897 ModuleDescriptor* descriptor = scope()->AsModuleScope()->module();
898 for (auto entry : descriptor->namespace_imports()) {
899 builder()
900 ->LoadLiteral(Smi::FromInt(entry->module_request))
901 .StoreAccumulatorInRegister(module_request)
902 .CallRuntime(Runtime::kGetModuleNamespace, module_request);
903 Variable* var = scope()->LookupLocal(entry->local_name);
904 DCHECK_NOT_NULL(var);
905 BuildVariableAssignment(var, Token::INIT, FeedbackVectorSlot::Invalid(),
906 HoleCheckMode::kElided);
907 }
908 }
909
VisitDeclarations(Declaration::List * declarations)910 void BytecodeGenerator::VisitDeclarations(Declaration::List* declarations) {
911 RegisterAllocationScope register_scope(this);
912 DCHECK(globals_builder()->empty());
913 for (Declaration* decl : *declarations) {
914 RegisterAllocationScope register_scope(this);
915 Visit(decl);
916 }
917 if (globals_builder()->empty()) return;
918
919 globals_builder()->set_constant_pool_entry(
920 builder()->AllocateConstantPoolEntry());
921 int encoded_flags = info()->GetDeclareGlobalsFlags();
922
923 // Emit code to declare globals.
924 RegisterList args = register_allocator()->NewRegisterList(3);
925 builder()
926 ->LoadConstantPoolEntry(globals_builder()->constant_pool_entry())
927 .StoreAccumulatorInRegister(args[0])
928 .LoadLiteral(Smi::FromInt(encoded_flags))
929 .StoreAccumulatorInRegister(args[1])
930 .MoveRegister(Register::function_closure(), args[2])
931 .CallRuntime(Runtime::kDeclareGlobalsForInterpreter, args);
932
933 // Push and reset globals builder.
934 global_declarations_.push_back(globals_builder());
935 globals_builder_ = new (zone()) GlobalDeclarationsBuilder(zone());
936 }
937
VisitStatements(ZoneList<Statement * > * statements)938 void BytecodeGenerator::VisitStatements(ZoneList<Statement*>* statements) {
939 for (int i = 0; i < statements->length(); i++) {
940 // Allocate an outer register allocations scope for the statement.
941 RegisterAllocationScope allocation_scope(this);
942 Statement* stmt = statements->at(i);
943 Visit(stmt);
944 if (stmt->IsJump()) break;
945 }
946 }
947
VisitExpressionStatement(ExpressionStatement * stmt)948 void BytecodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
949 builder()->SetStatementPosition(stmt);
950 VisitForEffect(stmt->expression());
951 }
952
VisitEmptyStatement(EmptyStatement * stmt)953 void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
954 }
955
VisitIfStatement(IfStatement * stmt)956 void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) {
957 builder()->SetStatementPosition(stmt);
958 if (stmt->condition()->ToBooleanIsTrue()) {
959 // Generate then block unconditionally as always true.
960 Visit(stmt->then_statement());
961 } else if (stmt->condition()->ToBooleanIsFalse()) {
962 // Generate else block unconditionally if it exists.
963 if (stmt->HasElseStatement()) {
964 Visit(stmt->else_statement());
965 }
966 } else {
967 // TODO(oth): If then statement is BreakStatement or
968 // ContinueStatement we can reduce number of generated
969 // jump/jump_ifs here. See BasicLoops test.
970 BytecodeLabel end_label;
971 BytecodeLabels then_labels(zone()), else_labels(zone());
972 VisitForTest(stmt->condition(), &then_labels, &else_labels,
973 TestFallthrough::kThen);
974
975 then_labels.Bind(builder());
976 Visit(stmt->then_statement());
977
978 if (stmt->HasElseStatement()) {
979 builder()->Jump(&end_label);
980 else_labels.Bind(builder());
981 Visit(stmt->else_statement());
982 } else {
983 else_labels.Bind(builder());
984 }
985 builder()->Bind(&end_label);
986 }
987 }
988
VisitSloppyBlockFunctionStatement(SloppyBlockFunctionStatement * stmt)989 void BytecodeGenerator::VisitSloppyBlockFunctionStatement(
990 SloppyBlockFunctionStatement* stmt) {
991 Visit(stmt->statement());
992 }
993
VisitContinueStatement(ContinueStatement * stmt)994 void BytecodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
995 builder()->SetStatementPosition(stmt);
996 execution_control()->Continue(stmt->target());
997 }
998
VisitBreakStatement(BreakStatement * stmt)999 void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
1000 builder()->SetStatementPosition(stmt);
1001 execution_control()->Break(stmt->target());
1002 }
1003
VisitReturnStatement(ReturnStatement * stmt)1004 void BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
1005 builder()->SetStatementPosition(stmt);
1006 VisitForAccumulatorValue(stmt->expression());
1007 execution_control()->ReturnAccumulator();
1008 }
1009
VisitWithStatement(WithStatement * stmt)1010 void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) {
1011 builder()->SetStatementPosition(stmt);
1012 VisitForAccumulatorValue(stmt->expression());
1013 BuildNewLocalWithContext(stmt->scope());
1014 VisitInScope(stmt->statement(), stmt->scope());
1015 }
1016
VisitSwitchStatement(SwitchStatement * stmt)1017 void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
1018 // We need this scope because we visit for register values. We have to
1019 // maintain a execution result scope where registers can be allocated.
1020 ZoneList<CaseClause*>* clauses = stmt->cases();
1021 SwitchBuilder switch_builder(builder(), clauses->length());
1022 ControlScopeForBreakable scope(this, stmt, &switch_builder);
1023 int default_index = -1;
1024
1025 builder()->SetStatementPosition(stmt);
1026
1027 // Keep the switch value in a register until a case matches.
1028 Register tag = VisitForRegisterValue(stmt->tag());
1029
1030 // Iterate over all cases and create nodes for label comparison.
1031 for (int i = 0; i < clauses->length(); i++) {
1032 CaseClause* clause = clauses->at(i);
1033
1034 // The default is not a test, remember index.
1035 if (clause->is_default()) {
1036 default_index = i;
1037 continue;
1038 }
1039
1040 // Perform label comparison as if via '===' with tag.
1041 VisitForAccumulatorValue(clause->label());
1042 builder()->CompareOperation(
1043 Token::Value::EQ_STRICT, tag,
1044 feedback_index(clause->CompareOperationFeedbackSlot()));
1045 switch_builder.Case(i);
1046 }
1047
1048 if (default_index >= 0) {
1049 // Emit default jump if there is a default case.
1050 switch_builder.DefaultAt(default_index);
1051 } else {
1052 // Otherwise if we have reached here none of the cases matched, so jump to
1053 // the end.
1054 switch_builder.Break();
1055 }
1056
1057 // Iterate over all cases and create the case bodies.
1058 for (int i = 0; i < clauses->length(); i++) {
1059 CaseClause* clause = clauses->at(i);
1060 switch_builder.SetCaseTarget(i);
1061 VisitStatements(clause->statements());
1062 }
1063 switch_builder.BindBreakTarget();
1064 }
1065
VisitCaseClause(CaseClause * clause)1066 void BytecodeGenerator::VisitCaseClause(CaseClause* clause) {
1067 // Handled entirely in VisitSwitchStatement.
1068 UNREACHABLE();
1069 }
1070
VisitIterationBody(IterationStatement * stmt,LoopBuilder * loop_builder)1071 void BytecodeGenerator::VisitIterationBody(IterationStatement* stmt,
1072 LoopBuilder* loop_builder) {
1073 ControlScopeForIteration execution_control(this, stmt, loop_builder);
1074 builder()->StackCheck(stmt->position());
1075 Visit(stmt->body());
1076 loop_builder->BindContinueTarget();
1077 }
1078
VisitDoWhileStatement(DoWhileStatement * stmt)1079 void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
1080 LoopBuilder loop_builder(builder());
1081 if (stmt->cond()->ToBooleanIsFalse()) {
1082 VisitIterationBody(stmt, &loop_builder);
1083 } else if (stmt->cond()->ToBooleanIsTrue()) {
1084 VisitIterationHeader(stmt, &loop_builder);
1085 VisitIterationBody(stmt, &loop_builder);
1086 loop_builder.JumpToHeader(loop_depth_);
1087 } else {
1088 VisitIterationHeader(stmt, &loop_builder);
1089 VisitIterationBody(stmt, &loop_builder);
1090 builder()->SetExpressionAsStatementPosition(stmt->cond());
1091 BytecodeLabels loop_backbranch(zone());
1092 VisitForTest(stmt->cond(), &loop_backbranch, loop_builder.break_labels(),
1093 TestFallthrough::kThen);
1094 loop_backbranch.Bind(builder());
1095 loop_builder.JumpToHeader(loop_depth_);
1096 }
1097 loop_builder.EndLoop();
1098 }
1099
VisitWhileStatement(WhileStatement * stmt)1100 void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
1101 if (stmt->cond()->ToBooleanIsFalse()) {
1102 // If the condition is false there is no need to generate the loop.
1103 return;
1104 }
1105
1106 LoopBuilder loop_builder(builder());
1107 VisitIterationHeader(stmt, &loop_builder);
1108 if (!stmt->cond()->ToBooleanIsTrue()) {
1109 builder()->SetExpressionAsStatementPosition(stmt->cond());
1110 BytecodeLabels loop_body(zone());
1111 VisitForTest(stmt->cond(), &loop_body, loop_builder.break_labels(),
1112 TestFallthrough::kThen);
1113 loop_body.Bind(builder());
1114 }
1115 VisitIterationBody(stmt, &loop_builder);
1116 loop_builder.JumpToHeader(loop_depth_);
1117 loop_builder.EndLoop();
1118 }
1119
VisitForStatement(ForStatement * stmt)1120 void BytecodeGenerator::VisitForStatement(ForStatement* stmt) {
1121 if (stmt->init() != nullptr) {
1122 Visit(stmt->init());
1123 }
1124 if (stmt->cond() && stmt->cond()->ToBooleanIsFalse()) {
1125 // If the condition is known to be false there is no need to generate
1126 // body, next or condition blocks. Init block should be generated.
1127 return;
1128 }
1129
1130 LoopBuilder loop_builder(builder());
1131 VisitIterationHeader(stmt, &loop_builder);
1132 if (stmt->cond() && !stmt->cond()->ToBooleanIsTrue()) {
1133 builder()->SetExpressionAsStatementPosition(stmt->cond());
1134 BytecodeLabels loop_body(zone());
1135 VisitForTest(stmt->cond(), &loop_body, loop_builder.break_labels(),
1136 TestFallthrough::kThen);
1137 loop_body.Bind(builder());
1138 }
1139 VisitIterationBody(stmt, &loop_builder);
1140 if (stmt->next() != nullptr) {
1141 builder()->SetStatementPosition(stmt->next());
1142 Visit(stmt->next());
1143 }
1144 loop_builder.JumpToHeader(loop_depth_);
1145 loop_builder.EndLoop();
1146 }
1147
VisitForInAssignment(Expression * expr,FeedbackVectorSlot slot)1148 void BytecodeGenerator::VisitForInAssignment(Expression* expr,
1149 FeedbackVectorSlot slot) {
1150 DCHECK(expr->IsValidReferenceExpression());
1151
1152 // Evaluate assignment starting with the value to be stored in the
1153 // accumulator.
1154 Property* property = expr->AsProperty();
1155 LhsKind assign_type = Property::GetAssignType(property);
1156 switch (assign_type) {
1157 case VARIABLE: {
1158 VariableProxy* proxy = expr->AsVariableProxy();
1159 BuildVariableAssignment(proxy->var(), Token::ASSIGN, slot,
1160 proxy->hole_check_mode());
1161 break;
1162 }
1163 case NAMED_PROPERTY: {
1164 RegisterAllocationScope register_scope(this);
1165 Register value = register_allocator()->NewRegister();
1166 builder()->StoreAccumulatorInRegister(value);
1167 Register object = VisitForRegisterValue(property->obj());
1168 Handle<String> name = property->key()->AsLiteral()->AsPropertyName();
1169 builder()->LoadAccumulatorWithRegister(value);
1170 builder()->StoreNamedProperty(object, name, feedback_index(slot),
1171 language_mode());
1172 break;
1173 }
1174 case KEYED_PROPERTY: {
1175 RegisterAllocationScope register_scope(this);
1176 Register value = register_allocator()->NewRegister();
1177 builder()->StoreAccumulatorInRegister(value);
1178 Register object = VisitForRegisterValue(property->obj());
1179 Register key = VisitForRegisterValue(property->key());
1180 builder()->LoadAccumulatorWithRegister(value);
1181 builder()->StoreKeyedProperty(object, key, feedback_index(slot),
1182 language_mode());
1183 break;
1184 }
1185 case NAMED_SUPER_PROPERTY: {
1186 RegisterAllocationScope register_scope(this);
1187 RegisterList args = register_allocator()->NewRegisterList(4);
1188 builder()->StoreAccumulatorInRegister(args[3]);
1189 SuperPropertyReference* super_property =
1190 property->obj()->AsSuperPropertyReference();
1191 VisitForRegisterValue(super_property->this_var(), args[0]);
1192 VisitForRegisterValue(super_property->home_object(), args[1]);
1193 builder()
1194 ->LoadLiteral(property->key()->AsLiteral()->AsPropertyName())
1195 .StoreAccumulatorInRegister(args[2])
1196 .CallRuntime(StoreToSuperRuntimeId(), args);
1197 break;
1198 }
1199 case KEYED_SUPER_PROPERTY: {
1200 RegisterAllocationScope register_scope(this);
1201 RegisterList args = register_allocator()->NewRegisterList(4);
1202 builder()->StoreAccumulatorInRegister(args[3]);
1203 SuperPropertyReference* super_property =
1204 property->obj()->AsSuperPropertyReference();
1205 VisitForRegisterValue(super_property->this_var(), args[0]);
1206 VisitForRegisterValue(super_property->home_object(), args[1]);
1207 VisitForRegisterValue(property->key(), args[2]);
1208 builder()->CallRuntime(StoreKeyedToSuperRuntimeId(), args);
1209 break;
1210 }
1211 }
1212 }
1213
VisitForInStatement(ForInStatement * stmt)1214 void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) {
1215 if (stmt->subject()->IsNullLiteral() ||
1216 stmt->subject()->IsUndefinedLiteral()) {
1217 // ForIn generates lots of code, skip if it wouldn't produce any effects.
1218 return;
1219 }
1220
1221 LoopBuilder loop_builder(builder());
1222 BytecodeLabel subject_null_label, subject_undefined_label;
1223
1224 // Prepare the state for executing ForIn.
1225 builder()->SetExpressionAsStatementPosition(stmt->subject());
1226 VisitForAccumulatorValue(stmt->subject());
1227 builder()->JumpIfUndefined(&subject_undefined_label);
1228 builder()->JumpIfNull(&subject_null_label);
1229 Register receiver = register_allocator()->NewRegister();
1230 builder()->ConvertAccumulatorToObject(receiver);
1231
1232 // Used as kRegTriple and kRegPair in ForInPrepare and ForInNext.
1233 RegisterList triple = register_allocator()->NewRegisterList(3);
1234 Register cache_length = triple[2];
1235 builder()->ForInPrepare(receiver, triple);
1236
1237 // Set up loop counter
1238 Register index = register_allocator()->NewRegister();
1239 builder()->LoadLiteral(Smi::kZero);
1240 builder()->StoreAccumulatorInRegister(index);
1241
1242 // The loop
1243 VisitIterationHeader(stmt, &loop_builder);
1244 builder()->SetExpressionAsStatementPosition(stmt->each());
1245 builder()->ForInContinue(index, cache_length);
1246 loop_builder.BreakIfFalse();
1247 FeedbackVectorSlot slot = stmt->ForInFeedbackSlot();
1248 builder()->ForInNext(receiver, index, triple.Truncate(2),
1249 feedback_index(slot));
1250 loop_builder.ContinueIfUndefined();
1251 VisitForInAssignment(stmt->each(), stmt->EachFeedbackSlot());
1252 VisitIterationBody(stmt, &loop_builder);
1253 builder()->ForInStep(index);
1254 builder()->StoreAccumulatorInRegister(index);
1255 loop_builder.JumpToHeader(loop_depth_);
1256 loop_builder.EndLoop();
1257 builder()->Bind(&subject_null_label);
1258 builder()->Bind(&subject_undefined_label);
1259 }
1260
VisitForOfStatement(ForOfStatement * stmt)1261 void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
1262 LoopBuilder loop_builder(builder());
1263
1264 builder()->SetExpressionAsStatementPosition(stmt->assign_iterator());
1265 VisitForEffect(stmt->assign_iterator());
1266
1267 VisitIterationHeader(stmt, &loop_builder);
1268 builder()->SetExpressionAsStatementPosition(stmt->next_result());
1269 VisitForEffect(stmt->next_result());
1270 VisitForAccumulatorValue(stmt->result_done());
1271 loop_builder.BreakIfTrue();
1272
1273 VisitForEffect(stmt->assign_each());
1274 VisitIterationBody(stmt, &loop_builder);
1275 loop_builder.JumpToHeader(loop_depth_);
1276 loop_builder.EndLoop();
1277 }
1278
VisitTryCatchStatement(TryCatchStatement * stmt)1279 void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
1280 TryCatchBuilder try_control_builder(builder(), stmt->catch_prediction());
1281
1282 // Preserve the context in a dedicated register, so that it can be restored
1283 // when the handler is entered by the stack-unwinding machinery.
1284 // TODO(mstarzinger): Be smarter about register allocation.
1285 Register context = register_allocator()->NewRegister();
1286 builder()->MoveRegister(Register::current_context(), context);
1287
1288 // Evaluate the try-block inside a control scope. This simulates a handler
1289 // that is intercepting 'throw' control commands.
1290 try_control_builder.BeginTry(context);
1291 {
1292 ControlScopeForTryCatch scope(this, &try_control_builder);
1293 Visit(stmt->try_block());
1294 }
1295 try_control_builder.EndTry();
1296
1297 // Create a catch scope that binds the exception.
1298 BuildNewLocalCatchContext(stmt->variable(), stmt->scope());
1299 builder()->StoreAccumulatorInRegister(context);
1300
1301 // If requested, clear message object as we enter the catch block.
1302 if (stmt->clear_pending_message()) {
1303 builder()->CallRuntime(Runtime::kInterpreterClearPendingMessage);
1304 }
1305
1306 // Load the catch context into the accumulator.
1307 builder()->LoadAccumulatorWithRegister(context);
1308
1309 // Evaluate the catch-block.
1310 VisitInScope(stmt->catch_block(), stmt->scope());
1311 try_control_builder.EndCatch();
1312 }
1313
VisitTryFinallyStatement(TryFinallyStatement * stmt)1314 void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
1315 TryFinallyBuilder try_control_builder(builder(), stmt->catch_prediction());
1316
1317 // We keep a record of all paths that enter the finally-block to be able to
1318 // dispatch to the correct continuation point after the statements in the
1319 // finally-block have been evaluated.
1320 //
1321 // The try-finally construct can enter the finally-block in three ways:
1322 // 1. By exiting the try-block normally, falling through at the end.
1323 // 2. By exiting the try-block with a function-local control flow transfer
1324 // (i.e. through break/continue/return statements).
1325 // 3. By exiting the try-block with a thrown exception.
1326 //
1327 // The result register semantics depend on how the block was entered:
1328 // - ReturnStatement: It represents the return value being returned.
1329 // - ThrowStatement: It represents the exception being thrown.
1330 // - BreakStatement/ContinueStatement: Undefined and not used.
1331 // - Falling through into finally-block: Undefined and not used.
1332 Register token = register_allocator()->NewRegister();
1333 Register result = register_allocator()->NewRegister();
1334 ControlScope::DeferredCommands commands(this, token, result);
1335
1336 // Preserve the context in a dedicated register, so that it can be restored
1337 // when the handler is entered by the stack-unwinding machinery.
1338 // TODO(mstarzinger): Be smarter about register allocation.
1339 Register context = register_allocator()->NewRegister();
1340 builder()->MoveRegister(Register::current_context(), context);
1341
1342 // Evaluate the try-block inside a control scope. This simulates a handler
1343 // that is intercepting all control commands.
1344 try_control_builder.BeginTry(context);
1345 {
1346 ControlScopeForTryFinally scope(this, &try_control_builder, &commands);
1347 Visit(stmt->try_block());
1348 }
1349 try_control_builder.EndTry();
1350
1351 // Record fall-through and exception cases.
1352 commands.RecordFallThroughPath();
1353 try_control_builder.LeaveTry();
1354 try_control_builder.BeginHandler();
1355 commands.RecordHandlerReThrowPath();
1356
1357 // Pending message object is saved on entry.
1358 try_control_builder.BeginFinally();
1359 Register message = context; // Reuse register.
1360
1361 // Clear message object as we enter the finally block.
1362 builder()
1363 ->CallRuntime(Runtime::kInterpreterClearPendingMessage)
1364 .StoreAccumulatorInRegister(message);
1365
1366 // Evaluate the finally-block.
1367 Visit(stmt->finally_block());
1368 try_control_builder.EndFinally();
1369
1370 // Pending message object is restored on exit.
1371 builder()->CallRuntime(Runtime::kInterpreterSetPendingMessage, message);
1372
1373 // Dynamic dispatch after the finally-block.
1374 commands.ApplyDeferredCommands();
1375 }
1376
VisitDebuggerStatement(DebuggerStatement * stmt)1377 void BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
1378 builder()->SetStatementPosition(stmt);
1379 builder()->Debugger();
1380 }
1381
VisitFunctionLiteral(FunctionLiteral * expr)1382 void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
1383 uint8_t flags = CreateClosureFlags::Encode(expr->pretenure(),
1384 scope()->is_function_scope());
1385 size_t entry = builder()->AllocateConstantPoolEntry();
1386 builder()->CreateClosure(entry, flags);
1387 function_literals_.push_back(std::make_pair(expr, entry));
1388 }
1389
VisitClassLiteral(ClassLiteral * expr)1390 void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr) {
1391 VisitClassLiteralForRuntimeDefinition(expr);
1392
1393 // Load the "prototype" from the constructor.
1394 RegisterList args = register_allocator()->NewRegisterList(2);
1395 Register literal = args[0];
1396 Register prototype = args[1];
1397 FeedbackVectorSlot slot = expr->PrototypeSlot();
1398 builder()
1399 ->StoreAccumulatorInRegister(literal)
1400 .LoadNamedProperty(literal, prototype_string(), feedback_index(slot))
1401 .StoreAccumulatorInRegister(prototype);
1402
1403 VisitClassLiteralProperties(expr, literal, prototype);
1404 builder()->CallRuntime(Runtime::kToFastProperties, literal);
1405 // Assign to class variable.
1406 if (expr->class_variable_proxy() != nullptr) {
1407 VariableProxy* proxy = expr->class_variable_proxy();
1408 FeedbackVectorSlot slot = expr->NeedsProxySlot()
1409 ? expr->ProxySlot()
1410 : FeedbackVectorSlot::Invalid();
1411 BuildVariableAssignment(proxy->var(), Token::INIT, slot,
1412 HoleCheckMode::kElided);
1413 }
1414 }
1415
VisitClassLiteralForRuntimeDefinition(ClassLiteral * expr)1416 void BytecodeGenerator::VisitClassLiteralForRuntimeDefinition(
1417 ClassLiteral* expr) {
1418 RegisterAllocationScope register_scope(this);
1419 RegisterList args = register_allocator()->NewRegisterList(4);
1420 VisitForAccumulatorValueOrTheHole(expr->extends());
1421 builder()->StoreAccumulatorInRegister(args[0]);
1422 VisitForRegisterValue(expr->constructor(), args[1]);
1423 builder()
1424 ->LoadLiteral(Smi::FromInt(expr->start_position()))
1425 .StoreAccumulatorInRegister(args[2])
1426 .LoadLiteral(Smi::FromInt(expr->end_position()))
1427 .StoreAccumulatorInRegister(args[3])
1428 .CallRuntime(Runtime::kDefineClass, args);
1429 }
1430
VisitClassLiteralProperties(ClassLiteral * expr,Register literal,Register prototype)1431 void BytecodeGenerator::VisitClassLiteralProperties(ClassLiteral* expr,
1432 Register literal,
1433 Register prototype) {
1434 RegisterAllocationScope register_scope(this);
1435 RegisterList args = register_allocator()->NewRegisterList(5);
1436 Register receiver = args[0], key = args[1], value = args[2], attr = args[3],
1437 set_function_name = args[4];
1438
1439 bool attr_assigned = false;
1440 Register old_receiver = Register::invalid_value();
1441
1442 // Create nodes to store method values into the literal.
1443 for (int i = 0; i < expr->properties()->length(); i++) {
1444 ClassLiteral::Property* property = expr->properties()->at(i);
1445
1446 // Set-up receiver.
1447 Register new_receiver = property->is_static() ? literal : prototype;
1448 if (new_receiver != old_receiver) {
1449 builder()->MoveRegister(new_receiver, receiver);
1450 old_receiver = new_receiver;
1451 }
1452
1453 VisitForAccumulatorValue(property->key());
1454 builder()->ConvertAccumulatorToName(key);
1455
1456 if (property->is_static() && property->is_computed_name()) {
1457 // The static prototype property is read only. We handle the non computed
1458 // property name case in the parser. Since this is the only case where we
1459 // need to check for an own read only property we special case this so we
1460 // do not need to do this for every property.
1461 BytecodeLabel done;
1462 builder()
1463 ->LoadLiteral(prototype_string())
1464 .CompareOperation(Token::Value::EQ_STRICT, key)
1465 .JumpIfFalse(&done)
1466 .CallRuntime(Runtime::kThrowStaticPrototypeError)
1467 .Bind(&done);
1468 }
1469
1470 VisitForRegisterValue(property->value(), value);
1471 VisitSetHomeObject(value, receiver, property);
1472
1473 if (!attr_assigned) {
1474 builder()
1475 ->LoadLiteral(Smi::FromInt(DONT_ENUM))
1476 .StoreAccumulatorInRegister(attr);
1477 attr_assigned = true;
1478 }
1479
1480 switch (property->kind()) {
1481 case ClassLiteral::Property::METHOD: {
1482 builder()
1483 ->LoadLiteral(Smi::FromInt(property->NeedsSetFunctionName()))
1484 .StoreAccumulatorInRegister(set_function_name)
1485 .CallRuntime(Runtime::kDefineDataPropertyInLiteral, args);
1486 break;
1487 }
1488 case ClassLiteral::Property::GETTER: {
1489 builder()->CallRuntime(Runtime::kDefineGetterPropertyUnchecked,
1490 args.Truncate(4));
1491 break;
1492 }
1493 case ClassLiteral::Property::SETTER: {
1494 builder()->CallRuntime(Runtime::kDefineSetterPropertyUnchecked,
1495 args.Truncate(4));
1496 break;
1497 }
1498 case ClassLiteral::Property::FIELD: {
1499 UNREACHABLE();
1500 break;
1501 }
1502 }
1503 }
1504 }
1505
VisitNativeFunctionLiteral(NativeFunctionLiteral * expr)1506 void BytecodeGenerator::VisitNativeFunctionLiteral(
1507 NativeFunctionLiteral* expr) {
1508 size_t entry = builder()->AllocateConstantPoolEntry();
1509 builder()->CreateClosure(entry, NOT_TENURED);
1510 native_function_literals_.push_back(std::make_pair(expr, entry));
1511 }
1512
VisitDoExpression(DoExpression * expr)1513 void BytecodeGenerator::VisitDoExpression(DoExpression* expr) {
1514 VisitBlock(expr->block());
1515 VisitVariableProxy(expr->result());
1516 }
1517
VisitConditional(Conditional * expr)1518 void BytecodeGenerator::VisitConditional(Conditional* expr) {
1519 if (expr->condition()->ToBooleanIsTrue()) {
1520 // Generate then block unconditionally as always true.
1521 VisitForAccumulatorValue(expr->then_expression());
1522 } else if (expr->condition()->ToBooleanIsFalse()) {
1523 // Generate else block unconditionally if it exists.
1524 VisitForAccumulatorValue(expr->else_expression());
1525 } else {
1526 BytecodeLabel end_label;
1527 BytecodeLabels then_labels(zone()), else_labels(zone());
1528
1529 VisitForTest(expr->condition(), &then_labels, &else_labels,
1530 TestFallthrough::kThen);
1531
1532 then_labels.Bind(builder());
1533 VisitForAccumulatorValue(expr->then_expression());
1534 builder()->Jump(&end_label);
1535
1536 else_labels.Bind(builder());
1537 VisitForAccumulatorValue(expr->else_expression());
1538 builder()->Bind(&end_label);
1539 }
1540 }
1541
VisitLiteral(Literal * expr)1542 void BytecodeGenerator::VisitLiteral(Literal* expr) {
1543 if (!execution_result()->IsEffect()) {
1544 const AstValue* raw_value = expr->raw_value();
1545 if (raw_value->IsSmi()) {
1546 builder()->LoadLiteral(raw_value->AsSmi());
1547 } else if (raw_value->IsUndefined()) {
1548 builder()->LoadUndefined();
1549 } else if (raw_value->IsTrue()) {
1550 builder()->LoadTrue();
1551 } else if (raw_value->IsFalse()) {
1552 builder()->LoadFalse();
1553 } else if (raw_value->IsNull()) {
1554 builder()->LoadNull();
1555 } else if (raw_value->IsTheHole()) {
1556 builder()->LoadTheHole();
1557 } else {
1558 builder()->LoadLiteral(raw_value->value());
1559 }
1560 }
1561 }
1562
VisitRegExpLiteral(RegExpLiteral * expr)1563 void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
1564 // Materialize a regular expression literal.
1565 builder()->CreateRegExpLiteral(expr->pattern(), expr->literal_index(),
1566 expr->flags());
1567 }
1568
VisitObjectLiteral(ObjectLiteral * expr)1569 void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
1570 // Copy the literal boilerplate.
1571 uint8_t flags = CreateObjectLiteralFlags::Encode(
1572 FastCloneShallowObjectStub::IsSupported(expr),
1573 FastCloneShallowObjectStub::PropertiesCount(expr->properties_count()),
1574 expr->ComputeFlags());
1575 // If constant properties is an empty fixed array, use our cached
1576 // empty_fixed_array to ensure it's only added to the constant pool once.
1577 Handle<FixedArray> constant_properties = expr->properties_count() == 0
1578 ? empty_fixed_array()
1579 : expr->constant_properties();
1580 Register literal = register_allocator()->NewRegister();
1581 builder()->CreateObjectLiteral(constant_properties, expr->literal_index(),
1582 flags, literal);
1583
1584 // Store computed values into the literal.
1585 int property_index = 0;
1586 AccessorTable accessor_table(zone());
1587 for (; property_index < expr->properties()->length(); property_index++) {
1588 ObjectLiteral::Property* property = expr->properties()->at(property_index);
1589 if (property->is_computed_name()) break;
1590 if (property->IsCompileTimeValue()) continue;
1591
1592 RegisterAllocationScope inner_register_scope(this);
1593 Literal* key = property->key()->AsLiteral();
1594 switch (property->kind()) {
1595 case ObjectLiteral::Property::CONSTANT:
1596 UNREACHABLE();
1597 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1598 DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value()));
1599 // Fall through.
1600 case ObjectLiteral::Property::COMPUTED: {
1601 // It is safe to use [[Put]] here because the boilerplate already
1602 // contains computed properties with an uninitialized value.
1603 if (key->IsStringLiteral()) {
1604 DCHECK(key->IsPropertyName());
1605 if (property->emit_store()) {
1606 VisitForAccumulatorValue(property->value());
1607 if (FunctionLiteral::NeedsHomeObject(property->value())) {
1608 RegisterAllocationScope register_scope(this);
1609 Register value = register_allocator()->NewRegister();
1610 builder()->StoreAccumulatorInRegister(value);
1611 builder()->StoreNamedProperty(
1612 literal, key->AsPropertyName(),
1613 feedback_index(property->GetSlot(0)), language_mode());
1614 VisitSetHomeObject(value, literal, property, 1);
1615 } else {
1616 builder()->StoreNamedProperty(
1617 literal, key->AsPropertyName(),
1618 feedback_index(property->GetSlot(0)), language_mode());
1619 }
1620 } else {
1621 VisitForEffect(property->value());
1622 }
1623 } else {
1624 RegisterList args = register_allocator()->NewRegisterList(4);
1625
1626 builder()->MoveRegister(literal, args[0]);
1627 VisitForRegisterValue(property->key(), args[1]);
1628 VisitForRegisterValue(property->value(), args[2]);
1629 if (property->emit_store()) {
1630 builder()
1631 ->LoadLiteral(Smi::FromInt(SLOPPY))
1632 .StoreAccumulatorInRegister(args[3])
1633 .CallRuntime(Runtime::kSetProperty, args);
1634 Register value = args[2];
1635 VisitSetHomeObject(value, literal, property);
1636 }
1637 }
1638 break;
1639 }
1640 case ObjectLiteral::Property::PROTOTYPE: {
1641 DCHECK(property->emit_store());
1642 RegisterList args = register_allocator()->NewRegisterList(2);
1643 builder()->MoveRegister(literal, args[0]);
1644 VisitForRegisterValue(property->value(), args[1]);
1645 builder()->CallRuntime(Runtime::kInternalSetPrototype, args);
1646 break;
1647 }
1648 case ObjectLiteral::Property::GETTER:
1649 if (property->emit_store()) {
1650 accessor_table.lookup(key)->second->getter = property;
1651 }
1652 break;
1653 case ObjectLiteral::Property::SETTER:
1654 if (property->emit_store()) {
1655 accessor_table.lookup(key)->second->setter = property;
1656 }
1657 break;
1658 }
1659 }
1660
1661 // Define accessors, using only a single call to the runtime for each pair of
1662 // corresponding getters and setters.
1663 for (AccessorTable::Iterator it = accessor_table.begin();
1664 it != accessor_table.end(); ++it) {
1665 RegisterAllocationScope inner_register_scope(this);
1666 RegisterList args = register_allocator()->NewRegisterList(5);
1667 builder()->MoveRegister(literal, args[0]);
1668 VisitForRegisterValue(it->first, args[1]);
1669 VisitObjectLiteralAccessor(literal, it->second->getter, args[2]);
1670 VisitObjectLiteralAccessor(literal, it->second->setter, args[3]);
1671 builder()
1672 ->LoadLiteral(Smi::FromInt(NONE))
1673 .StoreAccumulatorInRegister(args[4])
1674 .CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, args);
1675 }
1676
1677 // Object literals have two parts. The "static" part on the left contains no
1678 // computed property names, and so we can compute its map ahead of time; see
1679 // Runtime_CreateObjectLiteralBoilerplate. The second "dynamic" part starts
1680 // with the first computed property name and continues with all properties to
1681 // its right. All the code from above initializes the static component of the
1682 // object literal, and arranges for the map of the result to reflect the
1683 // static order in which the keys appear. For the dynamic properties, we
1684 // compile them into a series of "SetOwnProperty" runtime calls. This will
1685 // preserve insertion order.
1686 for (; property_index < expr->properties()->length(); property_index++) {
1687 ObjectLiteral::Property* property = expr->properties()->at(property_index);
1688 RegisterAllocationScope inner_register_scope(this);
1689
1690 if (property->kind() == ObjectLiteral::Property::PROTOTYPE) {
1691 DCHECK(property->emit_store());
1692 RegisterList args = register_allocator()->NewRegisterList(2);
1693 builder()->MoveRegister(literal, args[0]);
1694 VisitForRegisterValue(property->value(), args[1]);
1695 builder()->CallRuntime(Runtime::kInternalSetPrototype, args);
1696 continue;
1697 }
1698
1699 switch (property->kind()) {
1700 case ObjectLiteral::Property::CONSTANT:
1701 case ObjectLiteral::Property::COMPUTED:
1702 case ObjectLiteral::Property::MATERIALIZED_LITERAL: {
1703 RegisterList args = register_allocator()->NewRegisterList(5);
1704 builder()->MoveRegister(literal, args[0]);
1705 VisitForAccumulatorValue(property->key());
1706 builder()->ConvertAccumulatorToName(args[1]);
1707 VisitForRegisterValue(property->value(), args[2]);
1708 VisitSetHomeObject(args[2], literal, property);
1709 builder()
1710 ->LoadLiteral(Smi::FromInt(NONE))
1711 .StoreAccumulatorInRegister(args[3])
1712 .LoadLiteral(Smi::FromInt(property->NeedsSetFunctionName()))
1713 .StoreAccumulatorInRegister(args[4]);
1714 builder()->CallRuntime(Runtime::kDefineDataPropertyInLiteral, args);
1715 break;
1716 }
1717 case ObjectLiteral::Property::GETTER:
1718 case ObjectLiteral::Property::SETTER: {
1719 RegisterList args = register_allocator()->NewRegisterList(4);
1720 builder()->MoveRegister(literal, args[0]);
1721 VisitForAccumulatorValue(property->key());
1722 builder()->ConvertAccumulatorToName(args[1]);
1723 VisitForRegisterValue(property->value(), args[2]);
1724 VisitSetHomeObject(args[2], literal, property);
1725 builder()
1726 ->LoadLiteral(Smi::FromInt(NONE))
1727 .StoreAccumulatorInRegister(args[3]);
1728 Runtime::FunctionId function_id =
1729 property->kind() == ObjectLiteral::Property::GETTER
1730 ? Runtime::kDefineGetterPropertyUnchecked
1731 : Runtime::kDefineSetterPropertyUnchecked;
1732 builder()->CallRuntime(function_id, args);
1733 break;
1734 }
1735 case ObjectLiteral::Property::PROTOTYPE:
1736 UNREACHABLE(); // Handled specially above.
1737 break;
1738 }
1739 }
1740
1741 builder()->LoadAccumulatorWithRegister(literal);
1742 }
1743
VisitArrayLiteral(ArrayLiteral * expr)1744 void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
1745 // Deep-copy the literal boilerplate.
1746 int runtime_flags = expr->ComputeFlags();
1747 bool use_fast_shallow_clone =
1748 (runtime_flags & ArrayLiteral::kShallowElements) != 0 &&
1749 expr->values()->length() <= JSArray::kInitialMaxFastElementArray;
1750 uint8_t flags =
1751 CreateArrayLiteralFlags::Encode(use_fast_shallow_clone, runtime_flags);
1752 builder()->CreateArrayLiteral(expr->constant_elements(),
1753 expr->literal_index(), flags);
1754 Register index, literal;
1755
1756 // Evaluate all the non-constant subexpressions and store them into the
1757 // newly cloned array.
1758 bool literal_in_accumulator = true;
1759 for (int array_index = 0; array_index < expr->values()->length();
1760 array_index++) {
1761 Expression* subexpr = expr->values()->at(array_index);
1762 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
1763 DCHECK(!subexpr->IsSpread());
1764
1765 if (literal_in_accumulator) {
1766 index = register_allocator()->NewRegister();
1767 literal = register_allocator()->NewRegister();
1768 builder()->StoreAccumulatorInRegister(literal);
1769 literal_in_accumulator = false;
1770 }
1771
1772 FeedbackVectorSlot slot = expr->LiteralFeedbackSlot();
1773 builder()
1774 ->LoadLiteral(Smi::FromInt(array_index))
1775 .StoreAccumulatorInRegister(index);
1776 VisitForAccumulatorValue(subexpr);
1777 builder()->StoreKeyedProperty(literal, index, feedback_index(slot),
1778 language_mode());
1779 }
1780
1781 if (!literal_in_accumulator) {
1782 // Restore literal array into accumulator.
1783 builder()->LoadAccumulatorWithRegister(literal);
1784 }
1785 }
1786
VisitVariableProxy(VariableProxy * proxy)1787 void BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) {
1788 builder()->SetExpressionPosition(proxy);
1789 BuildVariableLoad(proxy->var(), proxy->VariableFeedbackSlot(),
1790 proxy->hole_check_mode());
1791 }
1792
BuildVariableLoad(Variable * variable,FeedbackVectorSlot slot,HoleCheckMode hole_check_mode,TypeofMode typeof_mode)1793 void BytecodeGenerator::BuildVariableLoad(Variable* variable,
1794 FeedbackVectorSlot slot,
1795 HoleCheckMode hole_check_mode,
1796 TypeofMode typeof_mode) {
1797 switch (variable->location()) {
1798 case VariableLocation::LOCAL: {
1799 Register source(Register(variable->index()));
1800 // We need to load the variable into the accumulator, even when in a
1801 // VisitForRegisterScope, in order to avoid register aliasing if
1802 // subsequent expressions assign to the same variable.
1803 builder()->LoadAccumulatorWithRegister(source);
1804 if (hole_check_mode == HoleCheckMode::kRequired) {
1805 BuildThrowIfHole(variable->name());
1806 }
1807 break;
1808 }
1809 case VariableLocation::PARAMETER: {
1810 // The parameter indices are shifted by 1 (receiver is variable
1811 // index -1 but is parameter index 0 in BytecodeArrayBuilder).
1812 Register source = builder()->Parameter(variable->index() + 1);
1813 // We need to load the variable into the accumulator, even when in a
1814 // VisitForRegisterScope, in order to avoid register aliasing if
1815 // subsequent expressions assign to the same variable.
1816 builder()->LoadAccumulatorWithRegister(source);
1817 if (hole_check_mode == HoleCheckMode::kRequired) {
1818 BuildThrowIfHole(variable->name());
1819 }
1820 break;
1821 }
1822 case VariableLocation::UNALLOCATED: {
1823 builder()->LoadGlobal(feedback_index(slot), typeof_mode);
1824 break;
1825 }
1826 case VariableLocation::CONTEXT: {
1827 int depth = execution_context()->ContextChainDepth(variable->scope());
1828 ContextScope* context = execution_context()->Previous(depth);
1829 Register context_reg;
1830 if (context) {
1831 context_reg = context->reg();
1832 depth = 0;
1833 } else {
1834 context_reg = execution_context()->reg();
1835 }
1836
1837 builder()->LoadContextSlot(context_reg, variable->index(), depth);
1838 if (hole_check_mode == HoleCheckMode::kRequired) {
1839 BuildThrowIfHole(variable->name());
1840 }
1841 break;
1842 }
1843 case VariableLocation::LOOKUP: {
1844 switch (variable->mode()) {
1845 case DYNAMIC_LOCAL: {
1846 Variable* local_variable = variable->local_if_not_shadowed();
1847 int depth =
1848 execution_context()->ContextChainDepth(local_variable->scope());
1849 builder()->LoadLookupContextSlot(variable->name(), typeof_mode,
1850 local_variable->index(), depth);
1851 if (hole_check_mode == HoleCheckMode::kRequired) {
1852 BuildThrowIfHole(variable->name());
1853 }
1854 break;
1855 }
1856 case DYNAMIC_GLOBAL: {
1857 int depth = scope()->ContextChainLengthUntilOutermostSloppyEval();
1858 builder()->LoadLookupGlobalSlot(variable->name(), typeof_mode,
1859 feedback_index(slot), depth);
1860 break;
1861 }
1862 default:
1863 builder()->LoadLookupSlot(variable->name(), typeof_mode);
1864 }
1865 break;
1866 }
1867 case VariableLocation::MODULE: {
1868 int depth = execution_context()->ContextChainDepth(variable->scope());
1869 builder()->LoadModuleVariable(variable->index(), depth);
1870 if (hole_check_mode == HoleCheckMode::kRequired) {
1871 BuildThrowIfHole(variable->name());
1872 }
1873 break;
1874 }
1875 }
1876 }
1877
BuildVariableLoadForAccumulatorValue(Variable * variable,FeedbackVectorSlot slot,HoleCheckMode hole_check_mode,TypeofMode typeof_mode)1878 void BytecodeGenerator::BuildVariableLoadForAccumulatorValue(
1879 Variable* variable, FeedbackVectorSlot slot, HoleCheckMode hole_check_mode,
1880 TypeofMode typeof_mode) {
1881 ValueResultScope accumulator_result(this);
1882 BuildVariableLoad(variable, slot, hole_check_mode, typeof_mode);
1883 }
1884
BuildReturn()1885 void BytecodeGenerator::BuildReturn() {
1886 if (FLAG_trace) {
1887 RegisterAllocationScope register_scope(this);
1888 Register result = register_allocator()->NewRegister();
1889 // Runtime returns {result} value, preserving accumulator.
1890 builder()->StoreAccumulatorInRegister(result).CallRuntime(
1891 Runtime::kTraceExit, result);
1892 }
1893 builder()->Return();
1894 }
1895
BuildReThrow()1896 void BytecodeGenerator::BuildReThrow() { builder()->ReThrow(); }
1897
BuildAbort(BailoutReason bailout_reason)1898 void BytecodeGenerator::BuildAbort(BailoutReason bailout_reason) {
1899 RegisterAllocationScope register_scope(this);
1900 Register reason = register_allocator()->NewRegister();
1901 builder()
1902 ->LoadLiteral(Smi::FromInt(static_cast<int>(bailout_reason)))
1903 .StoreAccumulatorInRegister(reason)
1904 .CallRuntime(Runtime::kAbort, reason);
1905 }
1906
BuildThrowReferenceError(Handle<String> name)1907 void BytecodeGenerator::BuildThrowReferenceError(Handle<String> name) {
1908 RegisterAllocationScope register_scope(this);
1909 Register name_reg = register_allocator()->NewRegister();
1910 builder()->LoadLiteral(name).StoreAccumulatorInRegister(name_reg).CallRuntime(
1911 Runtime::kThrowReferenceError, name_reg);
1912 }
1913
BuildThrowIfHole(Handle<String> name)1914 void BytecodeGenerator::BuildThrowIfHole(Handle<String> name) {
1915 // TODO(interpreter): Can the parser reduce the number of checks
1916 // performed? Or should there be a ThrowIfHole bytecode.
1917 BytecodeLabel no_reference_error;
1918 builder()->JumpIfNotHole(&no_reference_error);
1919 BuildThrowReferenceError(name);
1920 builder()->Bind(&no_reference_error);
1921 }
1922
BuildThrowIfNotHole(Handle<String> name)1923 void BytecodeGenerator::BuildThrowIfNotHole(Handle<String> name) {
1924 // TODO(interpreter): Can the parser reduce the number of checks
1925 // performed? Or should there be a ThrowIfNotHole bytecode.
1926 BytecodeLabel no_reference_error, reference_error;
1927 builder()
1928 ->JumpIfNotHole(&reference_error)
1929 .Jump(&no_reference_error)
1930 .Bind(&reference_error);
1931 BuildThrowReferenceError(name);
1932 builder()->Bind(&no_reference_error);
1933 }
1934
BuildHoleCheckForVariableAssignment(Variable * variable,Token::Value op)1935 void BytecodeGenerator::BuildHoleCheckForVariableAssignment(Variable* variable,
1936 Token::Value op) {
1937 if (variable->is_this() && variable->mode() == CONST && op == Token::INIT) {
1938 // Perform an initialization check for 'this'. 'this' variable is the
1939 // only variable able to trigger bind operations outside the TDZ
1940 // via 'super' calls.
1941 BuildThrowIfNotHole(variable->name());
1942 } else {
1943 // Perform an initialization check for let/const declared variables.
1944 // E.g. let x = (x = 20); is not allowed.
1945 DCHECK(IsLexicalVariableMode(variable->mode()));
1946 BuildThrowIfHole(variable->name());
1947 }
1948 }
1949
BuildVariableAssignment(Variable * variable,Token::Value op,FeedbackVectorSlot slot,HoleCheckMode hole_check_mode)1950 void BytecodeGenerator::BuildVariableAssignment(Variable* variable,
1951 Token::Value op,
1952 FeedbackVectorSlot slot,
1953 HoleCheckMode hole_check_mode) {
1954 VariableMode mode = variable->mode();
1955 RegisterAllocationScope assignment_register_scope(this);
1956 BytecodeLabel end_label;
1957 switch (variable->location()) {
1958 case VariableLocation::PARAMETER:
1959 case VariableLocation::LOCAL: {
1960 Register destination;
1961 if (VariableLocation::PARAMETER == variable->location()) {
1962 destination = Register(builder()->Parameter(variable->index() + 1));
1963 } else {
1964 destination = Register(variable->index());
1965 }
1966
1967 if (hole_check_mode == HoleCheckMode::kRequired) {
1968 // Load destination to check for hole.
1969 Register value_temp = register_allocator()->NewRegister();
1970 builder()
1971 ->StoreAccumulatorInRegister(value_temp)
1972 .LoadAccumulatorWithRegister(destination);
1973
1974 BuildHoleCheckForVariableAssignment(variable, op);
1975 builder()->LoadAccumulatorWithRegister(value_temp);
1976 }
1977
1978 if (mode != CONST || op == Token::INIT) {
1979 builder()->StoreAccumulatorInRegister(destination);
1980 } else if (variable->throw_on_const_assignment(language_mode())) {
1981 builder()->CallRuntime(Runtime::kThrowConstAssignError);
1982 }
1983 break;
1984 }
1985 case VariableLocation::UNALLOCATED: {
1986 builder()->StoreGlobal(variable->name(), feedback_index(slot),
1987 language_mode());
1988 break;
1989 }
1990 case VariableLocation::CONTEXT: {
1991 int depth = execution_context()->ContextChainDepth(variable->scope());
1992 ContextScope* context = execution_context()->Previous(depth);
1993 Register context_reg;
1994
1995 if (context) {
1996 context_reg = context->reg();
1997 depth = 0;
1998 } else {
1999 context_reg = execution_context()->reg();
2000 }
2001
2002 if (hole_check_mode == HoleCheckMode::kRequired) {
2003 // Load destination to check for hole.
2004 Register value_temp = register_allocator()->NewRegister();
2005 builder()
2006 ->StoreAccumulatorInRegister(value_temp)
2007 .LoadContextSlot(context_reg, variable->index(), depth);
2008
2009 BuildHoleCheckForVariableAssignment(variable, op);
2010 builder()->LoadAccumulatorWithRegister(value_temp);
2011 }
2012
2013 if (mode != CONST || op == Token::INIT) {
2014 builder()->StoreContextSlot(context_reg, variable->index(), depth);
2015 } else if (variable->throw_on_const_assignment(language_mode())) {
2016 builder()->CallRuntime(Runtime::kThrowConstAssignError);
2017 }
2018 break;
2019 }
2020 case VariableLocation::LOOKUP: {
2021 builder()->StoreLookupSlot(variable->name(), language_mode());
2022 break;
2023 }
2024 case VariableLocation::MODULE: {
2025 DCHECK(IsDeclaredVariableMode(mode));
2026
2027 if (mode == CONST && op != Token::INIT) {
2028 builder()->CallRuntime(Runtime::kThrowConstAssignError);
2029 break;
2030 }
2031
2032 // If we don't throw above, we know that we're dealing with an
2033 // export because imports are const and we do not generate initializing
2034 // assignments for them.
2035 DCHECK(variable->IsExport());
2036
2037 int depth = execution_context()->ContextChainDepth(variable->scope());
2038 if (hole_check_mode == HoleCheckMode::kRequired) {
2039 Register value_temp = register_allocator()->NewRegister();
2040 builder()
2041 ->StoreAccumulatorInRegister(value_temp)
2042 .LoadModuleVariable(variable->index(), depth);
2043 BuildHoleCheckForVariableAssignment(variable, op);
2044 builder()->LoadAccumulatorWithRegister(value_temp);
2045 }
2046 builder()->StoreModuleVariable(variable->index(), depth);
2047 break;
2048 }
2049 }
2050 }
2051
VisitAssignment(Assignment * expr)2052 void BytecodeGenerator::VisitAssignment(Assignment* expr) {
2053 DCHECK(expr->target()->IsValidReferenceExpressionOrThis());
2054 Register object, key;
2055 RegisterList super_property_args;
2056 Handle<String> name;
2057
2058 // Left-hand side can only be a property, a global or a variable slot.
2059 Property* property = expr->target()->AsProperty();
2060 LhsKind assign_type = Property::GetAssignType(property);
2061
2062 // Evaluate LHS expression.
2063 switch (assign_type) {
2064 case VARIABLE:
2065 // Nothing to do to evaluate variable assignment LHS.
2066 break;
2067 case NAMED_PROPERTY: {
2068 object = VisitForRegisterValue(property->obj());
2069 name = property->key()->AsLiteral()->AsPropertyName();
2070 break;
2071 }
2072 case KEYED_PROPERTY: {
2073 object = VisitForRegisterValue(property->obj());
2074 key = VisitForRegisterValue(property->key());
2075 break;
2076 }
2077 case NAMED_SUPER_PROPERTY: {
2078 super_property_args = register_allocator()->NewRegisterList(4);
2079 SuperPropertyReference* super_property =
2080 property->obj()->AsSuperPropertyReference();
2081 VisitForRegisterValue(super_property->this_var(), super_property_args[0]);
2082 VisitForRegisterValue(super_property->home_object(),
2083 super_property_args[1]);
2084 builder()
2085 ->LoadLiteral(property->key()->AsLiteral()->AsPropertyName())
2086 .StoreAccumulatorInRegister(super_property_args[2]);
2087 break;
2088 }
2089 case KEYED_SUPER_PROPERTY: {
2090 super_property_args = register_allocator()->NewRegisterList(4);
2091 SuperPropertyReference* super_property =
2092 property->obj()->AsSuperPropertyReference();
2093 VisitForRegisterValue(super_property->this_var(), super_property_args[0]);
2094 VisitForRegisterValue(super_property->home_object(),
2095 super_property_args[1]);
2096 VisitForRegisterValue(property->key(), super_property_args[2]);
2097 break;
2098 }
2099 }
2100
2101 // Evaluate the value and potentially handle compound assignments by loading
2102 // the left-hand side value and performing a binary operation.
2103 if (expr->is_compound()) {
2104 Register old_value = register_allocator()->NewRegister();
2105 switch (assign_type) {
2106 case VARIABLE: {
2107 VariableProxy* proxy = expr->target()->AsVariableProxy();
2108 BuildVariableLoad(proxy->var(), proxy->VariableFeedbackSlot(),
2109 proxy->hole_check_mode());
2110 builder()->StoreAccumulatorInRegister(old_value);
2111 break;
2112 }
2113 case NAMED_PROPERTY: {
2114 FeedbackVectorSlot slot = property->PropertyFeedbackSlot();
2115 builder()
2116 ->LoadNamedProperty(object, name, feedback_index(slot))
2117 .StoreAccumulatorInRegister(old_value);
2118 break;
2119 }
2120 case KEYED_PROPERTY: {
2121 // Key is already in accumulator at this point due to evaluating the
2122 // LHS above.
2123 FeedbackVectorSlot slot = property->PropertyFeedbackSlot();
2124 builder()
2125 ->LoadKeyedProperty(object, feedback_index(slot))
2126 .StoreAccumulatorInRegister(old_value);
2127 break;
2128 }
2129 case NAMED_SUPER_PROPERTY: {
2130 builder()
2131 ->CallRuntime(Runtime::kLoadFromSuper,
2132 super_property_args.Truncate(3))
2133 .StoreAccumulatorInRegister(old_value);
2134 break;
2135 }
2136 case KEYED_SUPER_PROPERTY: {
2137 builder()
2138 ->CallRuntime(Runtime::kLoadKeyedFromSuper,
2139 super_property_args.Truncate(3))
2140 .StoreAccumulatorInRegister(old_value);
2141 break;
2142 }
2143 }
2144 VisitForAccumulatorValue(expr->value());
2145 FeedbackVectorSlot slot =
2146 expr->binary_operation()->BinaryOperationFeedbackSlot();
2147 builder()->BinaryOperation(expr->binary_op(), old_value,
2148 feedback_index(slot));
2149 } else {
2150 VisitForAccumulatorValue(expr->value());
2151 }
2152
2153 // Store the value.
2154 builder()->SetExpressionPosition(expr);
2155 FeedbackVectorSlot slot = expr->AssignmentSlot();
2156 switch (assign_type) {
2157 case VARIABLE: {
2158 // TODO(oth): The BuildVariableAssignment() call is hard to reason about.
2159 // Is the value in the accumulator safe? Yes, but scary.
2160 VariableProxy* proxy = expr->target()->AsVariableProxy();
2161 BuildVariableAssignment(proxy->var(), expr->op(), slot,
2162 proxy->hole_check_mode());
2163 break;
2164 }
2165 case NAMED_PROPERTY:
2166 builder()->StoreNamedProperty(object, name, feedback_index(slot),
2167 language_mode());
2168 break;
2169 case KEYED_PROPERTY:
2170 builder()->StoreKeyedProperty(object, key, feedback_index(slot),
2171 language_mode());
2172 break;
2173 case NAMED_SUPER_PROPERTY: {
2174 builder()
2175 ->StoreAccumulatorInRegister(super_property_args[3])
2176 .CallRuntime(StoreToSuperRuntimeId(), super_property_args);
2177 break;
2178 }
2179 case KEYED_SUPER_PROPERTY: {
2180 builder()
2181 ->StoreAccumulatorInRegister(super_property_args[3])
2182 .CallRuntime(StoreKeyedToSuperRuntimeId(), super_property_args);
2183 break;
2184 }
2185 }
2186 }
2187
VisitYield(Yield * expr)2188 void BytecodeGenerator::VisitYield(Yield* expr) {
2189 builder()->SetExpressionPosition(expr);
2190 Register value = VisitForRegisterValue(expr->expression());
2191
2192 Register generator = VisitForRegisterValue(expr->generator_object());
2193
2194 // Save context, registers, and state. Then return.
2195 builder()
2196 ->LoadLiteral(Smi::FromInt(expr->yield_id()))
2197 .SuspendGenerator(generator)
2198 .LoadAccumulatorWithRegister(value)
2199 .Return(); // Hard return (ignore any finally blocks).
2200
2201 builder()->Bind(&(generator_resume_points_[expr->yield_id()]));
2202 // Upon resume, we continue here.
2203
2204 {
2205 RegisterAllocationScope register_scope(this);
2206
2207 // Update state to indicate that we have finished resuming. Loop headers
2208 // rely on this.
2209 builder()
2210 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting))
2211 .StoreAccumulatorInRegister(generator_state_);
2212
2213 Register input = register_allocator()->NewRegister();
2214 builder()
2215 ->CallRuntime(Runtime::kInlineGeneratorGetInputOrDebugPos, generator)
2216 .StoreAccumulatorInRegister(input);
2217
2218 Register resume_mode = register_allocator()->NewRegister();
2219 builder()
2220 ->CallRuntime(Runtime::kInlineGeneratorGetResumeMode, generator)
2221 .StoreAccumulatorInRegister(resume_mode);
2222
2223 // Now dispatch on resume mode.
2224
2225 BytecodeLabel resume_with_next;
2226 BytecodeLabel resume_with_return;
2227 BytecodeLabel resume_with_throw;
2228
2229 builder()
2230 ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kNext))
2231 .CompareOperation(Token::EQ_STRICT, resume_mode)
2232 .JumpIfTrue(&resume_with_next)
2233 .LoadLiteral(Smi::FromInt(JSGeneratorObject::kThrow))
2234 .CompareOperation(Token::EQ_STRICT, resume_mode)
2235 .JumpIfTrue(&resume_with_throw)
2236 .Jump(&resume_with_return);
2237
2238 builder()->Bind(&resume_with_return);
2239 {
2240 RegisterList args = register_allocator()->NewRegisterList(2);
2241 builder()
2242 ->MoveRegister(input, args[0])
2243 .LoadTrue()
2244 .StoreAccumulatorInRegister(args[1])
2245 .CallRuntime(Runtime::kInlineCreateIterResultObject, args);
2246 execution_control()->ReturnAccumulator();
2247 }
2248
2249 builder()->Bind(&resume_with_throw);
2250 builder()->SetExpressionPosition(expr);
2251 builder()->LoadAccumulatorWithRegister(input);
2252 if (expr->rethrow_on_exception()) {
2253 builder()->ReThrow();
2254 } else {
2255 builder()->Throw();
2256 }
2257
2258 builder()->Bind(&resume_with_next);
2259 builder()->LoadAccumulatorWithRegister(input);
2260 }
2261 }
2262
VisitThrow(Throw * expr)2263 void BytecodeGenerator::VisitThrow(Throw* expr) {
2264 VisitForAccumulatorValue(expr->exception());
2265 builder()->SetExpressionPosition(expr);
2266 builder()->Throw();
2267 }
2268
VisitPropertyLoad(Register obj,Property * expr)2269 void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* expr) {
2270 LhsKind property_kind = Property::GetAssignType(expr);
2271 FeedbackVectorSlot slot = expr->PropertyFeedbackSlot();
2272 builder()->SetExpressionPosition(expr);
2273 switch (property_kind) {
2274 case VARIABLE:
2275 UNREACHABLE();
2276 case NAMED_PROPERTY: {
2277 builder()->LoadNamedProperty(obj,
2278 expr->key()->AsLiteral()->AsPropertyName(),
2279 feedback_index(slot));
2280 break;
2281 }
2282 case KEYED_PROPERTY: {
2283 VisitForAccumulatorValue(expr->key());
2284 builder()->LoadKeyedProperty(obj, feedback_index(slot));
2285 break;
2286 }
2287 case NAMED_SUPER_PROPERTY:
2288 VisitNamedSuperPropertyLoad(expr, Register::invalid_value());
2289 break;
2290 case KEYED_SUPER_PROPERTY:
2291 VisitKeyedSuperPropertyLoad(expr, Register::invalid_value());
2292 break;
2293 }
2294 }
2295
VisitPropertyLoadForRegister(Register obj,Property * expr,Register destination)2296 void BytecodeGenerator::VisitPropertyLoadForRegister(Register obj,
2297 Property* expr,
2298 Register destination) {
2299 ValueResultScope result_scope(this);
2300 VisitPropertyLoad(obj, expr);
2301 builder()->StoreAccumulatorInRegister(destination);
2302 }
2303
VisitNamedSuperPropertyLoad(Property * property,Register opt_receiver_out)2304 void BytecodeGenerator::VisitNamedSuperPropertyLoad(Property* property,
2305 Register opt_receiver_out) {
2306 RegisterAllocationScope register_scope(this);
2307 SuperPropertyReference* super_property =
2308 property->obj()->AsSuperPropertyReference();
2309 RegisterList args = register_allocator()->NewRegisterList(3);
2310 VisitForRegisterValue(super_property->this_var(), args[0]);
2311 VisitForRegisterValue(super_property->home_object(), args[1]);
2312 builder()
2313 ->LoadLiteral(property->key()->AsLiteral()->AsPropertyName())
2314 .StoreAccumulatorInRegister(args[2])
2315 .CallRuntime(Runtime::kLoadFromSuper, args);
2316
2317 if (opt_receiver_out.is_valid()) {
2318 builder()->MoveRegister(args[0], opt_receiver_out);
2319 }
2320 }
2321
VisitKeyedSuperPropertyLoad(Property * property,Register opt_receiver_out)2322 void BytecodeGenerator::VisitKeyedSuperPropertyLoad(Property* property,
2323 Register opt_receiver_out) {
2324 RegisterAllocationScope register_scope(this);
2325 SuperPropertyReference* super_property =
2326 property->obj()->AsSuperPropertyReference();
2327 RegisterList args = register_allocator()->NewRegisterList(3);
2328 VisitForRegisterValue(super_property->this_var(), args[0]);
2329 VisitForRegisterValue(super_property->home_object(), args[1]);
2330 VisitForRegisterValue(property->key(), args[2]);
2331 builder()->CallRuntime(Runtime::kLoadKeyedFromSuper, args);
2332
2333 if (opt_receiver_out.is_valid()) {
2334 builder()->MoveRegister(args[0], opt_receiver_out);
2335 }
2336 }
2337
VisitProperty(Property * expr)2338 void BytecodeGenerator::VisitProperty(Property* expr) {
2339 LhsKind property_kind = Property::GetAssignType(expr);
2340 if (property_kind != NAMED_SUPER_PROPERTY &&
2341 property_kind != KEYED_SUPER_PROPERTY) {
2342 Register obj = VisitForRegisterValue(expr->obj());
2343 VisitPropertyLoad(obj, expr);
2344 } else {
2345 VisitPropertyLoad(Register::invalid_value(), expr);
2346 }
2347 }
2348
VisitArguments(ZoneList<Expression * > * args,RegisterList * arg_regs)2349 void BytecodeGenerator::VisitArguments(ZoneList<Expression*>* args,
2350 RegisterList* arg_regs) {
2351 // Visit arguments.
2352 for (int i = 0; i < static_cast<int>(args->length()); i++) {
2353 VisitAndPushIntoRegisterList(args->at(i), arg_regs);
2354 }
2355 }
2356
VisitCall(Call * expr)2357 void BytecodeGenerator::VisitCall(Call* expr) {
2358 Expression* callee_expr = expr->expression();
2359 Call::CallType call_type = expr->GetCallType();
2360
2361 if (call_type == Call::SUPER_CALL) {
2362 return VisitCallSuper(expr);
2363 }
2364
2365 Register callee = register_allocator()->NewRegister();
2366 // Grow the args list as we visit receiver / arguments to avoid allocating all
2367 // the registers up-front. Otherwise these registers are unavailable during
2368 // receiver / argument visiting and we can end up with memory leaks due to
2369 // registers keeping objects alive.
2370 RegisterList args = register_allocator()->NewGrowableRegisterList();
2371
2372 // Prepare the callee and the receiver to the function call. This depends on
2373 // the semantics of the underlying call type.
2374 switch (call_type) {
2375 case Call::NAMED_PROPERTY_CALL:
2376 case Call::KEYED_PROPERTY_CALL: {
2377 Property* property = callee_expr->AsProperty();
2378 VisitAndPushIntoRegisterList(property->obj(), &args);
2379 VisitPropertyLoadForRegister(args[0], property, callee);
2380 break;
2381 }
2382 case Call::GLOBAL_CALL: {
2383 // Receiver is undefined for global calls.
2384 BuildPushUndefinedIntoRegisterList(&args);
2385 // Load callee as a global variable.
2386 VariableProxy* proxy = callee_expr->AsVariableProxy();
2387 BuildVariableLoadForAccumulatorValue(proxy->var(),
2388 proxy->VariableFeedbackSlot(),
2389 proxy->hole_check_mode());
2390 builder()->StoreAccumulatorInRegister(callee);
2391 break;
2392 }
2393 case Call::WITH_CALL: {
2394 Register receiver = register_allocator()->GrowRegisterList(&args);
2395 DCHECK(callee_expr->AsVariableProxy()->var()->IsLookupSlot());
2396 {
2397 RegisterAllocationScope inner_register_scope(this);
2398 Register name = register_allocator()->NewRegister();
2399
2400 // Call %LoadLookupSlotForCall to get the callee and receiver.
2401 DCHECK(Register::AreContiguous(callee, receiver));
2402 RegisterList result_pair(callee.index(), 2);
2403 USE(receiver);
2404 Variable* variable = callee_expr->AsVariableProxy()->var();
2405 builder()
2406 ->LoadLiteral(variable->name())
2407 .StoreAccumulatorInRegister(name)
2408 .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, name,
2409 result_pair);
2410 }
2411 break;
2412 }
2413 case Call::OTHER_CALL: {
2414 BuildPushUndefinedIntoRegisterList(&args);
2415 VisitForRegisterValue(callee_expr, callee);
2416 break;
2417 }
2418 case Call::NAMED_SUPER_PROPERTY_CALL: {
2419 Register receiver = register_allocator()->GrowRegisterList(&args);
2420 Property* property = callee_expr->AsProperty();
2421 VisitNamedSuperPropertyLoad(property, receiver);
2422 builder()->StoreAccumulatorInRegister(callee);
2423 break;
2424 }
2425 case Call::KEYED_SUPER_PROPERTY_CALL: {
2426 Register receiver = register_allocator()->GrowRegisterList(&args);
2427 Property* property = callee_expr->AsProperty();
2428 VisitKeyedSuperPropertyLoad(property, receiver);
2429 builder()->StoreAccumulatorInRegister(callee);
2430 break;
2431 }
2432 case Call::SUPER_CALL:
2433 UNREACHABLE();
2434 break;
2435 }
2436
2437 // Evaluate all arguments to the function call and store in sequential args
2438 // registers.
2439 VisitArguments(expr->arguments(), &args);
2440 CHECK_EQ(expr->arguments()->length() + 1, args.register_count());
2441
2442 // Resolve callee for a potential direct eval call. This block will mutate the
2443 // callee value.
2444 if (expr->is_possibly_eval() && expr->arguments()->length() > 0) {
2445 RegisterAllocationScope inner_register_scope(this);
2446 // Set up arguments for ResolvePossiblyDirectEval by copying callee, source
2447 // strings and function closure, and loading language and
2448 // position.
2449 RegisterList runtime_call_args = register_allocator()->NewRegisterList(6);
2450 builder()
2451 ->MoveRegister(callee, runtime_call_args[0])
2452 .MoveRegister(args[1], runtime_call_args[1])
2453 .MoveRegister(Register::function_closure(), runtime_call_args[2])
2454 .LoadLiteral(Smi::FromInt(language_mode()))
2455 .StoreAccumulatorInRegister(runtime_call_args[3])
2456 .LoadLiteral(
2457 Smi::FromInt(execution_context()->scope()->start_position()))
2458 .StoreAccumulatorInRegister(runtime_call_args[4])
2459 .LoadLiteral(Smi::FromInt(expr->position()))
2460 .StoreAccumulatorInRegister(runtime_call_args[5]);
2461
2462 // Call ResolvePossiblyDirectEval and modify the callee.
2463 builder()
2464 ->CallRuntime(Runtime::kResolvePossiblyDirectEval, runtime_call_args)
2465 .StoreAccumulatorInRegister(callee);
2466 }
2467
2468 builder()->SetExpressionPosition(expr);
2469
2470 int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot());
2471 builder()->Call(callee, args, feedback_slot_index, call_type,
2472 expr->tail_call_mode());
2473 }
2474
VisitCallSuper(Call * expr)2475 void BytecodeGenerator::VisitCallSuper(Call* expr) {
2476 RegisterAllocationScope register_scope(this);
2477 SuperCallReference* super = expr->expression()->AsSuperCallReference();
2478
2479 // Prepare the constructor to the super call.
2480 Register this_function = VisitForRegisterValue(super->this_function_var());
2481 builder()->CallRuntime(Runtime::kInlineGetSuperConstructor, this_function);
2482
2483 Register constructor = this_function; // Re-use dead this_function register.
2484 builder()->StoreAccumulatorInRegister(constructor);
2485
2486 RegisterList args = register_allocator()->NewGrowableRegisterList();
2487 VisitArguments(expr->arguments(), &args);
2488
2489 // The new target is loaded into the accumulator from the
2490 // {new.target} variable.
2491 VisitForAccumulatorValue(super->new_target_var());
2492
2493 // Call construct.
2494 builder()->SetExpressionPosition(expr);
2495 // TODO(turbofan): For now we do gather feedback on super constructor
2496 // calls, utilizing the existing machinery to inline the actual call
2497 // target and the JSCreate for the implicit receiver allocation. This
2498 // is not an ideal solution for super constructor calls, but it gets
2499 // the job done for now. In the long run we might want to revisit this
2500 // and come up with a better way.
2501 int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot());
2502 builder()->New(constructor, args, feedback_slot_index);
2503 }
2504
VisitCallNew(CallNew * expr)2505 void BytecodeGenerator::VisitCallNew(CallNew* expr) {
2506 Register constructor = VisitForRegisterValue(expr->expression());
2507 RegisterList args = register_allocator()->NewGrowableRegisterList();
2508 VisitArguments(expr->arguments(), &args);
2509
2510 builder()->SetExpressionPosition(expr);
2511 // The accumulator holds new target which is the same as the
2512 // constructor for CallNew.
2513 builder()
2514 ->LoadAccumulatorWithRegister(constructor)
2515 .New(constructor, args, feedback_index(expr->CallNewFeedbackSlot()));
2516 }
2517
VisitCallRuntime(CallRuntime * expr)2518 void BytecodeGenerator::VisitCallRuntime(CallRuntime* expr) {
2519 if (expr->is_jsruntime()) {
2520 RegisterList args = register_allocator()->NewGrowableRegisterList();
2521 // Allocate a register for the receiver and load it with undefined.
2522 BuildPushUndefinedIntoRegisterList(&args);
2523 VisitArguments(expr->arguments(), &args);
2524 builder()->CallJSRuntime(expr->context_index(), args);
2525 } else {
2526 // Evaluate all arguments to the runtime call.
2527 RegisterList args = register_allocator()->NewGrowableRegisterList();
2528 VisitArguments(expr->arguments(), &args);
2529 Runtime::FunctionId function_id = expr->function()->function_id;
2530 builder()->CallRuntime(function_id, args);
2531 }
2532 }
2533
VisitVoid(UnaryOperation * expr)2534 void BytecodeGenerator::VisitVoid(UnaryOperation* expr) {
2535 VisitForEffect(expr->expression());
2536 builder()->LoadUndefined();
2537 }
2538
VisitTypeOf(UnaryOperation * expr)2539 void BytecodeGenerator::VisitTypeOf(UnaryOperation* expr) {
2540 if (expr->expression()->IsVariableProxy()) {
2541 // Typeof does not throw a reference error on global variables, hence we
2542 // perform a non-contextual load in case the operand is a variable proxy.
2543 VariableProxy* proxy = expr->expression()->AsVariableProxy();
2544 BuildVariableLoadForAccumulatorValue(
2545 proxy->var(), proxy->VariableFeedbackSlot(), proxy->hole_check_mode(),
2546 INSIDE_TYPEOF);
2547 } else {
2548 VisitForAccumulatorValue(expr->expression());
2549 }
2550 builder()->TypeOf();
2551 }
2552
VisitNot(UnaryOperation * expr)2553 void BytecodeGenerator::VisitNot(UnaryOperation* expr) {
2554 if (execution_result()->IsEffect()) {
2555 VisitForEffect(expr->expression());
2556 } else if (execution_result()->IsTest()) {
2557 TestResultScope* test_result = execution_result()->AsTest();
2558 // No actual logical negation happening, we just swap the control flow by
2559 // swapping the target labels and the fallthrough branch.
2560 VisitForTest(expr->expression(), test_result->else_labels(),
2561 test_result->then_labels(),
2562 test_result->inverted_fallthrough());
2563 test_result->SetResultConsumedByTest();
2564 } else {
2565 VisitForAccumulatorValue(expr->expression());
2566 builder()->LogicalNot();
2567 }
2568 }
2569
VisitUnaryOperation(UnaryOperation * expr)2570 void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
2571 switch (expr->op()) {
2572 case Token::Value::NOT:
2573 VisitNot(expr);
2574 break;
2575 case Token::Value::TYPEOF:
2576 VisitTypeOf(expr);
2577 break;
2578 case Token::Value::VOID:
2579 VisitVoid(expr);
2580 break;
2581 case Token::Value::DELETE:
2582 VisitDelete(expr);
2583 break;
2584 case Token::Value::BIT_NOT:
2585 case Token::Value::ADD:
2586 case Token::Value::SUB:
2587 // These operators are converted to an equivalent binary operators in
2588 // the parser. These operators are not expected to be visited here.
2589 UNREACHABLE();
2590 default:
2591 UNREACHABLE();
2592 }
2593 }
2594
VisitDelete(UnaryOperation * expr)2595 void BytecodeGenerator::VisitDelete(UnaryOperation* expr) {
2596 if (expr->expression()->IsProperty()) {
2597 // Delete of an object property is allowed both in sloppy
2598 // and strict modes.
2599 Property* property = expr->expression()->AsProperty();
2600 Register object = VisitForRegisterValue(property->obj());
2601 VisitForAccumulatorValue(property->key());
2602 builder()->Delete(object, language_mode());
2603 } else if (expr->expression()->IsVariableProxy()) {
2604 // Delete of an unqualified identifier is allowed in sloppy mode but is
2605 // not allowed in strict mode. Deleting 'this' is allowed in both modes.
2606 VariableProxy* proxy = expr->expression()->AsVariableProxy();
2607 Variable* variable = proxy->var();
2608 DCHECK(is_sloppy(language_mode()) || variable->is_this());
2609 switch (variable->location()) {
2610 case VariableLocation::UNALLOCATED: {
2611 // Global var, let, const or variables not explicitly declared.
2612 Register native_context = register_allocator()->NewRegister();
2613 Register global_object = register_allocator()->NewRegister();
2614 builder()
2615 ->LoadContextSlot(execution_context()->reg(),
2616 Context::NATIVE_CONTEXT_INDEX, 0)
2617 .StoreAccumulatorInRegister(native_context)
2618 .LoadContextSlot(native_context, Context::EXTENSION_INDEX, 0)
2619 .StoreAccumulatorInRegister(global_object)
2620 .LoadLiteral(variable->name())
2621 .Delete(global_object, language_mode());
2622 break;
2623 }
2624 case VariableLocation::PARAMETER:
2625 case VariableLocation::LOCAL:
2626 case VariableLocation::CONTEXT: {
2627 // Deleting local var/let/const, context variables, and arguments
2628 // does not have any effect.
2629 if (variable->is_this()) {
2630 builder()->LoadTrue();
2631 } else {
2632 builder()->LoadFalse();
2633 }
2634 break;
2635 }
2636 case VariableLocation::LOOKUP: {
2637 Register name_reg = register_allocator()->NewRegister();
2638 builder()
2639 ->LoadLiteral(variable->name())
2640 .StoreAccumulatorInRegister(name_reg)
2641 .CallRuntime(Runtime::kDeleteLookupSlot, name_reg);
2642 break;
2643 }
2644 default:
2645 UNREACHABLE();
2646 }
2647 } else {
2648 // Delete of an unresolvable reference returns true.
2649 VisitForEffect(expr->expression());
2650 builder()->LoadTrue();
2651 }
2652 }
2653
VisitCountOperation(CountOperation * expr)2654 void BytecodeGenerator::VisitCountOperation(CountOperation* expr) {
2655 DCHECK(expr->expression()->IsValidReferenceExpressionOrThis());
2656
2657 // Left-hand side can only be a property, a global or a variable slot.
2658 Property* property = expr->expression()->AsProperty();
2659 LhsKind assign_type = Property::GetAssignType(property);
2660
2661 bool is_postfix = expr->is_postfix() && !execution_result()->IsEffect();
2662
2663 // Evaluate LHS expression and get old value.
2664 Register object, key, old_value;
2665 RegisterList super_property_args;
2666 Handle<String> name;
2667 switch (assign_type) {
2668 case VARIABLE: {
2669 VariableProxy* proxy = expr->expression()->AsVariableProxy();
2670 BuildVariableLoadForAccumulatorValue(proxy->var(),
2671 proxy->VariableFeedbackSlot(),
2672 proxy->hole_check_mode());
2673 break;
2674 }
2675 case NAMED_PROPERTY: {
2676 FeedbackVectorSlot slot = property->PropertyFeedbackSlot();
2677 object = VisitForRegisterValue(property->obj());
2678 name = property->key()->AsLiteral()->AsPropertyName();
2679 builder()->LoadNamedProperty(object, name, feedback_index(slot));
2680 break;
2681 }
2682 case KEYED_PROPERTY: {
2683 FeedbackVectorSlot slot = property->PropertyFeedbackSlot();
2684 object = VisitForRegisterValue(property->obj());
2685 // Use visit for accumulator here since we need the key in the accumulator
2686 // for the LoadKeyedProperty.
2687 key = register_allocator()->NewRegister();
2688 VisitForAccumulatorValue(property->key());
2689 builder()->StoreAccumulatorInRegister(key).LoadKeyedProperty(
2690 object, feedback_index(slot));
2691 break;
2692 }
2693 case NAMED_SUPER_PROPERTY: {
2694 super_property_args = register_allocator()->NewRegisterList(4);
2695 RegisterList load_super_args = super_property_args.Truncate(3);
2696 SuperPropertyReference* super_property =
2697 property->obj()->AsSuperPropertyReference();
2698 VisitForRegisterValue(super_property->this_var(), load_super_args[0]);
2699 VisitForRegisterValue(super_property->home_object(), load_super_args[1]);
2700 builder()
2701 ->LoadLiteral(property->key()->AsLiteral()->AsPropertyName())
2702 .StoreAccumulatorInRegister(load_super_args[2])
2703 .CallRuntime(Runtime::kLoadFromSuper, load_super_args);
2704 break;
2705 }
2706 case KEYED_SUPER_PROPERTY: {
2707 super_property_args = register_allocator()->NewRegisterList(4);
2708 RegisterList load_super_args = super_property_args.Truncate(3);
2709 SuperPropertyReference* super_property =
2710 property->obj()->AsSuperPropertyReference();
2711 VisitForRegisterValue(super_property->this_var(), load_super_args[0]);
2712 VisitForRegisterValue(super_property->home_object(), load_super_args[1]);
2713 VisitForRegisterValue(property->key(), load_super_args[2]);
2714 builder()->CallRuntime(Runtime::kLoadKeyedFromSuper, load_super_args);
2715 break;
2716 }
2717 }
2718
2719 // Save result for postfix expressions.
2720 if (is_postfix) {
2721 // Convert old value into a number before saving it.
2722 old_value = register_allocator()->NewRegister();
2723 builder()
2724 ->ConvertAccumulatorToNumber(old_value)
2725 .LoadAccumulatorWithRegister(old_value);
2726 }
2727
2728 // Perform +1/-1 operation.
2729 FeedbackVectorSlot slot = expr->CountBinaryOpFeedbackSlot();
2730 builder()->CountOperation(expr->binary_op(), feedback_index(slot));
2731
2732 // Store the value.
2733 builder()->SetExpressionPosition(expr);
2734 FeedbackVectorSlot feedback_slot = expr->CountSlot();
2735 switch (assign_type) {
2736 case VARIABLE: {
2737 VariableProxy* proxy = expr->expression()->AsVariableProxy();
2738 BuildVariableAssignment(proxy->var(), expr->op(), feedback_slot,
2739 proxy->hole_check_mode());
2740 break;
2741 }
2742 case NAMED_PROPERTY: {
2743 builder()->StoreNamedProperty(object, name, feedback_index(feedback_slot),
2744 language_mode());
2745 break;
2746 }
2747 case KEYED_PROPERTY: {
2748 builder()->StoreKeyedProperty(object, key, feedback_index(feedback_slot),
2749 language_mode());
2750 break;
2751 }
2752 case NAMED_SUPER_PROPERTY: {
2753 builder()
2754 ->StoreAccumulatorInRegister(super_property_args[3])
2755 .CallRuntime(StoreToSuperRuntimeId(), super_property_args);
2756 break;
2757 }
2758 case KEYED_SUPER_PROPERTY: {
2759 builder()
2760 ->StoreAccumulatorInRegister(super_property_args[3])
2761 .CallRuntime(StoreKeyedToSuperRuntimeId(), super_property_args);
2762 break;
2763 }
2764 }
2765
2766 // Restore old value for postfix expressions.
2767 if (is_postfix) {
2768 builder()->LoadAccumulatorWithRegister(old_value);
2769 }
2770 }
2771
VisitBinaryOperation(BinaryOperation * binop)2772 void BytecodeGenerator::VisitBinaryOperation(BinaryOperation* binop) {
2773 switch (binop->op()) {
2774 case Token::COMMA:
2775 VisitCommaExpression(binop);
2776 break;
2777 case Token::OR:
2778 VisitLogicalOrExpression(binop);
2779 break;
2780 case Token::AND:
2781 VisitLogicalAndExpression(binop);
2782 break;
2783 default:
2784 VisitArithmeticExpression(binop);
2785 break;
2786 }
2787 }
2788
VisitCompareOperation(CompareOperation * expr)2789 void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) {
2790 Register lhs = VisitForRegisterValue(expr->left());
2791 VisitForAccumulatorValue(expr->right());
2792 builder()->SetExpressionPosition(expr);
2793 FeedbackVectorSlot slot = expr->CompareOperationFeedbackSlot();
2794 builder()->CompareOperation(expr->op(), lhs, feedback_index(slot));
2795 }
2796
VisitArithmeticExpression(BinaryOperation * expr)2797 void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) {
2798 // TODO(rmcilroy): Special case "x * 1.0" and "x * -1" which are generated for
2799 // +x and -x by the parser.
2800 Register lhs = VisitForRegisterValue(expr->left());
2801 VisitForAccumulatorValue(expr->right());
2802 FeedbackVectorSlot slot = expr->BinaryOperationFeedbackSlot();
2803 builder()->BinaryOperation(expr->op(), lhs, feedback_index(slot));
2804 }
2805
VisitSpread(Spread * expr)2806 void BytecodeGenerator::VisitSpread(Spread* expr) { UNREACHABLE(); }
2807
VisitEmptyParentheses(EmptyParentheses * expr)2808 void BytecodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) {
2809 UNREACHABLE();
2810 }
2811
VisitThisFunction(ThisFunction * expr)2812 void BytecodeGenerator::VisitThisFunction(ThisFunction* expr) {
2813 builder()->LoadAccumulatorWithRegister(Register::function_closure());
2814 }
2815
VisitSuperCallReference(SuperCallReference * expr)2816 void BytecodeGenerator::VisitSuperCallReference(SuperCallReference* expr) {
2817 // Handled by VisitCall().
2818 UNREACHABLE();
2819 }
2820
VisitSuperPropertyReference(SuperPropertyReference * expr)2821 void BytecodeGenerator::VisitSuperPropertyReference(
2822 SuperPropertyReference* expr) {
2823 builder()->CallRuntime(Runtime::kThrowUnsupportedSuperError);
2824 }
2825
VisitCommaExpression(BinaryOperation * binop)2826 void BytecodeGenerator::VisitCommaExpression(BinaryOperation* binop) {
2827 VisitForEffect(binop->left());
2828 Visit(binop->right());
2829 }
2830
VisitLogicalOrExpression(BinaryOperation * binop)2831 void BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) {
2832 Expression* left = binop->left();
2833 Expression* right = binop->right();
2834
2835 if (execution_result()->IsTest()) {
2836 TestResultScope* test_result = execution_result()->AsTest();
2837
2838 if (left->ToBooleanIsTrue()) {
2839 builder()->Jump(test_result->NewThenLabel());
2840 } else if (left->ToBooleanIsFalse() && right->ToBooleanIsFalse()) {
2841 builder()->Jump(test_result->NewElseLabel());
2842 } else {
2843 BytecodeLabels test_right(zone());
2844 VisitForTest(left, test_result->then_labels(), &test_right,
2845 TestFallthrough::kElse);
2846 test_right.Bind(builder());
2847 VisitForTest(right, test_result->then_labels(),
2848 test_result->else_labels(), test_result->fallthrough());
2849 }
2850 test_result->SetResultConsumedByTest();
2851 } else {
2852 if (left->ToBooleanIsTrue()) {
2853 VisitForAccumulatorValue(left);
2854 } else if (left->ToBooleanIsFalse()) {
2855 VisitForAccumulatorValue(right);
2856 } else {
2857 BytecodeLabel end_label;
2858 VisitForAccumulatorValue(left);
2859 builder()->JumpIfTrue(&end_label);
2860 VisitForAccumulatorValue(right);
2861 builder()->Bind(&end_label);
2862 }
2863 }
2864 }
2865
VisitLogicalAndExpression(BinaryOperation * binop)2866 void BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) {
2867 Expression* left = binop->left();
2868 Expression* right = binop->right();
2869
2870 if (execution_result()->IsTest()) {
2871 TestResultScope* test_result = execution_result()->AsTest();
2872
2873 if (left->ToBooleanIsFalse()) {
2874 builder()->Jump(test_result->NewElseLabel());
2875 } else if (left->ToBooleanIsTrue() && right->ToBooleanIsTrue()) {
2876 builder()->Jump(test_result->NewThenLabel());
2877 } else {
2878 BytecodeLabels test_right(zone());
2879 VisitForTest(left, &test_right, test_result->else_labels(),
2880 TestFallthrough::kThen);
2881 test_right.Bind(builder());
2882 VisitForTest(right, test_result->then_labels(),
2883 test_result->else_labels(), test_result->fallthrough());
2884 }
2885 test_result->SetResultConsumedByTest();
2886 } else {
2887 if (left->ToBooleanIsFalse()) {
2888 VisitForAccumulatorValue(left);
2889 } else if (left->ToBooleanIsTrue()) {
2890 VisitForAccumulatorValue(right);
2891 } else {
2892 BytecodeLabel end_label;
2893 VisitForAccumulatorValue(left);
2894 builder()->JumpIfFalse(&end_label);
2895 VisitForAccumulatorValue(right);
2896 builder()->Bind(&end_label);
2897 }
2898 }
2899 }
2900
VisitRewritableExpression(RewritableExpression * expr)2901 void BytecodeGenerator::VisitRewritableExpression(RewritableExpression* expr) {
2902 Visit(expr->expression());
2903 }
2904
BuildNewLocalActivationContext()2905 void BytecodeGenerator::BuildNewLocalActivationContext() {
2906 ValueResultScope value_execution_result(this);
2907 Scope* scope = this->scope();
2908
2909 // Create the appropriate context.
2910 if (scope->is_script_scope()) {
2911 RegisterList args = register_allocator()->NewRegisterList(2);
2912 builder()
2913 ->LoadAccumulatorWithRegister(Register::function_closure())
2914 .StoreAccumulatorInRegister(args[0])
2915 .LoadLiteral(scope->scope_info())
2916 .StoreAccumulatorInRegister(args[1])
2917 .CallRuntime(Runtime::kNewScriptContext, args);
2918 } else if (scope->is_module_scope()) {
2919 // We don't need to do anything for the outer script scope.
2920 DCHECK(scope->outer_scope()->is_script_scope());
2921
2922 // A JSFunction representing a module is called with the module object as
2923 // its sole argument, which we pass on to PushModuleContext.
2924 RegisterList args = register_allocator()->NewRegisterList(3);
2925 builder()
2926 ->MoveRegister(builder()->Parameter(1), args[0])
2927 .LoadAccumulatorWithRegister(Register::function_closure())
2928 .StoreAccumulatorInRegister(args[1])
2929 .LoadLiteral(scope->scope_info())
2930 .StoreAccumulatorInRegister(args[2])
2931 .CallRuntime(Runtime::kPushModuleContext, args);
2932 } else {
2933 int slot_count = scope->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
2934 if (slot_count <= FastNewFunctionContextStub::kMaximumSlots) {
2935 builder()->CreateFunctionContext(slot_count);
2936 } else {
2937 builder()->CallRuntime(Runtime::kNewFunctionContext,
2938 Register::function_closure());
2939 }
2940 }
2941 }
2942
BuildLocalActivationContextInitialization()2943 void BytecodeGenerator::BuildLocalActivationContextInitialization() {
2944 DeclarationScope* scope = this->scope();
2945
2946 if (scope->has_this_declaration() && scope->receiver()->IsContextSlot()) {
2947 Variable* variable = scope->receiver();
2948 Register receiver(builder()->Parameter(0));
2949 // Context variable (at bottom of the context chain).
2950 DCHECK_EQ(0, scope->ContextChainLength(variable->scope()));
2951 builder()->LoadAccumulatorWithRegister(receiver).StoreContextSlot(
2952 execution_context()->reg(), variable->index(), 0);
2953 }
2954
2955 // Copy parameters into context if necessary.
2956 int num_parameters = scope->num_parameters();
2957 for (int i = 0; i < num_parameters; i++) {
2958 Variable* variable = scope->parameter(i);
2959 if (!variable->IsContextSlot()) continue;
2960
2961 // The parameter indices are shifted by 1 (receiver is variable
2962 // index -1 but is parameter index 0 in BytecodeArrayBuilder).
2963 Register parameter(builder()->Parameter(i + 1));
2964 // Context variable (at bottom of the context chain).
2965 DCHECK_EQ(0, scope->ContextChainLength(variable->scope()));
2966 builder()->LoadAccumulatorWithRegister(parameter).StoreContextSlot(
2967 execution_context()->reg(), variable->index(), 0);
2968 }
2969 }
2970
BuildNewLocalBlockContext(Scope * scope)2971 void BytecodeGenerator::BuildNewLocalBlockContext(Scope* scope) {
2972 ValueResultScope value_execution_result(this);
2973 DCHECK(scope->is_block_scope());
2974
2975 VisitFunctionClosureForContext();
2976 builder()->CreateBlockContext(scope->scope_info());
2977 }
2978
BuildNewLocalWithContext(Scope * scope)2979 void BytecodeGenerator::BuildNewLocalWithContext(Scope* scope) {
2980 ValueResultScope value_execution_result(this);
2981
2982 Register extension_object = register_allocator()->NewRegister();
2983
2984 builder()->ConvertAccumulatorToObject(extension_object);
2985 VisitFunctionClosureForContext();
2986 builder()->CreateWithContext(extension_object, scope->scope_info());
2987 }
2988
BuildNewLocalCatchContext(Variable * variable,Scope * scope)2989 void BytecodeGenerator::BuildNewLocalCatchContext(Variable* variable,
2990 Scope* scope) {
2991 ValueResultScope value_execution_result(this);
2992 DCHECK(variable->IsContextSlot());
2993
2994 Register exception = register_allocator()->NewRegister();
2995 builder()->StoreAccumulatorInRegister(exception);
2996 VisitFunctionClosureForContext();
2997 builder()->CreateCatchContext(exception, variable->name(),
2998 scope->scope_info());
2999 }
3000
VisitObjectLiteralAccessor(Register home_object,ObjectLiteralProperty * property,Register value_out)3001 void BytecodeGenerator::VisitObjectLiteralAccessor(
3002 Register home_object, ObjectLiteralProperty* property, Register value_out) {
3003 if (property == nullptr) {
3004 builder()->LoadNull().StoreAccumulatorInRegister(value_out);
3005 } else {
3006 VisitForRegisterValue(property->value(), value_out);
3007 VisitSetHomeObject(value_out, home_object, property);
3008 }
3009 }
3010
VisitSetHomeObject(Register value,Register home_object,LiteralProperty * property,int slot_number)3011 void BytecodeGenerator::VisitSetHomeObject(Register value, Register home_object,
3012 LiteralProperty* property,
3013 int slot_number) {
3014 Expression* expr = property->value();
3015 if (FunctionLiteral::NeedsHomeObject(expr)) {
3016 FeedbackVectorSlot slot = property->GetSlot(slot_number);
3017 builder()
3018 ->LoadAccumulatorWithRegister(home_object)
3019 .StoreNamedProperty(value, home_object_symbol(), feedback_index(slot),
3020 language_mode());
3021 }
3022 }
3023
VisitArgumentsObject(Variable * variable)3024 void BytecodeGenerator::VisitArgumentsObject(Variable* variable) {
3025 if (variable == nullptr) return;
3026
3027 DCHECK(variable->IsContextSlot() || variable->IsStackAllocated());
3028
3029 // Allocate and initialize a new arguments object and assign to the
3030 // {arguments} variable.
3031 CreateArgumentsType type =
3032 is_strict(language_mode()) || !info()->has_simple_parameters()
3033 ? CreateArgumentsType::kUnmappedArguments
3034 : CreateArgumentsType::kMappedArguments;
3035 builder()->CreateArguments(type);
3036 BuildVariableAssignment(variable, Token::ASSIGN,
3037 FeedbackVectorSlot::Invalid(),
3038 HoleCheckMode::kElided);
3039 }
3040
VisitRestArgumentsArray(Variable * rest)3041 void BytecodeGenerator::VisitRestArgumentsArray(Variable* rest) {
3042 if (rest == nullptr) return;
3043
3044 // Allocate and initialize a new rest parameter and assign to the {rest}
3045 // variable.
3046 builder()->CreateArguments(CreateArgumentsType::kRestParameter);
3047 DCHECK(rest->IsContextSlot() || rest->IsStackAllocated());
3048 BuildVariableAssignment(rest, Token::ASSIGN, FeedbackVectorSlot::Invalid(),
3049 HoleCheckMode::kElided);
3050 }
3051
VisitThisFunctionVariable(Variable * variable)3052 void BytecodeGenerator::VisitThisFunctionVariable(Variable* variable) {
3053 if (variable == nullptr) return;
3054
3055 // Store the closure we were called with in the given variable.
3056 builder()->LoadAccumulatorWithRegister(Register::function_closure());
3057 BuildVariableAssignment(variable, Token::INIT, FeedbackVectorSlot::Invalid(),
3058 HoleCheckMode::kElided);
3059 }
3060
VisitNewTargetVariable(Variable * variable)3061 void BytecodeGenerator::VisitNewTargetVariable(Variable* variable) {
3062 if (variable == nullptr) return;
3063
3064 // Store the new target we were called with in the given variable.
3065 builder()->LoadAccumulatorWithRegister(Register::new_target());
3066 BuildVariableAssignment(variable, Token::INIT, FeedbackVectorSlot::Invalid(),
3067 HoleCheckMode::kElided);
3068
3069 // TODO(mstarzinger): The <new.target> register is not set by the deoptimizer
3070 // and we need to make sure {BytecodeRegisterOptimizer} flushes its state
3071 // before a local variable containing the <new.target> is used. Using a label
3072 // as below flushes the entire pipeline, we should be more specific here.
3073 BytecodeLabel flush_state_label;
3074 builder()->Bind(&flush_state_label);
3075 }
3076
VisitFunctionClosureForContext()3077 void BytecodeGenerator::VisitFunctionClosureForContext() {
3078 ValueResultScope value_execution_result(this);
3079 DeclarationScope* closure_scope =
3080 execution_context()->scope()->GetClosureScope();
3081 if (closure_scope->is_script_scope()) {
3082 // Contexts nested in the native context have a canonical empty function as
3083 // their closure, not the anonymous closure containing the global code.
3084 Register native_context = register_allocator()->NewRegister();
3085 builder()
3086 ->LoadContextSlot(execution_context()->reg(),
3087 Context::NATIVE_CONTEXT_INDEX, 0)
3088 .StoreAccumulatorInRegister(native_context)
3089 .LoadContextSlot(native_context, Context::CLOSURE_INDEX, 0);
3090 } else if (closure_scope->is_eval_scope()) {
3091 // Contexts created by a call to eval have the same closure as the
3092 // context calling eval, not the anonymous closure containing the eval
3093 // code. Fetch it from the context.
3094 builder()->LoadContextSlot(execution_context()->reg(),
3095 Context::CLOSURE_INDEX, 0);
3096 } else {
3097 DCHECK(closure_scope->is_function_scope() ||
3098 closure_scope->is_module_scope());
3099 builder()->LoadAccumulatorWithRegister(Register::function_closure());
3100 }
3101 }
3102
3103 // Visits the expression |expr| and places the result in the accumulator.
VisitForAccumulatorValue(Expression * expr)3104 void BytecodeGenerator::VisitForAccumulatorValue(Expression* expr) {
3105 ValueResultScope accumulator_scope(this);
3106 Visit(expr);
3107 }
3108
VisitForAccumulatorValueOrTheHole(Expression * expr)3109 void BytecodeGenerator::VisitForAccumulatorValueOrTheHole(Expression* expr) {
3110 if (expr == nullptr) {
3111 builder()->LoadTheHole();
3112 } else {
3113 VisitForAccumulatorValue(expr);
3114 }
3115 }
3116
3117 // Visits the expression |expr| and discards the result.
VisitForEffect(Expression * expr)3118 void BytecodeGenerator::VisitForEffect(Expression* expr) {
3119 EffectResultScope effect_scope(this);
3120 Visit(expr);
3121 }
3122
3123 // Visits the expression |expr| and returns the register containing
3124 // the expression result.
VisitForRegisterValue(Expression * expr)3125 Register BytecodeGenerator::VisitForRegisterValue(Expression* expr) {
3126 VisitForAccumulatorValue(expr);
3127 Register result = register_allocator()->NewRegister();
3128 builder()->StoreAccumulatorInRegister(result);
3129 return result;
3130 }
3131
3132 // Visits the expression |expr| and stores the expression result in
3133 // |destination|.
VisitForRegisterValue(Expression * expr,Register destination)3134 void BytecodeGenerator::VisitForRegisterValue(Expression* expr,
3135 Register destination) {
3136 ValueResultScope register_scope(this);
3137 Visit(expr);
3138 builder()->StoreAccumulatorInRegister(destination);
3139 }
3140
3141 // Visits the expression |expr| and pushes the result into a new register
3142 // added to the end of |reg_list|.
VisitAndPushIntoRegisterList(Expression * expr,RegisterList * reg_list)3143 void BytecodeGenerator::VisitAndPushIntoRegisterList(Expression* expr,
3144 RegisterList* reg_list) {
3145 {
3146 ValueResultScope register_scope(this);
3147 Visit(expr);
3148 }
3149 // Grow the register list after visiting the expression to avoid reserving
3150 // the register across the expression evaluation, which could cause memory
3151 // leaks for deep expressions due to dead objects being kept alive by pointers
3152 // in registers.
3153 Register destination = register_allocator()->GrowRegisterList(reg_list);
3154 builder()->StoreAccumulatorInRegister(destination);
3155 }
3156
BuildPushUndefinedIntoRegisterList(RegisterList * reg_list)3157 void BytecodeGenerator::BuildPushUndefinedIntoRegisterList(
3158 RegisterList* reg_list) {
3159 Register reg = register_allocator()->GrowRegisterList(reg_list);
3160 builder()->LoadUndefined().StoreAccumulatorInRegister(reg);
3161 }
3162
3163 // Visits the expression |expr| for testing its boolean value and jumping to the
3164 // |then| or |other| label depending on value and short-circuit semantics
VisitForTest(Expression * expr,BytecodeLabels * then_labels,BytecodeLabels * else_labels,TestFallthrough fallthrough)3165 void BytecodeGenerator::VisitForTest(Expression* expr,
3166 BytecodeLabels* then_labels,
3167 BytecodeLabels* else_labels,
3168 TestFallthrough fallthrough) {
3169 bool result_consumed;
3170 {
3171 // To make sure that all temporary registers are returned before generating
3172 // jumps below, we ensure that the result scope is deleted before doing so.
3173 // Dead registers might be materialized otherwise.
3174 TestResultScope test_result(this, then_labels, else_labels, fallthrough);
3175 Visit(expr);
3176 result_consumed = test_result.ResultConsumedByTest();
3177 }
3178 if (!result_consumed) {
3179 switch (fallthrough) {
3180 case TestFallthrough::kThen:
3181 builder()->JumpIfFalse(else_labels->New());
3182 break;
3183 case TestFallthrough::kElse:
3184 builder()->JumpIfTrue(then_labels->New());
3185 break;
3186 case TestFallthrough::kNone:
3187 builder()->JumpIfTrue(then_labels->New());
3188 builder()->Jump(else_labels->New());
3189 }
3190 }
3191 }
3192
VisitInScope(Statement * stmt,Scope * scope)3193 void BytecodeGenerator::VisitInScope(Statement* stmt, Scope* scope) {
3194 ContextScope context_scope(this, scope);
3195 DCHECK(scope->declarations()->is_empty());
3196 Visit(stmt);
3197 }
3198
language_mode() const3199 LanguageMode BytecodeGenerator::language_mode() const {
3200 return execution_context()->scope()->language_mode();
3201 }
3202
feedback_index(FeedbackVectorSlot slot) const3203 int BytecodeGenerator::feedback_index(FeedbackVectorSlot slot) const {
3204 return TypeFeedbackVector::GetIndex(slot);
3205 }
3206
StoreToSuperRuntimeId()3207 Runtime::FunctionId BytecodeGenerator::StoreToSuperRuntimeId() {
3208 return is_strict(language_mode()) ? Runtime::kStoreToSuper_Strict
3209 : Runtime::kStoreToSuper_Sloppy;
3210 }
3211
StoreKeyedToSuperRuntimeId()3212 Runtime::FunctionId BytecodeGenerator::StoreKeyedToSuperRuntimeId() {
3213 return is_strict(language_mode()) ? Runtime::kStoreKeyedToSuper_Strict
3214 : Runtime::kStoreKeyedToSuper_Sloppy;
3215 }
3216
3217 } // namespace interpreter
3218 } // namespace internal
3219 } // namespace v8
3220