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