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(¬_resuming);
825 BuildIndexedJump(generator_state_, first_yield,
826 stmt->yield_count(), generator_resume_points_);
827 builder()->Bind(¬_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(®ular_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(®ular_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