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