Line data Source code
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/api-inl.h"
8 : #include "src/ast/ast-source-ranges.h"
9 : #include "src/ast/scopes.h"
10 : #include "src/builtins/builtins-constructor.h"
11 : #include "src/compiler.h"
12 : #include "src/interpreter/bytecode-flags.h"
13 : #include "src/interpreter/bytecode-jump-table.h"
14 : #include "src/interpreter/bytecode-label.h"
15 : #include "src/interpreter/bytecode-register-allocator.h"
16 : #include "src/interpreter/control-flow-builders.h"
17 : #include "src/objects-inl.h"
18 : #include "src/objects/debug-objects.h"
19 : #include "src/objects/literal-objects-inl.h"
20 : #include "src/objects/smi.h"
21 : #include "src/parsing/parse-info.h"
22 : #include "src/parsing/token.h"
23 : #include "src/unoptimized-compilation-info.h"
24 :
25 : namespace v8 {
26 : namespace internal {
27 : namespace interpreter {
28 :
29 : // Scoped class tracking context objects created by the visitor. Represents
30 : // mutations of the context chain within the function body, allowing pushing and
31 : // popping of the current {context_register} during visitation.
32 : class BytecodeGenerator::ContextScope {
33 : public:
34 2406655 : ContextScope(BytecodeGenerator* generator, Scope* scope)
35 : : generator_(generator),
36 : scope_(scope),
37 2406655 : outer_(generator_->execution_context()),
38 : register_(Register::current_context()),
39 4813310 : depth_(0) {
40 : DCHECK(scope->NeedsContext() || outer_ == nullptr);
41 2406654 : if (outer_) {
42 319576 : depth_ = outer_->depth_ + 1;
43 :
44 : // Push the outer context into a new context register.
45 : Register outer_context_reg =
46 319576 : generator_->register_allocator()->NewRegister();
47 319582 : outer_->set_register(outer_context_reg);
48 319582 : generator_->builder()->PushContext(outer_context_reg);
49 : }
50 2406658 : generator_->set_execution_context(this);
51 2406658 : }
52 :
53 2406477 : ~ContextScope() {
54 2406477 : if (outer_) {
55 : DCHECK_EQ(register_.index(), Register::current_context().index());
56 319574 : generator_->builder()->PopContext(outer_->reg());
57 319588 : outer_->set_register(register_);
58 : }
59 2406491 : generator_->set_execution_context(outer_);
60 2406491 : }
61 :
62 : // Returns the depth of the given |scope| for the current execution context.
63 : int ContextChainDepth(Scope* scope) {
64 2699207 : return scope_->ContextChainLength(scope);
65 : }
66 :
67 : // Returns the execution context at |depth| in the current context chain if it
68 : // is a function local execution context, otherwise returns nullptr.
69 : ContextScope* Previous(int depth) {
70 2659653 : if (depth > depth_) {
71 : return nullptr;
72 : }
73 :
74 : ContextScope* previous = this;
75 22522 : for (int i = depth; i > 0; --i) {
76 22522 : previous = previous->outer_;
77 : }
78 : return previous;
79 : }
80 :
81 : Register reg() const { return register_; }
82 :
83 : private:
84 : const BytecodeArrayBuilder* builder() const { return generator_->builder(); }
85 :
86 639170 : void set_register(Register reg) { register_ = reg; }
87 :
88 : BytecodeGenerator* generator_;
89 : Scope* scope_;
90 : ContextScope* outer_;
91 : Register register_;
92 : int depth_;
93 : };
94 :
95 : // Scoped class for tracking control statements entered by the
96 : // visitor. The pattern derives AstGraphBuilder::ControlScope.
97 : class BytecodeGenerator::ControlScope {
98 : public:
99 15198894 : explicit ControlScope(BytecodeGenerator* generator)
100 : : generator_(generator),
101 : outer_(generator->execution_control()),
102 22798341 : context_(generator->execution_context()) {
103 : generator_->set_execution_control(this);
104 : }
105 7599312 : virtual ~ControlScope() { generator_->set_execution_control(outer()); }
106 :
107 : void Break(Statement* stmt) {
108 47165 : PerformCommand(CMD_BREAK, stmt, kNoSourcePosition);
109 : }
110 : void Continue(Statement* stmt) {
111 3541 : PerformCommand(CMD_CONTINUE, stmt, kNoSourcePosition);
112 : }
113 : void ReturnAccumulator(int source_position = kNoSourcePosition) {
114 2053930 : PerformCommand(CMD_RETURN, nullptr, source_position);
115 : }
116 : void AsyncReturnAccumulator(int source_position = kNoSourcePosition) {
117 8273 : PerformCommand(CMD_ASYNC_RETURN, nullptr, source_position);
118 : }
119 :
120 : class DeferredCommands;
121 :
122 : protected:
123 : enum Command {
124 : CMD_BREAK,
125 : CMD_CONTINUE,
126 : CMD_RETURN,
127 : CMD_ASYNC_RETURN,
128 : CMD_RETHROW
129 : };
130 : static constexpr bool CommandUsesAccumulator(Command command) {
131 : return command != CMD_BREAK && command != CMD_CONTINUE;
132 : }
133 :
134 : void PerformCommand(Command command, Statement* statement,
135 : int source_position);
136 : virtual bool Execute(Command command, Statement* statement,
137 : int source_position) = 0;
138 :
139 : // Helper to pop the context chain to a depth expected by this control scope.
140 : // Note that it is the responsibility of each individual {Execute} method to
141 : // trigger this when commands are handled and control-flow continues locally.
142 : void PopContextToExpectedDepth();
143 :
144 : BytecodeGenerator* generator() const { return generator_; }
145 : ControlScope* outer() const { return outer_; }
146 : ContextScope* context() const { return context_; }
147 :
148 : private:
149 : BytecodeGenerator* generator_;
150 : ControlScope* outer_;
151 : ContextScope* context_;
152 :
153 : DISALLOW_COPY_AND_ASSIGN(ControlScope);
154 : };
155 :
156 : // Helper class for a try-finally control scope. It can record intercepted
157 : // control-flow commands that cause entry into a finally-block, and re-apply
158 : // them after again leaving that block. Special tokens are used to identify
159 : // paths going through the finally-block to dispatch after leaving the block.
160 : class BytecodeGenerator::ControlScope::DeferredCommands final {
161 : public:
162 : // Fixed value tokens for paths we know we need.
163 : // Fallthrough is set to -1 to make it the fallthrough case of the jump table,
164 : // where the remaining cases start at 0.
165 : static const int kFallthroughToken = -1;
166 : // TODO(leszeks): Rethrow being 0 makes it use up a valuable LdaZero, which
167 : // means that other commands (such as break or return) have to use LdaSmi.
168 : // This can very slightly bloat bytecode, so perhaps token values should all
169 : // be shifted down by 1.
170 : static const int kRethrowToken = 0;
171 :
172 83196 : DeferredCommands(BytecodeGenerator* generator, Register token_register,
173 : Register result_register)
174 : : generator_(generator),
175 : deferred_(generator->zone()),
176 : token_register_(token_register),
177 : result_register_(result_register),
178 : return_token_(-1),
179 83196 : async_return_token_(-1) {
180 : // There's always a rethrow path.
181 : // TODO(leszeks): We could decouple deferred_ index and token to allow us
182 : // to still push this lazily.
183 : STATIC_ASSERT(kRethrowToken == 0);
184 83197 : deferred_.push_back({CMD_RETHROW, nullptr, kRethrowToken});
185 41599 : }
186 :
187 : // One recorded control-flow command.
188 : struct Entry {
189 : Command command; // The command type being applied on this path.
190 : Statement* statement; // The target statement for the command or {nullptr}.
191 : int token; // A token identifying this particular path.
192 : };
193 :
194 : // Records a control-flow command while entering the finally-block. This also
195 : // generates a new dispatch token that identifies one particular path. This
196 : // expects the result to be in the accumulator.
197 209681 : void RecordCommand(Command command, Statement* statement) {
198 52421 : int token = GetTokenForCommand(command, statement);
199 :
200 : DCHECK_LT(token, deferred_.size());
201 : DCHECK_EQ(deferred_[token].command, command);
202 : DCHECK_EQ(deferred_[token].statement, statement);
203 : DCHECK_EQ(deferred_[token].token, token);
204 :
205 52417 : if (CommandUsesAccumulator(command)) {
206 52166 : builder()->StoreAccumulatorInRegister(result_register_);
207 : }
208 52419 : builder()->LoadLiteral(Smi::FromInt(token));
209 52422 : builder()->StoreAccumulatorInRegister(token_register_);
210 52422 : if (!CommandUsesAccumulator(command)) {
211 : // If we're not saving the accumulator in the result register, shove a
212 : // harmless value there instead so that it is still considered "killed" in
213 : // the liveness analysis. Normally we would LdaUndefined first, but the
214 : // Smi token value is just as good, and by reusing it we save a bytecode.
215 253 : builder()->StoreAccumulatorInRegister(result_register_);
216 : }
217 52422 : }
218 :
219 : // Records the dispatch token to be used to identify the re-throw path when
220 : // the finally-block has been entered through the exception handler. This
221 : // expects the exception to be in the accumulator.
222 : void RecordHandlerReThrowPath() {
223 : // The accumulator contains the exception object.
224 41605 : RecordCommand(CMD_RETHROW, nullptr);
225 : }
226 :
227 : // Records the dispatch token to be used to identify the implicit fall-through
228 : // path at the end of a try-block into the corresponding finally-block.
229 124808 : void RecordFallThroughPath() {
230 41599 : builder()->LoadLiteral(Smi::FromInt(kFallthroughToken));
231 41605 : builder()->StoreAccumulatorInRegister(token_register_);
232 : // Since we're not saving the accumulator in the result register, shove a
233 : // harmless value there instead so that it is still considered "killed" in
234 : // the liveness analysis. Normally we would LdaUndefined first, but the Smi
235 : // token value is just as good, and by reusing it we save a bytecode.
236 41604 : builder()->StoreAccumulatorInRegister(result_register_);
237 41605 : }
238 :
239 : // Applies all recorded control-flow commands after the finally-block again.
240 : // This generates a dynamic dispatch on the token from the entry point.
241 222841 : void ApplyDeferredCommands() {
242 83192 : if (deferred_.size() == 0) return;
243 :
244 : BytecodeLabel fall_through;
245 :
246 41596 : if (deferred_.size() == 1) {
247 : // For a single entry, just jump to the fallthrough if we don't match the
248 : // entry token.
249 : const Entry& entry = deferred_[0];
250 :
251 : builder()
252 78448 : ->LoadLiteral(Smi::FromInt(entry.token))
253 39233 : .CompareReference(token_register_)
254 39233 : .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &fall_through);
255 :
256 39233 : if (CommandUsesAccumulator(entry.command)) {
257 39233 : builder()->LoadAccumulatorWithRegister(result_register_);
258 : }
259 : execution_control()->PerformCommand(entry.command, entry.statement,
260 78466 : kNoSourcePosition);
261 : } else {
262 : // For multiple entries, build a jump table and switch on the token,
263 : // jumping to the fallthrough if none of them match.
264 :
265 : BytecodeJumpTable* jump_table =
266 4744 : builder()->AllocateJumpTable(static_cast<int>(deferred_.size()), 0);
267 : builder()
268 2372 : ->LoadAccumulatorWithRegister(token_register_)
269 2372 : .SwitchOnSmiNoFeedback(jump_table)
270 2372 : .Jump(&fall_through);
271 10564 : for (const Entry& entry : deferred_) {
272 11640 : builder()->Bind(jump_table, entry.token);
273 :
274 5820 : if (CommandUsesAccumulator(entry.command)) {
275 5567 : builder()->LoadAccumulatorWithRegister(result_register_);
276 : }
277 : execution_control()->PerformCommand(entry.command, entry.statement,
278 11640 : kNoSourcePosition);
279 : }
280 : }
281 :
282 41604 : builder()->Bind(&fall_through);
283 : }
284 :
285 : BytecodeArrayBuilder* builder() { return generator_->builder(); }
286 45053 : ControlScope* execution_control() { return generator_->execution_control(); }
287 :
288 : private:
289 52414 : int GetTokenForCommand(Command command, Statement* statement) {
290 52414 : switch (command) {
291 : case CMD_RETURN:
292 2045 : return GetReturnToken();
293 : case CMD_ASYNC_RETURN:
294 2516 : return GetAsyncReturnToken();
295 : case CMD_RETHROW:
296 : return kRethrowToken;
297 : default:
298 : // TODO(leszeks): We could also search for entries with the same
299 : // command and statement.
300 253 : return GetNewTokenForCommand(command, statement);
301 : }
302 : }
303 :
304 2045 : int GetReturnToken() {
305 2045 : if (return_token_ == -1) {
306 1896 : return_token_ = GetNewTokenForCommand(CMD_RETURN, nullptr);
307 : }
308 2045 : return return_token_;
309 : }
310 :
311 2516 : int GetAsyncReturnToken() {
312 2516 : if (async_return_token_ == -1) {
313 1299 : async_return_token_ = GetNewTokenForCommand(CMD_ASYNC_RETURN, nullptr);
314 : }
315 2516 : return async_return_token_;
316 : }
317 :
318 : int GetNewTokenForCommand(Command command, Statement* statement) {
319 6896 : int token = static_cast<int>(deferred_.size());
320 6896 : deferred_.push_back({command, statement, token});
321 : return token;
322 : }
323 :
324 : BytecodeGenerator* generator_;
325 : ZoneVector<Entry> deferred_;
326 : Register token_register_;
327 : Register result_register_;
328 :
329 : // Tokens for commands that don't need a statement.
330 : int return_token_;
331 : int async_return_token_;
332 : };
333 :
334 : // Scoped class for dealing with control flow reaching the function level.
335 2087013 : class BytecodeGenerator::ControlScopeForTopLevel final
336 : : public BytecodeGenerator::ControlScope {
337 : public:
338 : explicit ControlScopeForTopLevel(BytecodeGenerator* generator)
339 2087089 : : ControlScope(generator) {}
340 :
341 : protected:
342 2094657 : bool Execute(Command command, Statement* statement,
343 : int source_position) override {
344 2094657 : switch (command) {
345 : case CMD_BREAK: // We should never see break/continue in top-level.
346 : case CMD_CONTINUE:
347 0 : UNREACHABLE();
348 : case CMD_RETURN:
349 : // No need to pop contexts, execution leaves the method body.
350 2094733 : generator()->BuildReturn(source_position);
351 2053748 : return true;
352 : case CMD_ASYNC_RETURN:
353 : // No need to pop contexts, execution leaves the method body.
354 7057 : generator()->BuildAsyncReturn(source_position);
355 7057 : return true;
356 : case CMD_RETHROW:
357 : // No need to pop contexts, execution leaves the method body.
358 : generator()->BuildReThrow();
359 34048 : return true;
360 : }
361 : return false;
362 : }
363 : };
364 :
365 : // Scoped class for enabling break inside blocks and switch blocks.
366 5104139 : class BytecodeGenerator::ControlScopeForBreakable final
367 : : public BytecodeGenerator::ControlScope {
368 : public:
369 : ControlScopeForBreakable(BytecodeGenerator* generator,
370 : BreakableStatement* statement,
371 : BreakableControlFlowBuilder* control_builder)
372 : : ControlScope(generator),
373 : statement_(statement),
374 5104198 : control_builder_(control_builder) {}
375 :
376 : protected:
377 409290 : bool Execute(Command command, Statement* statement,
378 : int source_position) override {
379 409290 : if (statement != statement_) return false;
380 26807 : switch (command) {
381 : case CMD_BREAK:
382 26807 : PopContextToExpectedDepth();
383 26807 : control_builder_->Break();
384 26807 : return true;
385 : case CMD_CONTINUE:
386 : case CMD_RETURN:
387 : case CMD_ASYNC_RETURN:
388 : case CMD_RETHROW:
389 : break;
390 : }
391 : return false;
392 : }
393 :
394 : private:
395 : Statement* statement_;
396 : BreakableControlFlowBuilder* control_builder_;
397 : };
398 :
399 : // Scoped class for enabling 'break' and 'continue' in iteration
400 : // constructs, e.g. do...while, while..., for...
401 : class BytecodeGenerator::ControlScopeForIteration final
402 : : public BytecodeGenerator::ControlScope {
403 : public:
404 : ControlScopeForIteration(BytecodeGenerator* generator,
405 : IterationStatement* statement,
406 : LoopBuilder* loop_builder)
407 : : ControlScope(generator),
408 : statement_(statement),
409 259472 : loop_builder_(loop_builder) {
410 259472 : generator->loop_depth_++;
411 : }
412 259470 : ~ControlScopeForIteration() override { generator()->loop_depth_--; }
413 :
414 : protected:
415 67661 : bool Execute(Command command, Statement* statement,
416 : int source_position) override {
417 67661 : if (statement != statement_) return false;
418 23900 : switch (command) {
419 : case CMD_BREAK:
420 20358 : PopContextToExpectedDepth();
421 20358 : loop_builder_->Break();
422 20360 : return true;
423 : case CMD_CONTINUE:
424 3541 : PopContextToExpectedDepth();
425 3541 : loop_builder_->Continue();
426 3541 : return true;
427 : case CMD_RETURN:
428 : case CMD_ASYNC_RETURN:
429 : case CMD_RETHROW:
430 : break;
431 : }
432 : return false;
433 : }
434 :
435 : private:
436 : Statement* statement_;
437 : LoopBuilder* loop_builder_;
438 : };
439 :
440 : // Scoped class for enabling 'throw' in try-catch constructs.
441 107089 : class BytecodeGenerator::ControlScopeForTryCatch final
442 : : public BytecodeGenerator::ControlScope {
443 : public:
444 : ControlScopeForTryCatch(BytecodeGenerator* generator,
445 : TryCatchBuilder* try_catch_builder)
446 107087 : : ControlScope(generator) {}
447 :
448 : protected:
449 13978 : bool Execute(Command command, Statement* statement,
450 : int source_position) override {
451 13978 : switch (command) {
452 : case CMD_BREAK:
453 : case CMD_CONTINUE:
454 : case CMD_RETURN:
455 : case CMD_ASYNC_RETURN:
456 : break;
457 : case CMD_RETHROW:
458 : // No need to pop contexts, execution re-enters the method body via the
459 : // stack unwinding mechanism which itself restores contexts correctly.
460 1553 : generator()->BuildReThrow();
461 1553 : return true;
462 : }
463 : return false;
464 : }
465 : };
466 :
467 : // Scoped class for enabling control flow through try-finally constructs.
468 41601 : class BytecodeGenerator::ControlScopeForTryFinally final
469 : : public BytecodeGenerator::ControlScope {
470 : public:
471 : ControlScopeForTryFinally(BytecodeGenerator* generator,
472 : TryFinallyBuilder* try_finally_builder,
473 : DeferredCommands* commands)
474 : : ControlScope(generator),
475 : try_finally_builder_(try_finally_builder),
476 41601 : commands_(commands) {}
477 :
478 : protected:
479 10814 : bool Execute(Command command, Statement* statement,
480 : int source_position) override {
481 10814 : switch (command) {
482 : case CMD_BREAK:
483 : case CMD_CONTINUE:
484 : case CMD_RETURN:
485 : case CMD_ASYNC_RETURN:
486 : case CMD_RETHROW:
487 10814 : PopContextToExpectedDepth();
488 : // We don't record source_position here since we don't generate return
489 : // bytecode right here and will generate it later as part of finally
490 : // block. Each return bytecode generated in finally block will get own
491 : // return source position from corresponded return statement or we'll
492 : // use end of function if no return statement is presented.
493 10816 : commands_->RecordCommand(command, statement);
494 10817 : try_finally_builder_->LeaveTry();
495 10817 : return true;
496 : }
497 : return false;
498 : }
499 :
500 : private:
501 : TryFinallyBuilder* try_finally_builder_;
502 : DeferredCommands* commands_;
503 : };
504 :
505 : // Allocate and fetch the coverage indices tracking NaryLogical Expressions.
506 : class BytecodeGenerator::NaryCodeCoverageSlots {
507 : public:
508 20848 : NaryCodeCoverageSlots(BytecodeGenerator* generator, NaryOperation* expr)
509 20848 : : generator_(generator) {
510 41696 : if (generator_->block_coverage_builder_ == nullptr) return;
511 592 : for (size_t i = 0; i < expr->subsequent_length(); i++) {
512 : coverage_slots_.push_back(
513 732 : generator_->AllocateNaryBlockCoverageSlotIfEnabled(expr, i));
514 : }
515 : }
516 :
517 : int GetSlotFor(size_t subsequent_expr_index) const {
518 79182 : if (generator_->block_coverage_builder_ == nullptr) {
519 : return BlockCoverageBuilder::kNoCoverageArraySlot;
520 : }
521 : DCHECK(coverage_slots_.size() > subsequent_expr_index);
522 336 : return coverage_slots_[subsequent_expr_index];
523 : }
524 :
525 : private:
526 : BytecodeGenerator* generator_;
527 : std::vector<int> coverage_slots_;
528 : };
529 :
530 2157779 : void BytecodeGenerator::ControlScope::PerformCommand(Command command,
531 : Statement* statement,
532 : int source_position) {
533 438664 : ControlScope* current = this;
534 438664 : do {
535 2596443 : if (current->Execute(command, statement, source_position)) {
536 2157934 : return;
537 : }
538 : current = current->outer();
539 : } while (current != nullptr);
540 0 : UNREACHABLE();
541 : }
542 :
543 123042 : void BytecodeGenerator::ControlScope::PopContextToExpectedDepth() {
544 : // Pop context to the expected depth. Note that this can in fact pop multiple
545 : // contexts at once because the {PopContext} bytecode takes a saved register.
546 123042 : if (generator()->execution_context() != context()) {
547 9457 : generator()->builder()->PopContext(context()->reg());
548 : }
549 61522 : }
550 :
551 : class BytecodeGenerator::RegisterAllocationScope final {
552 : public:
553 : explicit RegisterAllocationScope(BytecodeGenerator* generator)
554 : : generator_(generator),
555 : outer_next_register_index_(
556 79694387 : generator->register_allocator()->next_register_index()) {}
557 :
558 79678744 : ~RegisterAllocationScope() {
559 : generator_->register_allocator()->ReleaseRegisters(
560 79678744 : outer_next_register_index_);
561 79678047 : }
562 :
563 : BytecodeGenerator* generator() const { return generator_; }
564 :
565 : private:
566 : BytecodeGenerator* generator_;
567 : int outer_next_register_index_;
568 :
569 : DISALLOW_COPY_AND_ASSIGN(RegisterAllocationScope);
570 : };
571 :
572 : class BytecodeGenerator::AccumulatorPreservingScope final {
573 : public:
574 2417117 : explicit AccumulatorPreservingScope(BytecodeGenerator* generator,
575 : AccumulatorPreservingMode mode)
576 2417117 : : generator_(generator) {
577 2417117 : if (mode == AccumulatorPreservingMode::kPreserve) {
578 : saved_accumulator_register_ =
579 144 : generator_->register_allocator()->NewRegister();
580 : generator_->builder()->StoreAccumulatorInRegister(
581 144 : saved_accumulator_register_);
582 : }
583 2417117 : }
584 :
585 : ~AccumulatorPreservingScope() {
586 2417145 : if (saved_accumulator_register_.is_valid()) {
587 : generator_->builder()->LoadAccumulatorWithRegister(
588 144 : saved_accumulator_register_);
589 : }
590 : }
591 :
592 : private:
593 : BytecodeGenerator* generator_;
594 : Register saved_accumulator_register_;
595 :
596 : DISALLOW_COPY_AND_ASSIGN(AccumulatorPreservingScope);
597 : };
598 :
599 : // Scoped base class for determining how the result of an expression will be
600 : // used.
601 : class BytecodeGenerator::ExpressionResultScope {
602 : public:
603 43948281 : ExpressionResultScope(BytecodeGenerator* generator, Expression::Context kind)
604 : : outer_(generator->execution_result()),
605 : allocator_(generator),
606 : kind_(kind),
607 87896562 : type_hint_(TypeHint::kAny) {
608 : generator->set_execution_result(this);
609 : }
610 :
611 43948174 : ~ExpressionResultScope() {
612 43948174 : allocator_.generator()->set_execution_result(outer_);
613 : }
614 :
615 : bool IsEffect() const { return kind_ == Expression::kEffect; }
616 : bool IsValue() const { return kind_ == Expression::kValue; }
617 : bool IsTest() const { return kind_ == Expression::kTest; }
618 :
619 : TestResultScope* AsTest() {
620 : DCHECK(IsTest());
621 : return reinterpret_cast<TestResultScope*>(this);
622 : }
623 :
624 : // Specify expression always returns a Boolean result value.
625 : void SetResultIsBoolean() {
626 : DCHECK_EQ(type_hint_, TypeHint::kAny);
627 1228412 : type_hint_ = TypeHint::kBoolean;
628 : }
629 :
630 : void SetResultIsString() {
631 : DCHECK_EQ(type_hint_, TypeHint::kAny);
632 1742385 : type_hint_ = TypeHint::kString;
633 : }
634 :
635 : TypeHint type_hint() const { return type_hint_; }
636 :
637 : private:
638 : ExpressionResultScope* outer_;
639 : RegisterAllocationScope allocator_;
640 : Expression::Context kind_;
641 : TypeHint type_hint_;
642 :
643 : DISALLOW_COPY_AND_ASSIGN(ExpressionResultScope);
644 : };
645 :
646 : // Scoped class used when the result of the current expression is not
647 : // expected to produce a result.
648 : class BytecodeGenerator::EffectResultScope final
649 : : public ExpressionResultScope {
650 : public:
651 : explicit EffectResultScope(BytecodeGenerator* generator)
652 : : ExpressionResultScope(generator, Expression::kEffect) {}
653 : };
654 :
655 : // Scoped class used when the result of the current expression to be
656 : // evaluated should go into the interpreter's accumulator.
657 1686352 : class BytecodeGenerator::ValueResultScope final : public ExpressionResultScope {
658 : public:
659 843181 : explicit ValueResultScope(BytecodeGenerator* generator)
660 1686362 : : ExpressionResultScope(generator, Expression::kValue) {}
661 : };
662 :
663 : // Scoped class used when the result of the current expression to be
664 : // evaluated is only tested with jumps to two branches.
665 : class BytecodeGenerator::TestResultScope final : public ExpressionResultScope {
666 : public:
667 : TestResultScope(BytecodeGenerator* generator, BytecodeLabels* then_labels,
668 : BytecodeLabels* else_labels, TestFallthrough fallthrough)
669 : : ExpressionResultScope(generator, Expression::kTest),
670 : result_consumed_by_test_(false),
671 : fallthrough_(fallthrough),
672 : then_labels_(then_labels),
673 1019705 : else_labels_(else_labels) {}
674 :
675 : // Used when code special cases for TestResultScope and consumes any
676 : // possible value by testing and jumping to a then/else label.
677 348398 : void SetResultConsumedByTest() { result_consumed_by_test_ = true; }
678 : bool result_consumed_by_test() { return result_consumed_by_test_; }
679 :
680 : // Inverts the control flow of the operation, swapping the then and else
681 : // labels and the fallthrough.
682 242216 : void InvertControlFlow() {
683 : std::swap(then_labels_, else_labels_);
684 242216 : fallthrough_ = inverted_fallthrough();
685 : }
686 :
687 43306 : BytecodeLabel* NewThenLabel() { return then_labels_->New(); }
688 14441 : BytecodeLabel* NewElseLabel() { return else_labels_->New(); }
689 :
690 : BytecodeLabels* then_labels() const { return then_labels_; }
691 : BytecodeLabels* else_labels() const { return else_labels_; }
692 :
693 : void set_then_labels(BytecodeLabels* then_labels) {
694 : then_labels_ = then_labels;
695 : }
696 : void set_else_labels(BytecodeLabels* else_labels) {
697 : else_labels_ = else_labels;
698 : }
699 :
700 : TestFallthrough fallthrough() const { return fallthrough_; }
701 : TestFallthrough inverted_fallthrough() const {
702 242216 : switch (fallthrough_) {
703 : case TestFallthrough::kThen:
704 : return TestFallthrough::kElse;
705 : case TestFallthrough::kElse:
706 : return TestFallthrough::kThen;
707 : default:
708 : return TestFallthrough::kNone;
709 : }
710 : }
711 : void set_fallthrough(TestFallthrough fallthrough) {
712 : fallthrough_ = fallthrough;
713 : }
714 :
715 : private:
716 : bool result_consumed_by_test_;
717 : TestFallthrough fallthrough_;
718 : BytecodeLabels* then_labels_;
719 : BytecodeLabels* else_labels_;
720 :
721 : DISALLOW_COPY_AND_ASSIGN(TestResultScope);
722 : };
723 :
724 : // Used to build a list of global declaration initial value pairs.
725 : class BytecodeGenerator::GlobalDeclarationsBuilder final : public ZoneObject {
726 : public:
727 2203662 : explicit GlobalDeclarationsBuilder(Zone* zone)
728 : : declarations_(0, zone),
729 : constant_pool_entry_(0),
730 2203658 : has_constant_pool_entry_(false) {}
731 :
732 : void AddFunctionDeclaration(const AstRawString* name, FeedbackSlot slot,
733 : FeedbackSlot literal_slot,
734 : FunctionLiteral* func) {
735 : DCHECK(!slot.IsInvalid());
736 489620 : declarations_.push_back(Declaration(name, slot, literal_slot, func));
737 : }
738 :
739 : void AddUndefinedDeclaration(const AstRawString* name, FeedbackSlot slot) {
740 : DCHECK(!slot.IsInvalid());
741 2518165 : declarations_.push_back(Declaration(name, slot, nullptr));
742 : }
743 :
744 106125 : Handle<FixedArray> AllocateDeclarations(UnoptimizedCompilationInfo* info,
745 : Handle<Script> script,
746 : Isolate* isolate) {
747 : DCHECK(has_constant_pool_entry_);
748 : int array_index = 0;
749 : Handle<FixedArray> data = isolate->factory()->NewFixedArray(
750 212250 : static_cast<int>(declarations_.size() * 4), TENURED);
751 1497571 : for (const Declaration& declaration : declarations_) {
752 1285320 : FunctionLiteral* func = declaration.func;
753 : Handle<Object> initial_value;
754 1285320 : if (func == nullptr) {
755 : initial_value = isolate->factory()->undefined_value();
756 : } else {
757 211852 : initial_value = Compiler::GetSharedFunctionInfo(func, script, isolate);
758 : }
759 :
760 : // Return a null handle if any initial values can't be created. Caller
761 : // will set stack overflow.
762 1285321 : if (initial_value.is_null()) return Handle<FixedArray>();
763 :
764 3855963 : data->set(array_index++, *declaration.name->string());
765 1285321 : data->set(array_index++, Smi::FromInt(declaration.slot.ToInt()));
766 : Object undefined_or_literal_slot;
767 1285321 : if (declaration.literal_slot.IsInvalid()) {
768 1073468 : undefined_or_literal_slot = ReadOnlyRoots(isolate).undefined_value();
769 : } else {
770 : undefined_or_literal_slot =
771 211853 : Smi::FromInt(declaration.literal_slot.ToInt());
772 : }
773 2570641 : data->set(array_index++, undefined_or_literal_slot);
774 2570642 : data->set(array_index++, *initial_value);
775 : }
776 106126 : return data;
777 : }
778 :
779 : size_t constant_pool_entry() {
780 : DCHECK(has_constant_pool_entry_);
781 : return constant_pool_entry_;
782 : }
783 :
784 : void set_constant_pool_entry(size_t constant_pool_entry) {
785 : DCHECK(!empty());
786 : DCHECK(!has_constant_pool_entry_);
787 116567 : constant_pool_entry_ = constant_pool_entry;
788 116567 : has_constant_pool_entry_ = true;
789 : }
790 :
791 : bool empty() { return declarations_.empty(); }
792 :
793 : private:
794 : struct Declaration {
795 4407324 : Declaration() : slot(FeedbackSlot::Invalid()), func(nullptr) {}
796 : Declaration(const AstRawString* name, FeedbackSlot slot,
797 : FeedbackSlot literal_slot, FunctionLiteral* func)
798 244801 : : name(name), slot(slot), literal_slot(literal_slot), func(func) {}
799 : Declaration(const AstRawString* name, FeedbackSlot slot,
800 : FunctionLiteral* func)
801 : : name(name),
802 : slot(slot),
803 : literal_slot(FeedbackSlot::Invalid()),
804 1259068 : func(func) {}
805 :
806 : const AstRawString* name;
807 : FeedbackSlot slot;
808 : FeedbackSlot literal_slot;
809 : FunctionLiteral* func;
810 : };
811 : ZoneVector<Declaration> declarations_;
812 : size_t constant_pool_entry_;
813 : bool has_constant_pool_entry_;
814 : };
815 :
816 : class BytecodeGenerator::CurrentScope final {
817 : public:
818 5207354 : CurrentScope(BytecodeGenerator* generator, Scope* scope)
819 : : generator_(generator), outer_scope_(generator->current_scope()) {
820 5207354 : if (scope != nullptr) {
821 : DCHECK_EQ(outer_scope_, scope->outer_scope());
822 : generator_->set_current_scope(scope);
823 : }
824 : }
825 : ~CurrentScope() {
826 5207438 : if (outer_scope_ != generator_->current_scope()) {
827 : generator_->set_current_scope(outer_scope_);
828 : }
829 : }
830 :
831 : private:
832 : BytecodeGenerator* generator_;
833 : Scope* outer_scope_;
834 : };
835 :
836 : class BytecodeGenerator::FeedbackSlotCache : public ZoneObject {
837 : public:
838 : explicit FeedbackSlotCache(Zone* zone) : map_(zone) {}
839 :
840 : void Put(FeedbackSlotKind slot_kind, Variable* variable, FeedbackSlot slot) {
841 : PutImpl(slot_kind, 0, variable, slot);
842 : }
843 : void Put(FeedbackSlotKind slot_kind, AstNode* node, FeedbackSlot slot) {
844 : PutImpl(slot_kind, 0, node, slot);
845 : }
846 : void Put(FeedbackSlotKind slot_kind, int variable_index,
847 : const AstRawString* name, FeedbackSlot slot) {
848 : PutImpl(slot_kind, variable_index, name, slot);
849 : }
850 :
851 : FeedbackSlot Get(FeedbackSlotKind slot_kind, Variable* variable) const {
852 9063556 : return GetImpl(slot_kind, 0, variable);
853 : }
854 : FeedbackSlot Get(FeedbackSlotKind slot_kind, AstNode* node) const {
855 2894961 : return GetImpl(slot_kind, 0, node);
856 : }
857 : FeedbackSlot Get(FeedbackSlotKind slot_kind, int variable_index,
858 : const AstRawString* name) const {
859 772543 : return GetImpl(slot_kind, variable_index, name);
860 : }
861 :
862 : private:
863 : typedef std::tuple<FeedbackSlotKind, int, const void*> Key;
864 :
865 : void PutImpl(FeedbackSlotKind slot_kind, int index, const void* node,
866 : FeedbackSlot slot) {
867 : Key key = std::make_tuple(slot_kind, index, node);
868 : auto entry = std::make_pair(key, slot);
869 : map_.insert(entry);
870 : }
871 :
872 12729820 : FeedbackSlot GetImpl(FeedbackSlotKind slot_kind, int index,
873 : const void* node) const {
874 : Key key = std::make_tuple(slot_kind, index, node);
875 : auto iter = map_.find(key);
876 12730991 : if (iter != map_.end()) {
877 5115439 : return iter->second;
878 : }
879 7615552 : return FeedbackSlot();
880 : }
881 :
882 : ZoneMap<Key, FeedbackSlot> map_;
883 : };
884 :
885 : class BytecodeGenerator::IteratorRecord final {
886 : public:
887 : IteratorRecord(Register object_register, Register next_register,
888 : IteratorType type = IteratorType::kNormal)
889 : : type_(type), object_(object_register), next_(next_register) {
890 : DCHECK(object_.is_valid() && next_.is_valid());
891 : }
892 :
893 : inline IteratorType type() const { return type_; }
894 : inline Register object() const { return object_; }
895 : inline Register next() const { return next_; }
896 :
897 : private:
898 : IteratorType type_;
899 : Register object_;
900 : Register next_;
901 : };
902 :
903 : #ifdef DEBUG
904 :
905 : static bool IsInEagerLiterals(
906 : FunctionLiteral* literal,
907 : const std::vector<FunctionLiteral*>& eager_literals) {
908 : for (FunctionLiteral* eager_literal : eager_literals) {
909 : if (literal == eager_literal) return true;
910 : }
911 : return false;
912 : }
913 :
914 : #endif // DEBUG
915 :
916 2087099 : BytecodeGenerator::BytecodeGenerator(
917 4174200 : UnoptimizedCompilationInfo* info,
918 : const AstStringConstants* ast_string_constants,
919 20871907 : std::vector<FunctionLiteral*>* eager_inner_literals)
920 : : zone_(info->zone()),
921 : builder_(zone(), info->num_parameters_including_this(),
922 2087101 : info->scope()->num_stack_slots(), info->feedback_vector_spec(),
923 : info->SourcePositionRecordingMode()),
924 : info_(info),
925 : ast_string_constants_(ast_string_constants),
926 2087110 : closure_scope_(info->scope()),
927 2087109 : current_scope_(info->scope()),
928 : eager_inner_literals_(eager_inner_literals),
929 : feedback_slot_cache_(new (zone()) FeedbackSlotCache(zone())),
930 2087101 : globals_builder_(new (zone()) GlobalDeclarationsBuilder(zone())),
931 : block_coverage_builder_(nullptr),
932 : global_declarations_(0, zone()),
933 : function_literals_(0, zone()),
934 : native_function_literals_(0, zone()),
935 : object_literals_(0, zone()),
936 : array_literals_(0, zone()),
937 : class_literals_(0, zone()),
938 : template_objects_(0, zone()),
939 : execution_control_(nullptr),
940 : execution_context_(nullptr),
941 : execution_result_(nullptr),
942 : incoming_new_target_or_generator_(),
943 : dummy_feedback_slot_(feedback_spec(), FeedbackSlotKind::kCompareOp),
944 : generator_jump_table_(nullptr),
945 : suspend_count_(0),
946 : loop_depth_(0),
947 20871035 : catch_prediction_(HandlerTable::UNCAUGHT) {
948 : DCHECK_EQ(closure_scope(), closure_scope()->GetClosureScope());
949 2087101 : if (info->has_source_range_map()) {
950 : block_coverage_builder_ = new (zone())
951 884 : BlockCoverageBuilder(zone(), builder(), info->source_range_map());
952 : }
953 2087101 : }
954 :
955 2063523 : Handle<BytecodeArray> BytecodeGenerator::FinalizeBytecode(
956 2064408 : Isolate* isolate, Handle<Script> script) {
957 : DCHECK(ThreadId::Current().Equals(isolate->thread_id()));
958 : #ifdef DEBUG
959 : // Unoptimized compilation should be context-independent. Verify that we don't
960 : // access the native context by nulling it out during finalization.
961 : SaveAndSwitchContext save(isolate, Context());
962 : #endif
963 :
964 2063523 : AllocateDeferredConstants(isolate, script);
965 :
966 2063524 : if (block_coverage_builder_) {
967 : info()->set_coverage_info(
968 884 : isolate->factory()->NewCoverageInfo(block_coverage_builder_->slots()));
969 884 : if (FLAG_trace_block_coverage) {
970 0 : info()->coverage_info()->Print(info()->literal()->GetDebugName());
971 : }
972 : }
973 :
974 2063524 : if (HasStackOverflow()) return Handle<BytecodeArray>();
975 2063524 : Handle<BytecodeArray> bytecode_array = builder()->ToBytecodeArray(isolate);
976 :
977 2063531 : if (incoming_new_target_or_generator_.is_valid()) {
978 : bytecode_array->set_incoming_new_target_or_generator_register(
979 211048 : incoming_new_target_or_generator_);
980 : }
981 :
982 2063531 : return bytecode_array;
983 : }
984 :
985 2063521 : void BytecodeGenerator::AllocateDeferredConstants(Isolate* isolate,
986 106125 : Handle<Script> script) {
987 : // Build global declaration pair arrays.
988 4339293 : for (GlobalDeclarationsBuilder* globals_builder : global_declarations_) {
989 : Handle<FixedArray> declarations =
990 106125 : globals_builder->AllocateDeclarations(info(), script, isolate);
991 106126 : if (declarations.is_null()) return SetStackOverflow();
992 : builder()->SetDeferredConstantPoolEntry(
993 106126 : globals_builder->constant_pool_entry(), declarations);
994 : }
995 :
996 : // Find or build shared function infos.
997 6493537 : for (std::pair<FunctionLiteral*, size_t> literal : function_literals_) {
998 : FunctionLiteral* expr = literal.first;
999 : Handle<SharedFunctionInfo> shared_info =
1000 2366491 : Compiler::GetSharedFunctionInfo(expr, script, isolate);
1001 2366494 : if (shared_info.is_null()) return SetStackOverflow();
1002 2366494 : builder()->SetDeferredConstantPoolEntry(literal.second, shared_info);
1003 : }
1004 :
1005 : // Find or build shared function infos for the native function templates.
1006 4128784 : for (std::pair<NativeFunctionLiteral*, size_t> literal :
1007 1734 : native_function_literals_) {
1008 5202 : NativeFunctionLiteral* expr = literal.first;
1009 : v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
1010 :
1011 : // Compute the function template for the native function.
1012 : v8::Local<v8::FunctionTemplate> info =
1013 : expr->extension()->GetNativeFunctionTemplate(
1014 3468 : v8_isolate, Utils::ToLocal(expr->name()));
1015 : DCHECK(!info.IsEmpty());
1016 :
1017 : Handle<SharedFunctionInfo> shared_info =
1018 : FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(
1019 1734 : isolate, Utils::OpenHandle(*info), expr->name());
1020 : DCHECK(!shared_info.is_null());
1021 1734 : builder()->SetDeferredConstantPoolEntry(literal.second, shared_info);
1022 : }
1023 :
1024 : // Build object literal constant properties
1025 4312390 : for (std::pair<ObjectLiteral*, size_t> literal : object_literals_) {
1026 185338 : ObjectLiteral* object_literal = literal.first;
1027 185338 : if (object_literal->properties_count() > 0) {
1028 : // If constant properties is an empty fixed array, we've already added it
1029 : // to the constant pool when visiting the object literal.
1030 : Handle<ObjectBoilerplateDescription> constant_properties =
1031 : object_literal->GetOrBuildBoilerplateDescription(isolate);
1032 :
1033 : builder()->SetDeferredConstantPoolEntry(literal.second,
1034 185341 : constant_properties);
1035 : }
1036 : }
1037 :
1038 : // Build array literal constant elements
1039 4267824 : for (std::pair<ArrayLiteral*, size_t> literal : array_literals_) {
1040 : ArrayLiteral* array_literal = literal.first;
1041 : Handle<ArrayBoilerplateDescription> constant_elements =
1042 : array_literal->GetOrBuildBoilerplateDescription(isolate);
1043 140770 : builder()->SetDeferredConstantPoolEntry(literal.second, constant_elements);
1044 : }
1045 :
1046 : // Build class literal boilerplates.
1047 4166488 : for (std::pair<ClassLiteral*, size_t> literal : class_literals_) {
1048 : ClassLiteral* class_literal = literal.first;
1049 : Handle<ClassBoilerplate> class_boilerplate =
1050 39434 : ClassBoilerplate::BuildClassBoilerplate(isolate, class_literal);
1051 39434 : builder()->SetDeferredConstantPoolEntry(literal.second, class_boilerplate);
1052 : }
1053 :
1054 : // Build template literals.
1055 4128772 : for (std::pair<GetTemplateObject*, size_t> literal : template_objects_) {
1056 : GetTemplateObject* get_template_object = literal.first;
1057 : Handle<TemplateObjectDescription> description =
1058 1718 : get_template_object->GetOrBuildDescription(isolate);
1059 1718 : builder()->SetDeferredConstantPoolEntry(literal.second, description);
1060 : }
1061 : }
1062 :
1063 8537638 : void BytecodeGenerator::GenerateBytecode(uintptr_t stack_limit) {
1064 : DisallowHeapAllocation no_allocation;
1065 : DisallowHandleAllocation no_handles;
1066 : DisallowHandleDereference no_deref;
1067 :
1068 : InitializeAstVisitor(stack_limit);
1069 :
1070 : // Initialize the incoming context.
1071 2087087 : ContextScope incoming_context(this, closure_scope());
1072 :
1073 : // Initialize control scope.
1074 : ControlScopeForTopLevel control(this);
1075 :
1076 2086944 : RegisterAllocationScope register_scope(this);
1077 :
1078 2087089 : AllocateTopLevelRegisters();
1079 :
1080 4174178 : if (info()->literal()->CanSuspend()) {
1081 9267 : BuildGeneratorPrologue();
1082 : }
1083 :
1084 2087088 : if (closure_scope()->NeedsContext()) {
1085 : // Push a new inner context scope for the function.
1086 189290 : BuildNewLocalActivationContext();
1087 189287 : ContextScope local_function_context(this, closure_scope());
1088 189290 : BuildLocalActivationContextInitialization();
1089 189286 : GenerateBytecodeBody();
1090 : } else {
1091 1897798 : GenerateBytecodeBody();
1092 : }
1093 :
1094 : // Check that we are not falling off the end.
1095 2087013 : DCHECK(!builder()->RequiresImplicitReturn());
1096 2086962 : }
1097 :
1098 20887126 : void BytecodeGenerator::GenerateBytecodeBody() {
1099 : // Build the arguments object if it is used.
1100 2087075 : VisitArgumentsObject(closure_scope()->arguments());
1101 :
1102 : // Build rest arguments array if it is used.
1103 : Variable* rest_parameter = closure_scope()->rest_parameter();
1104 2087080 : VisitRestArgumentsArray(rest_parameter);
1105 :
1106 : // Build assignment to the function name or {.this_function}
1107 : // variables if used.
1108 2087079 : VisitThisFunctionVariable(closure_scope()->function_var());
1109 2087077 : VisitThisFunctionVariable(closure_scope()->this_function_var());
1110 :
1111 : // Build assignment to {new.target} variable if it is used.
1112 2087078 : VisitNewTargetVariable(closure_scope()->new_target_var());
1113 :
1114 : // Create a generator object if necessary and initialize the
1115 : // {.generator_object} variable.
1116 4174150 : if (IsResumableFunction(info()->literal()->kind())) {
1117 10941 : BuildGeneratorObjectVariableInitialization();
1118 : }
1119 :
1120 : // Emit tracing call if requested to do so.
1121 2087075 : if (FLAG_trace) builder()->CallRuntime(Runtime::kTraceEnter);
1122 :
1123 : // Emit type profile call.
1124 2087075 : if (info()->collect_type_profile()) {
1125 68 : feedback_spec()->AddTypeProfileSlot();
1126 68 : int num_parameters = closure_scope()->num_parameters();
1127 164 : for (int i = 0; i < num_parameters; i++) {
1128 96 : Register parameter(builder()->Parameter(i));
1129 96 : builder()->LoadAccumulatorWithRegister(parameter).CollectTypeProfile(
1130 192 : closure_scope()->parameter(i)->initializer_position());
1131 : }
1132 : }
1133 :
1134 : // Visit declarations within the function scope.
1135 2087075 : VisitDeclarations(closure_scope()->declarations());
1136 :
1137 : // Emit initializing assignments for module namespace imports (if any).
1138 2087067 : VisitModuleNamespaceImports();
1139 :
1140 : // Perform a stack-check before the body.
1141 2087071 : builder()->StackCheck(info()->literal()->start_position());
1142 :
1143 : // The derived constructor case is handled in VisitCallSuper.
1144 2103279 : if (IsBaseConstructor(function_kind()) &&
1145 16180 : info()->literal()->requires_instance_members_initializer()) {
1146 : BuildInstanceMemberInitialization(Register::function_closure(),
1147 530 : builder()->Receiver());
1148 : }
1149 :
1150 : // Visit statements in the function body.
1151 2087099 : VisitStatements(info()->literal()->body());
1152 :
1153 : // Emit an implicit return instruction in case control flow can fall off the
1154 : // end of the function without an explicit return being present on all paths.
1155 2087014 : if (builder()->RequiresImplicitReturn()) {
1156 378801 : builder()->LoadUndefined();
1157 378797 : BuildReturn();
1158 : }
1159 2087014 : }
1160 :
1161 4174174 : void BytecodeGenerator::AllocateTopLevelRegisters() {
1162 4174174 : if (IsResumableFunction(info()->literal()->kind())) {
1163 : // Either directly use generator_object_var or allocate a new register for
1164 : // the incoming generator object.
1165 10941 : Variable* generator_object_var = closure_scope()->generator_object_var();
1166 10941 : if (generator_object_var->location() == VariableLocation::LOCAL) {
1167 : incoming_new_target_or_generator_ =
1168 10941 : GetRegisterForLocalVariable(generator_object_var);
1169 : } else {
1170 0 : incoming_new_target_or_generator_ = register_allocator()->NewRegister();
1171 : }
1172 2076150 : } else if (closure_scope()->new_target_var()) {
1173 : // Either directly use new_target_var or allocate a new register for
1174 : // the incoming new target object.
1175 99650 : Variable* new_target_var = closure_scope()->new_target_var();
1176 99650 : if (new_target_var->location() == VariableLocation::LOCAL) {
1177 : incoming_new_target_or_generator_ =
1178 5449 : GetRegisterForLocalVariable(new_target_var);
1179 : } else {
1180 94200 : incoming_new_target_or_generator_ = register_allocator()->NewRegister();
1181 : }
1182 : }
1183 2087090 : }
1184 :
1185 9267 : void BytecodeGenerator::BuildGeneratorPrologue() {
1186 : DCHECK_GT(info()->literal()->suspend_count(), 0);
1187 : DCHECK(generator_object().is_valid());
1188 : generator_jump_table_ =
1189 9267 : builder()->AllocateJumpTable(info()->literal()->suspend_count(), 0);
1190 :
1191 : // If the generator is not undefined, this is a resume, so perform state
1192 : // dispatch.
1193 9267 : builder()->SwitchOnGeneratorState(generator_object(), generator_jump_table_);
1194 :
1195 : // Otherwise, fall-through to the ordinary function prologue, after which we
1196 : // will run into the generator object creation and other extra code inserted
1197 : // by the parser.
1198 9267 : }
1199 :
1200 10211437 : void BytecodeGenerator::VisitBlock(Block* stmt) {
1201 : // Visit declarations and statements.
1202 : CurrentScope current_scope(this, stmt->scope());
1203 5282613 : if (stmt->scope() != nullptr && stmt->scope()->NeedsContext()) {
1204 24227 : BuildNewLocalBlockContext(stmt->scope());
1205 24227 : ContextScope scope(this, stmt->scope());
1206 24226 : VisitBlockDeclarationsAndStatements(stmt);
1207 : } else {
1208 5069378 : VisitBlockDeclarationsAndStatements(stmt);
1209 : }
1210 5093674 : }
1211 :
1212 10187172 : void BytecodeGenerator::VisitBlockDeclarationsAndStatements(Block* stmt) {
1213 5093586 : BlockBuilder block_builder(builder(), block_coverage_builder_, stmt);
1214 : ControlScopeForBreakable execution_control(this, stmt, &block_builder);
1215 5093586 : if (stmt->scope() != nullptr) {
1216 189007 : VisitDeclarations(stmt->scope()->declarations());
1217 : }
1218 5093586 : VisitStatements(stmt->statements());
1219 5093662 : }
1220 :
1221 8672495 : void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) {
1222 8957646 : Variable* variable = decl->var();
1223 : // Unused variables don't need to be visited.
1224 13480738 : if (!variable->is_used()) return;
1225 :
1226 6321017 : switch (variable->location()) {
1227 : case VariableLocation::UNALLOCATED: {
1228 : DCHECK(!variable->binding_needs_init());
1229 : FeedbackSlot slot =
1230 1259024 : GetCachedLoadGlobalICSlot(NOT_INSIDE_TYPEOF, variable);
1231 : globals_builder()->AddUndefinedDeclaration(variable->raw_name(), slot);
1232 : break;
1233 : }
1234 : case VariableLocation::LOCAL:
1235 1034169 : if (variable->binding_needs_init()) {
1236 3266 : Register destination(builder()->Local(variable->index()));
1237 3266 : builder()->LoadTheHole().StoreAccumulatorInRegister(destination);
1238 : }
1239 : break;
1240 : case VariableLocation::PARAMETER:
1241 2283442 : if (variable->binding_needs_init()) {
1242 0 : Register destination(builder()->Parameter(variable->index()));
1243 0 : builder()->LoadTheHole().StoreAccumulatorInRegister(destination);
1244 : }
1245 : break;
1246 : case VariableLocation::CONTEXT:
1247 1444827 : if (variable->binding_needs_init()) {
1248 : DCHECK_EQ(0, execution_context()->ContextChainDepth(variable->scope()));
1249 673088 : builder()->LoadTheHole().StoreContextSlot(execution_context()->reg(),
1250 673082 : variable->index(), 0);
1251 : }
1252 : break;
1253 : case VariableLocation::LOOKUP: {
1254 : DCHECK_EQ(VariableMode::kDynamic, variable->mode());
1255 : DCHECK(!variable->binding_needs_init());
1256 :
1257 281885 : Register name = register_allocator()->NewRegister();
1258 :
1259 : builder()
1260 281885 : ->LoadLiteral(variable->raw_name())
1261 281885 : .StoreAccumulatorInRegister(name)
1262 281885 : .CallRuntime(Runtime::kDeclareEvalVar, name);
1263 : break;
1264 : }
1265 : case VariableLocation::MODULE:
1266 17745 : if (variable->IsExport() && variable->binding_needs_init()) {
1267 17063 : builder()->LoadTheHole();
1268 17063 : BuildVariableAssignment(variable, Token::INIT, HoleCheckMode::kElided);
1269 : }
1270 : // Nothing to do for imports.
1271 : break;
1272 : }
1273 : }
1274 :
1275 2107332 : void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) {
1276 1077079 : Variable* variable = decl->var();
1277 : DCHECK(variable->mode() == VariableMode::kLet ||
1278 : variable->mode() == VariableMode::kVar ||
1279 : variable->mode() == VariableMode::kDynamic);
1280 : // Unused variables don't need to be visited.
1281 1106656 : if (!variable->is_used()) return;
1282 :
1283 547780 : switch (variable->location()) {
1284 : case VariableLocation::UNALLOCATED: {
1285 : FeedbackSlot slot =
1286 244778 : GetCachedLoadGlobalICSlot(NOT_INSIDE_TYPEOF, variable);
1287 244806 : FeedbackSlot literal_slot = GetCachedCreateClosureSlot(decl->fun());
1288 : globals_builder()->AddFunctionDeclaration(variable->raw_name(), slot,
1289 : literal_slot, decl->fun());
1290 244819 : AddToEagerLiteralsIfEager(decl->fun());
1291 : break;
1292 : }
1293 : case VariableLocation::PARAMETER:
1294 : case VariableLocation::LOCAL: {
1295 23672 : VisitFunctionLiteral(decl->fun());
1296 23676 : BuildVariableAssignment(variable, Token::INIT, HoleCheckMode::kElided);
1297 23676 : break;
1298 : }
1299 : case VariableLocation::CONTEXT: {
1300 : DCHECK_EQ(0, execution_context()->ContextChainDepth(variable->scope()));
1301 271785 : VisitFunctionLiteral(decl->fun());
1302 : builder()->StoreContextSlot(execution_context()->reg(), variable->index(),
1303 271786 : 0);
1304 271786 : break;
1305 : }
1306 : case VariableLocation::LOOKUP: {
1307 7177 : RegisterList args = register_allocator()->NewRegisterList(2);
1308 : builder()
1309 7177 : ->LoadLiteral(variable->raw_name())
1310 7177 : .StoreAccumulatorInRegister(args[0]);
1311 7177 : VisitFunctionLiteral(decl->fun());
1312 7177 : builder()->StoreAccumulatorInRegister(args[1]).CallRuntime(
1313 7177 : Runtime::kDeclareEvalFunction, args);
1314 : break;
1315 : }
1316 : case VariableLocation::MODULE:
1317 : DCHECK_EQ(variable->mode(), VariableMode::kLet);
1318 : DCHECK(variable->IsExport());
1319 370 : VisitForAccumulatorValue(decl->fun());
1320 370 : BuildVariableAssignment(variable, Token::INIT, HoleCheckMode::kElided);
1321 370 : break;
1322 : }
1323 : DCHECK_IMPLIES(decl->fun()->ShouldEagerCompile(),
1324 : IsInEagerLiterals(decl->fun(), *eager_inner_literals_));
1325 : }
1326 :
1327 2088440 : void BytecodeGenerator::VisitModuleNamespaceImports() {
1328 4172894 : if (!closure_scope()->is_module_scope()) return;
1329 :
1330 : RegisterAllocationScope register_scope(this);
1331 1242 : Register module_request = register_allocator()->NewRegister();
1332 :
1333 1242 : ModuleDescriptor* descriptor = closure_scope()->AsModuleScope()->module();
1334 2614 : for (auto entry : descriptor->namespace_imports()) {
1335 : builder()
1336 260 : ->LoadLiteral(Smi::FromInt(entry->module_request))
1337 130 : .StoreAccumulatorInRegister(module_request)
1338 130 : .CallRuntime(Runtime::kGetModuleNamespace, module_request);
1339 130 : Variable* var = closure_scope()->LookupInModule(entry->local_name);
1340 130 : BuildVariableAssignment(var, Token::INIT, HoleCheckMode::kElided);
1341 1242 : }
1342 : }
1343 :
1344 5218910 : void BytecodeGenerator::VisitDeclarations(Declaration::List* declarations) {
1345 : RegisterAllocationScope register_scope(this);
1346 : DCHECK(globals_builder()->empty());
1347 11929669 : for (Declaration* decl : *declarations) {
1348 : RegisterAllocationScope register_scope(this);
1349 7293588 : Visit(decl);
1350 7293699 : }
1351 4519565 : if (globals_builder()->empty()) return;
1352 :
1353 : globals_builder()->set_constant_pool_entry(
1354 116569 : builder()->AllocateDeferredConstantPoolEntry());
1355 116567 : int encoded_flags = DeclareGlobalsEvalFlag::encode(info()->is_eval()) |
1356 116567 : DeclareGlobalsNativeFlag::encode(info()->is_native());
1357 :
1358 : // Emit code to declare globals.
1359 116567 : RegisterList args = register_allocator()->NewRegisterList(3);
1360 : builder()
1361 116563 : ->LoadConstantPoolEntry(globals_builder()->constant_pool_entry())
1362 116565 : .StoreAccumulatorInRegister(args[0])
1363 116558 : .LoadLiteral(Smi::FromInt(encoded_flags))
1364 116551 : .StoreAccumulatorInRegister(args[1])
1365 233120 : .MoveRegister(Register::function_closure(), args[2])
1366 116547 : .CallRuntime(Runtime::kDeclareGlobals, args);
1367 :
1368 : // Push and reset globals builder.
1369 233132 : global_declarations_.push_back(globals_builder());
1370 116566 : globals_builder_ = new (zone()) GlobalDeclarationsBuilder(zone());
1371 : }
1372 :
1373 7260809 : void BytecodeGenerator::VisitStatements(
1374 22225242 : const ZonePtrList<Statement>* statements) {
1375 44450484 : for (int i = 0; i < statements->length(); i++) {
1376 : // Allocate an outer register allocations scope for the statement.
1377 : RegisterAllocationScope allocation_scope(this);
1378 16886635 : Statement* stmt = statements->at(i);
1379 16886635 : Visit(stmt);
1380 16886416 : if (builder()->RemainderOfBlockIsDead()) break;
1381 14964616 : }
1382 7260426 : }
1383 :
1384 19986168 : void BytecodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
1385 : builder()->SetStatementPosition(stmt);
1386 9993084 : VisitForEffect(stmt->expression());
1387 9992701 : }
1388 :
1389 0 : void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {}
1390 :
1391 3433237 : void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) {
1392 : ConditionalControlFlowBuilder conditional_builder(
1393 567151 : builder(), block_coverage_builder_, stmt);
1394 : builder()->SetStatementPosition(stmt);
1395 :
1396 567152 : if (stmt->condition()->ToBooleanIsTrue()) {
1397 : // Generate then block unconditionally as always true.
1398 429 : conditional_builder.Then();
1399 429 : Visit(stmt->then_statement());
1400 566725 : } else if (stmt->condition()->ToBooleanIsFalse()) {
1401 : // Generate else block unconditionally if it exists.
1402 8301 : if (stmt->HasElseStatement()) {
1403 7043 : conditional_builder.Else();
1404 7043 : Visit(stmt->else_statement());
1405 : }
1406 : } else {
1407 : // TODO(oth): If then statement is BreakStatement or
1408 : // ContinueStatement we can reduce number of generated
1409 : // jump/jump_ifs here. See BasicLoops test.
1410 : VisitForTest(stmt->condition(), conditional_builder.then_labels(),
1411 558425 : conditional_builder.else_labels(), TestFallthrough::kThen);
1412 :
1413 558430 : conditional_builder.Then();
1414 558432 : Visit(stmt->then_statement());
1415 :
1416 558433 : if (stmt->HasElseStatement()) {
1417 41147 : conditional_builder.JumpToEnd();
1418 41147 : conditional_builder.Else();
1419 41146 : Visit(stmt->else_statement());
1420 : }
1421 567163 : }
1422 567151 : }
1423 :
1424 3086 : void BytecodeGenerator::VisitSloppyBlockFunctionStatement(
1425 3086 : SloppyBlockFunctionStatement* stmt) {
1426 3086 : Visit(stmt->statement());
1427 3088 : }
1428 :
1429 7082 : void BytecodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
1430 : AllocateBlockCoverageSlotIfEnabled(stmt, SourceRangeKind::kContinuation);
1431 : builder()->SetStatementPosition(stmt);
1432 : execution_control()->Continue(stmt->target());
1433 3541 : }
1434 :
1435 94330 : void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
1436 : AllocateBlockCoverageSlotIfEnabled(stmt, SourceRangeKind::kContinuation);
1437 : builder()->SetStatementPosition(stmt);
1438 : execution_control()->Break(stmt->target());
1439 47167 : }
1440 :
1441 6159845 : void BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
1442 : AllocateBlockCoverageSlotIfEnabled(stmt, SourceRangeKind::kContinuation);
1443 : builder()->SetStatementPosition(stmt);
1444 2053239 : VisitForAccumulatorValue(stmt->expression());
1445 2053395 : if (stmt->is_async_return()) {
1446 : execution_control()->AsyncReturnAccumulator(stmt->end_position());
1447 : } else {
1448 : execution_control()->ReturnAccumulator(stmt->end_position());
1449 : }
1450 2053374 : }
1451 :
1452 11819 : void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) {
1453 : builder()->SetStatementPosition(stmt);
1454 2954 : VisitForAccumulatorValue(stmt->expression());
1455 2956 : BuildNewLocalWithContext(stmt->scope());
1456 2955 : VisitInScope(stmt->statement(), stmt->scope());
1457 2956 : }
1458 :
1459 21224 : void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
1460 : // We need this scope because we visit for register values. We have to
1461 : // maintain a execution result scope where registers can be allocated.
1462 202634 : ZonePtrList<CaseClause>* clauses = stmt->cases();
1463 : SwitchBuilder switch_builder(builder(), block_coverage_builder_, stmt,
1464 10612 : clauses->length());
1465 : ControlScopeForBreakable scope(this, stmt, &switch_builder);
1466 : int default_index = -1;
1467 :
1468 : builder()->SetStatementPosition(stmt);
1469 :
1470 : // Keep the switch value in a register until a case matches.
1471 10612 : Register tag = VisitForRegisterValue(stmt->tag());
1472 : FeedbackSlot slot = clauses->length() > 0
1473 10584 : ? feedback_spec()->AddCompareICSlot()
1474 10612 : : FeedbackSlot::Invalid();
1475 :
1476 : // Iterate over all cases and create nodes for label comparison.
1477 181410 : for (int i = 0; i < clauses->length(); i++) {
1478 80093 : CaseClause* clause = clauses->at(i);
1479 :
1480 : // The default is not a test, remember index.
1481 80093 : if (clause->is_default()) {
1482 : default_index = i;
1483 : continue;
1484 : }
1485 :
1486 : // Perform label comparison as if via '===' with tag.
1487 72643 : VisitForAccumulatorValue(clause->label());
1488 : builder()->CompareOperation(Token::Value::EQ_STRICT, tag,
1489 72643 : feedback_index(slot));
1490 72643 : switch_builder.Case(ToBooleanMode::kAlreadyBoolean, i);
1491 : }
1492 :
1493 10612 : if (default_index >= 0) {
1494 : // Emit default jump if there is a default case.
1495 7450 : switch_builder.DefaultAt(default_index);
1496 : } else {
1497 : // Otherwise if we have reached here none of the cases matched, so jump to
1498 : // the end.
1499 : switch_builder.Break();
1500 : }
1501 :
1502 : // Iterate over all cases and create the case bodies.
1503 170798 : for (int i = 0; i < clauses->length(); i++) {
1504 80093 : CaseClause* clause = clauses->at(i);
1505 80093 : switch_builder.SetCaseTarget(i, clause);
1506 80093 : VisitStatements(clause->statements());
1507 10612 : }
1508 10612 : }
1509 :
1510 : template <typename TryBodyFunc, typename CatchBodyFunc>
1511 107075 : void BytecodeGenerator::BuildTryCatch(
1512 : TryBodyFunc try_body_func, CatchBodyFunc catch_body_func,
1513 : HandlerTable::CatchPrediction catch_prediction,
1514 : TryCatchStatement* stmt_for_coverage) {
1515 : TryCatchBuilder try_control_builder(
1516 : builder(),
1517 : stmt_for_coverage == nullptr ? nullptr : block_coverage_builder_,
1518 107075 : stmt_for_coverage, catch_prediction);
1519 :
1520 : // Preserve the context in a dedicated register, so that it can be restored
1521 : // when the handler is entered by the stack-unwinding machinery.
1522 : // TODO(mstarzinger): Be smarter about register allocation.
1523 107081 : Register context = register_allocator()->NewRegister();
1524 107088 : builder()->MoveRegister(Register::current_context(), context);
1525 :
1526 : // Evaluate the try-block inside a control scope. This simulates a handler
1527 : // that is intercepting 'throw' control commands.
1528 107089 : try_control_builder.BeginTry(context);
1529 : {
1530 : ControlScopeForTryCatch scope(this, &try_control_builder);
1531 107087 : try_body_func();
1532 : }
1533 107089 : try_control_builder.EndTry();
1534 :
1535 107074 : catch_body_func(context);
1536 :
1537 107091 : try_control_builder.EndCatch();
1538 107068 : }
1539 :
1540 : template <typename TryBodyFunc, typename FinallyBodyFunc>
1541 41598 : void BytecodeGenerator::BuildTryFinally(
1542 : TryBodyFunc try_body_func, FinallyBodyFunc finally_body_func,
1543 : HandlerTable::CatchPrediction catch_prediction,
1544 : TryFinallyStatement* stmt_for_coverage) {
1545 : // We can't know whether the finally block will override ("catch") an
1546 : // exception thrown in the try block, so we just adopt the outer prediction.
1547 : TryFinallyBuilder try_control_builder(
1548 : builder(),
1549 : stmt_for_coverage == nullptr ? nullptr : block_coverage_builder_,
1550 41598 : stmt_for_coverage, catch_prediction);
1551 :
1552 : // We keep a record of all paths that enter the finally-block to be able to
1553 : // dispatch to the correct continuation point after the statements in the
1554 : // finally-block have been evaluated.
1555 : //
1556 : // The try-finally construct can enter the finally-block in three ways:
1557 : // 1. By exiting the try-block normally, falling through at the end.
1558 : // 2. By exiting the try-block with a function-local control flow transfer
1559 : // (i.e. through break/continue/return statements).
1560 : // 3. By exiting the try-block with a thrown exception.
1561 : //
1562 : // The result register semantics depend on how the block was entered:
1563 : // - ReturnStatement: It represents the return value being returned.
1564 : // - ThrowStatement: It represents the exception being thrown.
1565 : // - BreakStatement/ContinueStatement: Undefined and not used.
1566 : // - Falling through into finally-block: Undefined and not used.
1567 41600 : Register token = register_allocator()->NewRegister();
1568 41605 : Register result = register_allocator()->NewRegister();
1569 41599 : ControlScope::DeferredCommands commands(this, token, result);
1570 :
1571 : // Preserve the context in a dedicated register, so that it can be restored
1572 : // when the handler is entered by the stack-unwinding machinery.
1573 : // TODO(mstarzinger): Be smarter about register allocation.
1574 41599 : Register context = register_allocator()->NewRegister();
1575 41604 : builder()->MoveRegister(Register::current_context(), context);
1576 :
1577 : // Evaluate the try-block inside a control scope. This simulates a handler
1578 : // that is intercepting all control commands.
1579 41602 : try_control_builder.BeginTry(context);
1580 : {
1581 : ControlScopeForTryFinally scope(this, &try_control_builder, &commands);
1582 38173 : try_body_func();
1583 : }
1584 41601 : try_control_builder.EndTry();
1585 :
1586 : // Record fall-through and exception cases.
1587 41605 : commands.RecordFallThroughPath();
1588 41602 : try_control_builder.LeaveTry();
1589 41605 : try_control_builder.BeginHandler();
1590 : commands.RecordHandlerReThrowPath();
1591 :
1592 : // Pending message object is saved on entry.
1593 41605 : try_control_builder.BeginFinally();
1594 41600 : Register message = context; // Reuse register.
1595 :
1596 : // Clear message object as we enter the finally block.
1597 41600 : builder()->LoadTheHole().SetPendingMessage().StoreAccumulatorInRegister(
1598 : message);
1599 :
1600 : // Evaluate the finally-block.
1601 : finally_body_func(token);
1602 41601 : try_control_builder.EndFinally();
1603 :
1604 : // Pending message object is restored on exit.
1605 41601 : builder()->LoadAccumulatorWithRegister(message).SetPendingMessage();
1606 :
1607 : // Dynamic dispatch after the finally-block.
1608 41604 : commands.ApplyDeferredCommands();
1609 41600 : }
1610 :
1611 518946 : void BytecodeGenerator::VisitIterationBody(IterationStatement* stmt,
1612 : LoopBuilder* loop_builder) {
1613 259453 : loop_builder->LoopBody();
1614 : ControlScopeForIteration execution_control(this, stmt, loop_builder);
1615 259472 : builder()->StackCheck(stmt->position());
1616 259493 : Visit(stmt->body());
1617 259482 : loop_builder->BindContinueTarget();
1618 259470 : }
1619 :
1620 4970 : void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
1621 1169 : LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt);
1622 1169 : if (stmt->cond()->ToBooleanIsFalse()) {
1623 346 : VisitIterationBody(stmt, &loop_builder);
1624 823 : } else if (stmt->cond()->ToBooleanIsTrue()) {
1625 220 : loop_builder.LoopHeader();
1626 220 : VisitIterationBody(stmt, &loop_builder);
1627 220 : loop_builder.JumpToHeader(loop_depth_);
1628 : } else {
1629 603 : loop_builder.LoopHeader();
1630 603 : VisitIterationBody(stmt, &loop_builder);
1631 : builder()->SetExpressionAsStatementPosition(stmt->cond());
1632 : BytecodeLabels loop_backbranch(zone());
1633 : VisitForTest(stmt->cond(), &loop_backbranch, loop_builder.break_labels(),
1634 603 : TestFallthrough::kThen);
1635 603 : loop_backbranch.Bind(builder());
1636 603 : loop_builder.JumpToHeader(loop_depth_);
1637 1170 : }
1638 1170 : }
1639 :
1640 74416 : void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
1641 13569 : LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt);
1642 :
1643 13569 : if (stmt->cond()->ToBooleanIsFalse()) {
1644 : // If the condition is false there is no need to generate the loop.
1645 111 : return;
1646 : }
1647 :
1648 13459 : loop_builder.LoopHeader();
1649 13459 : if (!stmt->cond()->ToBooleanIsTrue()) {
1650 : builder()->SetExpressionAsStatementPosition(stmt->cond());
1651 : BytecodeLabels loop_body(zone());
1652 : VisitForTest(stmt->cond(), &loop_body, loop_builder.break_labels(),
1653 11273 : TestFallthrough::kThen);
1654 11273 : loop_body.Bind(builder());
1655 : }
1656 13458 : VisitIterationBody(stmt, &loop_builder);
1657 13459 : loop_builder.JumpToHeader(loop_depth_);
1658 : }
1659 :
1660 1812397 : void BytecodeGenerator::VisitForStatement(ForStatement* stmt) {
1661 220105 : LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt);
1662 :
1663 220102 : if (stmt->init() != nullptr) {
1664 160105 : Visit(stmt->init());
1665 : }
1666 220121 : if (stmt->cond() && stmt->cond()->ToBooleanIsFalse()) {
1667 : // If the condition is known to be false there is no need to generate
1668 : // body, next or condition blocks. Init block should be generated.
1669 15467 : return;
1670 : }
1671 :
1672 204644 : loop_builder.LoopHeader();
1673 204650 : if (stmt->cond() && !stmt->cond()->ToBooleanIsTrue()) {
1674 : builder()->SetExpressionAsStatementPosition(stmt->cond());
1675 : BytecodeLabels loop_body(zone());
1676 : VisitForTest(stmt->cond(), &loop_body, loop_builder.break_labels(),
1677 187751 : TestFallthrough::kThen);
1678 187761 : loop_body.Bind(builder());
1679 : }
1680 204661 : VisitIterationBody(stmt, &loop_builder);
1681 204650 : if (stmt->next() != nullptr) {
1682 : builder()->SetStatementPosition(stmt->next());
1683 179516 : Visit(stmt->next());
1684 : }
1685 204645 : loop_builder.JumpToHeader(loop_depth_);
1686 : }
1687 :
1688 4787 : void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) {
1689 33258 : if (stmt->subject()->IsNullLiteral() ||
1690 4762 : stmt->subject()->IsUndefinedLiteral()) {
1691 : // ForIn generates lots of code, skip if it wouldn't produce any effects.
1692 51 : return;
1693 : }
1694 :
1695 : BytecodeLabel subject_null_label, subject_undefined_label;
1696 4741 : FeedbackSlot slot = feedback_spec()->AddForInSlot();
1697 :
1698 : // Prepare the state for executing ForIn.
1699 : builder()->SetExpressionAsStatementPosition(stmt->subject());
1700 4741 : VisitForAccumulatorValue(stmt->subject());
1701 4742 : builder()->JumpIfUndefined(&subject_undefined_label);
1702 4740 : builder()->JumpIfNull(&subject_null_label);
1703 4741 : Register receiver = register_allocator()->NewRegister();
1704 4741 : builder()->ToObject(receiver);
1705 :
1706 : // Used as kRegTriple and kRegPair in ForInPrepare and ForInNext.
1707 4741 : RegisterList triple = register_allocator()->NewRegisterList(3);
1708 4738 : Register cache_length = triple[2];
1709 4738 : builder()->ForInEnumerate(receiver);
1710 4742 : builder()->ForInPrepare(triple, feedback_index(slot));
1711 :
1712 : // Set up loop counter
1713 4742 : Register index = register_allocator()->NewRegister();
1714 4742 : builder()->LoadLiteral(Smi::zero());
1715 4742 : builder()->StoreAccumulatorInRegister(index);
1716 :
1717 : // The loop
1718 : {
1719 4742 : LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt);
1720 4739 : loop_builder.LoopHeader();
1721 : builder()->SetExpressionAsStatementPosition(stmt->each());
1722 4741 : builder()->ForInContinue(index, cache_length);
1723 : loop_builder.BreakIfFalse(ToBooleanMode::kAlreadyBoolean);
1724 : builder()->ForInNext(receiver, index, triple.Truncate(2),
1725 4742 : feedback_index(slot));
1726 : loop_builder.ContinueIfUndefined();
1727 :
1728 : // Assign accumulator value to the 'each' target.
1729 : {
1730 : EffectResultScope scope(this);
1731 : // Make sure to preserve the accumulator across the PrepareAssignmentLhs
1732 : // call.
1733 : AssignmentLhsData lhs_data = PrepareAssignmentLhs(
1734 4742 : stmt->each(), AccumulatorPreservingMode::kPreserve);
1735 : builder()->SetExpressionPosition(stmt->each());
1736 4741 : BuildAssignment(lhs_data, Token::ASSIGN, LookupHoistingMode::kNormal);
1737 : }
1738 :
1739 4739 : VisitIterationBody(stmt, &loop_builder);
1740 4738 : builder()->ForInStep(index);
1741 4741 : builder()->StoreAccumulatorInRegister(index);
1742 4742 : loop_builder.JumpToHeader(loop_depth_);
1743 : }
1744 4742 : builder()->Bind(&subject_null_label);
1745 4741 : builder()->Bind(&subject_undefined_label);
1746 : }
1747 :
1748 : // Desugar a for-of statement into an application of the iteration protocol.
1749 : //
1750 : // for (EACH of SUBJECT) BODY
1751 : //
1752 : // becomes
1753 : //
1754 : // iterator = %GetIterator(SUBJECT)
1755 : // try {
1756 : //
1757 : // loop {
1758 : // // Make sure we are considered 'done' if .next(), .done or .value fail.
1759 : // done = true
1760 : // value = iterator.next()
1761 : // if (value.done) break;
1762 : // value = value.value
1763 : // done = false
1764 : //
1765 : // EACH = value
1766 : // BODY
1767 : // }
1768 : // done = true
1769 : //
1770 : // } catch(e) {
1771 : // iteration_continuation = RETHROW
1772 : // } finally {
1773 : // %FinalizeIteration(iterator, done, iteration_continuation)
1774 : // }
1775 35458 : void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
1776 : EffectResultScope effect_scope(this);
1777 :
1778 106376 : builder()->SetExpressionAsStatementPosition(stmt->subject());
1779 35458 : VisitForAccumulatorValue(stmt->subject());
1780 :
1781 : // Store the iterator in a dedicated register so that it can be closed on
1782 : // exit, and the 'done' value in a dedicated register so that it can be
1783 : // changed and accessed independently of the iteration result.
1784 70920 : IteratorRecord iterator = BuildGetIteratorRecord(stmt->type());
1785 35460 : Register done = register_allocator()->NewRegister();
1786 35457 : builder()->LoadFalse();
1787 35459 : builder()->StoreAccumulatorInRegister(done);
1788 :
1789 : BuildTryFinally(
1790 : // Try block.
1791 35457 : [&]() {
1792 106376 : Register next_result = register_allocator()->NewRegister();
1793 :
1794 35460 : LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt);
1795 35458 : loop_builder.LoopHeader();
1796 :
1797 35456 : builder()->LoadTrue().StoreAccumulatorInRegister(done);
1798 :
1799 : // Call the iterator's .next() method. Break from the loop if the `done`
1800 : // property is truthy, otherwise load the value from the iterator result
1801 : // and append the argument.
1802 70920 : builder()->SetExpressionAsStatementPosition(stmt->each());
1803 35460 : BuildIteratorNext(iterator, next_result);
1804 : builder()->LoadNamedProperty(
1805 : next_result, ast_string_constants()->done_string(),
1806 141840 : feedback_index(feedback_spec()->AddLoadICSlot()));
1807 : loop_builder.BreakIfTrue(ToBooleanMode::kConvertToBoolean);
1808 :
1809 : builder()
1810 : // value = value.value
1811 : ->LoadNamedProperty(
1812 : next_result, ast_string_constants()->value_string(),
1813 141838 : feedback_index(feedback_spec()->AddLoadICSlot()));
1814 : // done = false, before the assignment to each happens, so that done is
1815 : // false if the assignment throws.
1816 : builder()
1817 35459 : ->StoreAccumulatorInRegister(next_result)
1818 35460 : .LoadFalse()
1819 70919 : .StoreAccumulatorInRegister(done);
1820 :
1821 : // Assign to the 'each' target.
1822 70920 : AssignmentLhsData lhs_data = PrepareAssignmentLhs(stmt->each());
1823 35460 : builder()->LoadAccumulatorWithRegister(next_result);
1824 35460 : BuildAssignment(lhs_data, Token::ASSIGN, LookupHoistingMode::kNormal);
1825 :
1826 35460 : VisitIterationBody(stmt, &loop_builder);
1827 :
1828 35454 : loop_builder.JumpToHeader(loop_depth_);
1829 35459 : },
1830 : // Finally block.
1831 : [&](Register iteration_continuation_token) {
1832 : // Finish the iteration in the finally block.
1833 35459 : BuildFinalizeIteration(iterator, done, iteration_continuation_token);
1834 : },
1835 35460 : HandlerTable::UNCAUGHT);
1836 35460 : }
1837 :
1838 68904 : void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
1839 : // Update catch prediction tracking. The updated catch_prediction value lasts
1840 : // until the end of the try_block in the AST node, and does not apply to the
1841 : // catch_block.
1842 68904 : HandlerTable::CatchPrediction outer_catch_prediction = catch_prediction();
1843 68904 : set_catch_prediction(stmt->GetCatchPrediction(outer_catch_prediction));
1844 :
1845 : BuildTryCatch(
1846 : // Try body.
1847 68906 : [&]() {
1848 68906 : Visit(stmt->try_block());
1849 68912 : set_catch_prediction(outer_catch_prediction);
1850 68912 : },
1851 : // Catch body.
1852 68902 : [&](Register context) {
1853 275632 : if (stmt->scope()) {
1854 : // Create a catch scope that binds the exception.
1855 68832 : BuildNewLocalCatchContext(stmt->scope());
1856 68836 : builder()->StoreAccumulatorInRegister(context);
1857 : }
1858 :
1859 : // If requested, clear message object as we enter the catch block.
1860 137824 : if (stmt->ShouldClearPendingException(outer_catch_prediction)) {
1861 68912 : builder()->LoadTheHole().SetPendingMessage();
1862 : }
1863 :
1864 : // Load the catch context into the accumulator.
1865 68907 : builder()->LoadAccumulatorWithRegister(context);
1866 :
1867 : // Evaluate the catch-block.
1868 137818 : if (stmt->scope()) {
1869 68837 : VisitInScope(stmt->catch_block(), stmt->scope());
1870 : } else {
1871 72 : VisitBlock(stmt->catch_block());
1872 : }
1873 68914 : },
1874 68904 : catch_prediction(), stmt);
1875 68899 : }
1876 :
1877 6856 : void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
1878 : BuildTryFinally(
1879 : // Try block.
1880 3428 : [&]() { Visit(stmt->try_block()); },
1881 : // Finally block.
1882 3428 : [&](Register body_continuation_token) { Visit(stmt->finally_block()); },
1883 6856 : catch_prediction(), stmt);
1884 3427 : }
1885 :
1886 0 : void BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
1887 : builder()->SetStatementPosition(stmt);
1888 6555 : builder()->Debugger();
1889 0 : }
1890 :
1891 5300328 : void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
1892 : DCHECK(expr->scope()->outer_scope() == current_scope());
1893 : uint8_t flags = CreateClosureFlags::Encode(
1894 5300328 : expr->pretenure(), closure_scope()->is_function_scope(),
1895 7950492 : info()->might_always_opt());
1896 2650177 : size_t entry = builder()->AllocateDeferredConstantPoolEntry();
1897 2650177 : FeedbackSlot slot = GetCachedCreateClosureSlot(expr);
1898 2650395 : builder()->CreateClosure(entry, feedback_index(slot), flags);
1899 5300468 : function_literals_.push_back(std::make_pair(expr, entry));
1900 2650232 : AddToEagerLiteralsIfEager(expr);
1901 2650249 : }
1902 :
1903 2895018 : void BytecodeGenerator::AddToEagerLiteralsIfEager(FunctionLiteral* literal) {
1904 2895018 : if (eager_inner_literals_ && literal->ShouldEagerCompile()) {
1905 : DCHECK(!IsInEagerLiterals(literal, *eager_inner_literals_));
1906 519332 : eager_inner_literals_->push_back(literal);
1907 : }
1908 2895019 : }
1909 :
1910 20401032 : bool BytecodeGenerator::ShouldOptimizeAsOneShot() const {
1911 10379343 : if (!FLAG_enable_one_shot_optimization) return false;
1912 :
1913 10362707 : if (loop_depth_ > 0) return false;
1914 :
1915 28120570 : return info()->literal()->is_toplevel() ||
1916 18098881 : info()->literal()->is_oneshot_iife();
1917 : }
1918 :
1919 43643 : void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr, Register name) {
1920 : size_t class_boilerplate_entry =
1921 41963 : builder()->AllocateDeferredConstantPoolEntry();
1922 83929 : class_literals_.push_back(std::make_pair(expr, class_boilerplate_entry));
1923 :
1924 637955 : VisitDeclarations(expr->scope()->declarations());
1925 41966 : Register class_constructor = register_allocator()->NewRegister();
1926 :
1927 : {
1928 : RegisterAllocationScope register_scope(this);
1929 41965 : RegisterList args = register_allocator()->NewGrowableRegisterList();
1930 :
1931 41965 : Register class_boilerplate = register_allocator()->GrowRegisterList(&args);
1932 : Register class_constructor_in_args =
1933 41966 : register_allocator()->GrowRegisterList(&args);
1934 41966 : Register super_class = register_allocator()->GrowRegisterList(&args);
1935 : DCHECK_EQ(ClassBoilerplate::kFirstDynamicArgumentIndex,
1936 : args.register_count());
1937 :
1938 41966 : VisitForAccumulatorValueOrTheHole(expr->extends());
1939 41965 : builder()->StoreAccumulatorInRegister(super_class);
1940 :
1941 41965 : VisitFunctionLiteral(expr->constructor());
1942 : builder()
1943 41964 : ->StoreAccumulatorInRegister(class_constructor)
1944 41965 : .MoveRegister(class_constructor, class_constructor_in_args)
1945 41965 : .LoadConstantPoolEntry(class_boilerplate_entry)
1946 41965 : .StoreAccumulatorInRegister(class_boilerplate);
1947 :
1948 : // Create computed names and method values nodes to store into the literal.
1949 692750 : for (int i = 0; i < expr->properties()->length(); i++) {
1950 622883 : ClassLiteral::Property* property = expr->properties()->at(i);
1951 607836 : if (property->is_computed_name()) {
1952 6038 : Register key = register_allocator()->GrowRegisterList(&args);
1953 :
1954 : builder()->SetExpressionAsStatementPosition(property->key());
1955 6039 : BuildLoadPropertyKey(property, key);
1956 6039 : if (property->is_static()) {
1957 : // The static prototype property is read only. We handle the non
1958 : // computed property name case in the parser. Since this is the only
1959 : // case where we need to check for an own read only property we
1960 : // special case this so we do not need to do this for every property.
1961 :
1962 : FeedbackSlot slot = GetDummyCompareICSlot();
1963 : BytecodeLabel done;
1964 : builder()
1965 1674 : ->LoadLiteral(ast_string_constants()->prototype_string())
1966 : .CompareOperation(Token::Value::EQ_STRICT, key,
1967 1674 : feedback_index(slot))
1968 1674 : .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &done)
1969 1674 : .CallRuntime(Runtime::kThrowStaticPrototypeError)
1970 1674 : .Bind(&done);
1971 : }
1972 :
1973 6039 : if (property->kind() == ClassLiteral::Property::FIELD) {
1974 : DCHECK(!property->is_private());
1975 : // Initialize field's name variable with the computed name.
1976 : DCHECK_NOT_NULL(property->computed_name_var());
1977 407 : builder()->LoadAccumulatorWithRegister(key);
1978 : BuildVariableAssignment(property->computed_name_var(), Token::INIT,
1979 407 : HoleCheckMode::kElided);
1980 : }
1981 : }
1982 :
1983 304414 : if (property->kind() == ClassLiteral::Property::FIELD) {
1984 989 : if (property->is_private()) {
1985 : RegisterAllocationScope private_name_register_scope(this);
1986 582 : Register private_name = register_allocator()->NewRegister();
1987 : VisitForRegisterValue(property->key(), private_name);
1988 : builder()
1989 1163 : ->LoadLiteral(property->key()->AsLiteral()->AsRawPropertyName())
1990 582 : .StoreAccumulatorInRegister(private_name)
1991 582 : .CallRuntime(Runtime::kCreatePrivateNameSymbol, private_name);
1992 : DCHECK_NOT_NULL(property->private_name_var());
1993 : BuildVariableAssignment(property->private_name_var(), Token::INIT,
1994 582 : HoleCheckMode::kElided);
1995 : }
1996 : // We don't compute field's value here, but instead do it in the
1997 : // initializer function.
1998 989 : continue;
1999 : }
2000 :
2001 303425 : Register value = register_allocator()->GrowRegisterList(&args);
2002 : VisitForRegisterValue(property->value(), value);
2003 : }
2004 :
2005 41962 : builder()->CallRuntime(Runtime::kDefineClass, args);
2006 : }
2007 41964 : Register prototype = register_allocator()->NewRegister();
2008 41963 : builder()->StoreAccumulatorInRegister(prototype);
2009 :
2010 : // Assign to class variable.
2011 41964 : if (expr->class_variable() != nullptr) {
2012 : DCHECK(expr->class_variable()->IsStackLocal() ||
2013 : expr->class_variable()->IsContextSlot());
2014 37813 : builder()->LoadAccumulatorWithRegister(class_constructor);
2015 : BuildVariableAssignment(expr->class_variable(), Token::INIT,
2016 37814 : HoleCheckMode::kElided);
2017 : }
2018 :
2019 41962 : if (expr->instance_members_initializer_function() != nullptr) {
2020 : Register initializer =
2021 947 : VisitForRegisterValue(expr->instance_members_initializer_function());
2022 :
2023 947 : if (FunctionLiteral::NeedsHomeObject(
2024 : expr->instance_members_initializer_function())) {
2025 24 : FeedbackSlot slot = feedback_spec()->AddStoreICSlot(language_mode());
2026 24 : builder()->LoadAccumulatorWithRegister(prototype).StoreHomeObjectProperty(
2027 24 : initializer, feedback_index(slot), language_mode());
2028 : }
2029 :
2030 946 : FeedbackSlot slot = feedback_spec()->AddStoreICSlot(language_mode());
2031 : builder()
2032 947 : ->LoadAccumulatorWithRegister(initializer)
2033 946 : .StoreClassFieldsInitializer(class_constructor, feedback_index(slot))
2034 947 : .LoadAccumulatorWithRegister(class_constructor);
2035 : }
2036 :
2037 41962 : if (expr->static_fields_initializer() != nullptr) {
2038 : // TODO(gsathya): This can be optimized away to be a part of the
2039 : // class boilerplate in the future. The name argument can be
2040 : // passed to the DefineClass runtime function and have it set
2041 : // there.
2042 517 : if (name.is_valid()) {
2043 6 : Register key = register_allocator()->NewRegister();
2044 : builder()
2045 6 : ->LoadLiteral(ast_string_constants()->name_string())
2046 6 : .StoreAccumulatorInRegister(key);
2047 :
2048 : DataPropertyInLiteralFlags data_property_flags =
2049 : DataPropertyInLiteralFlag::kNoFlags;
2050 : FeedbackSlot slot =
2051 6 : feedback_spec()->AddStoreDataPropertyInLiteralICSlot();
2052 6 : builder()->LoadAccumulatorWithRegister(name).StoreDataPropertyInLiteral(
2053 6 : class_constructor, key, data_property_flags, feedback_index(slot));
2054 : }
2055 :
2056 517 : RegisterList args = register_allocator()->NewRegisterList(1);
2057 : Register initializer =
2058 517 : VisitForRegisterValue(expr->static_fields_initializer());
2059 :
2060 517 : if (FunctionLiteral::NeedsHomeObject(expr->static_fields_initializer())) {
2061 23 : FeedbackSlot slot = feedback_spec()->AddStoreICSlot(language_mode());
2062 : builder()
2063 23 : ->LoadAccumulatorWithRegister(class_constructor)
2064 : .StoreHomeObjectProperty(initializer, feedback_index(slot),
2065 23 : language_mode());
2066 : }
2067 :
2068 : builder()
2069 517 : ->MoveRegister(class_constructor, args[0])
2070 : .CallProperty(initializer, args,
2071 1034 : feedback_index(feedback_spec()->AddCallICSlot()));
2072 : }
2073 41962 : builder()->LoadAccumulatorWithRegister(class_constructor);
2074 41963 : }
2075 :
2076 41957 : void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr) {
2077 41957 : VisitClassLiteral(expr, Register::invalid_value());
2078 41960 : }
2079 :
2080 118204 : void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr, Register name) {
2081 : CurrentScope current_scope(this, expr->scope());
2082 : DCHECK_NOT_NULL(expr->scope());
2083 41965 : if (expr->scope()->NeedsContext()) {
2084 34274 : BuildNewLocalBlockContext(expr->scope());
2085 34274 : ContextScope scope(this, expr->scope());
2086 34274 : BuildClassLiteral(expr, name);
2087 : } else {
2088 7691 : BuildClassLiteral(expr, name);
2089 : }
2090 41966 : }
2091 :
2092 1464 : void BytecodeGenerator::VisitInitializeClassMembersStatement(
2093 3645 : InitializeClassMembersStatement* stmt) {
2094 1464 : RegisterList args = register_allocator()->NewRegisterList(3);
2095 2928 : Register constructor = args[0], key = args[1], value = args[2];
2096 1464 : builder()->MoveRegister(builder()->Receiver(), constructor);
2097 :
2098 7290 : for (int i = 0; i < stmt->fields()->length(); i++) {
2099 11080 : ClassLiteral::Property* property = stmt->fields()->at(i);
2100 :
2101 6543 : if (property->is_computed_name()) {
2102 : DCHECK_EQ(property->kind(), ClassLiteral::Property::FIELD);
2103 : DCHECK(!property->is_private());
2104 : Variable* var = property->computed_name_var();
2105 : DCHECK_NOT_NULL(var);
2106 : // The computed name is already evaluated and stored in a
2107 : // variable at class definition time.
2108 407 : BuildVariableLoad(var, HoleCheckMode::kElided);
2109 407 : builder()->StoreAccumulatorInRegister(key);
2110 3548 : } else if (property->kind() == ClassLiteral::Property::FIELD &&
2111 : property->is_private()) {
2112 : Variable* private_name_var = property->private_name_var();
2113 : DCHECK_NOT_NULL(private_name_var);
2114 582 : BuildVariableLoad(private_name_var, HoleCheckMode::kElided);
2115 582 : builder()->StoreAccumulatorInRegister(key);
2116 : } else {
2117 1192 : BuildLoadPropertyKey(property, key);
2118 : }
2119 :
2120 : builder()->SetExpressionAsStatementPosition(property->value());
2121 : VisitForRegisterValue(property->value(), value);
2122 2181 : VisitSetHomeObject(value, constructor, property);
2123 :
2124 : Runtime::FunctionId function_id =
2125 2181 : property->kind() == ClassLiteral::Property::FIELD &&
2126 : !property->is_private()
2127 : ? Runtime::kCreateDataProperty
2128 2181 : : Runtime::kAddPrivateField;
2129 2181 : builder()->CallRuntime(function_id, args);
2130 : }
2131 1464 : }
2132 :
2133 856 : void BytecodeGenerator::BuildInstanceMemberInitialization(Register constructor,
2134 : Register instance) {
2135 856 : RegisterList args = register_allocator()->NewRegisterList(1);
2136 856 : Register initializer = register_allocator()->NewRegister();
2137 :
2138 856 : FeedbackSlot slot = feedback_spec()->AddLoadICSlot();
2139 : BytecodeLabel done;
2140 :
2141 : builder()
2142 856 : ->LoadClassFieldsInitializer(constructor, feedback_index(slot))
2143 : // TODO(gsathya): This jump can be elided for the base
2144 : // constructor and derived constructor. This is only required
2145 : // when called from an arrow function.
2146 856 : .JumpIfUndefined(&done)
2147 856 : .StoreAccumulatorInRegister(initializer)
2148 1712 : .MoveRegister(instance, args[0])
2149 : .CallProperty(initializer, args,
2150 1712 : feedback_index(feedback_spec()->AddCallICSlot()))
2151 856 : .Bind(&done);
2152 856 : }
2153 :
2154 1734 : void BytecodeGenerator::VisitNativeFunctionLiteral(
2155 : NativeFunctionLiteral* expr) {
2156 1734 : size_t entry = builder()->AllocateDeferredConstantPoolEntry();
2157 1734 : FeedbackSlot slot = feedback_spec()->AddCreateClosureSlot();
2158 1734 : builder()->CreateClosure(entry, feedback_index(slot), NOT_TENURED);
2159 3468 : native_function_literals_.push_back(std::make_pair(expr, entry));
2160 1734 : }
2161 :
2162 0 : void BytecodeGenerator::VisitDoExpression(DoExpression* expr) {
2163 0 : VisitBlock(expr->block());
2164 0 : VisitVariableProxy(expr->result());
2165 0 : }
2166 :
2167 174222 : void BytecodeGenerator::VisitConditional(Conditional* expr) {
2168 : ConditionalControlFlowBuilder conditional_builder(
2169 29191 : builder(), block_coverage_builder_, expr);
2170 :
2171 29191 : if (expr->condition()->ToBooleanIsTrue()) {
2172 : // Generate then block unconditionally as always true.
2173 234 : conditional_builder.Then();
2174 234 : VisitForAccumulatorValue(expr->then_expression());
2175 28958 : } else if (expr->condition()->ToBooleanIsFalse()) {
2176 : // Generate else block unconditionally if it exists.
2177 112 : conditional_builder.Else();
2178 112 : VisitForAccumulatorValue(expr->else_expression());
2179 : } else {
2180 : VisitForTest(expr->condition(), conditional_builder.then_labels(),
2181 28847 : conditional_builder.else_labels(), TestFallthrough::kThen);
2182 :
2183 28846 : conditional_builder.Then();
2184 28845 : VisitForAccumulatorValue(expr->then_expression());
2185 28847 : conditional_builder.JumpToEnd();
2186 :
2187 28844 : conditional_builder.Else();
2188 28844 : VisitForAccumulatorValue(expr->else_expression());
2189 29193 : }
2190 29193 : }
2191 :
2192 29487834 : void BytecodeGenerator::VisitLiteral(Literal* expr) {
2193 20332702 : if (execution_result()->IsEffect()) return;
2194 9041466 : switch (expr->type()) {
2195 : case Literal::kSmi:
2196 6655346 : builder()->LoadLiteral(expr->AsSmiLiteral());
2197 6655301 : break;
2198 : case Literal::kHeapNumber:
2199 270918 : builder()->LoadLiteral(expr->AsNumber());
2200 270919 : break;
2201 : case Literal::kUndefined:
2202 110114 : builder()->LoadUndefined();
2203 110119 : break;
2204 : case Literal::kBoolean:
2205 322092 : builder()->LoadBoolean(expr->ToBooleanIsTrue());
2206 : execution_result()->SetResultIsBoolean();
2207 : break;
2208 : case Literal::kNull:
2209 21762 : builder()->LoadNull();
2210 21765 : break;
2211 : case Literal::kTheHole:
2212 0 : builder()->LoadTheHole();
2213 0 : break;
2214 : case Literal::kString:
2215 1650301 : builder()->LoadLiteral(expr->AsRawString());
2216 : execution_result()->SetResultIsString();
2217 : break;
2218 : case Literal::kSymbol:
2219 1981 : builder()->LoadLiteral(expr->AsSymbol());
2220 1981 : break;
2221 : case Literal::kBigInt:
2222 9011 : builder()->LoadLiteral(expr->AsBigInt());
2223 9005 : break;
2224 : }
2225 : }
2226 :
2227 89778 : void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
2228 : // Materialize a regular expression literal.
2229 : builder()->CreateRegExpLiteral(
2230 : expr->raw_pattern(), feedback_index(feedback_spec()->AddLiteralSlot()),
2231 89778 : expr->flags());
2232 44892 : }
2233 :
2234 199277 : void BytecodeGenerator::BuildCreateObjectLiteral(Register literal,
2235 : uint8_t flags, size_t entry) {
2236 199277 : if (ShouldOptimizeAsOneShot()) {
2237 113008 : RegisterList args = register_allocator()->NewRegisterList(2);
2238 : builder()
2239 113024 : ->LoadConstantPoolEntry(entry)
2240 113028 : .StoreAccumulatorInRegister(args[0])
2241 113028 : .LoadLiteral(Smi::FromInt(flags))
2242 113033 : .StoreAccumulatorInRegister(args[1])
2243 113030 : .CallRuntime(Runtime::kCreateObjectLiteralWithoutAllocationSite, args)
2244 113022 : .StoreAccumulatorInRegister(literal);
2245 :
2246 : } else {
2247 : // TODO(cbruni): Directly generate runtime call for literals we cannot
2248 : // optimize once the CreateShallowObjectLiteral stub is in sync with the TF
2249 : // optimizations.
2250 86280 : int literal_index = feedback_index(feedback_spec()->AddLiteralSlot());
2251 : builder()
2252 86281 : ->CreateObjectLiteral(entry, literal_index, flags)
2253 86281 : .StoreAccumulatorInRegister(literal);
2254 : }
2255 199307 : }
2256 :
2257 426998 : void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
2258 426419 : expr->InitDepthAndFlags();
2259 :
2260 : // Fast path for the empty object literal which doesn't need an
2261 : // AllocationSite.
2262 227185 : if (expr->IsEmptyObjectLiteral()) {
2263 : DCHECK(expr->IsFastCloningSupported());
2264 27618 : builder()->CreateEmptyObjectLiteral();
2265 254805 : return;
2266 : }
2267 :
2268 : // Deep-copy the literal boilerplate.
2269 : uint8_t flags = CreateObjectLiteralFlags::Encode(
2270 199566 : expr->ComputeFlags(), expr->IsFastCloningSupported());
2271 :
2272 199553 : Register literal = register_allocator()->NewRegister();
2273 :
2274 : // Create literal object.
2275 : int property_index = 0;
2276 : bool clone_object_spread =
2277 199530 : expr->properties()->first()->kind() == ObjectLiteral::Property::SPREAD;
2278 199530 : if (clone_object_spread) {
2279 : // Avoid the slow path for spreads in the following common cases:
2280 : // 1) `let obj = { ...source }`
2281 : // 2) `let obj = { ...source, override: 1 }`
2282 : // 3) `let obj = { ...source, ...overrides }`
2283 : RegisterAllocationScope register_scope(this);
2284 267 : Expression* property = expr->properties()->first()->value();
2285 267 : Register from_value = VisitForRegisterValue(property);
2286 :
2287 : BytecodeLabels clone_object(zone());
2288 267 : builder()->JumpIfUndefined(clone_object.New());
2289 267 : builder()->JumpIfNull(clone_object.New());
2290 267 : builder()->ToObject(from_value);
2291 :
2292 267 : clone_object.Bind(builder());
2293 267 : int clone_index = feedback_index(feedback_spec()->AddCloneObjectSlot());
2294 267 : builder()->CloneObject(from_value, flags, clone_index);
2295 267 : builder()->StoreAccumulatorInRegister(literal);
2296 267 : property_index++;
2297 : } else {
2298 : size_t entry;
2299 : // If constant properties is an empty fixed array, use a cached empty fixed
2300 : // array to ensure it's only added to the constant pool once.
2301 199263 : if (expr->properties_count() == 0) {
2302 2192 : entry = builder()->EmptyObjectBoilerplateDescriptionConstantPoolEntry();
2303 : } else {
2304 197071 : entry = builder()->AllocateDeferredConstantPoolEntry();
2305 394187 : object_literals_.push_back(std::make_pair(expr, entry));
2306 : }
2307 199296 : BuildCreateObjectLiteral(literal, flags, entry);
2308 : }
2309 :
2310 : // Store computed values into the literal.
2311 : AccessorTable accessor_table(zone());
2312 2007393 : for (; property_index < expr->properties()->length(); property_index++) {
2313 2260726 : ObjectLiteral::Property* property = expr->properties()->at(property_index);
2314 2735522 : if (property->is_computed_name()) break;
2315 3763257 : if (!clone_object_spread && property->IsCompileTimeValue()) continue;
2316 :
2317 : RegisterAllocationScope inner_register_scope(this);
2318 492262 : Literal* key = property->key()->AsLiteral();
2319 251482 : switch (property->kind()) {
2320 : case ObjectLiteral::Property::SPREAD:
2321 0 : UNREACHABLE();
2322 : case ObjectLiteral::Property::CONSTANT:
2323 : case ObjectLiteral::Property::MATERIALIZED_LITERAL:
2324 : DCHECK(clone_object_spread || !property->value()->IsCompileTimeValue());
2325 : V8_FALLTHROUGH;
2326 : case ObjectLiteral::Property::COMPUTED: {
2327 : // It is safe to use [[Put]] here because the boilerplate already
2328 : // contains computed properties with an uninitialized value.
2329 241488 : if (key->IsStringLiteral()) {
2330 : DCHECK(key->IsPropertyName());
2331 240931 : if (property->emit_store()) {
2332 : builder()->SetExpressionPosition(property->value());
2333 240785 : VisitForAccumulatorValue(property->value());
2334 240789 : FeedbackSlot slot = feedback_spec()->AddStoreOwnICSlot();
2335 240792 : if (FunctionLiteral::NeedsHomeObject(property->value())) {
2336 : RegisterAllocationScope register_scope(this);
2337 546 : Register value = register_allocator()->NewRegister();
2338 546 : builder()->StoreAccumulatorInRegister(value);
2339 : builder()->StoreNamedOwnProperty(
2340 546 : literal, key->AsRawPropertyName(), feedback_index(slot));
2341 545 : VisitSetHomeObject(value, literal, property);
2342 : } else {
2343 : builder()->StoreNamedOwnProperty(
2344 240235 : literal, key->AsRawPropertyName(), feedback_index(slot));
2345 : }
2346 : } else {
2347 : builder()->SetExpressionPosition(property->value());
2348 149 : VisitForEffect(property->value());
2349 : }
2350 : } else {
2351 554 : RegisterList args = register_allocator()->NewRegisterList(3);
2352 :
2353 554 : builder()->MoveRegister(literal, args[0]);
2354 : builder()->SetExpressionPosition(property->key());
2355 : VisitForRegisterValue(property->key(), args[1]);
2356 : builder()->SetExpressionPosition(property->value());
2357 : VisitForRegisterValue(property->value(), args[2]);
2358 554 : if (property->emit_store()) {
2359 521 : builder()->CallRuntime(Runtime::kSetKeyedProperty, args);
2360 522 : Register value = args[2];
2361 522 : VisitSetHomeObject(value, literal, property);
2362 : }
2363 : }
2364 : break;
2365 : }
2366 : case ObjectLiteral::Property::PROTOTYPE: {
2367 : // __proto__:null is handled by CreateObjectLiteral.
2368 4086 : if (property->IsNullPrototype()) break;
2369 : DCHECK(property->emit_store());
2370 : DCHECK(!property->NeedsSetFunctionName());
2371 1256 : RegisterList args = register_allocator()->NewRegisterList(2);
2372 1256 : builder()->MoveRegister(literal, args[0]);
2373 : builder()->SetExpressionPosition(property->value());
2374 : VisitForRegisterValue(property->value(), args[1]);
2375 1256 : builder()->CallRuntime(Runtime::kInternalSetPrototype, args);
2376 1256 : break;
2377 : }
2378 : case ObjectLiteral::Property::GETTER:
2379 3922 : if (property->emit_store()) {
2380 3820 : accessor_table.lookup(key)->second->getter = property;
2381 : }
2382 : break;
2383 : case ObjectLiteral::Property::SETTER:
2384 1981 : if (property->emit_store()) {
2385 1885 : accessor_table.lookup(key)->second->setter = property;
2386 : }
2387 : break;
2388 : }
2389 251489 : }
2390 :
2391 : // Define accessors, using only a single call to the runtime for each pair of
2392 : // corresponding getters and setters.
2393 404023 : for (AccessorTable::Iterator it = accessor_table.begin();
2394 : it != accessor_table.end(); ++it) {
2395 : RegisterAllocationScope inner_register_scope(this);
2396 4992 : RegisterList args = register_allocator()->NewRegisterList(5);
2397 4993 : builder()->MoveRegister(literal, args[0]);
2398 4992 : VisitForRegisterValue(it->first, args[1]);
2399 4992 : VisitObjectLiteralAccessor(literal, it->second->getter, args[2]);
2400 4991 : VisitObjectLiteralAccessor(literal, it->second->setter, args[3]);
2401 : builder()
2402 4993 : ->LoadLiteral(Smi::FromInt(NONE))
2403 4993 : .StoreAccumulatorInRegister(args[4])
2404 4993 : .CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, args);
2405 4993 : }
2406 :
2407 : // Object literals have two parts. The "static" part on the left contains no
2408 : // computed property names, and so we can compute its map ahead of time; see
2409 : // Runtime_CreateObjectLiteralBoilerplate. The second "dynamic" part starts
2410 : // with the first computed property name and continues with all properties to
2411 : // its right. All the code from above initializes the static component of the
2412 : // object literal, and arranges for the map of the result to reflect the
2413 : // static order in which the keys appear. For the dynamic properties, we
2414 : // compile them into a series of "SetOwnProperty" runtime calls. This will
2415 : // preserve insertion order.
2416 2815 : for (; property_index < expr->properties()->length(); property_index++) {
2417 3150 : ObjectLiteral::Property* property = expr->properties()->at(property_index);
2418 : RegisterAllocationScope inner_register_scope(this);
2419 :
2420 2815 : if (property->IsPrototype()) {
2421 : // __proto__:null is handled by CreateObjectLiteral.
2422 36 : if (property->IsNullPrototype()) continue;
2423 : DCHECK(property->emit_store());
2424 : DCHECK(!property->NeedsSetFunctionName());
2425 30 : RegisterList args = register_allocator()->NewRegisterList(2);
2426 30 : builder()->MoveRegister(literal, args[0]);
2427 5624 : builder()->SetExpressionPosition(property->value());
2428 : VisitForRegisterValue(property->value(), args[1]);
2429 30 : builder()->CallRuntime(Runtime::kInternalSetPrototype, args);
2430 30 : continue;
2431 : }
2432 :
2433 2779 : switch (property->kind()) {
2434 : case ObjectLiteral::Property::CONSTANT:
2435 : case ObjectLiteral::Property::COMPUTED:
2436 : case ObjectLiteral::Property::MATERIALIZED_LITERAL: {
2437 2348 : Register key = register_allocator()->NewRegister();
2438 2348 : BuildLoadPropertyKey(property, key);
2439 : builder()->SetExpressionPosition(property->value());
2440 : Register value;
2441 :
2442 : // Static class fields require the name property to be set on
2443 : // the class, meaning we can't wait until the
2444 : // StoreDataPropertyInLiteral call later to set the name.
2445 2359 : if (property->value()->IsClassLiteral() &&
2446 24 : property->value()->AsClassLiteral()->static_fields_initializer() !=
2447 : nullptr) {
2448 6 : value = register_allocator()->NewRegister();
2449 12 : VisitClassLiteral(property->value()->AsClassLiteral(), key);
2450 6 : builder()->StoreAccumulatorInRegister(value);
2451 : } else {
2452 2341 : value = VisitForRegisterValue(property->value());
2453 : }
2454 2349 : VisitSetHomeObject(value, literal, property);
2455 :
2456 : DataPropertyInLiteralFlags data_property_flags =
2457 : DataPropertyInLiteralFlag::kNoFlags;
2458 2348 : if (property->NeedsSetFunctionName()) {
2459 : data_property_flags |= DataPropertyInLiteralFlag::kSetFunctionName;
2460 : }
2461 :
2462 : FeedbackSlot slot =
2463 2349 : feedback_spec()->AddStoreDataPropertyInLiteralICSlot();
2464 : builder()
2465 2349 : ->LoadAccumulatorWithRegister(value)
2466 : .StoreDataPropertyInLiteral(literal, key, data_property_flags,
2467 2349 : feedback_index(slot));
2468 : break;
2469 : }
2470 : case ObjectLiteral::Property::GETTER:
2471 : case ObjectLiteral::Property::SETTER: {
2472 335 : RegisterList args = register_allocator()->NewRegisterList(4);
2473 335 : builder()->MoveRegister(literal, args[0]);
2474 335 : BuildLoadPropertyKey(property, args[1]);
2475 : builder()->SetExpressionPosition(property->value());
2476 : VisitForRegisterValue(property->value(), args[2]);
2477 335 : VisitSetHomeObject(args[2], literal, property);
2478 : builder()
2479 335 : ->LoadLiteral(Smi::FromInt(NONE))
2480 335 : .StoreAccumulatorInRegister(args[3]);
2481 : Runtime::FunctionId function_id =
2482 : property->kind() == ObjectLiteral::Property::GETTER
2483 : ? Runtime::kDefineGetterPropertyUnchecked
2484 335 : : Runtime::kDefineSetterPropertyUnchecked;
2485 335 : builder()->CallRuntime(function_id, args);
2486 : break;
2487 : }
2488 : case ObjectLiteral::Property::SPREAD: {
2489 96 : RegisterList args = register_allocator()->NewRegisterList(2);
2490 96 : builder()->MoveRegister(literal, args[0]);
2491 : builder()->SetExpressionPosition(property->value());
2492 : VisitForRegisterValue(property->value(), args[1]);
2493 96 : builder()->CallRuntime(Runtime::kCopyDataProperties, args);
2494 : break;
2495 : }
2496 : case ObjectLiteral::Property::PROTOTYPE:
2497 0 : UNREACHABLE(); // Handled specially above.
2498 : break;
2499 : }
2500 2780 : }
2501 :
2502 199515 : builder()->LoadAccumulatorWithRegister(literal);
2503 : }
2504 :
2505 : // Fill an array with values from an iterator, starting at a given index. It is
2506 : // guaranteed that the loop will only terminate if the iterator is exhausted, or
2507 : // if one of iterator.next(), value.done, or value.value fail.
2508 : //
2509 : // In pseudocode:
2510 : //
2511 : // loop {
2512 : // value = iterator.next()
2513 : // if (value.done) break;
2514 : // value = value.value
2515 : // array[index++] = value
2516 : // }
2517 2074 : void BytecodeGenerator::BuildFillArrayWithIterator(
2518 : IteratorRecord iterator, Register array, Register index, Register value,
2519 : FeedbackSlot next_value_slot, FeedbackSlot next_done_slot,
2520 4150 : FeedbackSlot index_slot, FeedbackSlot element_slot) {
2521 : DCHECK(array.is_valid());
2522 : DCHECK(index.is_valid());
2523 : DCHECK(value.is_valid());
2524 :
2525 2074 : LoopBuilder loop_builder(builder(), nullptr, nullptr);
2526 2074 : loop_builder.LoopHeader();
2527 :
2528 : // Call the iterator's .next() method. Break from the loop if the `done`
2529 : // property is truthy, otherwise load the value from the iterator result and
2530 : // append the argument.
2531 2075 : BuildIteratorNext(iterator, value);
2532 : builder()->LoadNamedProperty(
2533 : value, ast_string_constants()->done_string(),
2534 4150 : feedback_index(feedback_spec()->AddLoadICSlot()));
2535 : loop_builder.BreakIfTrue(ToBooleanMode::kConvertToBoolean);
2536 :
2537 2075 : loop_builder.LoopBody();
2538 : builder()
2539 : // value = value.value
2540 : ->LoadNamedProperty(value, ast_string_constants()->value_string(),
2541 2075 : feedback_index(next_value_slot))
2542 : // array[index] = value
2543 2075 : .StoreInArrayLiteral(array, index, feedback_index(element_slot))
2544 : // index++
2545 2075 : .LoadAccumulatorWithRegister(index)
2546 2075 : .UnaryOperation(Token::INC, feedback_index(index_slot))
2547 2075 : .StoreAccumulatorInRegister(index);
2548 2075 : loop_builder.BindContinueTarget();
2549 2074 : loop_builder.JumpToHeader(loop_depth_);
2550 2075 : }
2551 :
2552 356387 : void BytecodeGenerator::BuildCreateArrayLiteral(
2553 356991 : const ZonePtrList<Expression>* elements, ArrayLiteral* expr) {
2554 : RegisterAllocationScope register_scope(this);
2555 356387 : Register index = register_allocator()->NewRegister();
2556 356403 : Register array = register_allocator()->NewRegister();
2557 : SharedFeedbackSlot element_slot(feedback_spec(),
2558 356393 : FeedbackSlotKind::kStoreInArrayLiteral);
2559 : ZonePtrList<Expression>::iterator current = elements->begin();
2560 : ZonePtrList<Expression>::iterator end = elements->end();
2561 : bool is_empty = elements->is_empty();
2562 :
2563 522188 : if (!is_empty && (*current)->IsSpread()) {
2564 : // If we have a leading spread, use CreateArrayFromIterable to create
2565 : // an array from it and then add the remaining components to that array.
2566 2051 : VisitForAccumulatorValue(*current);
2567 2053 : builder()->CreateArrayFromIterable().StoreAccumulatorInRegister(array);
2568 :
2569 2052 : if (++current != end) {
2570 : // If there are remaning elements, prepare the index register that is
2571 : // used for adding those elements. The next index is the length of the
2572 : // newly created array.
2573 542 : auto length = ast_string_constants()->length_string();
2574 542 : int length_load_slot = feedback_index(feedback_spec()->AddLoadICSlot());
2575 : builder()
2576 542 : ->LoadNamedProperty(array, length, length_load_slot)
2577 542 : .StoreAccumulatorInRegister(index);
2578 : }
2579 708671 : } else if (expr != nullptr) {
2580 : // There are some elements before the first (if any) spread, and we can
2581 : // use a boilerplate when creating the initial array from those elements.
2582 :
2583 : // First, allocate a constant pool entry for the boilerplate that will
2584 : // be created during finalization, and will contain all the constant
2585 : // elements before the first spread. This also handle the empty array case
2586 : // and one-shot optimization.
2587 : uint8_t flags = CreateArrayLiteralFlags::Encode(
2588 354324 : expr->IsFastCloningSupported(), expr->ComputeFlags());
2589 354323 : bool optimize_as_one_shot = ShouldOptimizeAsOneShot();
2590 : size_t entry;
2591 354328 : if (is_empty && optimize_as_one_shot) {
2592 52271 : entry = builder()->EmptyArrayBoilerplateDescriptionConstantPoolEntry();
2593 302057 : } else if (!is_empty) {
2594 163711 : entry = builder()->AllocateDeferredConstantPoolEntry();
2595 327429 : array_literals_.push_back(std::make_pair(expr, entry));
2596 : }
2597 :
2598 354326 : if (optimize_as_one_shot) {
2599 186343 : RegisterList args = register_allocator()->NewRegisterList(2);
2600 : builder()
2601 186351 : ->LoadConstantPoolEntry(entry)
2602 186350 : .StoreAccumulatorInRegister(args[0])
2603 186356 : .LoadLiteral(Smi::FromInt(flags))
2604 186348 : .StoreAccumulatorInRegister(args[1])
2605 186341 : .CallRuntime(Runtime::kCreateArrayLiteralWithoutAllocationSite, args);
2606 167983 : } else if (is_empty) {
2607 : // Empty array literal fast-path.
2608 138346 : int literal_index = feedback_index(feedback_spec()->AddLiteralSlot());
2609 : DCHECK(expr->IsFastCloningSupported());
2610 138346 : builder()->CreateEmptyArrayLiteral(literal_index);
2611 : } else {
2612 : // Create array literal from boilerplate.
2613 29637 : int literal_index = feedback_index(feedback_spec()->AddLiteralSlot());
2614 29637 : builder()->CreateArrayLiteral(entry, literal_index, flags);
2615 : }
2616 354330 : builder()->StoreAccumulatorInRegister(array);
2617 :
2618 : // Insert the missing non-constant elements, up until the first spread
2619 : // index, into the initial array (the remaining elements will be inserted
2620 : // below).
2621 : DCHECK_EQ(current, elements->begin());
2622 : ZonePtrList<Expression>::iterator first_spread_or_end =
2623 443 : expr->first_spread_index() >= 0 ? current + expr->first_spread_index()
2624 354770 : : end;
2625 : int array_index = 0;
2626 7521950 : for (; current != first_spread_or_end; ++current, array_index++) {
2627 7167619 : Expression* subexpr = *current;
2628 : DCHECK(!subexpr->IsSpread());
2629 : // Skip the constants.
2630 7167619 : if (subexpr->IsCompileTimeValue()) continue;
2631 :
2632 : builder()
2633 219089 : ->LoadLiteral(Smi::FromInt(array_index))
2634 219096 : .StoreAccumulatorInRegister(index);
2635 219095 : VisitForAccumulatorValue(subexpr);
2636 : builder()->StoreInArrayLiteral(array, index,
2637 219105 : feedback_index(element_slot.Get()));
2638 : }
2639 :
2640 354331 : if (current != end) {
2641 : // If there are remaining elements, prepare the index register
2642 : // to store the next element, which comes from the first spread.
2643 443 : builder()->LoadLiteral(array_index).StoreAccumulatorInRegister(index);
2644 : }
2645 : } else {
2646 : // In other cases, we prepare an empty array to be filled in below.
2647 : DCHECK(!elements->is_empty());
2648 : int literal_index = feedback_index(feedback_spec()->AddLiteralSlot());
2649 : builder()
2650 20 : ->CreateEmptyArrayLiteral(literal_index)
2651 20 : .StoreAccumulatorInRegister(array);
2652 : // Prepare the index for the first element.
2653 20 : builder()->LoadLiteral(Smi::FromInt(0)).StoreAccumulatorInRegister(index);
2654 : }
2655 :
2656 : // Now build insertions for the remaining elements from current to end.
2657 356389 : SharedFeedbackSlot index_slot(feedback_spec(), FeedbackSlotKind::kBinaryOp);
2658 : SharedFeedbackSlot length_slot(
2659 : feedback_spec(), feedback_spec()->GetStoreICSlot(LanguageMode::kStrict));
2660 3079 : for (; current != end; ++current) {
2661 3079 : Expression* subexpr = *current;
2662 3079 : if (subexpr->IsSpread()) {
2663 : RegisterAllocationScope scope(this);
2664 : builder()->SetExpressionAsStatementPosition(
2665 2982 : subexpr->AsSpread()->expression());
2666 1491 : VisitForAccumulatorValue(subexpr->AsSpread()->expression());
2667 1492 : IteratorRecord iterator = BuildGetIteratorRecord(IteratorType::kNormal);
2668 :
2669 1492 : Register value = register_allocator()->NewRegister();
2670 2984 : FeedbackSlot next_value_load_slot = feedback_spec()->AddLoadICSlot();
2671 2984 : FeedbackSlot next_done_load_slot = feedback_spec()->AddLoadICSlot();
2672 1492 : FeedbackSlot real_index_slot = index_slot.Get();
2673 1492 : FeedbackSlot real_element_slot = element_slot.Get();
2674 : BuildFillArrayWithIterator(iterator, array, index, value,
2675 : next_value_load_slot, next_done_load_slot,
2676 1492 : real_index_slot, real_element_slot);
2677 1588 : } else if (!subexpr->IsTheHoleLiteral()) {
2678 : // literal[index++] = subexpr
2679 1532 : VisitForAccumulatorValue(subexpr);
2680 : builder()
2681 : ->StoreInArrayLiteral(array, index,
2682 1532 : feedback_index(element_slot.Get()))
2683 1532 : .LoadAccumulatorWithRegister(index);
2684 : // Only increase the index if we are not the last element.
2685 1532 : if (current + 1 != end) {
2686 : builder()
2687 976 : ->UnaryOperation(Token::INC, feedback_index(index_slot.Get()))
2688 976 : .StoreAccumulatorInRegister(index);
2689 : }
2690 : } else {
2691 : // literal.length = ++index
2692 : // length_slot is only used when there are holes.
2693 56 : auto length = ast_string_constants()->length_string();
2694 : builder()
2695 56 : ->LoadAccumulatorWithRegister(index)
2696 112 : .UnaryOperation(Token::INC, feedback_index(index_slot.Get()))
2697 56 : .StoreAccumulatorInRegister(index)
2698 : .StoreNamedProperty(array, length, feedback_index(length_slot.Get()),
2699 112 : LanguageMode::kStrict);
2700 : }
2701 : }
2702 :
2703 356389 : builder()->LoadAccumulatorWithRegister(array);
2704 356409 : }
2705 :
2706 356366 : void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
2707 356366 : expr->InitDepthAndFlags();
2708 356373 : BuildCreateArrayLiteral(expr->values(), expr);
2709 356367 : }
2710 :
2711 0 : void BytecodeGenerator::VisitStoreInArrayLiteral(StoreInArrayLiteral* expr) {
2712 : builder()->SetExpressionAsStatementPosition(expr);
2713 : RegisterAllocationScope register_scope(this);
2714 0 : Register array = register_allocator()->NewRegister();
2715 0 : Register index = register_allocator()->NewRegister();
2716 : VisitForRegisterValue(expr->array(), array);
2717 : VisitForRegisterValue(expr->index(), index);
2718 0 : VisitForAccumulatorValue(expr->value());
2719 : builder()->StoreInArrayLiteral(
2720 : array, index,
2721 0 : feedback_index(feedback_spec()->AddStoreInArrayLiteralICSlot()));
2722 0 : }
2723 :
2724 20064138 : void BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) {
2725 : builder()->SetExpressionPosition(proxy);
2726 6688046 : BuildVariableLoad(proxy->var(), proxy->hole_check_mode());
2727 6688253 : }
2728 :
2729 34535480 : void BytecodeGenerator::BuildVariableLoad(Variable* variable,
2730 : HoleCheckMode hole_check_mode,
2731 8197769 : TypeofMode typeof_mode) {
2732 13385548 : switch (variable->location()) {
2733 : case VariableLocation::LOCAL: {
2734 2402627 : Register source(builder()->Local(variable->index()));
2735 : // We need to load the variable into the accumulator, even when in a
2736 : // VisitForRegisterScope, in order to avoid register aliasing if
2737 : // subsequent expressions assign to the same variable.
2738 2402537 : builder()->LoadAccumulatorWithRegister(source);
2739 2402653 : if (hole_check_mode == HoleCheckMode::kRequired) {
2740 2630 : BuildThrowIfHole(variable);
2741 : }
2742 : break;
2743 : }
2744 : case VariableLocation::PARAMETER: {
2745 : Register source;
2746 3755470 : if (variable->IsReceiver()) {
2747 2378692 : source = builder()->Receiver();
2748 : } else {
2749 1376778 : source = builder()->Parameter(variable->index());
2750 : }
2751 : // We need to load the variable into the accumulator, even when in a
2752 : // VisitForRegisterScope, in order to avoid register aliasing if
2753 : // subsequent expressions assign to the same variable.
2754 3755477 : builder()->LoadAccumulatorWithRegister(source);
2755 3755468 : if (hole_check_mode == HoleCheckMode::kRequired) {
2756 2169402 : BuildThrowIfHole(variable);
2757 : }
2758 : break;
2759 : }
2760 : case VariableLocation::UNALLOCATED: {
2761 : // The global identifier "undefined" is immutable. Everything
2762 : // else could be reassigned. For performance, we do a pointer comparison
2763 : // rather than checking if the raw_name is really "undefined".
2764 5846734 : if (variable->raw_name() == ast_string_constants()->undefined_string()) {
2765 79597 : builder()->LoadUndefined();
2766 : } else {
2767 5767137 : FeedbackSlot slot = GetCachedLoadGlobalICSlot(typeof_mode, variable);
2768 : builder()->LoadGlobal(variable->raw_name(), feedback_index(slot),
2769 5767513 : typeof_mode);
2770 : }
2771 : break;
2772 : }
2773 : case VariableLocation::CONTEXT: {
2774 995990 : int depth = execution_context()->ContextChainDepth(variable->scope());
2775 : ContextScope* context = execution_context()->Previous(depth);
2776 : Register context_reg;
2777 995984 : if (context) {
2778 926370 : context_reg = context->reg();
2779 : depth = 0;
2780 : } else {
2781 69614 : context_reg = execution_context()->reg();
2782 : }
2783 :
2784 : BytecodeArrayBuilder::ContextSlotMutability immutable =
2785 : (variable->maybe_assigned() == kNotAssigned)
2786 : ? BytecodeArrayBuilder::kImmutableSlot
2787 995984 : : BytecodeArrayBuilder::kMutableSlot;
2788 :
2789 : builder()->LoadContextSlot(context_reg, variable->index(), depth,
2790 995984 : immutable);
2791 995977 : if (hole_check_mode == HoleCheckMode::kRequired) {
2792 259270 : BuildThrowIfHole(variable);
2793 : }
2794 : break;
2795 : }
2796 : case VariableLocation::LOOKUP: {
2797 383531 : switch (variable->mode()) {
2798 : case VariableMode::kDynamicLocal: {
2799 6754 : Variable* local_variable = variable->local_if_not_shadowed();
2800 : int depth =
2801 3377 : execution_context()->ContextChainDepth(local_variable->scope());
2802 : builder()->LoadLookupContextSlot(variable->raw_name(), typeof_mode,
2803 3377 : local_variable->index(), depth);
2804 3377 : if (hole_check_mode == HoleCheckMode::kRequired) {
2805 1238 : BuildThrowIfHole(variable);
2806 : }
2807 : break;
2808 : }
2809 : case VariableMode::kDynamicGlobal: {
2810 : int depth =
2811 354324 : current_scope()->ContextChainLengthUntilOutermostSloppyEval();
2812 354324 : FeedbackSlot slot = GetCachedLoadGlobalICSlot(typeof_mode, variable);
2813 : builder()->LoadLookupGlobalSlot(variable->raw_name(), typeof_mode,
2814 354326 : feedback_index(slot), depth);
2815 : break;
2816 : }
2817 : default:
2818 25830 : builder()->LoadLookupSlot(variable->raw_name(), typeof_mode);
2819 : }
2820 : break;
2821 : }
2822 : case VariableLocation::MODULE: {
2823 1360 : int depth = execution_context()->ContextChainDepth(variable->scope());
2824 1360 : builder()->LoadModuleVariable(variable->index(), depth);
2825 1360 : if (hole_check_mode == HoleCheckMode::kRequired) {
2826 848 : BuildThrowIfHole(variable);
2827 : }
2828 : break;
2829 : }
2830 : }
2831 13385772 : }
2832 :
2833 4179002 : void BytecodeGenerator::BuildVariableLoadForAccumulatorValue(
2834 : Variable* variable, HoleCheckMode hole_check_mode, TypeofMode typeof_mode) {
2835 : ValueResultScope accumulator_result(this);
2836 4179002 : BuildVariableLoad(variable, hole_check_mode, typeof_mode);
2837 4179106 : }
2838 :
2839 7318380 : void BytecodeGenerator::BuildReturn(int source_position) {
2840 2439460 : if (FLAG_trace) {
2841 : RegisterAllocationScope register_scope(this);
2842 0 : Register result = register_allocator()->NewRegister();
2843 : // Runtime returns {result} value, preserving accumulator.
2844 0 : builder()->StoreAccumulatorInRegister(result).CallRuntime(
2845 0 : Runtime::kTraceExit, result);
2846 : }
2847 2439460 : if (info()->collect_type_profile()) {
2848 68 : builder()->CollectTypeProfile(info()->literal()->return_position());
2849 : }
2850 2439460 : builder()->SetReturnPosition(source_position, info()->literal());
2851 2439551 : builder()->Return();
2852 2439605 : }
2853 :
2854 20114 : void BytecodeGenerator::BuildAsyncReturn(int source_position) {
2855 : RegisterAllocationScope register_scope(this);
2856 :
2857 14112 : if (IsAsyncGeneratorFunction(info()->literal()->kind())) {
2858 1055 : RegisterList args = register_allocator()->NewRegisterList(3);
2859 : builder()
2860 1055 : ->MoveRegister(generator_object(), args[0]) // generator
2861 1055 : .StoreAccumulatorInRegister(args[1]) // value
2862 1055 : .LoadTrue()
2863 1055 : .StoreAccumulatorInRegister(args[2]) // done
2864 1055 : .CallRuntime(Runtime::kInlineAsyncGeneratorResolve, args);
2865 : } else {
2866 : DCHECK(IsAsyncFunction(info()->literal()->kind()));
2867 6001 : RegisterList args = register_allocator()->NewRegisterList(3);
2868 : builder()
2869 6002 : ->MoveRegister(generator_object(), args[0]) // generator
2870 6002 : .StoreAccumulatorInRegister(args[1]) // value
2871 18006 : .LoadBoolean(info()->literal()->CanSuspend())
2872 6002 : .StoreAccumulatorInRegister(args[2]) // can_suspend
2873 6002 : .CallRuntime(Runtime::kInlineAsyncFunctionResolve, args);
2874 : }
2875 :
2876 7057 : BuildReturn(source_position);
2877 7057 : }
2878 :
2879 35595 : void BytecodeGenerator::BuildReThrow() { builder()->ReThrow(); }
2880 :
2881 2770252 : void BytecodeGenerator::BuildThrowIfHole(Variable* variable) {
2882 2469920 : if (variable->is_this()) {
2883 : DCHECK(variable->mode() == VariableMode::kConst);
2884 2169588 : builder()->ThrowSuperNotCalledIfHole();
2885 : } else {
2886 300332 : builder()->ThrowReferenceErrorIfHole(variable->raw_name());
2887 : }
2888 2469921 : }
2889 :
2890 39056 : void BytecodeGenerator::BuildHoleCheckForVariableAssignment(Variable* variable,
2891 : Token::Value op) {
2892 41579 : if (variable->is_this() && variable->mode() == VariableMode::kConst &&
2893 : op == Token::INIT) {
2894 : // Perform an initialization check for 'this'. 'this' variable is the
2895 : // only variable able to trigger bind operations outside the TDZ
2896 : // via 'super' calls.
2897 2523 : builder()->ThrowSuperAlreadyCalledIfNotHole();
2898 : } else {
2899 : // Perform an initialization check for let/const declared variables.
2900 : // E.g. let x = (x = 20); is not allowed.
2901 : DCHECK(IsLexicalVariableMode(variable->mode()));
2902 36533 : BuildThrowIfHole(variable);
2903 : }
2904 39056 : }
2905 :
2906 5585213 : void BytecodeGenerator::BuildVariableAssignment(
2907 12874936 : Variable* variable, Token::Value op, HoleCheckMode hole_check_mode,
2908 3362149 : LookupHoistingMode lookup_hoisting_mode) {
2909 : VariableMode mode = variable->mode();
2910 : RegisterAllocationScope assignment_register_scope(this);
2911 : BytecodeLabel end_label;
2912 5585213 : switch (variable->location()) {
2913 : case VariableLocation::PARAMETER:
2914 : case VariableLocation::LOCAL: {
2915 : Register destination;
2916 2410897 : if (VariableLocation::PARAMETER == variable->location()) {
2917 27040 : if (variable->IsReceiver()) {
2918 2367 : destination = builder()->Receiver();
2919 : } else {
2920 24673 : destination = builder()->Parameter(variable->index());
2921 : }
2922 : } else {
2923 2383857 : destination = builder()->Local(variable->index());
2924 : }
2925 :
2926 2410897 : if (hole_check_mode == HoleCheckMode::kRequired) {
2927 : // Load destination to check for hole.
2928 4932 : Register value_temp = register_allocator()->NewRegister();
2929 : builder()
2930 4932 : ->StoreAccumulatorInRegister(value_temp)
2931 4932 : .LoadAccumulatorWithRegister(destination);
2932 :
2933 4932 : BuildHoleCheckForVariableAssignment(variable, op);
2934 4932 : builder()->LoadAccumulatorWithRegister(value_temp);
2935 : }
2936 :
2937 2410897 : if (mode != VariableMode::kConst || op == Token::INIT) {
2938 2406035 : builder()->StoreAccumulatorInRegister(destination);
2939 4862 : } else if (variable->throw_on_const_assignment(language_mode())) {
2940 4829 : builder()->CallRuntime(Runtime::kThrowConstAssignError);
2941 : }
2942 : break;
2943 : }
2944 : case VariableLocation::UNALLOCATED: {
2945 1438519 : FeedbackSlot slot = GetCachedStoreGlobalICSlot(language_mode(), variable);
2946 1438572 : builder()->StoreGlobal(variable->raw_name(), feedback_index(slot));
2947 : break;
2948 : }
2949 : case VariableLocation::CONTEXT: {
2950 1663668 : int depth = execution_context()->ContextChainDepth(variable->scope());
2951 : ContextScope* context = execution_context()->Previous(depth);
2952 : Register context_reg;
2953 :
2954 1663669 : if (context) {
2955 1651639 : context_reg = context->reg();
2956 : depth = 0;
2957 : } else {
2958 12030 : context_reg = execution_context()->reg();
2959 : }
2960 :
2961 1663669 : if (hole_check_mode == HoleCheckMode::kRequired) {
2962 : // Load destination to check for hole.
2963 34055 : Register value_temp = register_allocator()->NewRegister();
2964 : builder()
2965 34055 : ->StoreAccumulatorInRegister(value_temp)
2966 : .LoadContextSlot(context_reg, variable->index(), depth,
2967 34055 : BytecodeArrayBuilder::kMutableSlot);
2968 :
2969 34055 : BuildHoleCheckForVariableAssignment(variable, op);
2970 34055 : builder()->LoadAccumulatorWithRegister(value_temp);
2971 : }
2972 :
2973 1663669 : if (mode != VariableMode::kConst || op == Token::INIT) {
2974 1635599 : builder()->StoreContextSlot(context_reg, variable->index(), depth);
2975 28070 : } else if (variable->throw_on_const_assignment(language_mode())) {
2976 28048 : builder()->CallRuntime(Runtime::kThrowConstAssignError);
2977 : }
2978 : break;
2979 : }
2980 : case VariableLocation::LOOKUP: {
2981 : builder()->StoreLookupSlot(variable->raw_name(), language_mode(),
2982 37239 : lookup_hoisting_mode);
2983 37240 : break;
2984 : }
2985 : case VariableLocation::MODULE: {
2986 : DCHECK(IsDeclaredVariableMode(mode));
2987 :
2988 34922 : if (mode == VariableMode::kConst && op != Token::INIT) {
2989 110 : builder()->CallRuntime(Runtime::kThrowConstAssignError);
2990 110 : break;
2991 : }
2992 :
2993 : // If we don't throw above, we know that we're dealing with an
2994 : // export because imports are const and we do not generate initializing
2995 : // assignments for them.
2996 : DCHECK(variable->IsExport());
2997 :
2998 34812 : int depth = execution_context()->ContextChainDepth(variable->scope());
2999 34812 : if (hole_check_mode == HoleCheckMode::kRequired) {
3000 69 : Register value_temp = register_allocator()->NewRegister();
3001 : builder()
3002 69 : ->StoreAccumulatorInRegister(value_temp)
3003 69 : .LoadModuleVariable(variable->index(), depth);
3004 69 : BuildHoleCheckForVariableAssignment(variable, op);
3005 69 : builder()->LoadAccumulatorWithRegister(value_temp);
3006 : }
3007 34812 : builder()->StoreModuleVariable(variable->index(), depth);
3008 34812 : break;
3009 : }
3010 5585408 : }
3011 5585180 : }
3012 :
3013 2336329 : void BytecodeGenerator::BuildLoadNamedProperty(const Expression* object_expr,
3014 : Register object,
3015 : const AstRawString* name) {
3016 2336329 : if (ShouldOptimizeAsOneShot()) {
3017 1248916 : builder()->LoadNamedPropertyNoFeedback(object, name);
3018 : } else {
3019 1087470 : FeedbackSlot slot = GetCachedLoadICSlot(object_expr, name);
3020 1087466 : builder()->LoadNamedProperty(object, name, feedback_index(slot));
3021 : }
3022 2336387 : }
3023 :
3024 2385525 : void BytecodeGenerator::BuildStoreNamedProperty(const Expression* object_expr,
3025 : Register object,
3026 4771078 : const AstRawString* name) {
3027 : Register value;
3028 2385525 : if (!execution_result()->IsEffect()) {
3029 8305 : value = register_allocator()->NewRegister();
3030 8305 : builder()->StoreAccumulatorInRegister(value);
3031 : }
3032 :
3033 2385525 : if (ShouldOptimizeAsOneShot()) {
3034 112869 : builder()->StoreNamedPropertyNoFeedback(object, name, language_mode());
3035 : } else {
3036 2272664 : FeedbackSlot slot = GetCachedStoreICSlot(object_expr, name);
3037 : builder()->StoreNamedProperty(object, name, feedback_index(slot),
3038 2272663 : language_mode());
3039 : }
3040 :
3041 2385553 : if (!execution_result()->IsEffect()) {
3042 8305 : builder()->LoadAccumulatorWithRegister(value);
3043 : }
3044 2385552 : }
3045 :
3046 : // static
3047 : BytecodeGenerator::AssignmentLhsData
3048 0 : BytecodeGenerator::AssignmentLhsData::NonProperty(Expression* expr) {
3049 : return AssignmentLhsData(NON_PROPERTY, expr, RegisterList(), Register(),
3050 0 : Register(), nullptr, nullptr);
3051 : }
3052 : // static
3053 : BytecodeGenerator::AssignmentLhsData
3054 0 : BytecodeGenerator::AssignmentLhsData::NamedProperty(Expression* object_expr,
3055 : Register object,
3056 : const AstRawString* name) {
3057 : return AssignmentLhsData(NAMED_PROPERTY, nullptr, RegisterList(), object,
3058 0 : Register(), object_expr, name);
3059 : }
3060 : // static
3061 : BytecodeGenerator::AssignmentLhsData
3062 0 : BytecodeGenerator::AssignmentLhsData::KeyedProperty(Register object,
3063 : Register key) {
3064 : return AssignmentLhsData(KEYED_PROPERTY, nullptr, RegisterList(), object, key,
3065 0 : nullptr, nullptr);
3066 : }
3067 : // static
3068 : BytecodeGenerator::AssignmentLhsData
3069 0 : BytecodeGenerator::AssignmentLhsData::NamedSuperProperty(
3070 : RegisterList super_property_args) {
3071 : return AssignmentLhsData(NAMED_SUPER_PROPERTY, nullptr, super_property_args,
3072 0 : Register(), Register(), nullptr, nullptr);
3073 : }
3074 : // static
3075 : BytecodeGenerator::AssignmentLhsData
3076 0 : BytecodeGenerator::AssignmentLhsData::KeyedSuperProperty(
3077 : RegisterList super_property_args) {
3078 : return AssignmentLhsData(KEYED_SUPER_PROPERTY, nullptr, super_property_args,
3079 0 : Register(), Register(), nullptr, nullptr);
3080 : }
3081 :
3082 7470875 : BytecodeGenerator::AssignmentLhsData BytecodeGenerator::PrepareAssignmentLhs(
3083 : Expression* lhs, AccumulatorPreservingMode accumulator_preserving_mode) {
3084 : // Left-hand side can only be a property, a global or a variable slot.
3085 14690684 : Property* property = lhs->AsProperty();
3086 7470912 : AssignType assign_type = Property::GetAssignType(property);
3087 :
3088 : // Evaluate LHS expression.
3089 7470878 : switch (assign_type) {
3090 : case NON_PROPERTY:
3091 : return AssignmentLhsData::NonProperty(lhs);
3092 : case NAMED_PROPERTY: {
3093 2385537 : AccumulatorPreservingScope scope(this, accumulator_preserving_mode);
3094 2385534 : Register object = VisitForRegisterValue(property->obj());
3095 : const AstRawString* name =
3096 4771101 : property->key()->AsLiteral()->AsRawPropertyName();
3097 : return AssignmentLhsData::NamedProperty(property->obj(), object, name);
3098 : }
3099 : case KEYED_PROPERTY: {
3100 31017 : AccumulatorPreservingScope scope(this, accumulator_preserving_mode);
3101 31020 : Register object = VisitForRegisterValue(property->obj());
3102 31034 : Register key = VisitForRegisterValue(property->key());
3103 : return AssignmentLhsData::KeyedProperty(object, key);
3104 : }
3105 : case NAMED_SUPER_PROPERTY: {
3106 220 : AccumulatorPreservingScope scope(this, accumulator_preserving_mode);
3107 : RegisterList super_property_args =
3108 220 : register_allocator()->NewRegisterList(4);
3109 220 : SuperPropertyReference* super_property =
3110 220 : property->obj()->AsSuperPropertyReference();
3111 220 : BuildThisVariableLoad();
3112 220 : builder()->StoreAccumulatorInRegister(super_property_args[0]);
3113 : VisitForRegisterValue(super_property->home_object(),
3114 : super_property_args[1]);
3115 : builder()
3116 440 : ->LoadLiteral(property->key()->AsLiteral()->AsRawPropertyName())
3117 220 : .StoreAccumulatorInRegister(super_property_args[2]);
3118 : return AssignmentLhsData::NamedSuperProperty(super_property_args);
3119 : }
3120 : case KEYED_SUPER_PROPERTY: {
3121 340 : AccumulatorPreservingScope scope(this, accumulator_preserving_mode);
3122 : RegisterList super_property_args =
3123 340 : register_allocator()->NewRegisterList(4);
3124 340 : SuperPropertyReference* super_property =
3125 340 : property->obj()->AsSuperPropertyReference();
3126 340 : BuildThisVariableLoad();
3127 340 : builder()->StoreAccumulatorInRegister(super_property_args[0]);
3128 : VisitForRegisterValue(super_property->home_object(),
3129 : super_property_args[1]);
3130 : VisitForRegisterValue(property->key(), super_property_args[2]);
3131 : return AssignmentLhsData::KeyedSuperProperty(super_property_args);
3132 : }
3133 : }
3134 0 : UNREACHABLE();
3135 : }
3136 :
3137 : // Build the iteration finalizer called in the finally block of an iteration
3138 : // protocol execution. This closes the iterator if needed, and suppresses any
3139 : // exception it throws if necessary.
3140 : //
3141 : // In pseudo-code, this builds:
3142 : //
3143 : // if (!done) {
3144 : // let method = iterator.return
3145 : // if (method !== null && method !== undefined) {
3146 : // if (typeof(method) !== "function") throw TypeError
3147 : // try {
3148 : // let return_val = method.call(iterator)
3149 : // if (!%IsObject(return_val)) throw TypeError
3150 : // } catch (e) {
3151 : // if (iteration_continuation != RETHROW)
3152 : // rethrow e
3153 : // }
3154 : // }
3155 : // }
3156 : //
3157 : // For async iterators, iterator.close() becomes await iterator.close().
3158 38168 : void BytecodeGenerator::BuildFinalizeIteration(
3159 : IteratorRecord iterator, Register done,
3160 114519 : Register iteration_continuation_token) {
3161 : RegisterAllocationScope register_scope(this);
3162 : BytecodeLabels iterator_is_done(zone());
3163 :
3164 : // if (!done) {
3165 38175 : builder()->LoadAccumulatorWithRegister(done).JumpIfTrue(
3166 76345 : ToBooleanMode::kConvertToBoolean, iterator_is_done.New());
3167 :
3168 : // method = iterator.return
3169 : // if (method !== null && method !== undefined) {
3170 38176 : Register method = register_allocator()->NewRegister();
3171 : builder()
3172 : ->LoadNamedProperty(iterator.object(),
3173 : ast_string_constants()->return_string(),
3174 76349 : feedback_index(feedback_spec()->AddLoadICSlot()))
3175 38175 : .StoreAccumulatorInRegister(method)
3176 76351 : .JumpIfUndefined(iterator_is_done.New())
3177 76351 : .JumpIfNull(iterator_is_done.New());
3178 :
3179 : // if (typeof(method) !== "function") throw TypeError
3180 : BytecodeLabel if_callable;
3181 : builder()
3182 38177 : ->CompareTypeOf(TestTypeOfFlags::LiteralFlag::kFunction)
3183 38175 : .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &if_callable);
3184 : {
3185 : // throw %NewTypeError(kReturnMethodNotCallable)
3186 : RegisterAllocationScope register_scope(this);
3187 38176 : RegisterList new_type_error_args = register_allocator()->NewRegisterList(2);
3188 : builder()
3189 38175 : ->LoadLiteral(Smi::FromEnum(MessageTemplate::kReturnMethodNotCallable))
3190 38176 : .StoreAccumulatorInRegister(new_type_error_args[0])
3191 76350 : .LoadLiteral(ast_string_constants()->empty_string())
3192 38177 : .StoreAccumulatorInRegister(new_type_error_args[1])
3193 38177 : .CallRuntime(Runtime::kNewTypeError, new_type_error_args)
3194 38177 : .Throw();
3195 : }
3196 38177 : builder()->Bind(&if_callable);
3197 :
3198 : {
3199 : RegisterAllocationScope register_scope(this);
3200 : BuildTryCatch(
3201 : // try {
3202 : // let return_val = method.call(iterator)
3203 : // if (!%IsObject(return_val)) throw TypeError
3204 : // }
3205 38173 : [&]() {
3206 76350 : RegisterList args(iterator.object());
3207 : builder()->CallProperty(
3208 114519 : method, args, feedback_index(feedback_spec()->AddCallICSlot()));
3209 76354 : if (iterator.type() == IteratorType::kAsync) {
3210 335 : BuildAwait();
3211 : }
3212 38178 : builder()->JumpIfJSReceiver(iterator_is_done.New());
3213 : {
3214 : // Throw this exception inside the try block so that it is
3215 : // suppressed by the iteration continuation if necessary.
3216 38177 : RegisterAllocationScope register_scope(this);
3217 38177 : Register return_result = register_allocator()->NewRegister();
3218 : builder()
3219 38177 : ->StoreAccumulatorInRegister(return_result)
3220 : .CallRuntime(Runtime::kThrowIteratorResultNotAnObject,
3221 38176 : return_result);
3222 : }
3223 38177 : },
3224 :
3225 : // catch (e) {
3226 : // if (iteration_continuation != RETHROW)
3227 : // rethrow e
3228 : // }
3229 38171 : [&](Register context) {
3230 : // Reuse context register to store the exception.
3231 38171 : Register close_exception = context;
3232 38171 : builder()->StoreAccumulatorInRegister(close_exception);
3233 :
3234 : BytecodeLabel suppress_close_exception;
3235 : builder()
3236 : ->LoadLiteral(
3237 38177 : Smi::FromInt(ControlScope::DeferredCommands::kRethrowToken))
3238 76354 : .CompareReference(iteration_continuation_token)
3239 : .JumpIfTrue(ToBooleanMode::kAlreadyBoolean,
3240 38174 : &suppress_close_exception)
3241 38177 : .LoadAccumulatorWithRegister(close_exception)
3242 38177 : .ReThrow()
3243 38175 : .Bind(&suppress_close_exception);
3244 38177 : },
3245 38177 : HandlerTable::UNCAUGHT);
3246 : }
3247 :
3248 76348 : iterator_is_done.Bind(builder());
3249 38177 : }
3250 :
3251 : // Get the default value of a destructuring target. Will mutate the
3252 : // destructuring target expression if there is a default value.
3253 : //
3254 : // For
3255 : // a = b
3256 : // in
3257 : // let {a = b} = c
3258 : // returns b and mutates the input into a.
3259 22554 : Expression* BytecodeGenerator::GetDestructuringDefaultValue(
3260 : Expression** target) {
3261 : Expression* default_value = nullptr;
3262 45109 : if ((*target)->IsAssignment()) {
3263 3778 : Assignment* default_init = (*target)->AsAssignment();
3264 : DCHECK_EQ(default_init->op(), Token::ASSIGN);
3265 : default_value = default_init->value();
3266 1889 : *target = default_init->target();
3267 : DCHECK((*target)->IsValidReferenceExpression() || (*target)->IsPattern());
3268 : }
3269 22555 : return default_value;
3270 : }
3271 :
3272 : // Convert a destructuring assignment to an array literal into a sequence of
3273 : // iterator accesses into the value being assigned (in the accumulator).
3274 : //
3275 : // [a().x, ...b] = accumulator
3276 : //
3277 : // becomes
3278 : //
3279 : // iterator = %GetIterator(accumulator)
3280 : // try {
3281 : //
3282 : // // Individual assignments read off the value from iterator.next() This gets
3283 : // // repeated per destructuring element.
3284 : // if (!done) {
3285 : // // Make sure we are considered 'done' if .next(), .done or .value fail.
3286 : // done = true
3287 : // var next_result = iterator.next()
3288 : // var tmp_done = next_result.done
3289 : // if (!tmp_done) {
3290 : // value = next_result.value
3291 : // done = false
3292 : // }
3293 : // }
3294 : // if (done)
3295 : // value = undefined
3296 : // a().x = value
3297 : //
3298 : // // A spread receives the remaining items in the iterator.
3299 : // var array = []
3300 : // var index = 0
3301 : // %FillArrayWithIterator(iterator, array, index, done)
3302 : // done = true
3303 : // b = array
3304 : //
3305 : // } catch(e) {
3306 : // iteration_continuation = RETHROW
3307 : // } finally {
3308 : // %FinalizeIteration(iterator, done, iteration_continuation)
3309 : // }
3310 2714 : void BytecodeGenerator::BuildDestructuringArrayAssignment(
3311 : ArrayLiteral* pattern, Token::Value op,
3312 2716 : LookupHoistingMode lookup_hoisting_mode) {
3313 : RegisterAllocationScope scope(this);
3314 :
3315 2714 : Register value = register_allocator()->NewRegister();
3316 2715 : builder()->StoreAccumulatorInRegister(value);
3317 :
3318 : // Store the iterator in a dedicated register so that it can be closed on
3319 : // exit, and the 'done' value in a dedicated register so that it can be
3320 : // changed and accessed independently of the iteration result.
3321 2717 : IteratorRecord iterator = BuildGetIteratorRecord(IteratorType::kNormal);
3322 2717 : Register done = register_allocator()->NewRegister();
3323 2714 : builder()->LoadFalse();
3324 2716 : builder()->StoreAccumulatorInRegister(done);
3325 :
3326 : BuildTryFinally(
3327 : // Try block.
3328 2714 : [&]() {
3329 13286 : Register next_result = register_allocator()->NewRegister();
3330 5434 : FeedbackSlot next_value_load_slot = feedback_spec()->AddLoadICSlot();
3331 5432 : FeedbackSlot next_done_load_slot = feedback_spec()->AddLoadICSlot();
3332 :
3333 582 : Spread* spread = nullptr;
3334 8956 : for (Expression* target : *pattern->values()) {
3335 4105 : if (target->IsSpread()) {
3336 582 : spread = target->AsSpread();
3337 582 : break;
3338 : }
3339 :
3340 3523 : Expression* default_value = GetDestructuringDefaultValue(&target);
3341 7044 : if (!target->IsPattern()) {
3342 3183 : builder()->SetExpressionAsStatementPosition(target);
3343 : }
3344 :
3345 3522 : AssignmentLhsData lhs_data = PrepareAssignmentLhs(target);
3346 :
3347 : // if (!done) {
3348 : // // Make sure we are considered done if .next(), .done or .value
3349 : // // fail.
3350 : // done = true
3351 : // var next_result = iterator.next()
3352 : // var tmp_done = next_result.done
3353 : // if (!tmp_done) {
3354 : // value = next_result.value
3355 : // done = false
3356 : // }
3357 : // }
3358 : // if (done)
3359 : // value = undefined
3360 3524 : BytecodeLabels is_done(zone());
3361 :
3362 3524 : builder()->LoadAccumulatorWithRegister(done);
3363 : builder()->JumpIfTrue(ToBooleanMode::kConvertToBoolean,
3364 3524 : is_done.New());
3365 :
3366 3524 : builder()->LoadTrue().StoreAccumulatorInRegister(done);
3367 3524 : BuildIteratorNext(iterator, next_result);
3368 : builder()
3369 : ->LoadNamedProperty(next_result,
3370 : ast_string_constants()->done_string(),
3371 7048 : feedback_index(next_done_load_slot))
3372 7048 : .JumpIfTrue(ToBooleanMode::kConvertToBoolean, is_done.New())
3373 : .LoadNamedProperty(next_result,
3374 : ast_string_constants()->value_string(),
3375 10572 : feedback_index(next_value_load_slot))
3376 3524 : .StoreAccumulatorInRegister(next_result)
3377 3524 : .LoadFalse()
3378 7048 : .StoreAccumulatorInRegister(done)
3379 3524 : .LoadAccumulatorWithRegister(next_result);
3380 :
3381 : // Only do the assignment if this is not a hole (i.e. 'elided').
3382 3521 : if (!target->IsTheHoleLiteral()) {
3383 : // [<pattern> = <init>] = <value>
3384 : // becomes (roughly)
3385 : // temp = <value>.next();
3386 : // <pattern> = temp === undefined ? <init> : temp;
3387 : BytecodeLabel do_assignment;
3388 3412 : if (default_value) {
3389 454 : builder()->JumpIfNotUndefined(&do_assignment);
3390 : // Since done == true => temp == undefined, jump directly to using
3391 : // the default value for that case.
3392 454 : is_done.Bind(builder());
3393 454 : VisitForAccumulatorValue(default_value);
3394 : } else {
3395 2958 : builder()->Jump(&do_assignment);
3396 2960 : is_done.Bind(builder());
3397 2961 : builder()->LoadUndefined();
3398 : }
3399 3414 : builder()->Bind(&do_assignment);
3400 :
3401 3415 : BuildAssignment(lhs_data, op, lookup_hoisting_mode);
3402 : } else {
3403 : DCHECK_EQ(lhs_data.assign_type(), NON_PROPERTY);
3404 109 : is_done.Bind(builder());
3405 : }
3406 : }
3407 :
3408 2718 : if (spread) {
3409 582 : RegisterAllocationScope scope(this);
3410 :
3411 : // A spread is turned into a loop over the remainer of the iterator.
3412 : Expression* target = spread->expression();
3413 :
3414 582 : if (!target->IsPattern()) {
3415 : builder()->SetExpressionAsStatementPosition(spread);
3416 : }
3417 :
3418 582 : AssignmentLhsData lhs_data = PrepareAssignmentLhs(target);
3419 :
3420 : // var array = [];
3421 582 : Register array = register_allocator()->NewRegister();
3422 : builder()->CreateEmptyArrayLiteral(
3423 1746 : feedback_index(feedback_spec()->AddLiteralSlot()));
3424 583 : builder()->StoreAccumulatorInRegister(array);
3425 :
3426 : // var index = 0;
3427 583 : Register index = register_allocator()->NewRegister();
3428 583 : builder()->LoadLiteral(Smi::zero());
3429 583 : builder()->StoreAccumulatorInRegister(index);
3430 :
3431 : // Set done to true, since it's guaranteed to be true by the time the
3432 : // array fill completes.
3433 583 : builder()->LoadTrue().StoreAccumulatorInRegister(done);
3434 :
3435 : // Fill the array with the iterator.
3436 : FeedbackSlot element_slot =
3437 1749 : feedback_spec()->AddStoreInArrayLiteralICSlot();
3438 1749 : FeedbackSlot index_slot = feedback_spec()->AddBinaryOpICSlot();
3439 : BuildFillArrayWithIterator(iterator, array, index, next_result,
3440 : next_value_load_slot, next_done_load_slot,
3441 583 : index_slot, element_slot);
3442 :
3443 : // Assign the array to the LHS.
3444 583 : builder()->LoadAccumulatorWithRegister(array);
3445 583 : BuildAssignment(lhs_data, op, lookup_hoisting_mode);
3446 : }
3447 2719 : },
3448 : // Finally block.
3449 : [&](Register iteration_continuation_token) {
3450 : // Finish the iteration in the finally block.
3451 2717 : BuildFinalizeIteration(iterator, done, iteration_continuation_token);
3452 : },
3453 2716 : HandlerTable::UNCAUGHT);
3454 :
3455 2716 : if (!execution_result()->IsEffect()) {
3456 266 : builder()->LoadAccumulatorWithRegister(value);
3457 2716 : }
3458 2717 : }
3459 :
3460 : // Convert a destructuring assignment to an object literal into a sequence of
3461 : // property accesses into the value being assigned (in the accumulator).
3462 : //
3463 : // { y, [x++]: a(), ...b.c } = value
3464 : //
3465 : // becomes
3466 : //
3467 : // var rest_runtime_callargs = new Array(3);
3468 : // rest_runtime_callargs[0] = value;
3469 : //
3470 : // rest_runtime_callargs[1] = value;
3471 : // y = value.y;
3472 : //
3473 : // var temp1 = %ToName(x++);
3474 : // rest_runtime_callargs[2] = temp1;
3475 : // a() = value[temp1];
3476 : //
3477 : // b.c = %CopyDataPropertiesWithExcludedProperties.call(rest_runtime_callargs);
3478 11004 : void BytecodeGenerator::BuildDestructuringObjectAssignment(
3479 29832 : ObjectLiteral* pattern, Token::Value op,
3480 11004 : LookupHoistingMode lookup_hoisting_mode) {
3481 : RegisterAllocationScope scope(this);
3482 :
3483 : // if (value === null || value === undefined)
3484 : // throw new TypeError(kNonCoercible);
3485 : //
3486 : // TODO(leszeks): Eliminate check if value is known to be non-null (e.g.
3487 : // an object literal).
3488 : BytecodeLabel is_null_or_undefined, not_null_or_undefined;
3489 : builder()
3490 11004 : ->JumpIfNull(&is_null_or_undefined)
3491 11005 : .JumpIfNotUndefined(¬_null_or_undefined);
3492 :
3493 : {
3494 11005 : builder()->Bind(&is_null_or_undefined);
3495 : builder()->SetExpressionPosition(pattern);
3496 11005 : builder()->CallRuntime(Runtime::kThrowPatternAssignmentNonCoercible);
3497 : }
3498 :
3499 : // Store the assignment value in a register.
3500 : Register value;
3501 : RegisterList rest_runtime_callargs;
3502 11004 : if (pattern->has_rest_property()) {
3503 : rest_runtime_callargs =
3504 205 : register_allocator()->NewRegisterList(pattern->properties()->length());
3505 205 : value = rest_runtime_callargs[0];
3506 : } else {
3507 10799 : value = register_allocator()->NewRegister();
3508 : }
3509 11004 : builder()->Bind(¬_null_or_undefined).StoreAccumulatorInRegister(value);
3510 :
3511 : int i = 0;
3512 79110 : for (ObjectLiteralProperty* pattern_property : *pattern->properties()) {
3513 : RegisterAllocationScope scope(this);
3514 :
3515 : // The key of the pattern becomes the key into the RHS value, and the value
3516 : // of the pattern becomes the target of the assignment.
3517 : //
3518 : // e.g. { a: b } = o becomes b = o.a
3519 19033 : Expression* pattern_key = pattern_property->key();
3520 19033 : Expression* target = pattern_property->value();
3521 19033 : Expression* default_value = GetDestructuringDefaultValue(&target);
3522 :
3523 38066 : if (!target->IsPattern()) {
3524 : builder()->SetExpressionAsStatementPosition(target);
3525 : }
3526 :
3527 : // Calculate this property's key into the assignment RHS value, additionally
3528 : // storing the key for rest_runtime_callargs if needed.
3529 : //
3530 : // The RHS is accessed using the key either by LoadNamedProperty (if
3531 : // value_name is valid) or by LoadKeyedProperty (otherwise).
3532 : const AstRawString* value_name = nullptr;
3533 : Register value_key;
3534 :
3535 19033 : if (pattern_property->kind() != ObjectLiteralProperty::Kind::SPREAD) {
3536 18828 : if (pattern_key->IsPropertyName()) {
3537 37016 : value_name = pattern_key->AsLiteral()->AsRawPropertyName();
3538 : }
3539 18828 : if (pattern->has_rest_property() || !value_name) {
3540 383 : if (pattern->has_rest_property()) {
3541 129 : value_key = rest_runtime_callargs[i + 1];
3542 : } else {
3543 254 : value_key = register_allocator()->NewRegister();
3544 : }
3545 383 : if (pattern_property->is_computed_name()) {
3546 : // { [a()]: b().x } = c
3547 : // becomes
3548 : // var tmp = a()
3549 : // b().x = c[tmp]
3550 : DCHECK(!pattern_key->IsPropertyName() ||
3551 : !pattern_key->IsNumberLiteral());
3552 270 : VisitForAccumulatorValue(pattern_key);
3553 270 : builder()->ToName(value_key);
3554 : } else {
3555 : // We only need the key for non-computed properties when it is numeric
3556 : // or is being saved for the rest_runtime_callargs.
3557 : DCHECK(
3558 : pattern_key->IsNumberLiteral() ||
3559 : (pattern->has_rest_property() && pattern_key->IsPropertyName()));
3560 : VisitForRegisterValue(pattern_key, value_key);
3561 : }
3562 : }
3563 : }
3564 :
3565 19033 : AssignmentLhsData lhs_data = PrepareAssignmentLhs(target);
3566 :
3567 : // Get the value from the RHS.
3568 19034 : if (pattern_property->kind() == ObjectLiteralProperty::Kind::SPREAD) {
3569 : DCHECK_EQ(i, pattern->properties()->length() - 1);
3570 : DCHECK(!value_key.is_valid());
3571 : DCHECK_NULL(value_name);
3572 : builder()->CallRuntime(Runtime::kCopyDataPropertiesWithExcludedProperties,
3573 205 : rest_runtime_callargs);
3574 18829 : } else if (value_name) {
3575 : builder()->LoadNamedProperty(
3576 37018 : value, value_name, feedback_index(feedback_spec()->AddLoadICSlot()));
3577 : } else {
3578 : DCHECK(value_key.is_valid());
3579 320 : builder()->LoadAccumulatorWithRegister(value_key).LoadKeyedProperty(
3580 640 : value, feedback_index(feedback_spec()->AddKeyedLoadICSlot()));
3581 : }
3582 :
3583 : // {<pattern> = <init>} = <value>
3584 : // becomes
3585 : // temp = <value>;
3586 : // <pattern> = temp === undefined ? <init> : temp;
3587 19032 : if (default_value) {
3588 : BytecodeLabel value_not_undefined;
3589 1435 : builder()->JumpIfNotUndefined(&value_not_undefined);
3590 1435 : VisitForAccumulatorValue(default_value);
3591 1435 : builder()->Bind(&value_not_undefined);
3592 : }
3593 :
3594 19032 : BuildAssignment(lhs_data, op, lookup_hoisting_mode);
3595 :
3596 19032 : i++;
3597 19032 : }
3598 :
3599 11004 : if (!execution_result()->IsEffect()) {
3600 193 : builder()->LoadAccumulatorWithRegister(value);
3601 11004 : }
3602 11004 : }
3603 :
3604 7470576 : void BytecodeGenerator::BuildAssignment(
3605 14909611 : const AssignmentLhsData& lhs_data, Token::Value op,
3606 62065 : LookupHoistingMode lookup_hoisting_mode) {
3607 : // Assign the value to the LHS.
3608 7470576 : switch (lhs_data.assign_type()) {
3609 : case NON_PROPERTY: {
3610 10106963 : if (ObjectLiteral* pattern = lhs_data.expr()->AsObjectLiteral()) {
3611 : // Split object literals into destructuring.
3612 11005 : BuildDestructuringObjectAssignment(pattern, op, lookup_hoisting_mode);
3613 5042466 : } else if (ArrayLiteral* pattern = lhs_data.expr()->AsArrayLiteral()) {
3614 : // Split object literals into destructuring.
3615 2716 : BuildDestructuringArrayAssignment(pattern, op, lookup_hoisting_mode);
3616 : } else {
3617 : DCHECK(lhs_data.expr()->IsVariableProxy());
3618 10079500 : VariableProxy* proxy = lhs_data.expr()->AsVariableProxy();
3619 : BuildVariableAssignment(proxy->var(), op, proxy->hole_check_mode(),
3620 10079500 : lookup_hoisting_mode);
3621 : }
3622 : break;
3623 : }
3624 : case NAMED_PROPERTY: {
3625 : BuildStoreNamedProperty(lhs_data.object_expr(), lhs_data.object(),
3626 2385543 : lhs_data.name());
3627 2385545 : break;
3628 : }
3629 : case KEYED_PROPERTY: {
3630 31033 : FeedbackSlot slot = feedback_spec()->AddKeyedStoreICSlot(language_mode());
3631 : Register value;
3632 31033 : if (!execution_result()->IsEffect()) {
3633 1947 : value = register_allocator()->NewRegister();
3634 1947 : builder()->StoreAccumulatorInRegister(value);
3635 : }
3636 : builder()->StoreKeyedProperty(lhs_data.object(), lhs_data.key(),
3637 31021 : feedback_index(slot), language_mode());
3638 31032 : if (!execution_result()->IsEffect()) {
3639 1948 : builder()->LoadAccumulatorWithRegister(value);
3640 : }
3641 : break;
3642 : }
3643 : case NAMED_SUPER_PROPERTY: {
3644 : builder()
3645 220 : ->StoreAccumulatorInRegister(lhs_data.super_property_args()[3])
3646 220 : .CallRuntime(Runtime::kStoreToSuper, lhs_data.super_property_args());
3647 220 : break;
3648 : }
3649 : case KEYED_SUPER_PROPERTY: {
3650 : builder()
3651 340 : ->StoreAccumulatorInRegister(lhs_data.super_property_args()[3])
3652 : .CallRuntime(Runtime::kStoreKeyedToSuper,
3653 340 : lhs_data.super_property_args());
3654 340 : break;
3655 : }
3656 : }
3657 7470549 : }
3658 :
3659 21962648 : void BytecodeGenerator::VisitAssignment(Assignment* expr) {
3660 7320922 : AssignmentLhsData lhs_data = PrepareAssignmentLhs(expr->target());
3661 :
3662 7320913 : VisitForAccumulatorValue(expr->value());
3663 :
3664 : builder()->SetExpressionPosition(expr);
3665 7320813 : BuildAssignment(lhs_data, expr->op(), expr->lookup_hoisting_mode());
3666 7320673 : }
3667 :
3668 86637 : void BytecodeGenerator::VisitCompoundAssignment(CompoundAssignment* expr) {
3669 431814 : AssignmentLhsData lhs_data = PrepareAssignmentLhs(expr->target());
3670 :
3671 : // Evaluate the value and potentially handle compound assignments by loading
3672 : // the left-hand side value and performing a binary operation.
3673 86637 : switch (lhs_data.assign_type()) {
3674 : case NON_PROPERTY: {
3675 255794 : VariableProxy* proxy = expr->target()->AsVariableProxy();
3676 85264 : BuildVariableLoad(proxy->var(), proxy->hole_check_mode());
3677 85266 : break;
3678 : }
3679 : case NAMED_PROPERTY: {
3680 507 : BuildLoadNamedProperty(lhs_data.object_expr(), lhs_data.object(),
3681 1014 : lhs_data.name());
3682 507 : break;
3683 : }
3684 : case KEYED_PROPERTY: {
3685 804 : FeedbackSlot slot = feedback_spec()->AddKeyedLoadICSlot();
3686 : builder()
3687 804 : ->LoadAccumulatorWithRegister(lhs_data.key())
3688 804 : .LoadKeyedProperty(lhs_data.object(), feedback_index(slot));
3689 : break;
3690 : }
3691 : case NAMED_SUPER_PROPERTY: {
3692 : builder()->CallRuntime(Runtime::kLoadFromSuper,
3693 20 : lhs_data.super_property_args().Truncate(3));
3694 20 : break;
3695 : }
3696 : case KEYED_SUPER_PROPERTY: {
3697 : builder()->CallRuntime(Runtime::kLoadKeyedFromSuper,
3698 40 : lhs_data.super_property_args().Truncate(3));
3699 40 : break;
3700 : }
3701 : }
3702 259912 : BinaryOperation* binop = expr->AsCompoundAssignment()->binary_operation();
3703 86637 : FeedbackSlot slot = feedback_spec()->AddBinaryOpICSlot();
3704 86636 : if (expr->value()->IsSmiLiteral()) {
3705 : builder()->BinaryOperationSmiLiteral(
3706 : binop->op(), expr->value()->AsLiteral()->AsSmiLiteral(),
3707 63198 : feedback_index(slot));
3708 : } else {
3709 65569 : Register old_value = register_allocator()->NewRegister();
3710 65568 : builder()->StoreAccumulatorInRegister(old_value);
3711 65571 : VisitForAccumulatorValue(expr->value());
3712 65572 : builder()->BinaryOperation(binop->op(), old_value, feedback_index(slot));
3713 : }
3714 :
3715 : builder()->SetExpressionPosition(expr);
3716 86638 : BuildAssignment(lhs_data, expr->op(), expr->lookup_hoisting_mode());
3717 86639 : }
3718 :
3719 : // Suspends the generator to resume at the next suspend_id, with output stored
3720 : // in the accumulator. When the generator is resumed, the sent value is loaded
3721 : // in the accumulator.
3722 23606 : void BytecodeGenerator::BuildSuspendPoint(int position) {
3723 23606 : const int suspend_id = suspend_count_++;
3724 :
3725 23606 : RegisterList registers = register_allocator()->AllLiveRegisters();
3726 :
3727 : // Save context, registers, and state. This bytecode then returns the value
3728 : // in the accumulator.
3729 : builder()->SetExpressionPosition(position);
3730 23606 : builder()->SuspendGenerator(generator_object(), registers, suspend_id);
3731 :
3732 : // Upon resume, we continue here.
3733 23607 : builder()->Bind(generator_jump_table_, suspend_id);
3734 :
3735 : // Clobbers all registers and sets the accumulator to the
3736 : // [[input_or_debug_pos]] slot of the generator object.
3737 23607 : builder()->ResumeGenerator(generator_object(), registers);
3738 23607 : }
3739 :
3740 17224 : void BytecodeGenerator::VisitYield(Yield* expr) {
3741 : builder()->SetExpressionPosition(expr);
3742 16840 : VisitForAccumulatorValue(expr->expression());
3743 :
3744 : // If this is not the first yield
3745 8420 : if (suspend_count_ > 0) {
3746 3438 : if (IsAsyncGeneratorFunction(function_kind())) {
3747 : // AsyncGenerator yields (with the exception of the initial yield)
3748 : // delegate work to the AsyncGeneratorYield stub, which Awaits the operand
3749 : // and on success, wraps the value in an IteratorResult.
3750 : RegisterAllocationScope register_scope(this);
3751 384 : RegisterList args = register_allocator()->NewRegisterList(3);
3752 : builder()
3753 384 : ->MoveRegister(generator_object(), args[0]) // generator
3754 384 : .StoreAccumulatorInRegister(args[1]) // value
3755 768 : .LoadBoolean(catch_prediction() != HandlerTable::ASYNC_AWAIT)
3756 384 : .StoreAccumulatorInRegister(args[2]) // is_caught
3757 384 : .CallRuntime(Runtime::kInlineAsyncGeneratorYield, args);
3758 : } else {
3759 : // Generator yields (with the exception of the initial yield) wrap the
3760 : // value into IteratorResult.
3761 : RegisterAllocationScope register_scope(this);
3762 3054 : RegisterList args = register_allocator()->NewRegisterList(2);
3763 : builder()
3764 3054 : ->StoreAccumulatorInRegister(args[0]) // value
3765 3054 : .LoadFalse()
3766 3054 : .StoreAccumulatorInRegister(args[1]) // done
3767 3054 : .CallRuntime(Runtime::kInlineCreateIterResultObject, args);
3768 : }
3769 : }
3770 :
3771 8420 : BuildSuspendPoint(expr->position());
3772 : // At this point, the generator has been resumed, with the received value in
3773 : // the accumulator.
3774 :
3775 : // TODO(caitp): remove once yield* desugaring for async generators is handled
3776 : // in BytecodeGenerator.
3777 8420 : if (expr->on_abrupt_resume() == Yield::kNoControl) {
3778 : DCHECK(IsAsyncGeneratorFunction(function_kind()));
3779 0 : return;
3780 : }
3781 :
3782 8420 : Register input = register_allocator()->NewRegister();
3783 8420 : builder()->StoreAccumulatorInRegister(input).CallRuntime(
3784 8420 : Runtime::kInlineGeneratorGetResumeMode, generator_object());
3785 :
3786 : // Now dispatch on resume mode.
3787 : STATIC_ASSERT(JSGeneratorObject::kNext + 1 == JSGeneratorObject::kReturn);
3788 : BytecodeJumpTable* jump_table =
3789 8420 : builder()->AllocateJumpTable(2, JSGeneratorObject::kNext);
3790 :
3791 8420 : builder()->SwitchOnSmiNoFeedback(jump_table);
3792 :
3793 : {
3794 : // Resume with throw (switch fallthrough).
3795 : // TODO(leszeks): Add a debug-only check that the accumulator is
3796 : // JSGeneratorObject::kThrow.
3797 : builder()->SetExpressionPosition(expr);
3798 8420 : builder()->LoadAccumulatorWithRegister(input);
3799 8420 : builder()->Throw();
3800 : }
3801 :
3802 : {
3803 : // Resume with return.
3804 8420 : builder()->Bind(jump_table, JSGeneratorObject::kReturn);
3805 8420 : builder()->LoadAccumulatorWithRegister(input);
3806 8420 : if (IsAsyncGeneratorFunction(function_kind())) {
3807 : execution_control()->AsyncReturnAccumulator();
3808 : } else {
3809 : execution_control()->ReturnAccumulator();
3810 : }
3811 : }
3812 :
3813 : {
3814 : // Resume with next.
3815 8420 : builder()->Bind(jump_table, JSGeneratorObject::kNext);
3816 : BuildIncrementBlockCoverageCounterIfEnabled(expr,
3817 : SourceRangeKind::kContinuation);
3818 8420 : builder()->LoadAccumulatorWithRegister(input);
3819 : }
3820 : }
3821 :
3822 : // Desugaring of (yield* iterable)
3823 : //
3824 : // do {
3825 : // const kNext = 0;
3826 : // const kReturn = 1;
3827 : // const kThrow = 2;
3828 : //
3829 : // let output; // uninitialized
3830 : //
3831 : // let iteratorRecord = GetIterator(iterable);
3832 : // let iterator = iteratorRecord.[[Iterator]];
3833 : // let next = iteratorRecord.[[NextMethod]];
3834 : // let input = undefined;
3835 : // let resumeMode = kNext;
3836 : //
3837 : // while (true) {
3838 : // // From the generator to the iterator:
3839 : // // Forward input according to resumeMode and obtain output.
3840 : // switch (resumeMode) {
3841 : // case kNext:
3842 : // output = next.[[Call]](iterator, « »);;
3843 : // break;
3844 : // case kReturn:
3845 : // let iteratorReturn = iterator.return;
3846 : // if (IS_NULL_OR_UNDEFINED(iteratorReturn)) return input;
3847 : // output = iteratorReturn.[[Call]](iterator, «input»);
3848 : // break;
3849 : // case kThrow:
3850 : // let iteratorThrow = iterator.throw;
3851 : // if (IS_NULL_OR_UNDEFINED(iteratorThrow)) {
3852 : // let iteratorReturn = iterator.return;
3853 : // if (!IS_NULL_OR_UNDEFINED(iteratorReturn)) {
3854 : // output = iteratorReturn.[[Call]](iterator, « »);
3855 : // if (IS_ASYNC_GENERATOR) output = await output;
3856 : // if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
3857 : // }
3858 : // throw MakeTypeError(kThrowMethodMissing);
3859 : // }
3860 : // output = iteratorThrow.[[Call]](iterator, «input»);
3861 : // break;
3862 : // }
3863 : //
3864 : // if (IS_ASYNC_GENERATOR) output = await output;
3865 : // if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
3866 : // if (output.done) break;
3867 : //
3868 : // // From the generator to its user:
3869 : // // Forward output, receive new input, and determine resume mode.
3870 : // if (IS_ASYNC_GENERATOR) {
3871 : // // AsyncGeneratorYield abstract operation awaits the operand before
3872 : // // resolving the promise for the current AsyncGeneratorRequest.
3873 : // %_AsyncGeneratorYield(output.value)
3874 : // }
3875 : // input = Suspend(output);
3876 : // resumeMode = %GeneratorGetResumeMode();
3877 : // }
3878 : //
3879 : // if (resumeMode === kReturn) {
3880 : // return output.value;
3881 : // }
3882 : // output.value
3883 : // }
3884 1960 : void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
3885 194 : Register output = register_allocator()->NewRegister();
3886 194 : Register resume_mode = register_allocator()->NewRegister();
3887 : IteratorType iterator_type = IsAsyncGeneratorFunction(function_kind())
3888 : ? IteratorType::kAsync
3889 194 : : IteratorType::kNormal;
3890 :
3891 : {
3892 : RegisterAllocationScope register_scope(this);
3893 194 : RegisterList iterator_and_input = register_allocator()->NewRegisterList(2);
3894 194 : VisitForAccumulatorValue(expr->expression());
3895 : IteratorRecord iterator = BuildGetIteratorRecord(
3896 : register_allocator()->NewRegister() /* next method */,
3897 194 : iterator_and_input[0], iterator_type);
3898 :
3899 194 : Register input = iterator_and_input[1];
3900 194 : builder()->LoadUndefined().StoreAccumulatorInRegister(input);
3901 : builder()
3902 194 : ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kNext))
3903 194 : .StoreAccumulatorInRegister(resume_mode);
3904 :
3905 : {
3906 : // This loop builder does not construct counters as the loop is not
3907 : // visible to the user, and we therefore neither pass the block coverage
3908 : // builder nor the expression.
3909 : //
3910 : // In addition to the normal suspend for yield*, a yield* in an async
3911 : // generator has 2 additional suspends:
3912 : // - One for awaiting the iterator result of closing the generator when
3913 : // resumed with a "throw" completion, and a throw method is not
3914 : // present on the delegated iterator
3915 : // - One for awaiting the iterator result yielded by the delegated
3916 : // iterator
3917 :
3918 194 : LoopBuilder loop(builder(), nullptr, nullptr);
3919 194 : loop.LoopHeader();
3920 :
3921 : {
3922 : BytecodeLabels after_switch(zone());
3923 : BytecodeJumpTable* switch_jump_table =
3924 194 : builder()->AllocateJumpTable(2, 1);
3925 :
3926 : builder()
3927 194 : ->LoadAccumulatorWithRegister(resume_mode)
3928 194 : .SwitchOnSmiNoFeedback(switch_jump_table);
3929 :
3930 : // Fallthrough to default case.
3931 : // TODO(tebbi): Add debug code to check that {resume_mode} really is
3932 : // {JSGeneratorObject::kNext} in this case.
3933 : STATIC_ASSERT(JSGeneratorObject::kNext == 0);
3934 : {
3935 194 : FeedbackSlot slot = feedback_spec()->AddCallICSlot();
3936 : builder()->CallProperty(iterator.next(), iterator_and_input,
3937 194 : feedback_index(slot));
3938 194 : builder()->Jump(after_switch.New());
3939 : }
3940 :
3941 : STATIC_ASSERT(JSGeneratorObject::kReturn == 1);
3942 194 : builder()->Bind(switch_jump_table, JSGeneratorObject::kReturn);
3943 : {
3944 : const AstRawString* return_string =
3945 194 : ast_string_constants()->return_string();
3946 : BytecodeLabels no_return_method(zone());
3947 :
3948 : BuildCallIteratorMethod(iterator.object(), return_string,
3949 : iterator_and_input, after_switch.New(),
3950 194 : &no_return_method);
3951 194 : no_return_method.Bind(builder());
3952 194 : builder()->LoadAccumulatorWithRegister(input);
3953 194 : if (iterator_type == IteratorType::kAsync) {
3954 : execution_control()->AsyncReturnAccumulator();
3955 : } else {
3956 : execution_control()->ReturnAccumulator();
3957 : }
3958 : }
3959 :
3960 : STATIC_ASSERT(JSGeneratorObject::kThrow == 2);
3961 194 : builder()->Bind(switch_jump_table, JSGeneratorObject::kThrow);
3962 : {
3963 : const AstRawString* throw_string =
3964 194 : ast_string_constants()->throw_string();
3965 : BytecodeLabels no_throw_method(zone());
3966 : BuildCallIteratorMethod(iterator.object(), throw_string,
3967 : iterator_and_input, after_switch.New(),
3968 194 : &no_throw_method);
3969 :
3970 : // If there is no "throw" method, perform IteratorClose, and finally
3971 : // throw a TypeError.
3972 194 : no_throw_method.Bind(builder());
3973 194 : BuildIteratorClose(iterator, expr);
3974 194 : builder()->CallRuntime(Runtime::kThrowThrowMethodMissing);
3975 : }
3976 :
3977 194 : after_switch.Bind(builder());
3978 : }
3979 :
3980 194 : if (iterator_type == IteratorType::kAsync) {
3981 : // Await the result of the method invocation.
3982 204 : BuildAwait(expr->position());
3983 : }
3984 :
3985 : // Check that output is an object.
3986 : BytecodeLabel check_if_done;
3987 : builder()
3988 194 : ->StoreAccumulatorInRegister(output)
3989 194 : .JumpIfJSReceiver(&check_if_done)
3990 194 : .CallRuntime(Runtime::kThrowIteratorResultNotAnObject, output);
3991 :
3992 194 : builder()->Bind(&check_if_done);
3993 : // Break once output.done is true.
3994 : builder()->LoadNamedProperty(
3995 : output, ast_string_constants()->done_string(),
3996 388 : feedback_index(feedback_spec()->AddLoadICSlot()));
3997 :
3998 : loop.BreakIfTrue(ToBooleanMode::kConvertToBoolean);
3999 :
4000 : // Suspend the current generator.
4001 194 : if (iterator_type == IteratorType::kNormal) {
4002 184 : builder()->LoadAccumulatorWithRegister(output);
4003 : } else {
4004 : RegisterAllocationScope register_scope(this);
4005 : DCHECK_EQ(iterator_type, IteratorType::kAsync);
4006 : // If generatorKind is async, perform AsyncGeneratorYield(output.value),
4007 : // which will await `output.value` before resolving the current
4008 : // AsyncGeneratorRequest's promise.
4009 : builder()->LoadNamedProperty(
4010 : output, ast_string_constants()->value_string(),
4011 20 : feedback_index(feedback_spec()->AddLoadICSlot()));
4012 :
4013 10 : RegisterList args = register_allocator()->NewRegisterList(3);
4014 : builder()
4015 10 : ->MoveRegister(generator_object(), args[0]) // generator
4016 10 : .StoreAccumulatorInRegister(args[1]) // value
4017 20 : .LoadBoolean(catch_prediction() != HandlerTable::ASYNC_AWAIT)
4018 10 : .StoreAccumulatorInRegister(args[2]) // is_caught
4019 10 : .CallRuntime(Runtime::kInlineAsyncGeneratorYield, args);
4020 : }
4021 :
4022 194 : BuildSuspendPoint(expr->position());
4023 194 : builder()->StoreAccumulatorInRegister(input);
4024 : builder()
4025 : ->CallRuntime(Runtime::kInlineGeneratorGetResumeMode,
4026 194 : generator_object())
4027 194 : .StoreAccumulatorInRegister(resume_mode);
4028 :
4029 194 : loop.BindContinueTarget();
4030 194 : loop.JumpToHeader(loop_depth_);
4031 194 : }
4032 : }
4033 :
4034 : // Decide if we trigger a return or if the yield* expression should just
4035 : // produce a value.
4036 : BytecodeLabel completion_is_output_value;
4037 194 : Register output_value = register_allocator()->NewRegister();
4038 : builder()
4039 : ->LoadNamedProperty(output, ast_string_constants()->value_string(),
4040 388 : feedback_index(feedback_spec()->AddLoadICSlot()))
4041 194 : .StoreAccumulatorInRegister(output_value)
4042 194 : .LoadLiteral(Smi::FromInt(JSGeneratorObject::kReturn))
4043 194 : .CompareReference(resume_mode)
4044 194 : .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &completion_is_output_value)
4045 194 : .LoadAccumulatorWithRegister(output_value);
4046 194 : if (iterator_type == IteratorType::kAsync) {
4047 : execution_control()->AsyncReturnAccumulator();
4048 : } else {
4049 : execution_control()->ReturnAccumulator();
4050 : }
4051 :
4052 194 : builder()->Bind(&completion_is_output_value);
4053 : BuildIncrementBlockCoverageCounterIfEnabled(expr,
4054 : SourceRangeKind::kContinuation);
4055 194 : builder()->LoadAccumulatorWithRegister(output_value);
4056 194 : }
4057 :
4058 29982 : void BytecodeGenerator::BuildAwait(int position) {
4059 : // Rather than HandlerTable::UNCAUGHT, async functions use
4060 : // HandlerTable::ASYNC_AWAIT to communicate that top-level exceptions are
4061 : // transformed into promise rejections. This is necessary to prevent emitting
4062 : // multiple debug events for the same uncaught exception. There is no point
4063 : // in the body of an async function where catch prediction is
4064 : // HandlerTable::UNCAUGHT.
4065 : DCHECK(catch_prediction() != HandlerTable::UNCAUGHT);
4066 :
4067 : {
4068 : // Await(operand) and suspend.
4069 : RegisterAllocationScope register_scope(this);
4070 :
4071 : Runtime::FunctionId await_intrinsic_id;
4072 14991 : if (IsAsyncGeneratorFunction(function_kind())) {
4073 : await_intrinsic_id = catch_prediction() == HandlerTable::ASYNC_AWAIT
4074 : ? Runtime::kInlineAsyncGeneratorAwaitUncaught
4075 1308 : : Runtime::kInlineAsyncGeneratorAwaitCaught;
4076 : } else {
4077 : await_intrinsic_id = catch_prediction() == HandlerTable::ASYNC_AWAIT
4078 : ? Runtime::kInlineAsyncFunctionAwaitUncaught
4079 13683 : : Runtime::kInlineAsyncFunctionAwaitCaught;
4080 : }
4081 14991 : RegisterList args = register_allocator()->NewRegisterList(2);
4082 : builder()
4083 14992 : ->MoveRegister(generator_object(), args[0])
4084 14993 : .StoreAccumulatorInRegister(args[1])
4085 14992 : .CallRuntime(await_intrinsic_id, args);
4086 : }
4087 :
4088 14992 : BuildSuspendPoint(position);
4089 :
4090 14993 : Register input = register_allocator()->NewRegister();
4091 14993 : Register resume_mode = register_allocator()->NewRegister();
4092 :
4093 : // Now dispatch on resume mode.
4094 : BytecodeLabel resume_next;
4095 : builder()
4096 14993 : ->StoreAccumulatorInRegister(input)
4097 14993 : .CallRuntime(Runtime::kInlineGeneratorGetResumeMode, generator_object())
4098 14993 : .StoreAccumulatorInRegister(resume_mode)
4099 14993 : .LoadLiteral(Smi::FromInt(JSGeneratorObject::kNext))
4100 14993 : .CompareReference(resume_mode)
4101 14993 : .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &resume_next);
4102 :
4103 : // Resume with "throw" completion (rethrow the received value).
4104 : // TODO(leszeks): Add a debug-only check that the accumulator is
4105 : // JSGeneratorObject::kThrow.
4106 14993 : builder()->LoadAccumulatorWithRegister(input).ReThrow();
4107 :
4108 : // Resume with next.
4109 14993 : builder()->Bind(&resume_next);
4110 14993 : builder()->LoadAccumulatorWithRegister(input);
4111 14993 : }
4112 :
4113 14300 : void BytecodeGenerator::VisitAwait(Await* expr) {
4114 : builder()->SetExpressionPosition(expr);
4115 14300 : VisitForAccumulatorValue(expr->expression());
4116 14300 : BuildAwait(expr->position());
4117 : BuildIncrementBlockCoverageCounterIfEnabled(expr,
4118 : SourceRangeKind::kContinuation);
4119 14301 : }
4120 :
4121 38290 : void BytecodeGenerator::VisitThrow(Throw* expr) {
4122 : AllocateBlockCoverageSlotIfEnabled(expr, SourceRangeKind::kContinuation);
4123 19145 : VisitForAccumulatorValue(expr->exception());
4124 : builder()->SetExpressionPosition(expr);
4125 19146 : builder()->Throw();
4126 19147 : }
4127 :
4128 7286967 : void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* property) {
4129 2475911 : AssignType property_kind = Property::GetAssignType(property);
4130 2475991 : switch (property_kind) {
4131 : case NON_PROPERTY:
4132 0 : UNREACHABLE();
4133 : case NAMED_PROPERTY: {
4134 : builder()->SetExpressionPosition(property);
4135 : const AstRawString* name =
4136 4671700 : property->key()->AsLiteral()->AsRawPropertyName();
4137 2335837 : BuildLoadNamedProperty(property->obj(), obj, name);
4138 2335882 : break;
4139 : }
4140 : case KEYED_PROPERTY: {
4141 139356 : VisitForAccumulatorValue(property->key());
4142 : builder()->SetExpressionPosition(property);
4143 : builder()->LoadKeyedProperty(
4144 278714 : obj, feedback_index(feedback_spec()->AddKeyedLoadICSlot()));
4145 139363 : break;
4146 : }
4147 : case NAMED_SUPER_PROPERTY:
4148 417 : VisitNamedSuperPropertyLoad(property, Register::invalid_value());
4149 417 : break;
4150 : case KEYED_SUPER_PROPERTY:
4151 360 : VisitKeyedSuperPropertyLoad(property, Register::invalid_value());
4152 360 : break;
4153 : }
4154 2476017 : }
4155 :
4156 789519 : void BytecodeGenerator::VisitPropertyLoadForRegister(Register obj,
4157 : Property* expr,
4158 : Register destination) {
4159 : ValueResultScope result_scope(this);
4160 789519 : VisitPropertyLoad(obj, expr);
4161 789580 : builder()->StoreAccumulatorInRegister(destination);
4162 789585 : }
4163 :
4164 2658 : void BytecodeGenerator::VisitNamedSuperPropertyLoad(Property* property,
4165 : Register opt_receiver_out) {
4166 : RegisterAllocationScope register_scope(this);
4167 886 : SuperPropertyReference* super_property =
4168 886 : property->obj()->AsSuperPropertyReference();
4169 886 : RegisterList args = register_allocator()->NewRegisterList(3);
4170 886 : BuildThisVariableLoad();
4171 886 : builder()->StoreAccumulatorInRegister(args[0]);
4172 : VisitForRegisterValue(super_property->home_object(), args[1]);
4173 :
4174 : builder()->SetExpressionPosition(property);
4175 : builder()
4176 1772 : ->LoadLiteral(property->key()->AsLiteral()->AsRawPropertyName())
4177 886 : .StoreAccumulatorInRegister(args[2])
4178 886 : .CallRuntime(Runtime::kLoadFromSuper, args);
4179 :
4180 886 : if (opt_receiver_out.is_valid()) {
4181 469 : builder()->MoveRegister(args[0], opt_receiver_out);
4182 886 : }
4183 886 : }
4184 :
4185 1200 : void BytecodeGenerator::VisitKeyedSuperPropertyLoad(Property* property,
4186 : Register opt_receiver_out) {
4187 : RegisterAllocationScope register_scope(this);
4188 400 : SuperPropertyReference* super_property =
4189 400 : property->obj()->AsSuperPropertyReference();
4190 400 : RegisterList args = register_allocator()->NewRegisterList(3);
4191 400 : BuildThisVariableLoad();
4192 400 : builder()->StoreAccumulatorInRegister(args[0]);
4193 : VisitForRegisterValue(super_property->home_object(), args[1]);
4194 : VisitForRegisterValue(property->key(), args[2]);
4195 :
4196 : builder()->SetExpressionPosition(property);
4197 400 : builder()->CallRuntime(Runtime::kLoadKeyedFromSuper, args);
4198 :
4199 400 : if (opt_receiver_out.is_valid()) {
4200 40 : builder()->MoveRegister(args[0], opt_receiver_out);
4201 400 : }
4202 400 : }
4203 :
4204 3372021 : void BytecodeGenerator::VisitProperty(Property* expr) {
4205 1686391 : AssignType property_kind = Property::GetAssignType(expr);
4206 1686407 : if (property_kind != NAMED_SUPER_PROPERTY &&
4207 : property_kind != KEYED_SUPER_PROPERTY) {
4208 1685630 : Register obj = VisitForRegisterValue(expr->obj());
4209 1685689 : VisitPropertyLoad(obj, expr);
4210 : } else {
4211 777 : VisitPropertyLoad(Register::invalid_value(), expr);
4212 : }
4213 1686445 : }
4214 :
4215 0 : void BytecodeGenerator::VisitResolvedProperty(ResolvedProperty* expr) {
4216 : // Handled by VisitCall().
4217 0 : UNREACHABLE();
4218 : }
4219 :
4220 16663868 : void BytecodeGenerator::VisitArguments(const ZonePtrList<Expression>* args,
4221 : RegisterList* arg_regs) {
4222 : // Visit arguments.
4223 22720192 : for (int i = 0; i < static_cast<int>(args->length()); i++) {
4224 6056283 : VisitAndPushIntoRegisterList(args->at(i), arg_regs);
4225 : }
4226 5303813 : }
4227 :
4228 10320522 : void BytecodeGenerator::VisitCall(Call* expr) {
4229 : Expression* callee_expr = expr->expression();
4230 5109610 : Call::CallType call_type = expr->GetCallType();
4231 :
4232 5109612 : if (call_type == Call::SUPER_CALL) {
4233 5115010 : return VisitCallSuper(expr);
4234 : }
4235 :
4236 : // Grow the args list as we visit receiver / arguments to avoid allocating all
4237 : // the registers up-front. Otherwise these registers are unavailable during
4238 : // receiver / argument visiting and we can end up with memory leaks due to
4239 : // registers keeping objects alive.
4240 5104323 : Register callee = register_allocator()->NewRegister();
4241 5104309 : RegisterList args = register_allocator()->NewGrowableRegisterList();
4242 :
4243 : bool implicit_undefined_receiver = false;
4244 : // When a call contains a spread, a Call AST node is only created if there is
4245 : // exactly one spread, and it is the last argument.
4246 5104309 : bool is_spread_call = expr->only_last_arg_is_spread();
4247 5104269 : bool optimize_as_one_shot = ShouldOptimizeAsOneShot();
4248 :
4249 : // TODO(petermarshall): We have a lot of call bytecodes that are very similar,
4250 : // see if we can reduce the number by adding a separate argument which
4251 : // specifies the call type (e.g., property, spread, tailcall, etc.).
4252 :
4253 : // Prepare the callee and the receiver to the function call. This depends on
4254 : // the semantics of the underlying call type.
4255 5104280 : switch (call_type) {
4256 : case Call::NAMED_PROPERTY_CALL:
4257 : case Call::KEYED_PROPERTY_CALL: {
4258 1579047 : Property* property = callee_expr->AsProperty();
4259 789530 : VisitAndPushIntoRegisterList(property->obj(), &args);
4260 789567 : VisitPropertyLoadForRegister(args.last_register(), property, callee);
4261 789553 : break;
4262 : }
4263 : case Call::RESOLVED_PROPERTY_CALL: {
4264 0 : ResolvedProperty* resolved = callee_expr->AsResolvedProperty();
4265 0 : VisitAndPushIntoRegisterList(resolved->object(), &args);
4266 0 : VisitForAccumulatorValue(resolved->property());
4267 0 : builder()->StoreAccumulatorInRegister(callee);
4268 0 : break;
4269 : }
4270 : case Call::GLOBAL_CALL: {
4271 : // Receiver is undefined for global calls.
4272 3789571 : if (!is_spread_call && !optimize_as_one_shot) {
4273 : implicit_undefined_receiver = true;
4274 : } else {
4275 : // TODO(leszeks): There's no special bytecode for tail calls or spread
4276 : // calls with an undefined receiver, so just push undefined ourselves.
4277 687768 : BuildPushUndefinedIntoRegisterList(&args);
4278 : }
4279 : // Load callee as a global variable.
4280 11368936 : VariableProxy* proxy = callee_expr->AsVariableProxy();
4281 : BuildVariableLoadForAccumulatorValue(proxy->var(),
4282 3789629 : proxy->hole_check_mode());
4283 3789640 : builder()->StoreAccumulatorInRegister(callee);
4284 3789672 : break;
4285 : }
4286 : case Call::WITH_CALL: {
4287 4522 : Register receiver = register_allocator()->GrowRegisterList(&args);
4288 : DCHECK(callee_expr->AsVariableProxy()->var()->IsLookupSlot());
4289 : {
4290 : RegisterAllocationScope inner_register_scope(this);
4291 4522 : Register name = register_allocator()->NewRegister();
4292 :
4293 : // Call %LoadLookupSlotForCall to get the callee and receiver.
4294 4523 : RegisterList result_pair = register_allocator()->NewRegisterList(2);
4295 13566 : Variable* variable = callee_expr->AsVariableProxy()->var();
4296 : builder()
4297 4522 : ->LoadLiteral(variable->raw_name())
4298 4523 : .StoreAccumulatorInRegister(name)
4299 : .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, name,
4300 4523 : result_pair)
4301 4523 : .MoveRegister(result_pair[0], callee)
4302 4523 : .MoveRegister(result_pair[1], receiver);
4303 : }
4304 : break;
4305 : }
4306 : case Call::OTHER_CALL: {
4307 : // Receiver is undefined for other calls.
4308 520192 : if (!is_spread_call && !optimize_as_one_shot) {
4309 : implicit_undefined_receiver = true;
4310 : } else {
4311 : // TODO(leszeks): There's no special bytecode for tail calls or spread
4312 : // calls with an undefined receiver, so just push undefined ourselves.
4313 222196 : BuildPushUndefinedIntoRegisterList(&args);
4314 : }
4315 : VisitForRegisterValue(callee_expr, callee);
4316 : break;
4317 : }
4318 : case Call::NAMED_SUPER_PROPERTY_CALL: {
4319 469 : Register receiver = register_allocator()->GrowRegisterList(&args);
4320 469 : Property* property = callee_expr->AsProperty();
4321 469 : VisitNamedSuperPropertyLoad(property, receiver);
4322 469 : builder()->StoreAccumulatorInRegister(callee);
4323 : break;
4324 : }
4325 : case Call::KEYED_SUPER_PROPERTY_CALL: {
4326 40 : Register receiver = register_allocator()->GrowRegisterList(&args);
4327 40 : Property* property = callee_expr->AsProperty();
4328 40 : VisitKeyedSuperPropertyLoad(property, receiver);
4329 40 : builder()->StoreAccumulatorInRegister(callee);
4330 : break;
4331 : }
4332 : case Call::SUPER_CALL:
4333 0 : UNREACHABLE();
4334 : break;
4335 : }
4336 :
4337 : // Evaluate all arguments to the function call and store in sequential args
4338 : // registers.
4339 5104460 : VisitArguments(expr->arguments(), &args);
4340 5104370 : int reciever_arg_count = implicit_undefined_receiver ? 0 : 1;
4341 5104370 : CHECK_EQ(reciever_arg_count + expr->arguments()->length(),
4342 : args.register_count());
4343 :
4344 : // Resolve callee for a potential direct eval call. This block will mutate the
4345 : // callee value.
4346 5104370 : if (expr->is_possibly_eval() && expr->arguments()->length() > 0) {
4347 : RegisterAllocationScope inner_register_scope(this);
4348 : // Set up arguments for ResolvePossiblyDirectEval by copying callee, source
4349 : // strings and function closure, and loading language and
4350 : // position.
4351 213084 : Register first_arg = args[reciever_arg_count];
4352 106542 : RegisterList runtime_call_args = register_allocator()->NewRegisterList(6);
4353 : builder()
4354 106543 : ->MoveRegister(callee, runtime_call_args[0])
4355 106543 : .MoveRegister(first_arg, runtime_call_args[1])
4356 213085 : .MoveRegister(Register::function_closure(), runtime_call_args[2])
4357 106543 : .LoadLiteral(Smi::FromEnum(language_mode()))
4358 106542 : .StoreAccumulatorInRegister(runtime_call_args[3])
4359 213085 : .LoadLiteral(Smi::FromInt(current_scope()->start_position()))
4360 106541 : .StoreAccumulatorInRegister(runtime_call_args[4])
4361 213083 : .LoadLiteral(Smi::FromInt(expr->position()))
4362 106543 : .StoreAccumulatorInRegister(runtime_call_args[5]);
4363 :
4364 : // Call ResolvePossiblyDirectEval and modify the callee.
4365 : builder()
4366 106542 : ->CallRuntime(Runtime::kResolvePossiblyDirectEval, runtime_call_args)
4367 106542 : .StoreAccumulatorInRegister(callee);
4368 : }
4369 :
4370 : builder()->SetExpressionPosition(expr);
4371 :
4372 5104370 : if (is_spread_call) {
4373 : DCHECK(!implicit_undefined_receiver);
4374 : builder()->CallWithSpread(callee, args,
4375 3418 : feedback_index(feedback_spec()->AddCallICSlot()));
4376 5102661 : } else if (optimize_as_one_shot) {
4377 : DCHECK(!implicit_undefined_receiver);
4378 1215070 : builder()->CallNoFeedback(callee, args);
4379 7775182 : } else if (call_type == Call::NAMED_PROPERTY_CALL ||
4380 3887591 : call_type == Call::KEYED_PROPERTY_CALL ||
4381 3887591 : call_type == Call::RESOLVED_PROPERTY_CALL) {
4382 : DCHECK(!implicit_undefined_receiver);
4383 : builder()->CallProperty(callee, args,
4384 969155 : feedback_index(feedback_spec()->AddCallICSlot()));
4385 3403018 : } else if (implicit_undefined_receiver) {
4386 : builder()->CallUndefinedReceiver(
4387 6799503 : callee, args, feedback_index(feedback_spec()->AddCallICSlot()));
4388 : } else {
4389 : builder()->CallAnyReceiver(
4390 6542 : callee, args, feedback_index(feedback_spec()->AddCallICSlot()));
4391 : }
4392 : }
4393 :
4394 23680 : void BytecodeGenerator::VisitCallSuper(Call* expr) {
4395 : RegisterAllocationScope register_scope(this);
4396 15867 : SuperCallReference* super = expr->expression()->AsSuperCallReference();
4397 11199 : const ZonePtrList<Expression>* args = expr->arguments();
4398 :
4399 : int first_spread_index = 0;
4400 11820 : for (; first_spread_index < args->length(); first_spread_index++) {
4401 9184 : if (args->at(first_spread_index)->IsSpread()) break;
4402 : }
4403 :
4404 : // Prepare the constructor to the super call.
4405 5289 : Register this_function = VisitForRegisterValue(super->this_function_var());
4406 5290 : Register constructor = register_allocator()->NewRegister();
4407 : builder()
4408 5290 : ->LoadAccumulatorWithRegister(this_function)
4409 5290 : .GetSuperConstructor(constructor);
4410 :
4411 5289 : if (first_spread_index < expr->arguments()->length() - 1) {
4412 : // We rewrite something like
4413 : // super(1, ...x, 2)
4414 : // to
4415 : // %reflect_construct(constructor, [1, ...x, 2], new_target)
4416 : // That is, we implement (non-last-arg) spreads in super calls via our
4417 : // mechanism for spreads in array literals.
4418 :
4419 : // First generate the array containing all arguments.
4420 30 : BuildCreateArrayLiteral(args, nullptr);
4421 :
4422 : // Now pass that array to %reflect_construct.
4423 30 : RegisterList construct_args = register_allocator()->NewRegisterList(3);
4424 30 : builder()->StoreAccumulatorInRegister(construct_args[1]);
4425 30 : builder()->MoveRegister(constructor, construct_args[0]);
4426 : VisitForRegisterValue(super->new_target_var(), construct_args[2]);
4427 30 : builder()->CallJSRuntime(Context::REFLECT_CONSTRUCT_INDEX, construct_args);
4428 : } else {
4429 5259 : RegisterList args_regs = register_allocator()->NewGrowableRegisterList();
4430 5259 : VisitArguments(args, &args_regs);
4431 : // The new target is loaded into the accumulator from the
4432 : // {new.target} variable.
4433 5259 : VisitForAccumulatorValue(super->new_target_var());
4434 : builder()->SetExpressionPosition(expr);
4435 :
4436 5260 : int feedback_slot_index = feedback_index(feedback_spec()->AddCallICSlot());
4437 :
4438 5260 : if (first_spread_index == expr->arguments()->length() - 1) {
4439 : builder()->ConstructWithSpread(constructor, args_regs,
4440 3942 : feedback_slot_index);
4441 : } else {
4442 : DCHECK_EQ(first_spread_index, expr->arguments()->length());
4443 : // Call construct.
4444 : // TODO(turbofan): For now we do gather feedback on super constructor
4445 : // calls, utilizing the existing machinery to inline the actual call
4446 : // target and the JSCreate for the implicit receiver allocation. This
4447 : // is not an ideal solution for super constructor calls, but it gets
4448 : // the job done for now. In the long run we might want to revisit this
4449 : // and come up with a better way.
4450 1318 : builder()->Construct(constructor, args_regs, feedback_slot_index);
4451 : }
4452 : }
4453 :
4454 : // Explicit calls to the super constructor using super() perform an
4455 : // implicit binding assignment to the 'this' variable.
4456 : //
4457 : // Default constructors don't need have to do the assignment because
4458 : // 'this' isn't accessed in default constructors.
4459 10580 : if (!IsDefaultConstructor(info()->literal()->kind())) {
4460 2523 : Variable* var = closure_scope()->GetReceiverScope()->receiver();
4461 2523 : BuildVariableAssignment(var, Token::INIT, HoleCheckMode::kRequired);
4462 : }
4463 :
4464 : // The derived constructor has the correct bit set always, so we
4465 : // don't emit code to load and call the initializer if not
4466 : // required.
4467 : //
4468 : // For the arrow function or eval case, we always emit code to load
4469 : // and call the initializer.
4470 : //
4471 : // TODO(gsathya): In the future, we could tag nested arrow functions
4472 : // or eval with the correct bit so that we do the load conditionally
4473 : // if required.
4474 15673 : if (info()->literal()->requires_instance_members_initializer() ||
4475 5094 : !IsDerivedConstructor(info()->literal()->kind())) {
4476 326 : Register instance = register_allocator()->NewRegister();
4477 326 : builder()->StoreAccumulatorInRegister(instance);
4478 326 : BuildInstanceMemberInitialization(this_function, instance);
4479 326 : builder()->LoadAccumulatorWithRegister(instance);
4480 5290 : }
4481 5290 : }
4482 :
4483 137945 : void BytecodeGenerator::VisitCallNew(CallNew* expr) {
4484 137945 : Register constructor = VisitForRegisterValue(expr->expression());
4485 137964 : RegisterList args = register_allocator()->NewGrowableRegisterList();
4486 137964 : VisitArguments(expr->arguments(), &args);
4487 :
4488 : // The accumulator holds new target which is the same as the
4489 : // constructor for CallNew.
4490 : builder()->SetExpressionPosition(expr);
4491 137956 : builder()->LoadAccumulatorWithRegister(constructor);
4492 :
4493 137963 : int feedback_slot_index = feedback_index(feedback_spec()->AddCallICSlot());
4494 137965 : if (expr->only_last_arg_is_spread()) {
4495 171 : builder()->ConstructWithSpread(constructor, args, feedback_slot_index);
4496 : } else {
4497 137789 : builder()->Construct(constructor, args, feedback_slot_index);
4498 : }
4499 137969 : }
4500 :
4501 112418 : void BytecodeGenerator::VisitCallRuntime(CallRuntime* expr) {
4502 56198 : if (expr->is_jsruntime()) {
4503 362 : RegisterList args = register_allocator()->NewGrowableRegisterList();
4504 362 : VisitArguments(expr->arguments(), &args);
4505 362 : builder()->CallJSRuntime(expr->context_index(), args);
4506 : } else {
4507 : // Evaluate all arguments to the runtime call.
4508 55836 : RegisterList args = register_allocator()->NewGrowableRegisterList();
4509 55836 : VisitArguments(expr->arguments(), &args);
4510 55858 : Runtime::FunctionId function_id = expr->function()->function_id;
4511 55858 : builder()->CallRuntime(function_id, args);
4512 : }
4513 56226 : }
4514 :
4515 3335 : void BytecodeGenerator::VisitVoid(UnaryOperation* expr) {
4516 3335 : VisitForEffect(expr->expression());
4517 3335 : builder()->LoadUndefined();
4518 0 : }
4519 :
4520 162413 : void BytecodeGenerator::VisitForTypeOfValue(Expression* expr) {
4521 162415 : if (expr->IsVariableProxy()) {
4522 : // Typeof does not throw a reference error on global variables, hence we
4523 : // perform a non-contextual load in case the operand is a variable proxy.
4524 470289 : VariableProxy* proxy = expr->AsVariableProxy();
4525 : BuildVariableLoadForAccumulatorValue(proxy->var(), proxy->hole_check_mode(),
4526 156763 : INSIDE_TYPEOF);
4527 : } else {
4528 5652 : VisitForAccumulatorValue(expr);
4529 : }
4530 162416 : }
4531 :
4532 63024 : void BytecodeGenerator::VisitTypeOf(UnaryOperation* expr) {
4533 63024 : VisitForTypeOfValue(expr->expression());
4534 63025 : builder()->TypeOf();
4535 0 : }
4536 :
4537 572823 : void BytecodeGenerator::VisitNot(UnaryOperation* expr) {
4538 271731 : if (execution_result()->IsEffect()) {
4539 154 : VisitForEffect(expr->expression());
4540 271577 : } else if (execution_result()->IsTest()) {
4541 : // No actual logical negation happening, we just swap the control flow, by
4542 : // swapping the target labels and the fallthrough branch, and visit in the
4543 : // same test result context.
4544 : TestResultScope* test_result = execution_result()->AsTest();
4545 : test_result->InvertControlFlow();
4546 242216 : VisitInSameTestExecutionScope(expr->expression());
4547 : } else {
4548 29361 : TypeHint type_hint = VisitForAccumulatorValue(expr->expression());
4549 29361 : builder()->LogicalNot(ToBooleanModeFromTypeHint(type_hint));
4550 : // Always returns a boolean value.
4551 : execution_result()->SetResultIsBoolean();
4552 : }
4553 271732 : }
4554 :
4555 537768 : void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
4556 408594 : switch (expr->op()) {
4557 : case Token::Value::NOT:
4558 271733 : VisitNot(expr);
4559 271731 : break;
4560 : case Token::Value::TYPEOF:
4561 : VisitTypeOf(expr);
4562 : break;
4563 : case Token::Value::VOID:
4564 : VisitVoid(expr);
4565 : break;
4566 : case Token::Value::DELETE:
4567 5914 : VisitDelete(expr);
4568 5916 : break;
4569 : case Token::Value::ADD:
4570 : case Token::Value::SUB:
4571 : case Token::Value::BIT_NOT:
4572 64588 : VisitForAccumulatorValue(expr->expression());
4573 : builder()->SetExpressionPosition(expr);
4574 : builder()->UnaryOperation(
4575 129172 : expr->op(), feedback_index(feedback_spec()->AddBinaryOpICSlot()));
4576 64586 : break;
4577 : default:
4578 0 : UNREACHABLE();
4579 : }
4580 408593 : }
4581 :
4582 5915 : void BytecodeGenerator::VisitDelete(UnaryOperation* unary) {
4583 : Expression* expr = unary->expression();
4584 5917 : if (expr->IsProperty()) {
4585 : // Delete of an object property is allowed both in sloppy
4586 : // and strict modes.
4587 13134 : Property* property = expr->AsProperty();
4588 4378 : Register object = VisitForRegisterValue(property->obj());
4589 4378 : VisitForAccumulatorValue(property->key());
4590 4378 : builder()->Delete(object, language_mode());
4591 2349 : } else if (expr->IsVariableProxy() &&
4592 1620 : !expr->AsVariableProxy()->is_new_target()) {
4593 : // Delete of an unqualified identifier is allowed in sloppy mode but is
4594 : // not allowed in strict mode.
4595 : DCHECK(is_sloppy(language_mode()));
4596 2228 : Variable* variable = expr->AsVariableProxy()->var();
4597 798 : switch (variable->location()) {
4598 : case VariableLocation::PARAMETER:
4599 : case VariableLocation::LOCAL:
4600 : case VariableLocation::CONTEXT: {
4601 : // Deleting local var/let/const, context variables, and arguments
4602 : // does not have any effect.
4603 166 : builder()->LoadFalse();
4604 166 : break;
4605 : }
4606 : case VariableLocation::UNALLOCATED:
4607 : // TODO(adamk): Falling through to the runtime results in correct
4608 : // behavior, but does unnecessary context-walking (since scope
4609 : // analysis has already proven that the variable doesn't exist in
4610 : // any non-global scope). Consider adding a DeleteGlobal bytecode
4611 : // that knows how to deal with ScriptContexts as well as global
4612 : // object properties.
4613 : case VariableLocation::LOOKUP: {
4614 632 : Register name_reg = register_allocator()->NewRegister();
4615 : builder()
4616 632 : ->LoadLiteral(variable->raw_name())
4617 632 : .StoreAccumulatorInRegister(name_reg)
4618 632 : .CallRuntime(Runtime::kDeleteLookupSlot, name_reg);
4619 : break;
4620 : }
4621 : default:
4622 0 : UNREACHABLE();
4623 : }
4624 : } else {
4625 : // Delete of an unresolvable reference, new.target, and this returns true.
4626 741 : VisitForEffect(expr);
4627 741 : builder()->LoadTrue();
4628 : }
4629 5917 : }
4630 :
4631 1378836 : void BytecodeGenerator::VisitCountOperation(CountOperation* expr) {
4632 : DCHECK(expr->expression()->IsValidReferenceExpression());
4633 :
4634 : // Left-hand side can only be a property, a global or a variable slot.
4635 265647 : Property* property = expr->expression()->AsProperty();
4636 240429 : AssignType assign_type = Property::GetAssignType(property);
4637 :
4638 425158 : bool is_postfix = expr->is_postfix() && !execution_result()->IsEffect();
4639 :
4640 : // Evaluate LHS expression and get old value.
4641 : Register object, key, old_value;
4642 : RegisterList super_property_args;
4643 : const AstRawString* name;
4644 240438 : switch (assign_type) {
4645 : case NON_PROPERTY: {
4646 698004 : VariableProxy* proxy = expr->expression()->AsVariableProxy();
4647 : BuildVariableLoadForAccumulatorValue(proxy->var(),
4648 232668 : proxy->hole_check_mode());
4649 232704 : break;
4650 : }
4651 : case NAMED_PROPERTY: {
4652 4865 : object = VisitForRegisterValue(property->obj());
4653 9730 : name = property->key()->AsLiteral()->AsRawPropertyName();
4654 : builder()->LoadNamedProperty(
4655 : object, name,
4656 4865 : feedback_index(GetCachedLoadICSlot(property->obj(), name)));
4657 4865 : break;
4658 : }
4659 : case KEYED_PROPERTY: {
4660 2749 : object = VisitForRegisterValue(property->obj());
4661 : // Use visit for accumulator here since we need the key in the accumulator
4662 : // for the LoadKeyedProperty.
4663 2749 : key = register_allocator()->NewRegister();
4664 2749 : VisitForAccumulatorValue(property->key());
4665 2749 : builder()->StoreAccumulatorInRegister(key).LoadKeyedProperty(
4666 5498 : object, feedback_index(feedback_spec()->AddKeyedLoadICSlot()));
4667 2749 : break;
4668 : }
4669 : case NAMED_SUPER_PROPERTY: {
4670 45 : super_property_args = register_allocator()->NewRegisterList(4);
4671 45 : RegisterList load_super_args = super_property_args.Truncate(3);
4672 45 : SuperPropertyReference* super_property =
4673 45 : property->obj()->AsSuperPropertyReference();
4674 45 : BuildThisVariableLoad();
4675 45 : builder()->StoreAccumulatorInRegister(load_super_args[0]);
4676 : VisitForRegisterValue(super_property->home_object(), load_super_args[1]);
4677 : builder()
4678 90 : ->LoadLiteral(property->key()->AsLiteral()->AsRawPropertyName())
4679 45 : .StoreAccumulatorInRegister(load_super_args[2])
4680 45 : .CallRuntime(Runtime::kLoadFromSuper, load_super_args);
4681 : break;
4682 : }
4683 : case KEYED_SUPER_PROPERTY: {
4684 90 : super_property_args = register_allocator()->NewRegisterList(4);
4685 90 : RegisterList load_super_args = super_property_args.Truncate(3);
4686 90 : SuperPropertyReference* super_property =
4687 90 : property->obj()->AsSuperPropertyReference();
4688 90 : BuildThisVariableLoad();
4689 90 : builder()->StoreAccumulatorInRegister(load_super_args[0]);
4690 : VisitForRegisterValue(super_property->home_object(), load_super_args[1]);
4691 : VisitForRegisterValue(property->key(), load_super_args[2]);
4692 90 : builder()->CallRuntime(Runtime::kLoadKeyedFromSuper, load_super_args);
4693 : break;
4694 : }
4695 : }
4696 :
4697 : // Save result for postfix expressions.
4698 240474 : FeedbackSlot count_slot = feedback_spec()->AddBinaryOpICSlot();
4699 240418 : if (is_postfix) {
4700 26824 : old_value = register_allocator()->NewRegister();
4701 : // Convert old value into a number before saving it.
4702 : // TODO(ignition): Think about adding proper PostInc/PostDec bytecodes
4703 : // instead of this ToNumeric + Inc/Dec dance.
4704 : builder()
4705 26824 : ->ToNumeric(feedback_index(count_slot))
4706 26824 : .StoreAccumulatorInRegister(old_value);
4707 : }
4708 :
4709 : // Perform +1/-1 operation.
4710 240418 : builder()->UnaryOperation(expr->op(), feedback_index(count_slot));
4711 :
4712 : // Store the value.
4713 : builder()->SetExpressionPosition(expr);
4714 240431 : switch (assign_type) {
4715 : case NON_PROPERTY: {
4716 698072 : VariableProxy* proxy = expr->expression()->AsVariableProxy();
4717 : BuildVariableAssignment(proxy->var(), expr->op(),
4718 465378 : proxy->hole_check_mode());
4719 232705 : break;
4720 : }
4721 : case NAMED_PROPERTY: {
4722 4865 : FeedbackSlot slot = GetCachedStoreICSlot(property->obj(), name);
4723 : Register value;
4724 4865 : if (!execution_result()->IsEffect()) {
4725 4464 : value = register_allocator()->NewRegister();
4726 4464 : builder()->StoreAccumulatorInRegister(value);
4727 : }
4728 : builder()->StoreNamedProperty(object, name, feedback_index(slot),
4729 4865 : language_mode());
4730 4865 : if (!execution_result()->IsEffect()) {
4731 4464 : builder()->LoadAccumulatorWithRegister(value);
4732 : }
4733 : break;
4734 : }
4735 : case KEYED_PROPERTY: {
4736 2749 : FeedbackSlot slot = feedback_spec()->AddKeyedStoreICSlot(language_mode());
4737 : Register value;
4738 2749 : if (!execution_result()->IsEffect()) {
4739 478 : value = register_allocator()->NewRegister();
4740 478 : builder()->StoreAccumulatorInRegister(value);
4741 : }
4742 : builder()->StoreKeyedProperty(object, key, feedback_index(slot),
4743 2749 : language_mode());
4744 2749 : if (!execution_result()->IsEffect()) {
4745 478 : builder()->LoadAccumulatorWithRegister(value);
4746 : }
4747 : break;
4748 : }
4749 : case NAMED_SUPER_PROPERTY: {
4750 : builder()
4751 45 : ->StoreAccumulatorInRegister(super_property_args[3])
4752 45 : .CallRuntime(Runtime::kStoreToSuper, super_property_args);
4753 45 : break;
4754 : }
4755 : case KEYED_SUPER_PROPERTY: {
4756 : builder()
4757 90 : ->StoreAccumulatorInRegister(super_property_args[3])
4758 90 : .CallRuntime(Runtime::kStoreKeyedToSuper, super_property_args);
4759 90 : break;
4760 : }
4761 : }
4762 :
4763 : // Restore old value for postfix expressions.
4764 240442 : if (is_postfix) {
4765 26825 : builder()->LoadAccumulatorWithRegister(old_value);
4766 : }
4767 240442 : }
4768 :
4769 518558 : void BytecodeGenerator::VisitBinaryOperation(BinaryOperation* binop) {
4770 518558 : switch (binop->op()) {
4771 : case Token::COMMA:
4772 37648 : VisitCommaExpression(binop);
4773 37650 : break;
4774 : case Token::OR:
4775 40632 : VisitLogicalOrExpression(binop);
4776 40634 : break;
4777 : case Token::AND:
4778 83461 : VisitLogicalAndExpression(binop);
4779 83461 : break;
4780 : default:
4781 356817 : VisitArithmeticExpression(binop);
4782 356822 : break;
4783 : }
4784 518567 : }
4785 :
4786 111820 : void BytecodeGenerator::VisitNaryOperation(NaryOperation* expr) {
4787 111820 : switch (expr->op()) {
4788 : case Token::COMMA:
4789 325 : VisitNaryCommaExpression(expr);
4790 325 : break;
4791 : case Token::OR:
4792 20189 : VisitNaryLogicalOrExpression(expr);
4793 20190 : break;
4794 : case Token::AND:
4795 659 : VisitNaryLogicalAndExpression(expr);
4796 659 : break;
4797 : default:
4798 90647 : VisitNaryArithmeticExpression(expr);
4799 90651 : break;
4800 : }
4801 111825 : }
4802 :
4803 65459 : void BytecodeGenerator::BuildLiteralCompareNil(
4804 65459 : Token::Value op, BytecodeArrayBuilder::NilValue nil) {
4805 65459 : if (execution_result()->IsTest()) {
4806 106789 : TestResultScope* test_result = execution_result()->AsTest();
4807 53394 : switch (test_result->fallthrough()) {
4808 : case TestFallthrough::kThen:
4809 28860 : builder()->JumpIfNotNil(test_result->NewElseLabel(), op, nil);
4810 14430 : break;
4811 : case TestFallthrough::kElse:
4812 77930 : builder()->JumpIfNil(test_result->NewThenLabel(), op, nil);
4813 38965 : break;
4814 : case TestFallthrough::kNone:
4815 : builder()
4816 0 : ->JumpIfNil(test_result->NewThenLabel(), op, nil)
4817 0 : .Jump(test_result->NewElseLabel());
4818 : }
4819 : test_result->SetResultConsumedByTest();
4820 : } else {
4821 12065 : builder()->CompareNil(op, nil);
4822 : }
4823 65461 : }
4824 :
4825 4764789 : void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) {
4826 : Expression* sub_expr;
4827 : Literal* literal;
4828 876931 : if (expr->IsLiteralCompareTypeof(&sub_expr, &literal)) {
4829 : // Emit a fast literal comparion for expressions of the form:
4830 : // typeof(x) === 'string'.
4831 99389 : VisitForTypeOfValue(sub_expr);
4832 : builder()->SetExpressionPosition(expr);
4833 : TestTypeOfFlags::LiteralFlag literal_flag =
4834 198782 : TestTypeOfFlags::GetFlagForLiteral(ast_string_constants(), literal);
4835 99389 : if (literal_flag == TestTypeOfFlags::LiteralFlag::kOther) {
4836 242 : builder()->LoadFalse();
4837 : } else {
4838 99147 : builder()->CompareTypeOf(literal_flag);
4839 : }
4840 777569 : } else if (expr->IsLiteralCompareUndefined(&sub_expr)) {
4841 60391 : VisitForAccumulatorValue(sub_expr);
4842 : builder()->SetExpressionPosition(expr);
4843 60395 : BuildLiteralCompareNil(expr->op(), BytecodeArrayBuilder::kUndefinedValue);
4844 717166 : } else if (expr->IsLiteralCompareNull(&sub_expr)) {
4845 5069 : VisitForAccumulatorValue(sub_expr);
4846 : builder()->SetExpressionPosition(expr);
4847 5069 : BuildLiteralCompareNil(expr->op(), BytecodeArrayBuilder::kNullValue);
4848 : } else {
4849 712091 : Register lhs = VisitForRegisterValue(expr->left());
4850 712118 : VisitForAccumulatorValue(expr->right());
4851 : builder()->SetExpressionPosition(expr);
4852 712111 : if (expr->op() == Token::IN) {
4853 2379 : builder()->CompareOperation(expr->op(), lhs);
4854 709732 : } else if (expr->op() == Token::INSTANCEOF) {
4855 14759 : FeedbackSlot slot = feedback_spec()->AddInstanceOfSlot();
4856 14760 : builder()->CompareOperation(expr->op(), lhs, feedback_index(slot));
4857 : } else {
4858 694973 : FeedbackSlot slot = feedback_spec()->AddCompareICSlot();
4859 694974 : builder()->CompareOperation(expr->op(), lhs, feedback_index(slot));
4860 : }
4861 : }
4862 : // Always returns a boolean value.
4863 : execution_result()->SetResultIsBoolean();
4864 876949 : }
4865 :
4866 1594874 : void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) {
4867 356813 : FeedbackSlot slot = feedback_spec()->AddBinaryOpICSlot();
4868 : Expression* subexpr;
4869 356827 : Smi literal;
4870 356827 : if (expr->IsSmiLiteralOperation(&subexpr, &literal)) {
4871 119976 : TypeHint type_hint = VisitForAccumulatorValue(subexpr);
4872 : builder()->SetExpressionPosition(expr);
4873 : builder()->BinaryOperationSmiLiteral(expr->op(), literal,
4874 119976 : feedback_index(slot));
4875 119976 : if (expr->op() == Token::ADD && type_hint == TypeHint::kString) {
4876 : execution_result()->SetResultIsString();
4877 : }
4878 : } else {
4879 236855 : TypeHint lhs_type = VisitForAccumulatorValue(expr->left());
4880 236850 : Register lhs = register_allocator()->NewRegister();
4881 236847 : builder()->StoreAccumulatorInRegister(lhs);
4882 236856 : TypeHint rhs_type = VisitForAccumulatorValue(expr->right());
4883 342541 : if (expr->op() == Token::ADD &&
4884 105683 : (lhs_type == TypeHint::kString || rhs_type == TypeHint::kString)) {
4885 : execution_result()->SetResultIsString();
4886 : }
4887 :
4888 : builder()->SetExpressionPosition(expr);
4889 236858 : builder()->BinaryOperation(expr->op(), lhs, feedback_index(slot));
4890 : }
4891 356823 : }
4892 :
4893 503902 : void BytecodeGenerator::VisitNaryArithmeticExpression(NaryOperation* expr) {
4894 : // TODO(leszeks): Add support for lhs smi in commutative ops.
4895 90647 : TypeHint type_hint = VisitForAccumulatorValue(expr->first());
4896 :
4897 841930 : for (size_t i = 0; i < expr->subsequent_length(); ++i) {
4898 : RegisterAllocationScope register_scope(this);
4899 330313 : if (expr->subsequent(i)->IsSmiLiteral()) {
4900 : builder()->SetExpressionPosition(expr->subsequent_op_position(i));
4901 : builder()->BinaryOperationSmiLiteral(
4902 : expr->op(), expr->subsequent(i)->AsLiteral()->AsSmiLiteral(),
4903 178149 : feedback_index(feedback_spec()->AddBinaryOpICSlot()));
4904 : } else {
4905 285796 : Register lhs = register_allocator()->NewRegister();
4906 285805 : builder()->StoreAccumulatorInRegister(lhs);
4907 285806 : TypeHint rhs_hint = VisitForAccumulatorValue(expr->subsequent(i));
4908 285790 : if (rhs_hint == TypeHint::kString) type_hint = TypeHint::kString;
4909 : builder()->SetExpressionPosition(expr->subsequent_op_position(i));
4910 : builder()->BinaryOperation(
4911 : expr->op(), lhs,
4912 571584 : feedback_index(feedback_spec()->AddBinaryOpICSlot()));
4913 : }
4914 330288 : }
4915 :
4916 132114 : if (type_hint == TypeHint::kString && expr->op() == Token::ADD) {
4917 : // If any operand of an ADD is a String, a String is produced.
4918 : execution_result()->SetResultIsString();
4919 : }
4920 90652 : }
4921 :
4922 : // Note: the actual spreading is performed by the surrounding expression's
4923 : // visitor.
4924 7870 : void BytecodeGenerator::VisitSpread(Spread* expr) { Visit(expr->expression()); }
4925 :
4926 0 : void BytecodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) {
4927 0 : UNREACHABLE();
4928 : }
4929 :
4930 566 : void BytecodeGenerator::VisitImportCallExpression(ImportCallExpression* expr) {
4931 283 : RegisterList args = register_allocator()->NewRegisterList(2);
4932 : VisitForRegisterValue(expr->argument(), args[1]);
4933 : builder()
4934 283 : ->MoveRegister(Register::function_closure(), args[0])
4935 283 : .CallRuntime(Runtime::kDynamicImportCall, args);
4936 283 : }
4937 :
4938 39860 : void BytecodeGenerator::BuildGetIterator(IteratorType hint) {
4939 39860 : RegisterList args = register_allocator()->NewRegisterList(1);
4940 39862 : Register method = register_allocator()->NewRegister();
4941 39862 : Register obj = args[0];
4942 :
4943 39862 : if (hint == IteratorType::kAsync) {
4944 : // Set method to GetMethod(obj, @@asyncIterator)
4945 346 : builder()->StoreAccumulatorInRegister(obj).LoadAsyncIteratorProperty(
4946 692 : obj, feedback_index(feedback_spec()->AddLoadICSlot()));
4947 :
4948 : BytecodeLabel async_iterator_undefined, async_iterator_null, done;
4949 : // TODO(ignition): Add a single opcode for JumpIfNullOrUndefined
4950 346 : builder()->JumpIfUndefined(&async_iterator_undefined);
4951 346 : builder()->JumpIfNull(&async_iterator_null);
4952 :
4953 : // Let iterator be Call(method, obj)
4954 346 : builder()->StoreAccumulatorInRegister(method).CallProperty(
4955 692 : method, args, feedback_index(feedback_spec()->AddCallICSlot()));
4956 :
4957 : // If Type(iterator) is not Object, throw a TypeError exception.
4958 346 : builder()->JumpIfJSReceiver(&done);
4959 346 : builder()->CallRuntime(Runtime::kThrowSymbolAsyncIteratorInvalid);
4960 :
4961 346 : builder()->Bind(&async_iterator_undefined);
4962 346 : builder()->Bind(&async_iterator_null);
4963 : // If method is undefined,
4964 : // Let syncMethod be GetMethod(obj, @@iterator)
4965 : builder()
4966 : ->LoadIteratorProperty(obj,
4967 692 : feedback_index(feedback_spec()->AddLoadICSlot()))
4968 346 : .StoreAccumulatorInRegister(method);
4969 :
4970 : // Let syncIterator be Call(syncMethod, obj)
4971 : builder()->CallProperty(method, args,
4972 692 : feedback_index(feedback_spec()->AddCallICSlot()));
4973 :
4974 : // Return CreateAsyncFromSyncIterator(syncIterator)
4975 : // alias `method` register as it's no longer used
4976 346 : Register sync_iter = method;
4977 346 : builder()->StoreAccumulatorInRegister(sync_iter).CallRuntime(
4978 346 : Runtime::kInlineCreateAsyncFromSyncIterator, sync_iter);
4979 :
4980 346 : builder()->Bind(&done);
4981 : } else {
4982 : // Let method be GetMethod(obj, @@iterator).
4983 : builder()
4984 39513 : ->StoreAccumulatorInRegister(obj)
4985 : .LoadIteratorProperty(obj,
4986 79032 : feedback_index(feedback_spec()->AddLoadICSlot()))
4987 39516 : .StoreAccumulatorInRegister(method);
4988 :
4989 : // Let iterator be Call(method, obj).
4990 : builder()->CallProperty(method, args,
4991 79027 : feedback_index(feedback_spec()->AddCallICSlot()));
4992 :
4993 : // If Type(iterator) is not Object, throw a TypeError exception.
4994 : BytecodeLabel no_type_error;
4995 39516 : builder()->JumpIfJSReceiver(&no_type_error);
4996 39512 : builder()->CallRuntime(Runtime::kThrowSymbolIteratorInvalid);
4997 39516 : builder()->Bind(&no_type_error);
4998 : }
4999 39859 : }
5000 :
5001 : // Returns an IteratorRecord which is valid for the lifetime of the current
5002 : // register_allocation_scope.
5003 39860 : BytecodeGenerator::IteratorRecord BytecodeGenerator::BuildGetIteratorRecord(
5004 39859 : Register next, Register object, IteratorType hint) {
5005 : DCHECK(next.is_valid() && object.is_valid());
5006 39860 : BuildGetIterator(hint);
5007 :
5008 : builder()
5009 39859 : ->StoreAccumulatorInRegister(object)
5010 : .LoadNamedProperty(object, ast_string_constants()->next_string(),
5011 119580 : feedback_index(feedback_spec()->AddLoadICSlot()))
5012 39863 : .StoreAccumulatorInRegister(next);
5013 39863 : return IteratorRecord(object, next, hint);
5014 : }
5015 :
5016 39664 : BytecodeGenerator::IteratorRecord BytecodeGenerator::BuildGetIteratorRecord(
5017 : IteratorType hint) {
5018 39664 : Register next = register_allocator()->NewRegister();
5019 39668 : Register object = register_allocator()->NewRegister();
5020 39668 : return BuildGetIteratorRecord(next, object, hint);
5021 : }
5022 :
5023 82110 : void BytecodeGenerator::BuildIteratorNext(const IteratorRecord& iterator,
5024 : Register next_result) {
5025 : DCHECK(next_result.is_valid());
5026 : builder()->CallProperty(iterator.next(), RegisterList(iterator.object()),
5027 82111 : feedback_index(feedback_spec()->AddCallICSlot()));
5028 :
5029 41058 : if (iterator.type() == IteratorType::kAsync) {
5030 336 : BuildAwait();
5031 : }
5032 :
5033 : BytecodeLabel is_object;
5034 : builder()
5035 41058 : ->StoreAccumulatorInRegister(next_result)
5036 41056 : .JumpIfJSReceiver(&is_object)
5037 41058 : .CallRuntime(Runtime::kThrowIteratorResultNotAnObject, next_result)
5038 41059 : .Bind(&is_object);
5039 41059 : }
5040 :
5041 582 : void BytecodeGenerator::BuildCallIteratorMethod(Register iterator,
5042 : const AstRawString* method_name,
5043 : RegisterList receiver_and_args,
5044 : BytecodeLabel* if_called,
5045 : BytecodeLabels* if_notcalled) {
5046 : RegisterAllocationScope register_scope(this);
5047 :
5048 582 : Register method = register_allocator()->NewRegister();
5049 582 : FeedbackSlot slot = feedback_spec()->AddLoadICSlot();
5050 : builder()
5051 582 : ->LoadNamedProperty(iterator, method_name, feedback_index(slot))
5052 1164 : .JumpIfUndefined(if_notcalled->New())
5053 1164 : .JumpIfNull(if_notcalled->New())
5054 582 : .StoreAccumulatorInRegister(method)
5055 : .CallProperty(method, receiver_and_args,
5056 1164 : feedback_index(feedback_spec()->AddCallICSlot()))
5057 582 : .Jump(if_called);
5058 582 : }
5059 :
5060 388 : void BytecodeGenerator::BuildIteratorClose(const IteratorRecord& iterator,
5061 388 : Expression* expr) {
5062 : RegisterAllocationScope register_scope(this);
5063 : BytecodeLabels done(zone());
5064 : BytecodeLabel if_called;
5065 : RegisterList args = RegisterList(iterator.object());
5066 : BuildCallIteratorMethod(iterator.object(),
5067 : ast_string_constants()->return_string(), args,
5068 194 : &if_called, &done);
5069 194 : builder()->Bind(&if_called);
5070 :
5071 194 : if (iterator.type() == IteratorType::kAsync) {
5072 : DCHECK_NOT_NULL(expr);
5073 10 : BuildAwait(expr->position());
5074 : }
5075 :
5076 194 : builder()->JumpIfJSReceiver(done.New());
5077 : {
5078 : RegisterAllocationScope register_scope(this);
5079 194 : Register return_result = register_allocator()->NewRegister();
5080 : builder()
5081 194 : ->StoreAccumulatorInRegister(return_result)
5082 194 : .CallRuntime(Runtime::kThrowIteratorResultNotAnObject, return_result);
5083 : }
5084 :
5085 388 : done.Bind(builder());
5086 194 : }
5087 :
5088 1917 : void BytecodeGenerator::VisitGetTemplateObject(GetTemplateObject* expr) {
5089 : builder()->SetExpressionPosition(expr);
5090 1917 : size_t entry = builder()->AllocateDeferredConstantPoolEntry();
5091 3834 : template_objects_.push_back(std::make_pair(expr, entry));
5092 1917 : FeedbackSlot literal_slot = feedback_spec()->AddLiteralSlot();
5093 1917 : builder()->GetTemplateObject(entry, feedback_index(literal_slot));
5094 1917 : }
5095 :
5096 6822 : void BytecodeGenerator::VisitTemplateLiteral(TemplateLiteral* expr) {
5097 10187 : const ZonePtrList<const AstRawString>& parts = *expr->string_parts();
5098 27196 : const ZonePtrList<Expression>& substitutions = *expr->substitutions();
5099 : // Template strings with no substitutions are turned into StringLiterals.
5100 : DCHECK_GT(substitutions.length(), 0);
5101 : DCHECK_EQ(parts.length(), substitutions.length() + 1);
5102 :
5103 : // Generate string concatenation
5104 : // TODO(caitp): Don't generate feedback slot if it's not used --- introduce
5105 : // a simple, concise, reusable mechanism to lazily create reusable slots.
5106 6822 : FeedbackSlot slot = feedback_spec()->AddBinaryOpICSlot();
5107 6822 : Register last_part = register_allocator()->NewRegister();
5108 : bool last_part_valid = false;
5109 :
5110 : builder()->SetExpressionPosition(expr);
5111 27196 : for (int i = 0; i < substitutions.length(); ++i) {
5112 10187 : if (i != 0) {
5113 3365 : builder()->StoreAccumulatorInRegister(last_part);
5114 : last_part_valid = true;
5115 : }
5116 :
5117 20374 : if (!parts[i]->IsEmpty()) {
5118 7077 : builder()->LoadLiteral(parts[i]);
5119 7077 : if (last_part_valid) {
5120 3295 : builder()->BinaryOperation(Token::ADD, last_part, feedback_index(slot));
5121 : }
5122 7077 : builder()->StoreAccumulatorInRegister(last_part);
5123 : last_part_valid = true;
5124 : }
5125 :
5126 10187 : TypeHint type_hint = VisitForAccumulatorValue(substitutions[i]);
5127 10187 : if (type_hint != TypeHint::kString) {
5128 10177 : builder()->ToString();
5129 : }
5130 10187 : if (last_part_valid) {
5131 7147 : builder()->BinaryOperation(Token::ADD, last_part, feedback_index(slot));
5132 : }
5133 : last_part_valid = false;
5134 : }
5135 :
5136 13644 : if (!parts.last()->IsEmpty()) {
5137 2699 : builder()->StoreAccumulatorInRegister(last_part);
5138 2699 : builder()->LoadLiteral(parts.last());
5139 2699 : builder()->BinaryOperation(Token::ADD, last_part, feedback_index(slot));
5140 : }
5141 6822 : }
5142 :
5143 2432305 : void BytecodeGenerator::BuildThisVariableLoad() {
5144 2432305 : DeclarationScope* receiver_scope = closure_scope()->GetReceiverScope();
5145 : Variable* var = receiver_scope->receiver();
5146 : // TODO(littledan): implement 'this' hole check elimination.
5147 : HoleCheckMode hole_check_mode =
5148 : IsDerivedConstructor(receiver_scope->function_kind())
5149 : ? HoleCheckMode::kRequired
5150 2432310 : : HoleCheckMode::kElided;
5151 2432310 : BuildVariableLoad(var, hole_check_mode);
5152 2432316 : }
5153 :
5154 0 : void BytecodeGenerator::VisitThisExpression(ThisExpression* expr) {
5155 2430331 : BuildThisVariableLoad();
5156 0 : }
5157 :
5158 0 : void BytecodeGenerator::VisitSuperCallReference(SuperCallReference* expr) {
5159 : // Handled by VisitCall().
5160 0 : UNREACHABLE();
5161 : }
5162 :
5163 0 : void BytecodeGenerator::VisitSuperPropertyReference(
5164 : SuperPropertyReference* expr) {
5165 17 : builder()->CallRuntime(Runtime::kThrowUnsupportedSuperError);
5166 0 : }
5167 :
5168 75298 : void BytecodeGenerator::VisitCommaExpression(BinaryOperation* binop) {
5169 37648 : VisitForEffect(binop->left());
5170 37650 : Visit(binop->right());
5171 37650 : }
5172 :
5173 325 : void BytecodeGenerator::VisitNaryCommaExpression(NaryOperation* expr) {
5174 : DCHECK_GT(expr->subsequent_length(), 0);
5175 :
5176 325 : VisitForEffect(expr->first());
5177 5221118 : for (size_t i = 0; i < expr->subsequent_length() - 1; ++i) {
5178 2610234 : VisitForEffect(expr->subsequent(i));
5179 : }
5180 325 : Visit(expr->subsequent(expr->subsequent_length() - 1));
5181 325 : }
5182 :
5183 145104 : void BytecodeGenerator::VisitLogicalTestSubExpression(
5184 : Token::Value token, Expression* expr, BytecodeLabels* then_labels,
5185 145104 : BytecodeLabels* else_labels, int coverage_slot) {
5186 : DCHECK(token == Token::OR || token == Token::AND);
5187 :
5188 : BytecodeLabels test_next(zone());
5189 145104 : if (token == Token::OR) {
5190 91577 : VisitForTest(expr, then_labels, &test_next, TestFallthrough::kElse);
5191 : } else {
5192 : DCHECK_EQ(Token::AND, token);
5193 53527 : VisitForTest(expr, &test_next, else_labels, TestFallthrough::kThen);
5194 : }
5195 145106 : test_next.Bind(builder());
5196 :
5197 145106 : BuildIncrementBlockCoverageCounterIfEnabled(coverage_slot);
5198 145106 : }
5199 :
5200 67416 : void BytecodeGenerator::VisitLogicalTest(Token::Value token, Expression* left,
5201 : Expression* right,
5202 67416 : int right_coverage_slot) {
5203 : DCHECK(token == Token::OR || token == Token::AND);
5204 67416 : TestResultScope* test_result = execution_result()->AsTest();
5205 : BytecodeLabels* then_labels = test_result->then_labels();
5206 : BytecodeLabels* else_labels = test_result->else_labels();
5207 : TestFallthrough fallthrough = test_result->fallthrough();
5208 :
5209 : VisitLogicalTestSubExpression(token, left, then_labels, else_labels,
5210 67416 : right_coverage_slot);
5211 : // The last test has the same then, else and fallthrough as the parent test.
5212 67417 : VisitForTest(right, then_labels, else_labels, fallthrough);
5213 67417 : }
5214 :
5215 20302 : void BytecodeGenerator::VisitNaryLogicalTest(
5216 20302 : Token::Value token, NaryOperation* expr,
5217 20302 : const NaryCodeCoverageSlots* coverage_slots) {
5218 : DCHECK(token == Token::OR || token == Token::AND);
5219 : DCHECK_GT(expr->subsequent_length(), 0);
5220 :
5221 20302 : TestResultScope* test_result = execution_result()->AsTest();
5222 : BytecodeLabels* then_labels = test_result->then_labels();
5223 : BytecodeLabels* else_labels = test_result->else_labels();
5224 : TestFallthrough fallthrough = test_result->fallthrough();
5225 :
5226 : VisitLogicalTestSubExpression(token, expr->first(), then_labels, else_labels,
5227 20302 : coverage_slots->GetSlotFor(0));
5228 97992 : for (size_t i = 0; i < expr->subsequent_length() - 1; ++i) {
5229 : VisitLogicalTestSubExpression(token, expr->subsequent(i), then_labels,
5230 : else_labels,
5231 114772 : coverage_slots->GetSlotFor(i + 1));
5232 : }
5233 : // The last test has the same then, else and fallthrough as the parent test.
5234 : VisitForTest(expr->subsequent(expr->subsequent_length() - 1), then_labels,
5235 20303 : else_labels, fallthrough);
5236 20303 : }
5237 :
5238 22133 : bool BytecodeGenerator::VisitLogicalOrSubExpression(Expression* expr,
5239 : BytecodeLabels* end_labels,
5240 : int coverage_slot) {
5241 22133 : if (expr->ToBooleanIsTrue()) {
5242 1720 : VisitForAccumulatorValue(expr);
5243 1721 : end_labels->Bind(builder());
5244 1721 : return true;
5245 20414 : } else if (!expr->ToBooleanIsFalse()) {
5246 20233 : TypeHint type_hint = VisitForAccumulatorValue(expr);
5247 : builder()->JumpIfTrue(ToBooleanModeFromTypeHint(type_hint),
5248 40466 : end_labels->New());
5249 : }
5250 :
5251 20415 : BuildIncrementBlockCoverageCounterIfEnabled(coverage_slot);
5252 :
5253 20415 : return false;
5254 : }
5255 :
5256 31684 : bool BytecodeGenerator::VisitLogicalAndSubExpression(Expression* expr,
5257 : BytecodeLabels* end_labels,
5258 : int coverage_slot) {
5259 31684 : if (expr->ToBooleanIsFalse()) {
5260 169 : VisitForAccumulatorValue(expr);
5261 169 : end_labels->Bind(builder());
5262 169 : return true;
5263 31515 : } else if (!expr->ToBooleanIsTrue()) {
5264 29781 : TypeHint type_hint = VisitForAccumulatorValue(expr);
5265 : builder()->JumpIfFalse(ToBooleanModeFromTypeHint(type_hint),
5266 59562 : end_labels->New());
5267 : }
5268 :
5269 31516 : BuildIncrementBlockCoverageCounterIfEnabled(coverage_slot);
5270 :
5271 31516 : return false;
5272 : }
5273 :
5274 103119 : void BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) {
5275 : Expression* left = binop->left();
5276 : Expression* right = binop->right();
5277 :
5278 : int right_coverage_slot =
5279 : AllocateBlockCoverageSlotIfEnabled(binop, SourceRangeKind::kRight);
5280 :
5281 40633 : if (execution_result()->IsTest()) {
5282 4341 : TestResultScope* test_result = execution_result()->AsTest();
5283 18778 : if (left->ToBooleanIsTrue()) {
5284 4341 : builder()->Jump(test_result->NewThenLabel());
5285 14437 : } else if (left->ToBooleanIsFalse() && right->ToBooleanIsFalse()) {
5286 0 : BuildIncrementBlockCoverageCounterIfEnabled(right_coverage_slot);
5287 0 : builder()->Jump(test_result->NewElseLabel());
5288 : } else {
5289 14437 : VisitLogicalTest(Token::OR, left, right, right_coverage_slot);
5290 : }
5291 : test_result->SetResultConsumedByTest();
5292 : } else {
5293 : BytecodeLabels end_labels(zone());
5294 21855 : if (VisitLogicalOrSubExpression(left, &end_labels, right_coverage_slot)) {
5295 40634 : return;
5296 : }
5297 20165 : VisitForAccumulatorValue(right);
5298 20167 : end_labels.Bind(builder());
5299 : }
5300 : }
5301 :
5302 40516 : void BytecodeGenerator::VisitNaryLogicalOrExpression(NaryOperation* expr) {
5303 : Expression* first = expr->first();
5304 : DCHECK_GT(expr->subsequent_length(), 0);
5305 :
5306 20189 : NaryCodeCoverageSlots coverage_slots(this, expr);
5307 :
5308 20189 : if (execution_result()->IsTest()) {
5309 0 : TestResultScope* test_result = execution_result()->AsTest();
5310 20051 : if (first->ToBooleanIsTrue()) {
5311 0 : builder()->Jump(test_result->NewThenLabel());
5312 : } else {
5313 20051 : VisitNaryLogicalTest(Token::OR, expr, &coverage_slots);
5314 : }
5315 : test_result->SetResultConsumedByTest();
5316 : } else {
5317 : BytecodeLabels end_labels(zone());
5318 138 : if (VisitLogicalOrSubExpression(first, &end_labels,
5319 : coverage_slots.GetSlotFor(0))) {
5320 : return;
5321 : }
5322 248 : for (size_t i = 0; i < expr->subsequent_length() - 1; ++i) {
5323 141 : if (VisitLogicalOrSubExpression(expr->subsequent(i), &end_labels,
5324 141 : coverage_slots.GetSlotFor(i + 1))) {
5325 : return;
5326 : }
5327 : }
5328 : // We have to visit the last value even if it's true, because we need its
5329 : // actual value.
5330 107 : VisitForAccumulatorValue(expr->subsequent(expr->subsequent_length() - 1));
5331 107 : end_labels.Bind(builder());
5332 : }
5333 : }
5334 :
5335 197391 : void BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) {
5336 : Expression* left = binop->left();
5337 : Expression* right = binop->right();
5338 :
5339 : int right_coverage_slot =
5340 : AllocateBlockCoverageSlotIfEnabled(binop, SourceRangeKind::kRight);
5341 :
5342 83461 : if (execution_result()->IsTest()) {
5343 11 : TestResultScope* test_result = execution_result()->AsTest();
5344 52991 : if (left->ToBooleanIsFalse()) {
5345 11 : builder()->Jump(test_result->NewElseLabel());
5346 52980 : } else if (left->ToBooleanIsTrue() && right->ToBooleanIsTrue()) {
5347 0 : BuildIncrementBlockCoverageCounterIfEnabled(right_coverage_slot);
5348 0 : builder()->Jump(test_result->NewThenLabel());
5349 : } else {
5350 52980 : VisitLogicalTest(Token::AND, left, right, right_coverage_slot);
5351 : }
5352 : test_result->SetResultConsumedByTest();
5353 : } else {
5354 : BytecodeLabels end_labels(zone());
5355 30470 : if (VisitLogicalAndSubExpression(left, &end_labels, right_coverage_slot)) {
5356 83461 : return;
5357 : }
5358 30316 : VisitForAccumulatorValue(right);
5359 30317 : end_labels.Bind(builder());
5360 : }
5361 : }
5362 :
5363 1726 : void BytecodeGenerator::VisitNaryLogicalAndExpression(NaryOperation* expr) {
5364 : Expression* first = expr->first();
5365 : DCHECK_GT(expr->subsequent_length(), 0);
5366 :
5367 659 : NaryCodeCoverageSlots coverage_slots(this, expr);
5368 :
5369 659 : if (execution_result()->IsTest()) {
5370 0 : TestResultScope* test_result = execution_result()->AsTest();
5371 251 : if (first->ToBooleanIsFalse()) {
5372 0 : builder()->Jump(test_result->NewElseLabel());
5373 : } else {
5374 251 : VisitNaryLogicalTest(Token::AND, expr, &coverage_slots);
5375 : }
5376 : test_result->SetResultConsumedByTest();
5377 : } else {
5378 : BytecodeLabels end_labels(zone());
5379 408 : if (VisitLogicalAndSubExpression(first, &end_labels,
5380 : coverage_slots.GetSlotFor(0))) {
5381 : return;
5382 : }
5383 1199 : for (size_t i = 0; i < expr->subsequent_length() - 1; ++i) {
5384 807 : if (VisitLogicalAndSubExpression(expr->subsequent(i), &end_labels,
5385 807 : coverage_slots.GetSlotFor(i + 1))) {
5386 : return;
5387 : }
5388 : }
5389 : // We have to visit the last value even if it's false, because we need its
5390 : // actual value.
5391 392 : VisitForAccumulatorValue(expr->subsequent(expr->subsequent_length() - 1));
5392 392 : end_labels.Bind(builder());
5393 : }
5394 : }
5395 :
5396 378576 : void BytecodeGenerator::BuildNewLocalActivationContext() {
5397 : ValueResultScope value_execution_result(this);
5398 365569 : Scope* scope = closure_scope();
5399 : DCHECK_EQ(current_scope(), closure_scope());
5400 :
5401 : // Create the appropriate context.
5402 189288 : if (scope->is_script_scope()) {
5403 11765 : Register scope_reg = register_allocator()->NewRegister();
5404 : builder()
5405 11766 : ->LoadLiteral(scope)
5406 11766 : .StoreAccumulatorInRegister(scope_reg)
5407 11766 : .CallRuntime(Runtime::kNewScriptContext, scope_reg);
5408 177523 : } else if (scope->is_module_scope()) {
5409 : // We don't need to do anything for the outer script scope.
5410 : DCHECK(scope->outer_scope()->is_script_scope());
5411 :
5412 : // A JSFunction representing a module is called with the module object as
5413 : // its sole argument.
5414 1242 : RegisterList args = register_allocator()->NewRegisterList(2);
5415 : builder()
5416 1242 : ->MoveRegister(builder()->Parameter(0), args[0])
5417 1242 : .LoadLiteral(scope)
5418 1242 : .StoreAccumulatorInRegister(args[1])
5419 1242 : .CallRuntime(Runtime::kPushModuleContext, args);
5420 : } else {
5421 : DCHECK(scope->is_function_scope() || scope->is_eval_scope());
5422 176281 : int slot_count = scope->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
5423 176281 : if (slot_count <= ConstructorBuiltins::MaximumFunctionContextSlots()) {
5424 176264 : switch (scope->scope_type()) {
5425 : case EVAL_SCOPE:
5426 42277 : builder()->CreateEvalContext(scope, slot_count);
5427 42277 : break;
5428 : case FUNCTION_SCOPE:
5429 133987 : builder()->CreateFunctionContext(scope, slot_count);
5430 133988 : break;
5431 : default:
5432 0 : UNREACHABLE();
5433 : }
5434 : } else {
5435 17 : Register arg = register_allocator()->NewRegister();
5436 17 : builder()->LoadLiteral(scope).StoreAccumulatorInRegister(arg).CallRuntime(
5437 17 : Runtime::kNewFunctionContext, arg);
5438 : }
5439 : }
5440 189287 : }
5441 :
5442 326637 : void BytecodeGenerator::BuildLocalActivationContextInitialization() {
5443 425267 : DeclarationScope* scope = closure_scope();
5444 :
5445 319862 : if (scope->has_this_declaration() && scope->receiver()->IsContextSlot()) {
5446 105405 : Variable* variable = scope->receiver();
5447 105405 : Register receiver(builder()->Receiver());
5448 : // Context variable (at bottom of the context chain).
5449 : DCHECK_EQ(0, scope->ContextChainLength(variable->scope()));
5450 105405 : builder()->LoadAccumulatorWithRegister(receiver).StoreContextSlot(
5451 105405 : execution_context()->reg(), variable->index(), 0);
5452 : }
5453 :
5454 : // Copy parameters into context if necessary.
5455 : int num_parameters = scope->num_parameters();
5456 247848 : for (int i = 0; i < num_parameters; i++) {
5457 31946 : Variable* variable = scope->parameter(i);
5458 85178 : if (!variable->IsContextSlot()) continue;
5459 :
5460 31946 : Register parameter(builder()->Parameter(i));
5461 : // Context variable (at bottom of the context chain).
5462 : DCHECK_EQ(0, scope->ContextChainLength(variable->scope()));
5463 31946 : builder()->LoadAccumulatorWithRegister(parameter).StoreContextSlot(
5464 31946 : execution_context()->reg(), variable->index(), 0);
5465 : }
5466 189286 : }
5467 :
5468 58500 : void BytecodeGenerator::BuildNewLocalBlockContext(Scope* scope) {
5469 : ValueResultScope value_execution_result(this);
5470 : DCHECK(scope->is_block_scope());
5471 :
5472 58500 : builder()->CreateBlockContext(scope);
5473 58501 : }
5474 :
5475 2955 : void BytecodeGenerator::BuildNewLocalWithContext(Scope* scope) {
5476 : ValueResultScope value_execution_result(this);
5477 :
5478 2955 : Register extension_object = register_allocator()->NewRegister();
5479 :
5480 2955 : builder()->ToObject(extension_object);
5481 2956 : builder()->CreateWithContext(extension_object, scope);
5482 2955 : }
5483 :
5484 68828 : void BytecodeGenerator::BuildNewLocalCatchContext(Scope* scope) {
5485 : ValueResultScope value_execution_result(this);
5486 : DCHECK(scope->catch_variable()->IsContextSlot());
5487 :
5488 68828 : Register exception = register_allocator()->NewRegister();
5489 68837 : builder()->StoreAccumulatorInRegister(exception);
5490 68841 : builder()->CreateCatchContext(exception, scope);
5491 68837 : }
5492 :
5493 9981 : void BytecodeGenerator::VisitObjectLiteralAccessor(
5494 : Register home_object, ObjectLiteralProperty* property, Register value_out) {
5495 9981 : if (property == nullptr) {
5496 4279 : builder()->LoadNull().StoreAccumulatorInRegister(value_out);
5497 : } else {
5498 5702 : VisitForRegisterValue(property->value(), value_out);
5499 5702 : VisitSetHomeObject(value_out, home_object, property);
5500 : }
5501 9984 : }
5502 :
5503 11630 : void BytecodeGenerator::VisitSetHomeObject(Register value, Register home_object,
5504 11630 : LiteralProperty* property) {
5505 : Expression* expr = property->value();
5506 11630 : if (FunctionLiteral::NeedsHomeObject(expr)) {
5507 659 : FeedbackSlot slot = feedback_spec()->AddStoreICSlot(language_mode());
5508 : builder()
5509 659 : ->LoadAccumulatorWithRegister(home_object)
5510 659 : .StoreHomeObjectProperty(value, feedback_index(slot), language_mode());
5511 : }
5512 11634 : }
5513 :
5514 2186950 : void BytecodeGenerator::VisitArgumentsObject(Variable* variable) {
5515 4174152 : if (variable == nullptr) return;
5516 :
5517 : DCHECK(variable->IsContextSlot() || variable->IsStackAllocated());
5518 :
5519 : // Allocate and initialize a new arguments object and assign to the
5520 : // {arguments} variable.
5521 99874 : builder()->CreateArguments(closure_scope()->GetArgumentsType());
5522 99873 : BuildVariableAssignment(variable, Token::ASSIGN, HoleCheckMode::kElided);
5523 : }
5524 :
5525 2087076 : void BytecodeGenerator::VisitRestArgumentsArray(Variable* rest) {
5526 4174153 : if (rest == nullptr) return;
5527 :
5528 : // Allocate and initialize a new rest parameter and assign to the {rest}
5529 : // variable.
5530 5172 : builder()->CreateArguments(CreateArgumentsType::kRestParameter);
5531 : DCHECK(rest->IsContextSlot() || rest->IsStackAllocated());
5532 5173 : BuildVariableAssignment(rest, Token::ASSIGN, HoleCheckMode::kElided);
5533 : }
5534 :
5535 4174147 : void BytecodeGenerator::VisitThisFunctionVariable(Variable* variable) {
5536 8348294 : if (variable == nullptr) return;
5537 :
5538 : // Store the closure we were called with in the given variable.
5539 30967 : builder()->LoadAccumulatorWithRegister(Register::function_closure());
5540 30967 : BuildVariableAssignment(variable, Token::INIT, HoleCheckMode::kElided);
5541 : }
5542 :
5543 2286888 : void BytecodeGenerator::VisitNewTargetVariable(Variable* variable) {
5544 2087073 : if (variable == nullptr) return;
5545 :
5546 : // The generator resume trampoline abuses the new.target register
5547 : // to pass in the generator object. In ordinary calls, new.target is always
5548 : // undefined because generator functions are non-constructible, so don't
5549 : // assign anything to the new.target variable.
5550 200331 : if (IsResumableFunction(info()->literal()->kind())) return;
5551 :
5552 99650 : if (variable->location() == VariableLocation::LOCAL) {
5553 : // The new.target register was already assigned by entry trampoline.
5554 : DCHECK_EQ(incoming_new_target_or_generator_.index(),
5555 : GetRegisterForLocalVariable(variable).index());
5556 : return;
5557 : }
5558 :
5559 : // Store the new target we were called with in the given variable.
5560 94200 : builder()->LoadAccumulatorWithRegister(incoming_new_target_or_generator_);
5561 94200 : BuildVariableAssignment(variable, Token::INIT, HoleCheckMode::kElided);
5562 : }
5563 :
5564 28896 : void BytecodeGenerator::BuildGeneratorObjectVariableInitialization() {
5565 : DCHECK(IsResumableFunction(info()->literal()->kind()));
5566 :
5567 10941 : Variable* generator_object_var = closure_scope()->generator_object_var();
5568 : RegisterAllocationScope register_scope(this);
5569 10941 : RegisterList args = register_allocator()->NewRegisterList(2);
5570 : Runtime::FunctionId function_id =
5571 17955 : (IsAsyncFunction(info()->literal()->kind()) &&
5572 7014 : !IsAsyncGeneratorFunction(info()->literal()->kind()))
5573 : ? Runtime::kInlineAsyncFunctionEnter
5574 10941 : : Runtime::kInlineCreateJSGeneratorObject;
5575 : builder()
5576 10941 : ->MoveRegister(Register::function_closure(), args[0])
5577 21882 : .MoveRegister(builder()->Receiver(), args[1])
5578 10941 : .CallRuntime(function_id, args)
5579 10941 : .StoreAccumulatorInRegister(generator_object());
5580 :
5581 10941 : if (generator_object_var->location() == VariableLocation::LOCAL) {
5582 : // The generator object register is already set to the variable's local
5583 : // register.
5584 : DCHECK_EQ(generator_object().index(),
5585 : GetRegisterForLocalVariable(generator_object_var).index());
5586 : } else {
5587 : BuildVariableAssignment(generator_object_var, Token::INIT,
5588 0 : HoleCheckMode::kElided);
5589 10941 : }
5590 10941 : }
5591 :
5592 909903 : void BytecodeGenerator::BuildPushUndefinedIntoRegisterList(
5593 : RegisterList* reg_list) {
5594 909903 : Register reg = register_allocator()->GrowRegisterList(reg_list);
5595 909947 : builder()->LoadUndefined().StoreAccumulatorInRegister(reg);
5596 910101 : }
5597 :
5598 9914 : void BytecodeGenerator::BuildLoadPropertyKey(LiteralProperty* property,
5599 : Register out_reg) {
5600 9914 : if (property->key()->IsStringLiteral()) {
5601 : builder()
5602 4360 : ->LoadLiteral(property->key()->AsLiteral()->AsRawString())
5603 2180 : .StoreAccumulatorInRegister(out_reg);
5604 : } else {
5605 7734 : VisitForAccumulatorValue(property->key());
5606 7735 : builder()->ToName(out_reg);
5607 : }
5608 9914 : }
5609 :
5610 0 : int BytecodeGenerator::AllocateBlockCoverageSlotIfEnabled(
5611 : AstNode* node, SourceRangeKind kind) {
5612 2247153 : return (block_coverage_builder_ == nullptr)
5613 : ? BlockCoverageBuilder::kNoCoverageArraySlot
5614 2247153 : : block_coverage_builder_->AllocateBlockCoverageSlot(node, kind);
5615 : }
5616 :
5617 0 : int BytecodeGenerator::AllocateNaryBlockCoverageSlotIfEnabled(
5618 : NaryOperation* node, size_t index) {
5619 244 : return (block_coverage_builder_ == nullptr)
5620 : ? BlockCoverageBuilder::kNoCoverageArraySlot
5621 : : block_coverage_builder_->AllocateNaryBlockCoverageSlot(node,
5622 244 : index);
5623 : }
5624 :
5625 0 : void BytecodeGenerator::BuildIncrementBlockCoverageCounterIfEnabled(
5626 : AstNode* node, SourceRangeKind kind) {
5627 22915 : if (block_coverage_builder_ == nullptr) return;
5628 152 : block_coverage_builder_->IncrementBlockCounter(node, kind);
5629 : }
5630 :
5631 197037 : void BytecodeGenerator::BuildIncrementBlockCoverageCounterIfEnabled(
5632 : int coverage_array_slot) {
5633 197037 : if (block_coverage_builder_ != nullptr) {
5634 : block_coverage_builder_->IncrementBlockCounter(coverage_array_slot);
5635 : }
5636 197037 : }
5637 :
5638 : // Visits the expression |expr| and places the result in the accumulator.
5639 17265788 : BytecodeGenerator::TypeHint BytecodeGenerator::VisitForAccumulatorValue(
5640 : Expression* expr) {
5641 : ValueResultScope accumulator_scope(this);
5642 17265788 : Visit(expr);
5643 34531678 : return accumulator_scope.type_hint();
5644 : }
5645 :
5646 41966 : void BytecodeGenerator::VisitForAccumulatorValueOrTheHole(Expression* expr) {
5647 41966 : if (expr == nullptr) {
5648 33990 : builder()->LoadTheHole();
5649 : } else {
5650 7976 : VisitForAccumulatorValue(expr);
5651 : }
5652 41965 : }
5653 :
5654 : // Visits the expression |expr| and discards the result.
5655 12645692 : void BytecodeGenerator::VisitForEffect(Expression* expr) {
5656 : EffectResultScope effect_scope(this);
5657 12645692 : Visit(expr);
5658 12645304 : }
5659 :
5660 : // Visits the expression |expr| and returns the register containing
5661 : // the expression result.
5662 5015186 : Register BytecodeGenerator::VisitForRegisterValue(Expression* expr) {
5663 5015186 : VisitForAccumulatorValue(expr);
5664 5015286 : Register result = register_allocator()->NewRegister();
5665 5015293 : builder()->StoreAccumulatorInRegister(result);
5666 5015335 : return result;
5667 : }
5668 :
5669 : // Visits the expression |expr| and stores the expression result in
5670 : // |destination|.
5671 : void BytecodeGenerator::VisitForRegisterValue(Expression* expr,
5672 : Register destination) {
5673 843183 : ValueResultScope register_scope(this);
5674 843188 : Visit(expr);
5675 843187 : builder()->StoreAccumulatorInRegister(destination);
5676 : }
5677 :
5678 : // Visits the expression |expr| and pushes the result into a new register
5679 : // added to the end of |reg_list|.
5680 6845623 : void BytecodeGenerator::VisitAndPushIntoRegisterList(Expression* expr,
5681 : RegisterList* reg_list) {
5682 : {
5683 : ValueResultScope register_scope(this);
5684 6845623 : Visit(expr);
5685 : }
5686 : // Grow the register list after visiting the expression to avoid reserving
5687 : // the register across the expression evaluation, which could cause memory
5688 : // leaks for deep expressions due to dead objects being kept alive by pointers
5689 : // in registers.
5690 6845585 : Register destination = register_allocator()->GrowRegisterList(reg_list);
5691 6845561 : builder()->StoreAccumulatorInRegister(destination);
5692 6845711 : }
5693 :
5694 874247 : void BytecodeGenerator::BuildTest(ToBooleanMode mode,
5695 : BytecodeLabels* then_labels,
5696 : BytecodeLabels* else_labels,
5697 : TestFallthrough fallthrough) {
5698 874247 : switch (fallthrough) {
5699 : case TestFallthrough::kThen:
5700 594481 : builder()->JumpIfFalse(mode, else_labels->New());
5701 594503 : break;
5702 : case TestFallthrough::kElse:
5703 279771 : builder()->JumpIfTrue(mode, then_labels->New());
5704 279771 : break;
5705 : case TestFallthrough::kNone:
5706 0 : builder()->JumpIfTrue(mode, then_labels->New());
5707 0 : builder()->Jump(else_labels->New());
5708 0 : break;
5709 : }
5710 874269 : }
5711 :
5712 : // Visits the expression |expr| for testing its boolean value and jumping to the
5713 : // |then| or |other| label depending on value and short-circuit semantics
5714 1019705 : void BytecodeGenerator::VisitForTest(Expression* expr,
5715 : BytecodeLabels* then_labels,
5716 : BytecodeLabels* else_labels,
5717 : TestFallthrough fallthrough) {
5718 : bool result_consumed;
5719 : TypeHint type_hint;
5720 : {
5721 : // To make sure that all temporary registers are returned before generating
5722 : // jumps below, we ensure that the result scope is deleted before doing so.
5723 : // Dead registers might be materialized otherwise.
5724 : TestResultScope test_result(this, then_labels, else_labels, fallthrough);
5725 1019705 : Visit(expr);
5726 1019725 : result_consumed = test_result.result_consumed_by_test();
5727 1019725 : type_hint = test_result.type_hint();
5728 : // Labels and fallthrough might have been mutated, so update based on
5729 : // TestResultScope.
5730 1019725 : then_labels = test_result.then_labels();
5731 1019725 : else_labels = test_result.else_labels();
5732 1019725 : fallthrough = test_result.fallthrough();
5733 : }
5734 1019731 : if (!result_consumed) {
5735 : BuildTest(ToBooleanModeFromTypeHint(type_hint), then_labels, else_labels,
5736 671331 : fallthrough);
5737 : }
5738 1019744 : }
5739 :
5740 484434 : void BytecodeGenerator::VisitInSameTestExecutionScope(Expression* expr) {
5741 : DCHECK(execution_result()->IsTest());
5742 : {
5743 : RegisterAllocationScope reg_scope(this);
5744 242216 : Visit(expr);
5745 : }
5746 242218 : if (!execution_result()->AsTest()->result_consumed_by_test()) {
5747 202932 : TestResultScope* result_scope = execution_result()->AsTest();
5748 : BuildTest(ToBooleanModeFromTypeHint(result_scope->type_hint()),
5749 : result_scope->then_labels(), result_scope->else_labels(),
5750 405864 : result_scope->fallthrough());
5751 : result_scope->SetResultConsumedByTest();
5752 : }
5753 242217 : }
5754 :
5755 71784 : void BytecodeGenerator::VisitInScope(Statement* stmt, Scope* scope) {
5756 : DCHECK(scope->declarations()->is_empty());
5757 : CurrentScope current_scope(this, scope);
5758 143579 : ContextScope context_scope(this, scope);
5759 71790 : Visit(stmt);
5760 71798 : }
5761 :
5762 16391 : Register BytecodeGenerator::GetRegisterForLocalVariable(Variable* variable) {
5763 : DCHECK_EQ(VariableLocation::LOCAL, variable->location());
5764 16391 : return builder()->Local(variable->index());
5765 : }
5766 :
5767 2114139 : FunctionKind BytecodeGenerator::function_kind() const {
5768 2114139 : return info()->literal()->kind();
5769 : }
5770 :
5771 6271135 : LanguageMode BytecodeGenerator::language_mode() const {
5772 : return current_scope()->language_mode();
5773 : }
5774 :
5775 : Register BytecodeGenerator::generator_object() const {
5776 : DCHECK(IsResumableFunction(info()->literal()->kind()));
5777 : return incoming_new_target_or_generator_;
5778 : }
5779 :
5780 19925552 : FeedbackVectorSpec* BytecodeGenerator::feedback_spec() {
5781 : return info()->feedback_vector_spec();
5782 : }
5783 :
5784 : int BytecodeGenerator::feedback_index(FeedbackSlot slot) const {
5785 : DCHECK(!slot.IsInvalid());
5786 : return FeedbackVector::GetIndex(slot);
5787 : }
5788 :
5789 7625048 : FeedbackSlot BytecodeGenerator::GetCachedLoadGlobalICSlot(
5790 10656173 : TypeofMode typeof_mode, Variable* variable) {
5791 : FeedbackSlotKind slot_kind =
5792 : typeof_mode == INSIDE_TYPEOF
5793 : ? FeedbackSlotKind::kLoadGlobalInsideTypeof
5794 7625048 : : FeedbackSlotKind::kLoadGlobalNotInsideTypeof;
5795 : FeedbackSlot slot = feedback_slot_cache()->Get(slot_kind, variable);
5796 7625536 : if (!slot.IsInvalid()) {
5797 4594370 : return slot;
5798 : }
5799 3031166 : slot = feedback_spec()->AddLoadGlobalICSlot(typeof_mode);
5800 : feedback_slot_cache()->Put(slot_kind, variable, slot);
5801 3031325 : return slot;
5802 : }
5803 :
5804 1438508 : FeedbackSlot BytecodeGenerator::GetCachedStoreGlobalICSlot(
5805 2612902 : LanguageMode language_mode, Variable* variable) {
5806 : FeedbackSlotKind slot_kind = is_strict(language_mode)
5807 : ? FeedbackSlotKind::kStoreGlobalStrict
5808 1438508 : : FeedbackSlotKind::kStoreGlobalSloppy;
5809 : FeedbackSlot slot = feedback_slot_cache()->Get(slot_kind, variable);
5810 1438598 : if (!slot.IsInvalid()) {
5811 264212 : return slot;
5812 : }
5813 1174386 : slot = feedback_spec()->AddStoreGlobalICSlot(language_mode);
5814 : feedback_slot_cache()->Put(slot_kind, variable, slot);
5815 1174412 : return slot;
5816 : }
5817 :
5818 1092326 : FeedbackSlot BytecodeGenerator::GetCachedLoadICSlot(const Expression* expr,
5819 1245217 : const AstRawString* name) {
5820 1092326 : if (!FLAG_ignition_share_named_property_feedback) {
5821 0 : return feedback_spec()->AddLoadICSlot();
5822 : }
5823 : FeedbackSlotKind slot_kind = FeedbackSlotKind::kLoadProperty;
5824 1092332 : if (!expr->IsVariableProxy()) {
5825 342531 : return feedback_spec()->AddLoadICSlot();
5826 : }
5827 1995018 : const VariableProxy* proxy = expr->AsVariableProxy();
5828 : FeedbackSlot slot =
5829 749801 : feedback_slot_cache()->Get(slot_kind, proxy->var()->index(), name);
5830 749803 : if (!slot.IsInvalid()) {
5831 254387 : return slot;
5832 : }
5833 495416 : slot = feedback_spec()->AddLoadICSlot();
5834 495416 : feedback_slot_cache()->Put(slot_kind, proxy->var()->index(), name, slot);
5835 495420 : return slot;
5836 : }
5837 :
5838 2277528 : FeedbackSlot BytecodeGenerator::GetCachedStoreICSlot(const Expression* expr,
5839 42974 : const AstRawString* name) {
5840 2277528 : if (!FLAG_ignition_share_named_property_feedback) {
5841 0 : return feedback_spec()->AddStoreICSlot(language_mode());
5842 : }
5843 : FeedbackSlotKind slot_kind = is_strict(language_mode())
5844 : ? FeedbackSlotKind::kStoreNamedStrict
5845 2277528 : : FeedbackSlotKind::kStoreNamedSloppy;
5846 2277528 : if (!expr->IsVariableProxy()) {
5847 2254786 : return feedback_spec()->AddStoreICSlot(language_mode());
5848 : }
5849 65716 : const VariableProxy* proxy = expr->AsVariableProxy();
5850 : FeedbackSlot slot =
5851 22742 : feedback_slot_cache()->Get(slot_kind, proxy->var()->index(), name);
5852 22743 : if (!slot.IsInvalid()) {
5853 2511 : return slot;
5854 : }
5855 20232 : slot = feedback_spec()->AddStoreICSlot(language_mode());
5856 20232 : feedback_slot_cache()->Put(slot_kind, proxy->var()->index(), name, slot);
5857 20231 : return slot;
5858 : }
5859 :
5860 2894961 : FeedbackSlot BytecodeGenerator::GetCachedCreateClosureSlot(
5861 5790134 : FunctionLiteral* literal) {
5862 : FeedbackSlotKind slot_kind = FeedbackSlotKind::kCreateClosure;
5863 : FeedbackSlot slot = feedback_slot_cache()->Get(slot_kind, literal);
5864 2895166 : if (!slot.IsInvalid()) {
5865 0 : return slot;
5866 : }
5867 2895166 : slot = feedback_spec()->AddCreateClosureSlot();
5868 : feedback_slot_cache()->Put(slot_kind, literal, slot);
5869 2895179 : return slot;
5870 : }
5871 :
5872 0 : FeedbackSlot BytecodeGenerator::GetDummyCompareICSlot() {
5873 1674 : return dummy_feedback_slot_.Get();
5874 : }
5875 :
5876 : } // namespace interpreter
5877 : } // namespace internal
5878 178779 : } // namespace v8
|