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 2432254 : ContextScope(BytecodeGenerator* generator, Scope* scope)
35 : : generator_(generator),
36 : scope_(scope),
37 2432254 : outer_(generator_->execution_context()),
38 : register_(Register::current_context()),
39 4864508 : depth_(0) {
40 : DCHECK(scope->NeedsContext() || outer_ == nullptr);
41 2432260 : if (outer_) {
42 322514 : depth_ = outer_->depth_ + 1;
43 :
44 : // Push the outer context into a new context register.
45 : Register outer_context_reg =
46 322514 : generator_->register_allocator()->NewRegister();
47 322527 : outer_->set_register(outer_context_reg);
48 322527 : generator_->builder()->PushContext(outer_context_reg);
49 : }
50 2432291 : generator_->set_execution_context(this);
51 2432291 : }
52 :
53 2432133 : ~ContextScope() {
54 2432133 : if (outer_) {
55 : DCHECK_EQ(register_.index(), Register::current_context().index());
56 322514 : generator_->builder()->PopContext(outer_->reg());
57 322510 : outer_->set_register(register_);
58 : }
59 2432129 : generator_->set_execution_context(outer_);
60 2432129 : }
61 :
62 : // Returns the depth of the given |scope| for the current execution context.
63 : int ContextChainDepth(Scope* scope) {
64 2785836 : 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 2746102 : if (depth > depth_) {
71 : return nullptr;
72 : }
73 :
74 : ContextScope* previous = this;
75 47940 : for (int i = depth; i > 0; --i) {
76 47940 : 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 645037 : 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 15555192 : explicit ControlScope(BytecodeGenerator* generator)
100 : : generator_(generator),
101 : outer_(generator->execution_control()),
102 23332788 : context_(generator->execution_context()) {
103 : generator_->set_execution_control(this);
104 : }
105 7777353 : virtual ~ControlScope() { generator_->set_execution_control(outer()); }
106 :
107 : void Break(Statement* stmt) {
108 47172 : PerformCommand(CMD_BREAK, stmt, kNoSourcePosition);
109 : }
110 : void Continue(Statement* stmt) {
111 3733 : PerformCommand(CMD_CONTINUE, stmt, kNoSourcePosition);
112 : }
113 : void ReturnAccumulator(int source_position = kNoSourcePosition) {
114 2061287 : PerformCommand(CMD_RETURN, nullptr, source_position);
115 : }
116 : void AsyncReturnAccumulator(int source_position = kNoSourcePosition) {
117 8348 : 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 88204 : 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 88204 : 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 88213 : deferred_.push_back({CMD_RETHROW, nullptr, kRethrowToken});
185 44111 : }
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 222424 : void RecordCommand(Command command, Statement* statement) {
198 55602 : 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 55603 : if (CommandUsesAccumulator(command)) {
206 55349 : builder()->StoreAccumulatorInRegister(result_register_);
207 : }
208 55604 : builder()->LoadLiteral(Smi::FromInt(token));
209 55613 : builder()->StoreAccumulatorInRegister(token_register_);
210 55614 : 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 256 : builder()->StoreAccumulatorInRegister(result_register_);
216 : }
217 55614 : }
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 44111 : 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 132321 : void RecordFallThroughPath() {
230 44097 : builder()->LoadLiteral(Smi::FromInt(kFallthroughToken));
231 44111 : 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 44113 : builder()->StoreAccumulatorInRegister(result_register_);
237 44114 : }
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 235460 : void ApplyDeferredCommands() {
242 88196 : if (deferred_.size() == 0) return;
243 :
244 : BytecodeLabel fall_through;
245 :
246 44098 : 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 83410 : ->LoadLiteral(Smi::FromInt(entry.token))
253 41718 : .CompareReference(token_register_)
254 41717 : .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &fall_through);
255 :
256 41713 : if (CommandUsesAccumulator(entry.command)) {
257 41712 : builder()->LoadAccumulatorWithRegister(result_register_);
258 : }
259 : execution_control()->PerformCommand(entry.command, entry.statement,
260 83436 : 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 4786 : builder()->AllocateJumpTable(static_cast<int>(deferred_.size()), 0);
267 : builder()
268 2392 : ->LoadAccumulatorWithRegister(token_register_)
269 2393 : .SwitchOnSmiNoFeedback(jump_table)
270 2393 : .Jump(&fall_through);
271 10648 : for (const Entry& entry : deferred_) {
272 11724 : builder()->Bind(jump_table, entry.token);
273 :
274 5863 : if (CommandUsesAccumulator(entry.command)) {
275 5607 : builder()->LoadAccumulatorWithRegister(result_register_);
276 : }
277 : execution_control()->PerformCommand(entry.command, entry.statement,
278 11726 : kNoSourcePosition);
279 : }
280 : }
281 :
282 44110 : builder()->Bind(&fall_through);
283 : }
284 :
285 : BytecodeArrayBuilder* builder() { return generator_->builder(); }
286 47581 : ControlScope* execution_control() { return generator_->execution_control(); }
287 :
288 : private:
289 55598 : int GetTokenForCommand(Command command, Statement* statement) {
290 55598 : switch (command) {
291 : case CMD_RETURN:
292 2077 : 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 255 : return GetNewTokenForCommand(command, statement);
301 : }
302 : }
303 :
304 2077 : int GetReturnToken() {
305 2077 : if (return_token_ == -1) {
306 1915 : return_token_ = GetNewTokenForCommand(CMD_RETURN, nullptr);
307 : }
308 2077 : 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 6940 : int token = static_cast<int>(deferred_.size());
320 6939 : 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 2109621 : class BytecodeGenerator::ControlScopeForTopLevel final
336 : : public BytecodeGenerator::ControlScope {
337 : public:
338 : explicit ControlScopeForTopLevel(BytecodeGenerator* generator)
339 2109754 : : ControlScope(generator) {}
340 :
341 : protected:
342 2103691 : bool Execute(Command command, Statement* statement,
343 : int source_position) override {
344 2103691 : 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 2103795 : generator()->BuildReturn(source_position);
351 2061163 : return true;
352 : case CMD_ASYNC_RETURN:
353 : // No need to pop contexts, execution leaves the method body.
354 7131 : generator()->BuildAsyncReturn(source_position);
355 7131 : return true;
356 : case CMD_RETHROW:
357 : // No need to pop contexts, execution leaves the method body.
358 : generator()->BuildReThrow();
359 35886 : return true;
360 : }
361 : return false;
362 : }
363 : };
364 :
365 : // Scoped class for enabling break inside blocks and switch blocks.
366 5250534 : 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 5250646 : control_builder_(control_builder) {}
375 :
376 : protected:
377 407298 : bool Execute(Command command, Statement* statement,
378 : int source_position) override {
379 407298 : if (statement != statement_) return false;
380 26574 : switch (command) {
381 : case CMD_BREAK:
382 26575 : PopContextToExpectedDepth();
383 26575 : control_builder_->Break();
384 26575 : 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 262668 : loop_builder_(loop_builder) {
410 262668 : generator->loop_depth_++;
411 : }
412 262664 : ~ControlScopeForIteration() override { generator()->loop_depth_--; }
413 :
414 : protected:
415 67736 : bool Execute(Command command, Statement* statement,
416 : int source_position) override {
417 67736 : if (statement != statement_) return false;
418 24328 : switch (command) {
419 : case CMD_BREAK:
420 20595 : PopContextToExpectedDepth();
421 20595 : loop_builder_->Break();
422 20597 : return true;
423 : case CMD_CONTINUE:
424 3733 : PopContextToExpectedDepth();
425 3733 : loop_builder_->Continue();
426 3733 : 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 110424 : class BytecodeGenerator::ControlScopeForTryCatch final
442 : : public BytecodeGenerator::ControlScope {
443 : public:
444 : ControlScopeForTryCatch(BytecodeGenerator* generator,
445 : TryCatchBuilder* try_catch_builder)
446 110420 : : ControlScope(generator) {}
447 :
448 : protected:
449 14975 : bool Execute(Command command, Statement* statement,
450 : int source_position) override {
451 14975 : 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 1572 : generator()->BuildReThrow();
461 1572 : return true;
462 : }
463 : return false;
464 : }
465 : };
466 :
467 : // Scoped class for enabling control flow through try-finally constructs.
468 44110 : 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 44108 : commands_(commands) {}
477 :
478 : protected:
479 11498 : bool Execute(Command command, Statement* statement,
480 : int source_position) override {
481 11498 : switch (command) {
482 : case CMD_BREAK:
483 : case CMD_CONTINUE:
484 : case CMD_RETURN:
485 : case CMD_ASYNC_RETURN:
486 : case CMD_RETHROW:
487 11500 : 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 11500 : commands_->RecordCommand(command, statement);
494 11501 : try_finally_builder_->LeaveTry();
495 11501 : 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 19892 : NaryCodeCoverageSlots(BytecodeGenerator* generator, NaryOperation* expr)
509 19892 : : generator_(generator) {
510 39784 : if (generator_->block_coverage_builder_ == nullptr) return;
511 740 : for (size_t i = 0; i < expr->subsequent_length(); i++) {
512 : coverage_slots_.push_back(
513 915 : generator_->AllocateNaryBlockCoverageSlotIfEnabled(expr, i));
514 : }
515 : }
516 :
517 : int GetSlotFor(size_t subsequent_expr_index) const {
518 75133 : if (generator_->block_coverage_builder_ == nullptr) {
519 : return BlockCoverageBuilder::kNoCoverageArraySlot;
520 : }
521 : DCHECK(coverage_slots_.size() > subsequent_expr_index);
522 420 : return coverage_slots_[subsequent_expr_index];
523 : }
524 :
525 : private:
526 : BytecodeGenerator* generator_;
527 : std::vector<int> coverage_slots_;
528 : };
529 :
530 2167762 : void BytecodeGenerator::ControlScope::PerformCommand(Command command,
531 : Statement* statement,
532 : int source_position) {
533 437540 : ControlScope* current = this;
534 437540 : do {
535 2605302 : if (current->Execute(command, statement, source_position)) {
536 2168154 : return;
537 : }
538 : current = current->outer();
539 : } while (current != nullptr);
540 0 : UNREACHABLE();
541 : }
542 :
543 124806 : 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 124806 : if (generator()->execution_context() != context()) {
547 9491 : generator()->builder()->PopContext(context()->reg());
548 : }
549 62403 : }
550 :
551 : class BytecodeGenerator::RegisterAllocationScope final {
552 : public:
553 : explicit RegisterAllocationScope(BytecodeGenerator* generator)
554 : : generator_(generator),
555 : outer_next_register_index_(
556 78335621 : generator->register_allocator()->next_register_index()) {}
557 :
558 78309960 : ~RegisterAllocationScope() {
559 : generator_->register_allocator()->ReleaseRegisters(
560 78309960 : outer_next_register_index_);
561 78309303 : }
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 2424013 : explicit AccumulatorPreservingScope(BytecodeGenerator* generator,
575 : AccumulatorPreservingMode mode)
576 2424013 : : generator_(generator) {
577 2424013 : 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 2424013 : }
584 :
585 : ~AccumulatorPreservingScope() {
586 2424124 : 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 44355179 : ExpressionResultScope(BytecodeGenerator* generator, Expression::Context kind)
604 : : outer_(generator->execution_result()),
605 : allocator_(generator),
606 : kind_(kind),
607 88710358 : type_hint_(TypeHint::kAny) {
608 : generator->set_execution_result(this);
609 : }
610 :
611 44354573 : ~ExpressionResultScope() {
612 44354573 : 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 1179231 : type_hint_ = TypeHint::kBoolean;
628 : }
629 :
630 : void SetResultIsString() {
631 : DCHECK_EQ(type_hint_, TypeHint::kAny);
632 1765909 : 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 1697529 : class BytecodeGenerator::ValueResultScope final : public ExpressionResultScope {
658 : public:
659 848818 : explicit ValueResultScope(BytecodeGenerator* generator)
660 1697636 : : 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 972473 : 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 300269 : 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 207721 : void InvertControlFlow() {
683 : std::swap(then_labels_, else_labels_);
684 207721 : fallthrough_ = inverted_fallthrough();
685 : }
686 :
687 21001 : BytecodeLabel* NewThenLabel() { return then_labels_->New(); }
688 15304 : 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 207721 : 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 2227232 : explicit GlobalDeclarationsBuilder(Zone* zone)
728 : : declarations_(0, zone),
729 : constant_pool_entry_(0),
730 2227249 : 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 499401 : declarations_.push_back(Declaration(name, slot, literal_slot, func));
737 : }
738 :
739 : void AddUndefinedDeclaration(const AstRawString* name, FeedbackSlot slot) {
740 : DCHECK(!slot.IsInvalid());
741 2481254 : declarations_.push_back(Declaration(name, slot, nullptr));
742 : }
743 :
744 107218 : 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 214436 : static_cast<int>(declarations_.size() * 4), TENURED);
751 1493659 : for (const Declaration& declaration : declarations_) {
752 1279223 : FunctionLiteral* func = declaration.func;
753 : Handle<Object> initial_value;
754 1279223 : if (func == nullptr) {
755 : initial_value = isolate->factory()->undefined_value();
756 : } else {
757 217194 : 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 1279223 : if (initial_value.is_null()) return Handle<FixedArray>();
763 :
764 3837669 : data->set(array_index++, *declaration.name->string());
765 1279223 : data->set(array_index++, Smi::FromInt(declaration.slot.ToInt()));
766 : Object undefined_or_literal_slot;
767 1279223 : if (declaration.literal_slot.IsInvalid()) {
768 1062029 : undefined_or_literal_slot = ReadOnlyRoots(isolate).undefined_value();
769 : } else {
770 : undefined_or_literal_slot =
771 217194 : Smi::FromInt(declaration.literal_slot.ToInt());
772 : }
773 2558446 : data->set(array_index++, undefined_or_literal_slot);
774 2558446 : data->set(array_index++, *initial_value);
775 : }
776 107218 : 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 117500 : constant_pool_entry_ = constant_pool_entry;
788 117500 : has_constant_pool_entry_ = true;
789 : }
790 :
791 : bool empty() { return declarations_.empty(); }
792 :
793 : private:
794 : struct Declaration {
795 4454464 : Declaration() : slot(FeedbackSlot::Invalid()), func(nullptr) {}
796 : Declaration(const AstRawString* name, FeedbackSlot slot,
797 : FeedbackSlot literal_slot, FunctionLiteral* func)
798 249698 : : 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 1240607 : 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 5353787 : CurrentScope(BytecodeGenerator* generator, Scope* scope)
819 : : generator_(generator), outer_scope_(generator->current_scope()) {
820 5353787 : if (scope != nullptr) {
821 : DCHECK_EQ(outer_scope_, scope->outer_scope());
822 : generator_->set_current_scope(scope);
823 : }
824 : }
825 : ~CurrentScope() {
826 5353940 : 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 9145618 : return GetImpl(slot_kind, 0, variable);
853 : }
854 : FeedbackSlot Get(FeedbackSlotKind slot_kind, AstNode* node) const {
855 2854753 : return GetImpl(slot_kind, 0, node);
856 : }
857 : FeedbackSlot Get(FeedbackSlotKind slot_kind, int variable_index,
858 : const AstRawString* name) const {
859 3193182 : 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 15191951 : 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 15193007 : if (iter != map_.end()) {
877 7279134 : return iter->second;
878 : }
879 7913873 : 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 2109791 : BytecodeGenerator::BytecodeGenerator(
917 4219576 : UnoptimizedCompilationInfo* info,
918 : const AstStringConstants* ast_string_constants,
919 21099026 : std::vector<FunctionLiteral*>* eager_inner_literals)
920 : : zone_(info->zone()),
921 : builder_(zone(), info->num_parameters_including_this(),
922 2109799 : info->scope()->num_stack_slots(), info->feedback_vector_spec(),
923 : info->SourcePositionRecordingMode()),
924 : info_(info),
925 : ast_string_constants_(ast_string_constants),
926 2109810 : closure_scope_(info->scope()),
927 2109808 : current_scope_(info->scope()),
928 : eager_inner_literals_(eager_inner_literals),
929 : feedback_slot_cache_(new (zone()) FeedbackSlotCache(zone())),
930 2109793 : 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 21097961 : catch_prediction_(HandlerTable::UNCAUGHT) {
948 : DCHECK_EQ(closure_scope(), closure_scope()->GetClosureScope());
949 2109785 : if (info->has_source_range_map()) {
950 : block_coverage_builder_ = new (zone())
951 1080 : BlockCoverageBuilder(zone(), builder(), info->source_range_map());
952 : }
953 2109785 : }
954 :
955 2086359 : Handle<BytecodeArray> BytecodeGenerator::FinalizeBytecode(
956 2087437 : 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 : SaveContext save(isolate);
962 : isolate->set_context(Context());
963 : #endif
964 :
965 2086359 : AllocateDeferredConstants(isolate, script);
966 :
967 2086357 : if (block_coverage_builder_) {
968 : info()->set_coverage_info(
969 1080 : isolate->factory()->NewCoverageInfo(block_coverage_builder_->slots()));
970 1080 : if (FLAG_trace_block_coverage) {
971 0 : info()->coverage_info()->Print(info()->literal()->GetDebugName());
972 : }
973 : }
974 :
975 2086357 : if (HasStackOverflow()) return Handle<BytecodeArray>();
976 2086357 : Handle<BytecodeArray> bytecode_array = builder()->ToBytecodeArray(isolate);
977 :
978 2086383 : if (incoming_new_target_or_generator_.is_valid()) {
979 : bytecode_array->set_incoming_new_target_or_generator_register(
980 212292 : incoming_new_target_or_generator_);
981 : }
982 :
983 2086383 : return bytecode_array;
984 : }
985 :
986 2086348 : void BytecodeGenerator::AllocateDeferredConstants(Isolate* isolate,
987 107218 : Handle<Script> script) {
988 : // Build global declaration pair arrays.
989 4387132 : for (GlobalDeclarationsBuilder* globals_builder : global_declarations_) {
990 : Handle<FixedArray> declarations =
991 107218 : globals_builder->AllocateDeclarations(info(), script, isolate);
992 107218 : if (declarations.is_null()) return SetStackOverflow();
993 : builder()->SetDeferredConstantPoolEntry(
994 107218 : globals_builder->constant_pool_entry(), declarations);
995 : }
996 :
997 : // Find or build shared function infos.
998 6513097 : for (std::pair<FunctionLiteral*, size_t> literal : function_literals_) {
999 : FunctionLiteral* expr = literal.first;
1000 : Handle<SharedFunctionInfo> shared_info =
1001 2340388 : Compiler::GetSharedFunctionInfo(expr, script, isolate);
1002 2340406 : if (shared_info.is_null()) return SetStackOverflow();
1003 2340406 : builder()->SetDeferredConstantPoolEntry(literal.second, shared_info);
1004 : }
1005 :
1006 : // Find or build shared function infos for the native function templates.
1007 4174483 : for (std::pair<NativeFunctionLiteral*, size_t> literal :
1008 1761 : native_function_literals_) {
1009 5283 : NativeFunctionLiteral* expr = literal.first;
1010 : v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
1011 :
1012 : // Compute the function template for the native function.
1013 : v8::Local<v8::FunctionTemplate> info =
1014 : expr->extension()->GetNativeFunctionTemplate(
1015 3522 : v8_isolate, Utils::ToLocal(expr->name()));
1016 : DCHECK(!info.IsEmpty());
1017 :
1018 : Handle<SharedFunctionInfo> shared_info =
1019 : FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(
1020 1761 : isolate, Utils::OpenHandle(*info), expr->name());
1021 : DCHECK(!shared_info.is_null());
1022 1761 : builder()->SetDeferredConstantPoolEntry(literal.second, shared_info);
1023 : }
1024 :
1025 : // Build object literal constant properties
1026 4360482 : for (std::pair<ObjectLiteral*, size_t> literal : object_literals_) {
1027 187753 : ObjectLiteral* object_literal = literal.first;
1028 187753 : if (object_literal->properties_count() > 0) {
1029 : // If constant properties is an empty fixed array, we've already added it
1030 : // to the constant pool when visiting the object literal.
1031 : Handle<ObjectBoilerplateDescription> constant_properties =
1032 : object_literal->GetOrBuildBoilerplateDescription(isolate);
1033 :
1034 : builder()->SetDeferredConstantPoolEntry(literal.second,
1035 187763 : constant_properties);
1036 : }
1037 : }
1038 :
1039 : // Build array literal constant elements
1040 4327147 : for (std::pair<ArrayLiteral*, size_t> literal : array_literals_) {
1041 : ArrayLiteral* array_literal = literal.first;
1042 : Handle<ArrayBoilerplateDescription> constant_elements =
1043 : array_literal->GetOrBuildBoilerplateDescription(isolate);
1044 154412 : builder()->SetDeferredConstantPoolEntry(literal.second, constant_elements);
1045 : }
1046 :
1047 : // Build class literal boilerplates.
1048 4211572 : for (std::pair<ClassLiteral*, size_t> literal : class_literals_) {
1049 : ClassLiteral* class_literal = literal.first;
1050 : Handle<ClassBoilerplate> class_boilerplate =
1051 38836 : ClassBoilerplate::BuildClassBoilerplate(isolate, class_literal);
1052 38836 : builder()->SetDeferredConstantPoolEntry(literal.second, class_boilerplate);
1053 : }
1054 :
1055 : // Build template literals.
1056 4174580 : for (std::pair<GetTemplateObject*, size_t> literal : template_objects_) {
1057 : GetTemplateObject* get_template_object = literal.first;
1058 : Handle<TemplateObjectDescription> description =
1059 1844 : get_template_object->GetOrBuildDescription(isolate);
1060 1844 : builder()->SetDeferredConstantPoolEntry(literal.second, description);
1061 : }
1062 : }
1063 :
1064 8630688 : void BytecodeGenerator::GenerateBytecode(uintptr_t stack_limit) {
1065 : DisallowHeapAllocation no_allocation;
1066 : DisallowHandleAllocation no_handles;
1067 : DisallowHandleDereference no_deref;
1068 :
1069 : InitializeAstVisitor(stack_limit);
1070 :
1071 : // Initialize the incoming context.
1072 2109753 : ContextScope incoming_context(this, closure_scope());
1073 :
1074 : // Initialize control scope.
1075 : ControlScopeForTopLevel control(this);
1076 :
1077 2109532 : RegisterAllocationScope register_scope(this);
1078 :
1079 2109754 : AllocateTopLevelRegisters();
1080 :
1081 4219576 : if (info()->literal()->CanSuspend()) {
1082 9177 : BuildGeneratorPrologue();
1083 : }
1084 :
1085 2109764 : if (closure_scope()->NeedsContext()) {
1086 : // Push a new inner context scope for the function.
1087 191636 : BuildNewLocalActivationContext();
1088 191630 : ContextScope local_function_context(this, closure_scope());
1089 191631 : BuildLocalActivationContextInitialization();
1090 191624 : GenerateBytecodeBody();
1091 : } else {
1092 1918128 : GenerateBytecodeBody();
1093 : }
1094 :
1095 : // Check that we are not falling off the end.
1096 2109621 : DCHECK(!builder()->RequiresImplicitReturn());
1097 2109647 : }
1098 :
1099 21113919 : void BytecodeGenerator::GenerateBytecodeBody() {
1100 : // Build the arguments object if it is used.
1101 2109721 : VisitArgumentsObject(closure_scope()->arguments());
1102 :
1103 : // Build rest arguments array if it is used.
1104 : Variable* rest_parameter = closure_scope()->rest_parameter();
1105 2109727 : VisitRestArgumentsArray(rest_parameter);
1106 :
1107 : // Build assignment to the function name or {.this_function}
1108 : // variables if used.
1109 2109741 : VisitThisFunctionVariable(closure_scope()->function_var());
1110 2109736 : VisitThisFunctionVariable(closure_scope()->this_function_var());
1111 :
1112 : // Build assignment to {new.target} variable if it is used.
1113 2109741 : VisitNewTargetVariable(closure_scope()->new_target_var());
1114 :
1115 : // Create a generator object if necessary and initialize the
1116 : // {.generator_object} variable.
1117 2109725 : if (IsResumableFunction(info()->literal()->kind())) {
1118 10864 : BuildGeneratorObjectVariableInitialization();
1119 : }
1120 :
1121 : // Emit tracing call if requested to do so.
1122 2109761 : if (FLAG_trace) builder()->CallRuntime(Runtime::kTraceEnter);
1123 :
1124 : // Emit type profile call.
1125 2109761 : if (info()->collect_type_profile()) {
1126 85 : feedback_spec()->AddTypeProfileSlot();
1127 85 : int num_parameters = closure_scope()->num_parameters();
1128 205 : for (int i = 0; i < num_parameters; i++) {
1129 120 : Register parameter(builder()->Parameter(i));
1130 120 : builder()->LoadAccumulatorWithRegister(parameter).CollectTypeProfile(
1131 240 : closure_scope()->parameter(i)->initializer_position());
1132 : }
1133 : }
1134 :
1135 : // Visit declarations within the function scope.
1136 2109761 : VisitDeclarations(closure_scope()->declarations());
1137 :
1138 : // Emit initializing assignments for module namespace imports (if any).
1139 2109641 : VisitModuleNamespaceImports();
1140 :
1141 : // Perform a stack-check before the body.
1142 2109672 : builder()->StackCheck(info()->literal()->start_position());
1143 :
1144 : // The derived constructor case is handled in VisitCallSuper.
1145 2126129 : if (IsBaseConstructor(function_kind()) &&
1146 16332 : info()->literal()->requires_instance_members_initializer()) {
1147 : BuildInstanceMemberInitialization(Register::function_closure(),
1148 516 : builder()->Receiver());
1149 : }
1150 :
1151 : // Visit statements in the function body.
1152 2109797 : VisitStatements(info()->literal()->body());
1153 :
1154 : // Emit an implicit return instruction in case control flow can fall off the
1155 : // end of the function without an explicit return being present on all paths.
1156 2109506 : if (builder()->RequiresImplicitReturn()) {
1157 373649 : builder()->LoadUndefined();
1158 373650 : BuildReturn();
1159 : }
1160 2109518 : }
1161 :
1162 4219522 : void BytecodeGenerator::AllocateTopLevelRegisters() {
1163 2109738 : if (IsResumableFunction(info()->literal()->kind())) {
1164 : // Either directly use generator_object_var or allocate a new register for
1165 : // the incoming generator object.
1166 10864 : Variable* generator_object_var = closure_scope()->generator_object_var();
1167 10864 : if (generator_object_var->location() == VariableLocation::LOCAL) {
1168 : incoming_new_target_or_generator_ =
1169 10864 : GetRegisterForLocalVariable(generator_object_var);
1170 : } else {
1171 0 : incoming_new_target_or_generator_ = register_allocator()->NewRegister();
1172 : }
1173 2098920 : } else if (closure_scope()->new_target_var()) {
1174 : // Either directly use new_target_var or allocate a new register for
1175 : // the incoming new target object.
1176 100313 : Variable* new_target_var = closure_scope()->new_target_var();
1177 100313 : if (new_target_var->location() == VariableLocation::LOCAL) {
1178 : incoming_new_target_or_generator_ =
1179 5449 : GetRegisterForLocalVariable(new_target_var);
1180 : } else {
1181 94864 : incoming_new_target_or_generator_ = register_allocator()->NewRegister();
1182 : }
1183 : }
1184 2109784 : }
1185 :
1186 9177 : void BytecodeGenerator::BuildGeneratorPrologue() {
1187 : DCHECK_GT(info()->literal()->suspend_count(), 0);
1188 : DCHECK(generator_object().is_valid());
1189 : generator_jump_table_ =
1190 9177 : builder()->AllocateJumpTable(info()->literal()->suspend_count(), 0);
1191 :
1192 : // If the generator is not undefined, this is a resume, so perform state
1193 : // dispatch.
1194 9177 : builder()->SwitchOnGeneratorState(generator_object(), generator_jump_table_);
1195 :
1196 : // Otherwise, fall-through to the ordinary function prologue, after which we
1197 : // will run into the generator object creation and other extra code inserted
1198 : // by the parser.
1199 9177 : }
1200 :
1201 10505241 : void BytecodeGenerator::VisitBlock(Block* stmt) {
1202 : // Visit declarations and statements.
1203 : CurrentScope current_scope(this, stmt->scope());
1204 5435920 : if (stmt->scope() != nullptr && stmt->scope()->NeedsContext()) {
1205 24810 : BuildNewLocalBlockContext(stmt->scope());
1206 24805 : ContextScope scope(this, stmt->scope());
1207 24810 : VisitBlockDeclarationsAndStatements(stmt);
1208 : } else {
1209 5215408 : VisitBlockDeclarationsAndStatements(stmt);
1210 : }
1211 5240357 : }
1212 :
1213 10480412 : void BytecodeGenerator::VisitBlockDeclarationsAndStatements(Block* stmt) {
1214 5240206 : BlockBuilder block_builder(builder(), block_coverage_builder_, stmt);
1215 : ControlScopeForBreakable execution_control(this, stmt, &block_builder);
1216 5240206 : if (stmt->scope() != nullptr) {
1217 195705 : VisitDeclarations(stmt->scope()->declarations());
1218 : }
1219 5240214 : VisitStatements(stmt->statements());
1220 5240336 : }
1221 :
1222 6532267 : void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) {
1223 6817265 : Variable* variable = decl->var();
1224 4551038 : switch (variable->location()) {
1225 : case VariableLocation::UNALLOCATED: {
1226 : DCHECK(!variable->binding_needs_init());
1227 : FeedbackSlot slot =
1228 1240524 : GetCachedLoadGlobalICSlot(NOT_INSIDE_TYPEOF, variable);
1229 : globals_builder()->AddUndefinedDeclaration(variable->raw_name(), slot);
1230 : break;
1231 : }
1232 : case VariableLocation::LOCAL:
1233 1526758 : if (variable->binding_needs_init()) {
1234 3190 : Register destination(builder()->Local(variable->index()));
1235 3190 : builder()->LoadTheHole().StoreAccumulatorInRegister(destination);
1236 : }
1237 : break;
1238 : case VariableLocation::PARAMETER:
1239 586 : if (variable->binding_needs_init()) {
1240 0 : Register destination(builder()->Parameter(variable->index()));
1241 0 : builder()->LoadTheHole().StoreAccumulatorInRegister(destination);
1242 : }
1243 : break;
1244 : case VariableLocation::CONTEXT:
1245 1483876 : if (variable->binding_needs_init()) {
1246 : DCHECK_EQ(0, execution_context()->ContextChainDepth(variable->scope()));
1247 740622 : builder()->LoadTheHole().StoreContextSlot(execution_context()->reg(),
1248 740689 : variable->index(), 0);
1249 : }
1250 : break;
1251 : case VariableLocation::LOOKUP: {
1252 : DCHECK_EQ(VariableMode::kDynamic, variable->mode());
1253 : DCHECK(!variable->binding_needs_init());
1254 :
1255 281808 : Register name = register_allocator()->NewRegister();
1256 :
1257 : builder()
1258 281808 : ->LoadLiteral(variable->raw_name())
1259 281808 : .StoreAccumulatorInRegister(name)
1260 281808 : .CallRuntime(Runtime::kDeclareEvalVar, name);
1261 : break;
1262 : }
1263 : case VariableLocation::MODULE:
1264 17646 : if (variable->IsExport() && variable->binding_needs_init()) {
1265 17039 : builder()->LoadTheHole();
1266 17039 : BuildVariableAssignment(variable, Token::INIT, HoleCheckMode::kElided);
1267 : }
1268 : // Nothing to do for imports.
1269 : break;
1270 : }
1271 4551143 : }
1272 :
1273 1968909 : void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) {
1274 974436 : Variable* variable = decl->var();
1275 : DCHECK(variable->mode() == VariableMode::kLet ||
1276 : variable->mode() == VariableMode::kVar ||
1277 : variable->mode() == VariableMode::kDynamic);
1278 502260 : switch (variable->location()) {
1279 : case VariableLocation::UNALLOCATED: {
1280 : FeedbackSlot slot =
1281 249649 : GetCachedLoadGlobalICSlot(NOT_INSIDE_TYPEOF, variable);
1282 249680 : FeedbackSlot literal_slot = GetCachedCreateClosureSlot(decl->fun());
1283 : globals_builder()->AddFunctionDeclaration(variable->raw_name(), slot,
1284 : literal_slot, decl->fun());
1285 249703 : AddToEagerLiteralsIfEager(decl->fun());
1286 : break;
1287 : }
1288 : case VariableLocation::PARAMETER:
1289 : case VariableLocation::LOCAL: {
1290 29804 : VisitFunctionLiteral(decl->fun());
1291 29804 : BuildVariableAssignment(variable, Token::INIT, HoleCheckMode::kElided);
1292 29804 : break;
1293 : }
1294 : case VariableLocation::CONTEXT: {
1295 : DCHECK_EQ(0, execution_context()->ContextChainDepth(variable->scope()));
1296 215248 : VisitFunctionLiteral(decl->fun());
1297 : builder()->StoreContextSlot(execution_context()->reg(), variable->index(),
1298 215246 : 0);
1299 215249 : break;
1300 : }
1301 : case VariableLocation::LOOKUP: {
1302 7232 : RegisterList args = register_allocator()->NewRegisterList(2);
1303 : builder()
1304 7232 : ->LoadLiteral(variable->raw_name())
1305 7232 : .StoreAccumulatorInRegister(args[0]);
1306 7232 : VisitFunctionLiteral(decl->fun());
1307 7232 : builder()->StoreAccumulatorInRegister(args[1]).CallRuntime(
1308 7232 : Runtime::kDeclareEvalFunction, args);
1309 : break;
1310 : }
1311 : case VariableLocation::MODULE:
1312 : DCHECK_EQ(variable->mode(), VariableMode::kLet);
1313 : DCHECK(variable->IsExport());
1314 340 : VisitForAccumulatorValue(decl->fun());
1315 340 : BuildVariableAssignment(variable, Token::INIT, HoleCheckMode::kElided);
1316 340 : break;
1317 : }
1318 : DCHECK_IMPLIES(decl->fun()->ShouldEagerCompile(),
1319 : IsInEagerLiterals(decl->fun(), *eager_inner_literals_));
1320 502302 : }
1321 :
1322 2110866 : void BytecodeGenerator::VisitModuleNamespaceImports() {
1323 4218178 : if (!closure_scope()->is_module_scope()) return;
1324 :
1325 : RegisterAllocationScope register_scope(this);
1326 1098 : Register module_request = register_allocator()->NewRegister();
1327 :
1328 1098 : ModuleDescriptor* descriptor = closure_scope()->AsModuleScope()->module();
1329 2326 : for (auto entry : descriptor->namespace_imports()) {
1330 : builder()
1331 260 : ->LoadLiteral(Smi::FromInt(entry->module_request))
1332 130 : .StoreAccumulatorInRegister(module_request)
1333 130 : .CallRuntime(Runtime::kGetModuleNamespace, module_request);
1334 130 : Variable* var = closure_scope()->LookupInModule(entry->local_name);
1335 130 : BuildVariableAssignment(var, Token::INIT, HoleCheckMode::kElided);
1336 1098 : }
1337 : }
1338 :
1339 5280333 : void BytecodeGenerator::VisitDeclarations(Declaration::List* declarations) {
1340 : RegisterAllocationScope register_scope(this);
1341 : DCHECK(globals_builder()->empty());
1342 9746143 : for (Declaration* decl : *declarations) {
1343 : RegisterAllocationScope register_scope(this);
1344 5053262 : Visit(decl);
1345 5053379 : }
1346 4575467 : if (globals_builder()->empty()) return;
1347 :
1348 : globals_builder()->set_constant_pool_entry(
1349 117487 : builder()->AllocateDeferredConstantPoolEntry());
1350 117500 : int encoded_flags = DeclareGlobalsEvalFlag::encode(info()->is_eval()) |
1351 117500 : DeclareGlobalsNativeFlag::encode(info()->is_native());
1352 :
1353 : // Emit code to declare globals.
1354 117500 : RegisterList args = register_allocator()->NewRegisterList(3);
1355 : builder()
1356 117495 : ->LoadConstantPoolEntry(globals_builder()->constant_pool_entry())
1357 117489 : .StoreAccumulatorInRegister(args[0])
1358 117496 : .LoadLiteral(Smi::FromInt(encoded_flags))
1359 117434 : .StoreAccumulatorInRegister(args[1])
1360 234966 : .MoveRegister(Register::function_closure(), args[2])
1361 117428 : .CallRuntime(Runtime::kDeclareGlobals, args);
1362 :
1363 : // Push and reset globals builder.
1364 234957 : global_declarations_.push_back(globals_builder());
1365 117452 : globals_builder_ = new (zone()) GlobalDeclarationsBuilder(zone());
1366 : }
1367 :
1368 7429435 : void BytecodeGenerator::VisitStatements(
1369 22673419 : const ZonePtrList<Statement>* statements) {
1370 45346838 : for (int i = 0; i < statements->length(); i++) {
1371 : // Allocate an outer register allocations scope for the statement.
1372 : RegisterAllocationScope allocation_scope(this);
1373 17192589 : Statement* stmt = statements->at(i);
1374 17192589 : Visit(stmt);
1375 17191593 : if (builder()->RemainderOfBlockIsDead()) break;
1376 15244080 : }
1377 7428383 : }
1378 :
1379 20310700 : void BytecodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
1380 : builder()->SetStatementPosition(stmt);
1381 10155350 : VisitForEffect(stmt->expression());
1382 10154548 : }
1383 :
1384 0 : void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {}
1385 :
1386 3343515 : void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) {
1387 : ConditionalControlFlowBuilder conditional_builder(
1388 550542 : builder(), block_coverage_builder_, stmt);
1389 : builder()->SetStatementPosition(stmt);
1390 :
1391 550542 : if (stmt->condition()->ToBooleanIsTrue()) {
1392 : // Generate then block unconditionally as always true.
1393 442 : conditional_builder.Then();
1394 442 : Visit(stmt->then_statement());
1395 550101 : } else if (stmt->condition()->ToBooleanIsFalse()) {
1396 : // Generate else block unconditionally if it exists.
1397 8312 : if (stmt->HasElseStatement()) {
1398 7048 : conditional_builder.Else();
1399 7048 : Visit(stmt->else_statement());
1400 : }
1401 : } else {
1402 : // TODO(oth): If then statement is BreakStatement or
1403 : // ContinueStatement we can reduce number of generated
1404 : // jump/jump_ifs here. See BasicLoops test.
1405 : VisitForTest(stmt->condition(), conditional_builder.then_labels(),
1406 541794 : conditional_builder.else_labels(), TestFallthrough::kThen);
1407 :
1408 541805 : conditional_builder.Then();
1409 541799 : Visit(stmt->then_statement());
1410 :
1411 541810 : if (stmt->HasElseStatement()) {
1412 51132 : conditional_builder.JumpToEnd();
1413 51131 : conditional_builder.Else();
1414 51128 : Visit(stmt->else_statement());
1415 : }
1416 550562 : }
1417 550559 : }
1418 :
1419 3071 : void BytecodeGenerator::VisitSloppyBlockFunctionStatement(
1420 3071 : SloppyBlockFunctionStatement* stmt) {
1421 3071 : Visit(stmt->statement());
1422 3072 : }
1423 :
1424 7466 : void BytecodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
1425 : AllocateBlockCoverageSlotIfEnabled(stmt, SourceRangeKind::kContinuation);
1426 : builder()->SetStatementPosition(stmt);
1427 : execution_control()->Continue(stmt->target());
1428 3733 : }
1429 :
1430 94343 : void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
1431 : AllocateBlockCoverageSlotIfEnabled(stmt, SourceRangeKind::kContinuation);
1432 : builder()->SetStatementPosition(stmt);
1433 : execution_control()->Break(stmt->target());
1434 47171 : }
1435 :
1436 6182065 : void BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
1437 : AllocateBlockCoverageSlotIfEnabled(stmt, SourceRangeKind::kContinuation);
1438 : builder()->SetStatementPosition(stmt);
1439 2060592 : VisitForAccumulatorValue(stmt->expression());
1440 2060949 : if (stmt->is_async_return()) {
1441 : execution_control()->AsyncReturnAccumulator(stmt->end_position());
1442 : } else {
1443 : execution_control()->ReturnAccumulator(stmt->end_position());
1444 : }
1445 2060986 : }
1446 :
1447 11822 : void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) {
1448 : builder()->SetStatementPosition(stmt);
1449 2955 : VisitForAccumulatorValue(stmt->expression());
1450 2956 : BuildNewLocalWithContext(stmt->scope());
1451 2956 : VisitInScope(stmt->statement(), stmt->scope());
1452 2956 : }
1453 :
1454 20880 : void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
1455 : // We need this scope because we visit for register values. We have to
1456 : // maintain a execution result scope where registers can be allocated.
1457 199970 : ZonePtrList<CaseClause>* clauses = stmt->cases();
1458 : SwitchBuilder switch_builder(builder(), block_coverage_builder_, stmt,
1459 10440 : clauses->length());
1460 : ControlScopeForBreakable scope(this, stmt, &switch_builder);
1461 : int default_index = -1;
1462 :
1463 : builder()->SetStatementPosition(stmt);
1464 :
1465 : // Keep the switch value in a register until a case matches.
1466 10440 : Register tag = VisitForRegisterValue(stmt->tag());
1467 : FeedbackSlot slot = clauses->length() > 0
1468 10412 : ? feedback_spec()->AddCompareICSlot()
1469 10440 : : FeedbackSlot::Invalid();
1470 :
1471 : // Iterate over all cases and create nodes for label comparison.
1472 179090 : for (int i = 0; i < clauses->length(); i++) {
1473 79105 : CaseClause* clause = clauses->at(i);
1474 :
1475 : // The default is not a test, remember index.
1476 79105 : if (clause->is_default()) {
1477 : default_index = i;
1478 : continue;
1479 : }
1480 :
1481 : // Perform label comparison as if via '===' with tag.
1482 71853 : VisitForAccumulatorValue(clause->label());
1483 : builder()->CompareOperation(Token::Value::EQ_STRICT, tag,
1484 71853 : feedback_index(slot));
1485 71852 : switch_builder.Case(ToBooleanMode::kAlreadyBoolean, i);
1486 : }
1487 :
1488 10440 : if (default_index >= 0) {
1489 : // Emit default jump if there is a default case.
1490 7252 : switch_builder.DefaultAt(default_index);
1491 : } else {
1492 : // Otherwise if we have reached here none of the cases matched, so jump to
1493 : // the end.
1494 : switch_builder.Break();
1495 : }
1496 :
1497 : // Iterate over all cases and create the case bodies.
1498 168649 : for (int i = 0; i < clauses->length(); i++) {
1499 79105 : CaseClause* clause = clauses->at(i);
1500 79105 : switch_builder.SetCaseTarget(i, clause);
1501 79105 : VisitStatements(clause->statements());
1502 10440 : }
1503 10440 : }
1504 :
1505 : template <typename TryBodyFunc, typename CatchBodyFunc>
1506 110417 : void BytecodeGenerator::BuildTryCatch(
1507 : TryBodyFunc try_body_func, CatchBodyFunc catch_body_func,
1508 : HandlerTable::CatchPrediction catch_prediction,
1509 : TryCatchStatement* stmt_for_coverage) {
1510 : TryCatchBuilder try_control_builder(
1511 : builder(),
1512 : stmt_for_coverage == nullptr ? nullptr : block_coverage_builder_,
1513 110417 : stmt_for_coverage, catch_prediction);
1514 :
1515 : // Preserve the context in a dedicated register, so that it can be restored
1516 : // when the handler is entered by the stack-unwinding machinery.
1517 : // TODO(mstarzinger): Be smarter about register allocation.
1518 110421 : Register context = register_allocator()->NewRegister();
1519 110425 : builder()->MoveRegister(Register::current_context(), context);
1520 :
1521 : // Evaluate the try-block inside a control scope. This simulates a handler
1522 : // that is intercepting 'throw' control commands.
1523 110431 : try_control_builder.BeginTry(context);
1524 : {
1525 : ControlScopeForTryCatch scope(this, &try_control_builder);
1526 110420 : try_body_func();
1527 : }
1528 110424 : try_control_builder.EndTry();
1529 :
1530 110400 : catch_body_func(context);
1531 :
1532 110415 : try_control_builder.EndCatch();
1533 110388 : }
1534 :
1535 : template <typename TryBodyFunc, typename FinallyBodyFunc>
1536 44101 : void BytecodeGenerator::BuildTryFinally(
1537 : TryBodyFunc try_body_func, FinallyBodyFunc finally_body_func,
1538 : HandlerTable::CatchPrediction catch_prediction,
1539 : TryFinallyStatement* stmt_for_coverage) {
1540 : // We can't know whether the finally block will override ("catch") an
1541 : // exception thrown in the try block, so we just adopt the outer prediction.
1542 : TryFinallyBuilder try_control_builder(
1543 : builder(),
1544 : stmt_for_coverage == nullptr ? nullptr : block_coverage_builder_,
1545 44101 : stmt_for_coverage, catch_prediction);
1546 :
1547 : // We keep a record of all paths that enter the finally-block to be able to
1548 : // dispatch to the correct continuation point after the statements in the
1549 : // finally-block have been evaluated.
1550 : //
1551 : // The try-finally construct can enter the finally-block in three ways:
1552 : // 1. By exiting the try-block normally, falling through at the end.
1553 : // 2. By exiting the try-block with a function-local control flow transfer
1554 : // (i.e. through break/continue/return statements).
1555 : // 3. By exiting the try-block with a thrown exception.
1556 : //
1557 : // The result register semantics depend on how the block was entered:
1558 : // - ReturnStatement: It represents the return value being returned.
1559 : // - ThrowStatement: It represents the exception being thrown.
1560 : // - BreakStatement/ContinueStatement: Undefined and not used.
1561 : // - Falling through into finally-block: Undefined and not used.
1562 44102 : Register token = register_allocator()->NewRegister();
1563 44111 : Register result = register_allocator()->NewRegister();
1564 44109 : ControlScope::DeferredCommands commands(this, token, result);
1565 :
1566 : // Preserve the context in a dedicated register, so that it can be restored
1567 : // when the handler is entered by the stack-unwinding machinery.
1568 : // TODO(mstarzinger): Be smarter about register allocation.
1569 44111 : Register context = register_allocator()->NewRegister();
1570 44112 : builder()->MoveRegister(Register::current_context(), context);
1571 :
1572 : // Evaluate the try-block inside a control scope. This simulates a handler
1573 : // that is intercepting all control commands.
1574 44114 : try_control_builder.BeginTry(context);
1575 : {
1576 : ControlScopeForTryFinally scope(this, &try_control_builder, &commands);
1577 40737 : try_body_func();
1578 : }
1579 44110 : try_control_builder.EndTry();
1580 :
1581 : // Record fall-through and exception cases.
1582 44110 : commands.RecordFallThroughPath();
1583 44111 : try_control_builder.LeaveTry();
1584 44112 : try_control_builder.BeginHandler();
1585 : commands.RecordHandlerReThrowPath();
1586 :
1587 : // Pending message object is saved on entry.
1588 44113 : try_control_builder.BeginFinally();
1589 44111 : Register message = context; // Reuse register.
1590 :
1591 : // Clear message object as we enter the finally block.
1592 44111 : builder()->LoadTheHole().SetPendingMessage().StoreAccumulatorInRegister(
1593 : message);
1594 :
1595 : // Evaluate the finally-block.
1596 : finally_body_func(token);
1597 44109 : try_control_builder.EndFinally();
1598 :
1599 : // Pending message object is restored on exit.
1600 44106 : builder()->LoadAccumulatorWithRegister(message).SetPendingMessage();
1601 :
1602 : // Dynamic dispatch after the finally-block.
1603 44109 : commands.ApplyDeferredCommands();
1604 44109 : }
1605 :
1606 525342 : void BytecodeGenerator::VisitIterationBody(IterationStatement* stmt,
1607 : LoopBuilder* loop_builder) {
1608 262640 : loop_builder->LoopBody();
1609 : ControlScopeForIteration execution_control(this, stmt, loop_builder);
1610 262668 : builder()->StackCheck(stmt->position());
1611 262702 : Visit(stmt->body());
1612 262690 : loop_builder->BindContinueTarget();
1613 262664 : }
1614 :
1615 5164 : void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
1616 1215 : LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt);
1617 1216 : if (stmt->cond()->ToBooleanIsFalse()) {
1618 364 : VisitIterationBody(stmt, &loop_builder);
1619 852 : } else if (stmt->cond()->ToBooleanIsTrue()) {
1620 225 : loop_builder.LoopHeader();
1621 225 : VisitIterationBody(stmt, &loop_builder);
1622 225 : loop_builder.JumpToHeader(loop_depth_);
1623 : } else {
1624 627 : loop_builder.LoopHeader();
1625 627 : VisitIterationBody(stmt, &loop_builder);
1626 : builder()->SetExpressionAsStatementPosition(stmt->cond());
1627 : BytecodeLabels loop_backbranch(zone());
1628 : VisitForTest(stmt->cond(), &loop_backbranch, loop_builder.break_labels(),
1629 627 : TestFallthrough::kThen);
1630 627 : loop_backbranch.Bind(builder());
1631 627 : loop_builder.JumpToHeader(loop_depth_);
1632 1216 : }
1633 1217 : }
1634 :
1635 76239 : void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
1636 13970 : LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt);
1637 :
1638 13969 : if (stmt->cond()->ToBooleanIsFalse()) {
1639 : // If the condition is false there is no need to generate the loop.
1640 117 : return;
1641 : }
1642 :
1643 13854 : loop_builder.LoopHeader();
1644 13854 : if (!stmt->cond()->ToBooleanIsTrue()) {
1645 : builder()->SetExpressionAsStatementPosition(stmt->cond());
1646 : BytecodeLabels loop_body(zone());
1647 : VisitForTest(stmt->cond(), &loop_body, loop_builder.break_labels(),
1648 11482 : TestFallthrough::kThen);
1649 11483 : loop_body.Bind(builder());
1650 : }
1651 13856 : VisitIterationBody(stmt, &loop_builder);
1652 13855 : loop_builder.JumpToHeader(loop_depth_);
1653 : }
1654 :
1655 1813724 : void BytecodeGenerator::VisitForStatement(ForStatement* stmt) {
1656 220268 : LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt);
1657 :
1658 220267 : if (stmt->init() != nullptr) {
1659 159707 : Visit(stmt->init());
1660 : }
1661 220296 : if (stmt->cond() && stmt->cond()->ToBooleanIsFalse()) {
1662 : // If the condition is known to be false there is no need to generate
1663 : // body, next or condition blocks. Init block should be generated.
1664 15470 : return;
1665 : }
1666 :
1667 204814 : loop_builder.LoopHeader();
1668 204804 : if (stmt->cond() && !stmt->cond()->ToBooleanIsTrue()) {
1669 : builder()->SetExpressionAsStatementPosition(stmt->cond());
1670 : BytecodeLabels loop_body(zone());
1671 : VisitForTest(stmt->cond(), &loop_body, loop_builder.break_labels(),
1672 187884 : TestFallthrough::kThen);
1673 187904 : loop_body.Bind(builder());
1674 : }
1675 204825 : VisitIterationBody(stmt, &loop_builder);
1676 204803 : if (stmt->next() != nullptr) {
1677 : builder()->SetStatementPosition(stmt->next());
1678 179634 : Visit(stmt->next());
1679 : }
1680 204816 : loop_builder.JumpToHeader(loop_depth_);
1681 : }
1682 :
1683 4800 : void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) {
1684 33326 : if (stmt->subject()->IsNullLiteral() ||
1685 4776 : stmt->subject()->IsUndefinedLiteral()) {
1686 : // ForIn generates lots of code, skip if it wouldn't produce any effects.
1687 51 : return;
1688 : }
1689 :
1690 : BytecodeLabel subject_null_label, subject_undefined_label;
1691 4749 : FeedbackSlot slot = feedback_spec()->AddForInSlot();
1692 :
1693 : // Prepare the state for executing ForIn.
1694 : builder()->SetExpressionAsStatementPosition(stmt->subject());
1695 4749 : VisitForAccumulatorValue(stmt->subject());
1696 4751 : builder()->JumpIfUndefined(&subject_undefined_label);
1697 4751 : builder()->JumpIfNull(&subject_null_label);
1698 4750 : Register receiver = register_allocator()->NewRegister();
1699 4751 : builder()->ToObject(receiver);
1700 :
1701 : // Used as kRegTriple and kRegPair in ForInPrepare and ForInNext.
1702 4750 : RegisterList triple = register_allocator()->NewRegisterList(3);
1703 4751 : Register cache_length = triple[2];
1704 4751 : builder()->ForInEnumerate(receiver);
1705 4751 : builder()->ForInPrepare(triple, feedback_index(slot));
1706 :
1707 : // Set up loop counter
1708 4751 : Register index = register_allocator()->NewRegister();
1709 4751 : builder()->LoadLiteral(Smi::zero());
1710 4751 : builder()->StoreAccumulatorInRegister(index);
1711 :
1712 : // The loop
1713 : {
1714 4751 : LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt);
1715 4749 : loop_builder.LoopHeader();
1716 : builder()->SetExpressionAsStatementPosition(stmt->each());
1717 4751 : builder()->ForInContinue(index, cache_length);
1718 : loop_builder.BreakIfFalse(ToBooleanMode::kAlreadyBoolean);
1719 : builder()->ForInNext(receiver, index, triple.Truncate(2),
1720 4751 : feedback_index(slot));
1721 : loop_builder.ContinueIfUndefined();
1722 :
1723 : // Assign accumulator value to the 'each' target.
1724 : {
1725 : EffectResultScope scope(this);
1726 : // Make sure to preserve the accumulator across the PrepareAssignmentLhs
1727 : // call.
1728 : AssignmentLhsData lhs_data = PrepareAssignmentLhs(
1729 4751 : stmt->each(), AccumulatorPreservingMode::kPreserve);
1730 : builder()->SetExpressionPosition(stmt->each());
1731 4751 : BuildAssignment(lhs_data, Token::ASSIGN, LookupHoistingMode::kNormal);
1732 : }
1733 :
1734 4749 : VisitIterationBody(stmt, &loop_builder);
1735 4751 : builder()->ForInStep(index);
1736 4750 : builder()->StoreAccumulatorInRegister(index);
1737 4751 : loop_builder.JumpToHeader(loop_depth_);
1738 : }
1739 4751 : builder()->Bind(&subject_null_label);
1740 4751 : builder()->Bind(&subject_undefined_label);
1741 : }
1742 :
1743 : // Desugar a for-of statement into an application of the iteration protocol.
1744 : //
1745 : // for (EACH of SUBJECT) BODY
1746 : //
1747 : // becomes
1748 : //
1749 : // iterator = %GetIterator(SUBJECT)
1750 : // try {
1751 : //
1752 : // loop {
1753 : // // Make sure we are considered 'done' if .next(), .done or .value fail.
1754 : // done = true
1755 : // value = iterator.next()
1756 : // if (value.done) break;
1757 : // value = value.value
1758 : // done = false
1759 : //
1760 : // EACH = value
1761 : // BODY
1762 : // }
1763 : // done = true
1764 : //
1765 : // } catch(e) {
1766 : // iteration_continuation = RETHROW
1767 : // } finally {
1768 : // %FinalizeIteration(iterator, done, iteration_continuation)
1769 : // }
1770 38045 : void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
1771 : EffectResultScope effect_scope(this);
1772 :
1773 114144 : builder()->SetExpressionAsStatementPosition(stmt->subject());
1774 38045 : VisitForAccumulatorValue(stmt->subject());
1775 :
1776 : // Store the iterator in a dedicated register so that it can be closed on
1777 : // exit, and the 'done' value in a dedicated register so that it can be
1778 : // changed and accessed independently of the iteration result.
1779 76108 : IteratorRecord iterator = BuildGetIteratorRecord(stmt->type());
1780 38054 : Register done = register_allocator()->NewRegister();
1781 38048 : builder()->LoadFalse();
1782 38051 : builder()->StoreAccumulatorInRegister(done);
1783 :
1784 : BuildTryFinally(
1785 : // Try block.
1786 38039 : [&]() {
1787 114144 : Register next_result = register_allocator()->NewRegister();
1788 :
1789 38048 : LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt);
1790 38043 : loop_builder.LoopHeader();
1791 :
1792 38046 : builder()->LoadTrue().StoreAccumulatorInRegister(done);
1793 :
1794 : // Call the iterator's .next() method. Break from the loop if the `done`
1795 : // property is truthy, otherwise load the value from the iterator result
1796 : // and append the argument.
1797 76105 : builder()->SetExpressionAsStatementPosition(stmt->each());
1798 38051 : BuildIteratorNext(iterator, next_result);
1799 : builder()->LoadNamedProperty(
1800 : next_result, ast_string_constants()->done_string(),
1801 152204 : feedback_index(feedback_spec()->AddLoadICSlot()));
1802 : loop_builder.BreakIfTrue(ToBooleanMode::kConvertToBoolean);
1803 :
1804 : builder()
1805 : // value = value.value
1806 : ->LoadNamedProperty(
1807 : next_result, ast_string_constants()->value_string(),
1808 152214 : feedback_index(feedback_spec()->AddLoadICSlot()));
1809 : // done = false, before the assignment to each happens, so that done is
1810 : // false if the assignment throws.
1811 : builder()
1812 38045 : ->StoreAccumulatorInRegister(next_result)
1813 38046 : .LoadFalse()
1814 76099 : .StoreAccumulatorInRegister(done);
1815 :
1816 : // Assign to the 'each' target.
1817 76108 : AssignmentLhsData lhs_data = PrepareAssignmentLhs(stmt->each());
1818 38051 : builder()->LoadAccumulatorWithRegister(next_result);
1819 38054 : BuildAssignment(lhs_data, Token::ASSIGN, LookupHoistingMode::kNormal);
1820 :
1821 38051 : VisitIterationBody(stmt, &loop_builder);
1822 :
1823 38048 : loop_builder.JumpToHeader(loop_depth_);
1824 38052 : },
1825 : // Finally block.
1826 : [&](Register iteration_continuation_token) {
1827 : // Finish the iteration in the finally block.
1828 38049 : BuildFinalizeIteration(iterator, done, iteration_continuation_token);
1829 : },
1830 38051 : HandlerTable::UNCAUGHT);
1831 38051 : }
1832 :
1833 69680 : void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
1834 : // Update catch prediction tracking. The updated catch_prediction value lasts
1835 : // until the end of the try_block in the AST node, and does not apply to the
1836 : // catch_block.
1837 69680 : HandlerTable::CatchPrediction outer_catch_prediction = catch_prediction();
1838 69680 : set_catch_prediction(stmt->GetCatchPrediction(outer_catch_prediction));
1839 :
1840 : BuildTryCatch(
1841 : // Try body.
1842 69675 : [&]() {
1843 69675 : Visit(stmt->try_block());
1844 69680 : set_catch_prediction(outer_catch_prediction);
1845 69680 : },
1846 : // Catch body.
1847 69665 : [&](Register context) {
1848 278707 : if (stmt->scope()) {
1849 : // Create a catch scope that binds the exception.
1850 69602 : BuildNewLocalCatchContext(stmt->scope());
1851 69615 : builder()->StoreAccumulatorInRegister(context);
1852 : }
1853 :
1854 : // If requested, clear message object as we enter the catch block.
1855 139368 : if (stmt->ShouldClearPendingException(outer_catch_prediction)) {
1856 69684 : builder()->LoadTheHole().SetPendingMessage();
1857 : }
1858 :
1859 : // Load the catch context into the accumulator.
1860 69664 : builder()->LoadAccumulatorWithRegister(context);
1861 :
1862 : // Evaluate the catch-block.
1863 139358 : if (stmt->scope()) {
1864 69612 : VisitInScope(stmt->catch_block(), stmt->scope());
1865 : } else {
1866 67 : VisitBlock(stmt->catch_block());
1867 : }
1868 69675 : },
1869 69680 : catch_prediction(), stmt);
1870 69655 : }
1871 :
1872 6742 : void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
1873 : BuildTryFinally(
1874 : // Try block.
1875 3371 : [&]() { Visit(stmt->try_block()); },
1876 : // Finally block.
1877 3371 : [&](Register body_continuation_token) { Visit(stmt->finally_block()); },
1878 6742 : catch_prediction(), stmt);
1879 3370 : }
1880 :
1881 0 : void BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
1882 : builder()->SetStatementPosition(stmt);
1883 6525 : builder()->Debugger();
1884 0 : }
1885 :
1886 5210018 : void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
1887 : DCHECK(expr->scope()->outer_scope() == current_scope());
1888 : uint8_t flags = CreateClosureFlags::Encode(
1889 5210018 : expr->pretenure(), closure_scope()->is_function_scope(),
1890 7815027 : info()->might_always_opt());
1891 2605013 : size_t entry = builder()->AllocateDeferredConstantPoolEntry();
1892 2605122 : FeedbackSlot slot = GetCachedCreateClosureSlot(expr);
1893 2605362 : builder()->CreateClosure(entry, feedback_index(slot), flags);
1894 5210241 : function_literals_.push_back(std::make_pair(expr, entry));
1895 2605064 : AddToEagerLiteralsIfEager(expr);
1896 2605125 : }
1897 :
1898 2854714 : void BytecodeGenerator::AddToEagerLiteralsIfEager(FunctionLiteral* literal) {
1899 2854714 : if (eager_inner_literals_ && literal->ShouldEagerCompile()) {
1900 : DCHECK(!IsInEagerLiterals(literal, *eager_inner_literals_));
1901 524426 : eager_inner_literals_->push_back(literal);
1902 : }
1903 2854731 : }
1904 :
1905 21605169 : bool BytecodeGenerator::ShouldOptimizeAsOneShot() const {
1906 10501151 : if (!FLAG_enable_one_shot_optimization) return false;
1907 :
1908 10484654 : if (loop_depth_ > 0) return false;
1909 :
1910 : // A non-top-level iife is likely to be executed multiple times and so
1911 : // shouldn`t be optimized as one-shot.
1912 21229403 : bool is_toplevel_iife = info()->literal()->is_iife() &&
1913 978633 : current_scope()->outer_scope()->is_script_scope();
1914 10125385 : return info()->literal()->is_toplevel() || is_toplevel_iife;
1915 : }
1916 :
1917 42689 : void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr, Register name) {
1918 : size_t class_boilerplate_entry =
1919 41012 : builder()->AllocateDeferredConstantPoolEntry();
1920 82032 : class_literals_.push_back(std::make_pair(expr, class_boilerplate_entry));
1921 :
1922 632687 : VisitDeclarations(expr->scope()->declarations());
1923 41025 : Register class_constructor = register_allocator()->NewRegister();
1924 :
1925 : {
1926 : RegisterAllocationScope register_scope(this);
1927 41024 : RegisterList args = register_allocator()->NewGrowableRegisterList();
1928 :
1929 41024 : Register class_boilerplate = register_allocator()->GrowRegisterList(&args);
1930 : Register class_constructor_in_args =
1931 41026 : register_allocator()->GrowRegisterList(&args);
1932 41025 : Register super_class = register_allocator()->GrowRegisterList(&args);
1933 : DCHECK_EQ(ClassBoilerplate::kFirstDynamicArgumentIndex,
1934 : args.register_count());
1935 :
1936 41025 : VisitForAccumulatorValueOrTheHole(expr->extends());
1937 41014 : builder()->StoreAccumulatorInRegister(super_class);
1938 :
1939 41019 : VisitFunctionLiteral(expr->constructor());
1940 : builder()
1941 41025 : ->StoreAccumulatorInRegister(class_constructor)
1942 41025 : .MoveRegister(class_constructor, class_constructor_in_args)
1943 41020 : .LoadConstantPoolEntry(class_boilerplate_entry)
1944 41023 : .StoreAccumulatorInRegister(class_boilerplate);
1945 :
1946 : // Create computed names and method values nodes to store into the literal.
1947 695104 : for (int i = 0; i < expr->properties()->length(); i++) {
1948 627003 : ClassLiteral::Property* property = expr->properties()->at(i);
1949 612125 : if (property->is_computed_name()) {
1950 6023 : Register key = register_allocator()->GrowRegisterList(&args);
1951 :
1952 : builder()->SetExpressionAsStatementPosition(property->key());
1953 6021 : BuildLoadPropertyKey(property, key);
1954 6020 : if (property->is_static()) {
1955 : // The static prototype property is read only. We handle the non
1956 : // computed property name case in the parser. Since this is the only
1957 : // case where we need to check for an own read only property we
1958 : // special case this so we do not need to do this for every property.
1959 :
1960 : FeedbackSlot slot = GetDummyCompareICSlot();
1961 : BytecodeLabel done;
1962 : builder()
1963 1671 : ->LoadLiteral(ast_string_constants()->prototype_string())
1964 : .CompareOperation(Token::Value::EQ_STRICT, key,
1965 1671 : feedback_index(slot))
1966 1671 : .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &done)
1967 1671 : .CallRuntime(Runtime::kThrowStaticPrototypeError)
1968 1671 : .Bind(&done);
1969 : }
1970 :
1971 6019 : if (property->kind() == ClassLiteral::Property::FIELD) {
1972 : DCHECK(!property->is_private());
1973 : // Initialize field's name variable with the computed name.
1974 : DCHECK_NOT_NULL(property->computed_name_var());
1975 403 : builder()->LoadAccumulatorWithRegister(key);
1976 : BuildVariableAssignment(property->computed_name_var(), Token::INIT,
1977 403 : HoleCheckMode::kElided);
1978 : }
1979 : }
1980 :
1981 306525 : if (property->kind() == ClassLiteral::Property::FIELD) {
1982 955 : if (property->is_private()) {
1983 : RegisterAllocationScope private_name_register_scope(this);
1984 552 : Register private_name = register_allocator()->NewRegister();
1985 : VisitForRegisterValue(property->key(), private_name);
1986 : builder()
1987 1104 : ->LoadLiteral(property->key()->AsLiteral()->AsRawPropertyName())
1988 552 : .StoreAccumulatorInRegister(private_name)
1989 552 : .CallRuntime(Runtime::kCreatePrivateNameSymbol, private_name);
1990 : DCHECK_NOT_NULL(property->private_name_var());
1991 : BuildVariableAssignment(property->private_name_var(), Token::INIT,
1992 552 : HoleCheckMode::kElided);
1993 : }
1994 : // We don't compute field's value here, but instead do it in the
1995 : // initializer function.
1996 955 : continue;
1997 : }
1998 :
1999 305570 : Register value = register_allocator()->GrowRegisterList(&args);
2000 : VisitForRegisterValue(property->value(), value);
2001 : }
2002 :
2003 41023 : builder()->CallRuntime(Runtime::kDefineClass, args);
2004 : }
2005 41025 : Register prototype = register_allocator()->NewRegister();
2006 41026 : builder()->StoreAccumulatorInRegister(prototype);
2007 :
2008 : // Assign to class variable.
2009 41026 : if (expr->class_variable() != nullptr) {
2010 : DCHECK(expr->class_variable()->IsStackLocal() ||
2011 : expr->class_variable()->IsContextSlot());
2012 37097 : builder()->LoadAccumulatorWithRegister(class_constructor);
2013 : BuildVariableAssignment(expr->class_variable(), Token::INIT,
2014 37086 : HoleCheckMode::kElided);
2015 : }
2016 :
2017 41010 : if (expr->instance_members_initializer_function() != nullptr) {
2018 : Register initializer =
2019 912 : VisitForRegisterValue(expr->instance_members_initializer_function());
2020 :
2021 912 : if (FunctionLiteral::NeedsHomeObject(
2022 : expr->instance_members_initializer_function())) {
2023 24 : FeedbackSlot slot = feedback_spec()->AddStoreICSlot(language_mode());
2024 24 : builder()->LoadAccumulatorWithRegister(prototype).StoreHomeObjectProperty(
2025 24 : initializer, feedback_index(slot), language_mode());
2026 : }
2027 :
2028 912 : FeedbackSlot slot = feedback_spec()->AddStoreICSlot(language_mode());
2029 : builder()
2030 912 : ->LoadAccumulatorWithRegister(initializer)
2031 912 : .StoreClassFieldsInitializer(class_constructor, feedback_index(slot))
2032 912 : .LoadAccumulatorWithRegister(class_constructor);
2033 : }
2034 :
2035 41010 : if (expr->static_fields_initializer() != nullptr) {
2036 : // TODO(gsathya): This can be optimized away to be a part of the
2037 : // class boilerplate in the future. The name argument can be
2038 : // passed to the DefineClass runtime function and have it set
2039 : // there.
2040 515 : if (name.is_valid()) {
2041 6 : Register key = register_allocator()->NewRegister();
2042 : builder()
2043 6 : ->LoadLiteral(ast_string_constants()->name_string())
2044 6 : .StoreAccumulatorInRegister(key);
2045 :
2046 : DataPropertyInLiteralFlags data_property_flags =
2047 : DataPropertyInLiteralFlag::kNoFlags;
2048 : FeedbackSlot slot =
2049 6 : feedback_spec()->AddStoreDataPropertyInLiteralICSlot();
2050 6 : builder()->LoadAccumulatorWithRegister(name).StoreDataPropertyInLiteral(
2051 6 : class_constructor, key, data_property_flags, feedback_index(slot));
2052 : }
2053 :
2054 515 : RegisterList args = register_allocator()->NewRegisterList(1);
2055 : Register initializer =
2056 515 : VisitForRegisterValue(expr->static_fields_initializer());
2057 :
2058 515 : if (FunctionLiteral::NeedsHomeObject(expr->static_fields_initializer())) {
2059 23 : FeedbackSlot slot = feedback_spec()->AddStoreICSlot(language_mode());
2060 : builder()
2061 23 : ->LoadAccumulatorWithRegister(class_constructor)
2062 : .StoreHomeObjectProperty(initializer, feedback_index(slot),
2063 23 : language_mode());
2064 : }
2065 :
2066 : builder()
2067 515 : ->MoveRegister(class_constructor, args[0])
2068 : .CallProperty(initializer, args,
2069 1030 : feedback_index(feedback_spec()->AddCallICSlot()));
2070 : }
2071 41010 : builder()->LoadAccumulatorWithRegister(class_constructor);
2072 41014 : }
2073 :
2074 41005 : void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr) {
2075 41005 : VisitClassLiteral(expr, Register::invalid_value());
2076 41013 : }
2077 :
2078 115556 : void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr, Register name) {
2079 : CurrentScope current_scope(this, expr->scope());
2080 : DCHECK_NOT_NULL(expr->scope());
2081 41020 : if (expr->scope()->NeedsContext()) {
2082 33523 : BuildNewLocalBlockContext(expr->scope());
2083 33516 : ContextScope scope(this, expr->scope());
2084 33528 : BuildClassLiteral(expr, name);
2085 : } else {
2086 7497 : BuildClassLiteral(expr, name);
2087 : }
2088 41019 : }
2089 :
2090 1427 : void BytecodeGenerator::VisitInitializeClassMembersStatement(
2091 3573 : InitializeClassMembersStatement* stmt) {
2092 1427 : RegisterList args = register_allocator()->NewRegisterList(3);
2093 2854 : Register constructor = args[0], key = args[1], value = args[2];
2094 1427 : builder()->MoveRegister(builder()->Receiver(), constructor);
2095 :
2096 7146 : for (int i = 0; i < stmt->fields()->length(); i++) {
2097 10879 : ClassLiteral::Property* property = stmt->fields()->at(i);
2098 :
2099 6438 : if (property->is_computed_name()) {
2100 : DCHECK_EQ(property->kind(), ClassLiteral::Property::FIELD);
2101 : DCHECK(!property->is_private());
2102 : Variable* var = property->computed_name_var();
2103 : DCHECK_NOT_NULL(var);
2104 : // The computed name is already evaluated and stored in a
2105 : // variable at class definition time.
2106 403 : BuildVariableLoad(var, HoleCheckMode::kElided);
2107 403 : builder()->StoreAccumulatorInRegister(key);
2108 3486 : } else if (property->kind() == ClassLiteral::Property::FIELD &&
2109 : property->is_private()) {
2110 : Variable* private_name_var = property->private_name_var();
2111 : DCHECK_NOT_NULL(private_name_var);
2112 552 : BuildVariableLoad(private_name_var, HoleCheckMode::kElided);
2113 552 : builder()->StoreAccumulatorInRegister(key);
2114 : } else {
2115 1191 : BuildLoadPropertyKey(property, key);
2116 : }
2117 :
2118 : builder()->SetExpressionAsStatementPosition(property->value());
2119 : VisitForRegisterValue(property->value(), value);
2120 2146 : VisitSetHomeObject(value, constructor, property);
2121 :
2122 : Runtime::FunctionId function_id =
2123 2146 : property->kind() == ClassLiteral::Property::FIELD &&
2124 : !property->is_private()
2125 : ? Runtime::kCreateDataProperty
2126 2146 : : Runtime::kAddPrivateField;
2127 2146 : builder()->CallRuntime(function_id, args);
2128 : }
2129 1427 : }
2130 :
2131 837 : void BytecodeGenerator::BuildInstanceMemberInitialization(Register constructor,
2132 : Register instance) {
2133 837 : RegisterList args = register_allocator()->NewRegisterList(1);
2134 837 : Register initializer = register_allocator()->NewRegister();
2135 :
2136 837 : FeedbackSlot slot = feedback_spec()->AddLoadICSlot();
2137 : BytecodeLabel done;
2138 :
2139 : builder()
2140 837 : ->LoadClassFieldsInitializer(constructor, feedback_index(slot))
2141 : // TODO(gsathya): This jump can be elided for the base
2142 : // constructor and derived constructor. This is only required
2143 : // when called from an arrow function.
2144 837 : .JumpIfUndefined(&done)
2145 837 : .StoreAccumulatorInRegister(initializer)
2146 1674 : .MoveRegister(instance, args[0])
2147 : .CallProperty(initializer, args,
2148 1674 : feedback_index(feedback_spec()->AddCallICSlot()))
2149 837 : .Bind(&done);
2150 837 : }
2151 :
2152 1761 : void BytecodeGenerator::VisitNativeFunctionLiteral(
2153 : NativeFunctionLiteral* expr) {
2154 1761 : size_t entry = builder()->AllocateDeferredConstantPoolEntry();
2155 1761 : FeedbackSlot slot = feedback_spec()->AddCreateClosureSlot();
2156 1761 : builder()->CreateClosure(entry, feedback_index(slot), NOT_TENURED);
2157 3522 : native_function_literals_.push_back(std::make_pair(expr, entry));
2158 1761 : }
2159 :
2160 0 : void BytecodeGenerator::VisitDoExpression(DoExpression* expr) {
2161 0 : VisitBlock(expr->block());
2162 0 : VisitVariableProxy(expr->result());
2163 0 : }
2164 :
2165 181256 : void BytecodeGenerator::VisitConditional(Conditional* expr) {
2166 : ConditionalControlFlowBuilder conditional_builder(
2167 30359 : builder(), block_coverage_builder_, expr);
2168 :
2169 30358 : if (expr->condition()->ToBooleanIsTrue()) {
2170 : // Generate then block unconditionally as always true.
2171 230 : conditional_builder.Then();
2172 230 : VisitForAccumulatorValue(expr->then_expression());
2173 30129 : } else if (expr->condition()->ToBooleanIsFalse()) {
2174 : // Generate else block unconditionally if it exists.
2175 107 : conditional_builder.Else();
2176 107 : VisitForAccumulatorValue(expr->else_expression());
2177 : } else {
2178 : VisitForTest(expr->condition(), conditional_builder.then_labels(),
2179 30023 : conditional_builder.else_labels(), TestFallthrough::kThen);
2180 :
2181 30024 : conditional_builder.Then();
2182 30023 : VisitForAccumulatorValue(expr->then_expression());
2183 30028 : conditional_builder.JumpToEnd();
2184 :
2185 30027 : conditional_builder.Else();
2186 30027 : VisitForAccumulatorValue(expr->else_expression());
2187 30365 : }
2188 30365 : }
2189 :
2190 29971600 : void BytecodeGenerator::VisitLiteral(Literal* expr) {
2191 20636867 : if (execution_result()->IsEffect()) return;
2192 9193281 : switch (expr->type()) {
2193 : case Literal::kSmi:
2194 6780259 : builder()->LoadLiteral(expr->AsSmiLiteral());
2195 6780212 : break;
2196 : case Literal::kHeapNumber:
2197 273825 : builder()->LoadLiteral(expr->AsNumber());
2198 273824 : break;
2199 : case Literal::kUndefined:
2200 111156 : builder()->LoadUndefined();
2201 111153 : break;
2202 : case Literal::kBoolean:
2203 313600 : builder()->LoadBoolean(expr->ToBooleanIsTrue());
2204 : execution_result()->SetResultIsBoolean();
2205 : break;
2206 : case Literal::kNull:
2207 21620 : builder()->LoadNull();
2208 21615 : break;
2209 : case Literal::kTheHole:
2210 0 : builder()->LoadTheHole();
2211 0 : break;
2212 : case Literal::kString:
2213 1682018 : builder()->LoadLiteral(expr->AsRawString());
2214 : execution_result()->SetResultIsString();
2215 : break;
2216 : case Literal::kSymbol:
2217 1981 : builder()->LoadLiteral(expr->AsSymbol());
2218 1981 : break;
2219 : case Literal::kBigInt:
2220 8986 : builder()->LoadLiteral(expr->AsBigInt());
2221 8986 : break;
2222 : }
2223 : }
2224 :
2225 89997 : void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
2226 : // Materialize a regular expression literal.
2227 : builder()->CreateRegExpLiteral(
2228 : expr->raw_pattern(), feedback_index(feedback_spec()->AddLiteralSlot()),
2229 89997 : expr->flags());
2230 45001 : }
2231 :
2232 201532 : void BytecodeGenerator::BuildCreateObjectLiteral(Register literal,
2233 : uint8_t flags, size_t entry) {
2234 201532 : if (ShouldOptimizeAsOneShot()) {
2235 114124 : RegisterList args = register_allocator()->NewRegisterList(2);
2236 : builder()
2237 114142 : ->LoadConstantPoolEntry(entry)
2238 114158 : .StoreAccumulatorInRegister(args[0])
2239 114163 : .LoadLiteral(Smi::FromInt(flags))
2240 114156 : .StoreAccumulatorInRegister(args[1])
2241 114153 : .CallRuntime(Runtime::kCreateObjectLiteralWithoutAllocationSite, args)
2242 114141 : .StoreAccumulatorInRegister(literal);
2243 :
2244 : } else {
2245 : // TODO(cbruni): Directly generate runtime call for literals we cannot
2246 : // optimize once the CreateShallowObjectLiteral stub is in sync with the TF
2247 : // optimizations.
2248 87526 : int literal_index = feedback_index(feedback_spec()->AddLiteralSlot());
2249 : builder()
2250 87523 : ->CreateObjectLiteral(entry, literal_index, flags)
2251 87527 : .StoreAccumulatorInRegister(literal);
2252 : }
2253 201684 : }
2254 :
2255 432150 : void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
2256 431456 : expr->InitDepthAndFlags();
2257 :
2258 : // Fast path for the empty object literal which doesn't need an
2259 : // AllocationSite.
2260 230070 : if (expr->IsEmptyObjectLiteral()) {
2261 : DCHECK(expr->IsFastCloningSupported());
2262 28160 : builder()->CreateEmptyObjectLiteral();
2263 258193 : return;
2264 : }
2265 :
2266 : // Deep-copy the literal boilerplate.
2267 : uint8_t flags = CreateObjectLiteralFlags::Encode(
2268 201885 : expr->ComputeFlags(), expr->IsFastCloningSupported());
2269 :
2270 201846 : Register literal = register_allocator()->NewRegister();
2271 :
2272 : // Create literal object.
2273 : int property_index = 0;
2274 : bool clone_object_spread =
2275 201776 : expr->properties()->first()->kind() == ObjectLiteral::Property::SPREAD;
2276 201776 : if (clone_object_spread) {
2277 : // Avoid the slow path for spreads in the following common cases:
2278 : // 1) `let obj = { ...source }`
2279 : // 2) `let obj = { ...source, override: 1 }`
2280 : // 3) `let obj = { ...source, ...overrides }`
2281 : RegisterAllocationScope register_scope(this);
2282 262 : Expression* property = expr->properties()->first()->value();
2283 262 : Register from_value = VisitForRegisterValue(property);
2284 :
2285 : BytecodeLabels clone_object(zone());
2286 262 : builder()->JumpIfUndefined(clone_object.New());
2287 262 : builder()->JumpIfNull(clone_object.New());
2288 262 : builder()->ToObject(from_value);
2289 :
2290 261 : clone_object.Bind(builder());
2291 262 : int clone_index = feedback_index(feedback_spec()->AddCloneObjectSlot());
2292 262 : builder()->CloneObject(from_value, flags, clone_index);
2293 262 : builder()->StoreAccumulatorInRegister(literal);
2294 262 : property_index++;
2295 : } else {
2296 : size_t entry;
2297 : // If constant properties is an empty fixed array, use a cached empty fixed
2298 : // array to ensure it's only added to the constant pool once.
2299 201514 : if (expr->properties_count() == 0) {
2300 2247 : entry = builder()->EmptyObjectBoilerplateDescriptionConstantPoolEntry();
2301 : } else {
2302 199267 : entry = builder()->AllocateDeferredConstantPoolEntry();
2303 398668 : object_literals_.push_back(std::make_pair(expr, entry));
2304 : }
2305 201625 : BuildCreateObjectLiteral(literal, flags, entry);
2306 : }
2307 :
2308 : // Store computed values into the literal.
2309 : AccessorTable accessor_table(zone());
2310 2017143 : for (; property_index < expr->properties()->length(); property_index++) {
2311 2274473 : ObjectLiteral::Property* property = expr->properties()->at(property_index);
2312 2758175 : if (property->is_computed_name()) break;
2313 3778855 : if (!clone_object_spread && property->IsCompileTimeValue()) continue;
2314 :
2315 : RegisterAllocationScope inner_register_scope(this);
2316 500420 : Literal* key = property->key()->AsLiteral();
2317 255382 : switch (property->kind()) {
2318 : case ObjectLiteral::Property::SPREAD:
2319 0 : UNREACHABLE();
2320 : case ObjectLiteral::Property::CONSTANT:
2321 : case ObjectLiteral::Property::MATERIALIZED_LITERAL:
2322 : DCHECK(clone_object_spread || !property->value()->IsCompileTimeValue());
2323 : V8_FALLTHROUGH;
2324 : case ObjectLiteral::Property::COMPUTED: {
2325 : // It is safe to use [[Put]] here because the boilerplate already
2326 : // contains computed properties with an uninitialized value.
2327 245752 : if (key->IsStringLiteral()) {
2328 : DCHECK(key->IsPropertyName());
2329 245194 : if (property->emit_store()) {
2330 : builder()->SetExpressionPosition(property->value());
2331 245048 : VisitForAccumulatorValue(property->value());
2332 245060 : FeedbackSlot slot = feedback_spec()->AddStoreOwnICSlot();
2333 245060 : if (FunctionLiteral::NeedsHomeObject(property->value())) {
2334 : RegisterAllocationScope register_scope(this);
2335 546 : Register value = register_allocator()->NewRegister();
2336 546 : builder()->StoreAccumulatorInRegister(value);
2337 : builder()->StoreNamedOwnProperty(
2338 546 : literal, key->AsRawPropertyName(), feedback_index(slot));
2339 546 : VisitSetHomeObject(value, literal, property);
2340 : } else {
2341 : builder()->StoreNamedOwnProperty(
2342 244493 : literal, key->AsRawPropertyName(), feedback_index(slot));
2343 : }
2344 : } else {
2345 : builder()->SetExpressionPosition(property->value());
2346 151 : VisitForEffect(property->value());
2347 : }
2348 : } else {
2349 559 : RegisterList args = register_allocator()->NewRegisterList(4);
2350 :
2351 559 : builder()->MoveRegister(literal, args[0]);
2352 : builder()->SetExpressionPosition(property->key());
2353 : VisitForRegisterValue(property->key(), args[1]);
2354 : builder()->SetExpressionPosition(property->value());
2355 : VisitForRegisterValue(property->value(), args[2]);
2356 559 : if (property->emit_store()) {
2357 : builder()
2358 527 : ->LoadLiteral(Smi::FromEnum(LanguageMode::kSloppy))
2359 527 : .StoreAccumulatorInRegister(args[3])
2360 527 : .CallRuntime(Runtime::kSetKeyedProperty, args);
2361 527 : Register value = args[2];
2362 527 : VisitSetHomeObject(value, literal, property);
2363 : }
2364 : }
2365 : break;
2366 : }
2367 : case ObjectLiteral::Property::PROTOTYPE: {
2368 : // __proto__:null is handled by CreateObjectLiteral.
2369 4085 : if (property->IsNullPrototype()) break;
2370 : DCHECK(property->emit_store());
2371 : DCHECK(!property->NeedsSetFunctionName());
2372 1254 : RegisterList args = register_allocator()->NewRegisterList(2);
2373 1254 : builder()->MoveRegister(literal, args[0]);
2374 : builder()->SetExpressionPosition(property->value());
2375 : VisitForRegisterValue(property->value(), args[1]);
2376 1253 : builder()->CallRuntime(Runtime::kInternalSetPrototype, args);
2377 1254 : break;
2378 : }
2379 : case ObjectLiteral::Property::GETTER:
2380 3557 : if (property->emit_store()) {
2381 3456 : accessor_table.lookup(key)->second->getter = property;
2382 : }
2383 : break;
2384 : case ObjectLiteral::Property::SETTER:
2385 1981 : if (property->emit_store()) {
2386 1885 : accessor_table.lookup(key)->second->setter = property;
2387 : }
2388 : break;
2389 : }
2390 255401 : }
2391 :
2392 : // Define accessors, using only a single call to the runtime for each pair of
2393 : // corresponding getters and setters.
2394 408168 : for (AccessorTable::Iterator it = accessor_table.begin();
2395 : it != accessor_table.end(); ++it) {
2396 : RegisterAllocationScope inner_register_scope(this);
2397 4629 : RegisterList args = register_allocator()->NewRegisterList(5);
2398 4631 : builder()->MoveRegister(literal, args[0]);
2399 4631 : VisitForRegisterValue(it->first, args[1]);
2400 4631 : VisitObjectLiteralAccessor(literal, it->second->getter, args[2]);
2401 4629 : VisitObjectLiteralAccessor(literal, it->second->setter, args[3]);
2402 : builder()
2403 4629 : ->LoadLiteral(Smi::FromInt(NONE))
2404 4630 : .StoreAccumulatorInRegister(args[4])
2405 4630 : .CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, args);
2406 4631 : }
2407 :
2408 : // Object literals have two parts. The "static" part on the left contains no
2409 : // computed property names, and so we can compute its map ahead of time; see
2410 : // Runtime_CreateObjectLiteralBoilerplate. The second "dynamic" part starts
2411 : // with the first computed property name and continues with all properties to
2412 : // its right. All the code from above initializes the static component of the
2413 : // object literal, and arranges for the map of the result to reflect the
2414 : // static order in which the keys appear. For the dynamic properties, we
2415 : // compile them into a series of "SetOwnProperty" runtime calls. This will
2416 : // preserve insertion order.
2417 2868 : for (; property_index < expr->properties()->length(); property_index++) {
2418 3203 : ObjectLiteral::Property* property = expr->properties()->at(property_index);
2419 : RegisterAllocationScope inner_register_scope(this);
2420 :
2421 2867 : if (property->IsPrototype()) {
2422 : // __proto__:null is handled by CreateObjectLiteral.
2423 36 : if (property->IsNullPrototype()) continue;
2424 : DCHECK(property->emit_store());
2425 : DCHECK(!property->NeedsSetFunctionName());
2426 31 : RegisterList args = register_allocator()->NewRegisterList(2);
2427 31 : builder()->MoveRegister(literal, args[0]);
2428 5730 : builder()->SetExpressionPosition(property->value());
2429 : VisitForRegisterValue(property->value(), args[1]);
2430 31 : builder()->CallRuntime(Runtime::kInternalSetPrototype, args);
2431 31 : continue;
2432 : }
2433 :
2434 2831 : switch (property->kind()) {
2435 : case ObjectLiteral::Property::CONSTANT:
2436 : case ObjectLiteral::Property::COMPUTED:
2437 : case ObjectLiteral::Property::MATERIALIZED_LITERAL: {
2438 2398 : Register key = register_allocator()->NewRegister();
2439 2400 : BuildLoadPropertyKey(property, key);
2440 : builder()->SetExpressionPosition(property->value());
2441 : Register value;
2442 :
2443 : // Static class fields require the name property to be set on
2444 : // the class, meaning we can't wait until the
2445 : // StoreDataPropertyInLiteral call later to set the name.
2446 2413 : if (property->value()->IsClassLiteral() &&
2447 24 : property->value()->AsClassLiteral()->static_fields_initializer() !=
2448 : nullptr) {
2449 6 : value = register_allocator()->NewRegister();
2450 12 : VisitClassLiteral(property->value()->AsClassLiteral(), key);
2451 6 : builder()->StoreAccumulatorInRegister(value);
2452 : } else {
2453 2395 : value = VisitForRegisterValue(property->value());
2454 : }
2455 2400 : VisitSetHomeObject(value, literal, property);
2456 :
2457 : DataPropertyInLiteralFlags data_property_flags =
2458 : DataPropertyInLiteralFlag::kNoFlags;
2459 2398 : if (property->NeedsSetFunctionName()) {
2460 : data_property_flags |= DataPropertyInLiteralFlag::kSetFunctionName;
2461 : }
2462 :
2463 : FeedbackSlot slot =
2464 2400 : feedback_spec()->AddStoreDataPropertyInLiteralICSlot();
2465 : builder()
2466 2400 : ->LoadAccumulatorWithRegister(value)
2467 : .StoreDataPropertyInLiteral(literal, key, data_property_flags,
2468 2400 : feedback_index(slot));
2469 : break;
2470 : }
2471 : case ObjectLiteral::Property::GETTER:
2472 : case ObjectLiteral::Property::SETTER: {
2473 336 : RegisterList args = register_allocator()->NewRegisterList(4);
2474 336 : builder()->MoveRegister(literal, args[0]);
2475 336 : BuildLoadPropertyKey(property, args[1]);
2476 : builder()->SetExpressionPosition(property->value());
2477 : VisitForRegisterValue(property->value(), args[2]);
2478 336 : VisitSetHomeObject(args[2], literal, property);
2479 : builder()
2480 336 : ->LoadLiteral(Smi::FromInt(NONE))
2481 336 : .StoreAccumulatorInRegister(args[3]);
2482 : Runtime::FunctionId function_id =
2483 : property->kind() == ObjectLiteral::Property::GETTER
2484 : ? Runtime::kDefineGetterPropertyUnchecked
2485 336 : : Runtime::kDefineSetterPropertyUnchecked;
2486 336 : builder()->CallRuntime(function_id, args);
2487 : break;
2488 : }
2489 : case ObjectLiteral::Property::SPREAD: {
2490 96 : RegisterList args = register_allocator()->NewRegisterList(2);
2491 96 : builder()->MoveRegister(literal, args[0]);
2492 : builder()->SetExpressionPosition(property->value());
2493 : VisitForRegisterValue(property->value(), args[1]);
2494 96 : builder()->CallRuntime(Runtime::kCopyDataProperties, args);
2495 : break;
2496 : }
2497 : case ObjectLiteral::Property::PROTOTYPE:
2498 0 : UNREACHABLE(); // Handled specially above.
2499 : break;
2500 : }
2501 2833 : }
2502 :
2503 201771 : builder()->LoadAccumulatorWithRegister(literal);
2504 : }
2505 :
2506 : // Fill an array with values from an iterator, starting at a given index. It is
2507 : // guaranteed that the loop will only terminate if the iterator is exhausted, or
2508 : // if one of iterator.next(), value.done, or value.value fail.
2509 : //
2510 : // In pseudocode:
2511 : //
2512 : // loop {
2513 : // value = iterator.next()
2514 : // if (value.done) break;
2515 : // value = value.value
2516 : // array[index++] = value
2517 : // }
2518 2243 : void BytecodeGenerator::BuildFillArrayWithIterator(
2519 : IteratorRecord iterator, Register array, Register index, Register value,
2520 : FeedbackSlot next_value_slot, FeedbackSlot next_done_slot,
2521 4490 : FeedbackSlot index_slot, FeedbackSlot element_slot) {
2522 : DCHECK(array.is_valid());
2523 : DCHECK(index.is_valid());
2524 : DCHECK(value.is_valid());
2525 :
2526 2243 : LoopBuilder loop_builder(builder(), nullptr, nullptr);
2527 2243 : loop_builder.LoopHeader();
2528 :
2529 : // Call the iterator's .next() method. Break from the loop if the `done`
2530 : // property is truthy, otherwise load the value from the iterator result and
2531 : // append the argument.
2532 2244 : BuildIteratorNext(iterator, value);
2533 : builder()->LoadNamedProperty(
2534 : value, ast_string_constants()->done_string(),
2535 4490 : feedback_index(feedback_spec()->AddLoadICSlot()));
2536 : loop_builder.BreakIfTrue(ToBooleanMode::kConvertToBoolean);
2537 :
2538 2245 : loop_builder.LoopBody();
2539 : builder()
2540 : // value = value.value
2541 : ->LoadNamedProperty(value, ast_string_constants()->value_string(),
2542 2245 : feedback_index(next_value_slot))
2543 : // array[index] = value
2544 2243 : .StoreInArrayLiteral(array, index, feedback_index(element_slot))
2545 : // index++
2546 2243 : .LoadAccumulatorWithRegister(index)
2547 2245 : .UnaryOperation(Token::INC, feedback_index(index_slot))
2548 2244 : .StoreAccumulatorInRegister(index);
2549 2244 : loop_builder.BindContinueTarget();
2550 2243 : loop_builder.JumpToHeader(loop_depth_);
2551 2243 : }
2552 :
2553 379582 : void BytecodeGenerator::BuildCreateArrayLiteral(
2554 380263 : const ZonePtrList<Expression>* elements, ArrayLiteral* expr) {
2555 : RegisterAllocationScope register_scope(this);
2556 379582 : Register index = register_allocator()->NewRegister();
2557 379605 : Register array = register_allocator()->NewRegister();
2558 : SharedFeedbackSlot element_slot(feedback_spec(),
2559 379599 : FeedbackSlotKind::kStoreInArrayLiteral);
2560 : ZonePtrList<Expression>::iterator current = elements->begin();
2561 : ZonePtrList<Expression>::iterator end = elements->end();
2562 : bool is_empty = elements->is_empty();
2563 :
2564 557964 : if (!is_empty && (*current)->IsSpread()) {
2565 : // If we have a leading spread, use CreateArrayFromIterable to create
2566 : // an array from it and then add the remaining components to that array.
2567 2112 : VisitForAccumulatorValue(*current);
2568 2114 : builder()->CreateArrayFromIterable().StoreAccumulatorInRegister(array);
2569 :
2570 2113 : if (++current != end) {
2571 : // If there are remaning elements, prepare the index register that is
2572 : // used for adding those elements. The next index is the length of the
2573 : // newly created array.
2574 608 : auto length = ast_string_constants()->length_string();
2575 608 : int length_load_slot = feedback_index(feedback_spec()->AddLoadICSlot());
2576 : builder()
2577 608 : ->LoadNamedProperty(array, length, length_load_slot)
2578 608 : .StoreAccumulatorInRegister(index);
2579 : }
2580 754934 : } else if (expr != nullptr) {
2581 : // There are some elements before the first (if any) spread, and we can
2582 : // use a boilerplate when creating the initial array from those elements.
2583 :
2584 : // First, allocate a constant pool entry for the boilerplate that will
2585 : // be created during finalization, and will contain all the constant
2586 : // elements before the first spread. This also handle the empty array case
2587 : // and one-shot optimization.
2588 : uint8_t flags = CreateArrayLiteralFlags::Encode(
2589 377468 : expr->IsFastCloningSupported(), expr->ComputeFlags());
2590 377456 : bool optimize_as_one_shot = ShouldOptimizeAsOneShot();
2591 : size_t entry;
2592 377466 : if (is_empty && optimize_as_one_shot) {
2593 47360 : entry = builder()->EmptyArrayBoilerplateDescriptionConstantPoolEntry();
2594 330106 : } else if (!is_empty) {
2595 176215 : entry = builder()->AllocateDeferredConstantPoolEntry();
2596 352440 : array_literals_.push_back(std::make_pair(expr, entry));
2597 : }
2598 :
2599 377460 : if (optimize_as_one_shot) {
2600 191605 : RegisterList args = register_allocator()->NewRegisterList(2);
2601 : builder()
2602 191615 : ->LoadConstantPoolEntry(entry)
2603 191632 : .StoreAccumulatorInRegister(args[0])
2604 191634 : .LoadLiteral(Smi::FromInt(flags))
2605 191619 : .StoreAccumulatorInRegister(args[1])
2606 191626 : .CallRuntime(Runtime::kCreateArrayLiteralWithoutAllocationSite, args);
2607 185855 : } else if (is_empty) {
2608 : // Empty array literal fast-path.
2609 153894 : int literal_index = feedback_index(feedback_spec()->AddLiteralSlot());
2610 : DCHECK(expr->IsFastCloningSupported());
2611 153895 : builder()->CreateEmptyArrayLiteral(literal_index);
2612 : } else {
2613 : // Create array literal from boilerplate.
2614 31961 : int literal_index = feedback_index(feedback_spec()->AddLiteralSlot());
2615 31955 : builder()->CreateArrayLiteral(entry, literal_index, flags);
2616 : }
2617 377473 : builder()->StoreAccumulatorInRegister(array);
2618 :
2619 : // Insert the missing non-constant elements, up until the first spread
2620 : // index, into the initial array (the remaining elements will be inserted
2621 : // below).
2622 : DCHECK_EQ(current, elements->begin());
2623 : ZonePtrList<Expression>::iterator first_spread_or_end =
2624 463 : expr->first_spread_index() >= 0 ? current + expr->first_spread_index()
2625 377909 : : end;
2626 : int array_index = 0;
2627 7613883 : for (; current != first_spread_or_end; ++current, array_index++) {
2628 7236419 : Expression* subexpr = *current;
2629 : DCHECK(!subexpr->IsSpread());
2630 : // Skip the constants.
2631 7236419 : if (subexpr->IsCompileTimeValue()) continue;
2632 :
2633 : builder()
2634 238595 : ->LoadLiteral(Smi::FromInt(array_index))
2635 238602 : .StoreAccumulatorInRegister(index);
2636 238628 : VisitForAccumulatorValue(subexpr);
2637 : builder()->StoreInArrayLiteral(array, index,
2638 238594 : feedback_index(element_slot.Get()));
2639 : }
2640 :
2641 377464 : if (current != end) {
2642 : // If there are remaining elements, prepare the index register
2643 : // to store the next element, which comes from the first spread.
2644 463 : builder()->LoadLiteral(array_index).StoreAccumulatorInRegister(index);
2645 : }
2646 : } else {
2647 : // In other cases, we prepare an empty array to be filled in below.
2648 : DCHECK(!elements->is_empty());
2649 : int literal_index = feedback_index(feedback_spec()->AddLiteralSlot());
2650 : builder()
2651 20 : ->CreateEmptyArrayLiteral(literal_index)
2652 20 : .StoreAccumulatorInRegister(array);
2653 : // Prepare the index for the first element.
2654 20 : builder()->LoadLiteral(Smi::FromInt(0)).StoreAccumulatorInRegister(index);
2655 : }
2656 :
2657 : // Now build insertions for the remaining elements from current to end.
2658 379562 : SharedFeedbackSlot index_slot(feedback_spec(), FeedbackSlotKind::kBinaryOp);
2659 : SharedFeedbackSlot length_slot(
2660 : feedback_spec(), feedback_spec()->GetStoreICSlot(LanguageMode::kStrict));
2661 3431 : for (; current != end; ++current) {
2662 3428 : Expression* subexpr = *current;
2663 3429 : if (subexpr->IsSpread()) {
2664 : RegisterAllocationScope scope(this);
2665 : builder()->SetExpressionAsStatementPosition(
2666 3320 : subexpr->AsSpread()->expression());
2667 1661 : VisitForAccumulatorValue(subexpr->AsSpread()->expression());
2668 1661 : IteratorRecord iterator = BuildGetIteratorRecord(IteratorType::kNormal);
2669 :
2670 1662 : Register value = register_allocator()->NewRegister();
2671 3324 : FeedbackSlot next_value_load_slot = feedback_spec()->AddLoadICSlot();
2672 3324 : FeedbackSlot next_done_load_slot = feedback_spec()->AddLoadICSlot();
2673 1662 : FeedbackSlot real_index_slot = index_slot.Get();
2674 1662 : FeedbackSlot real_element_slot = element_slot.Get();
2675 : BuildFillArrayWithIterator(iterator, array, index, value,
2676 : next_value_load_slot, next_done_load_slot,
2677 1662 : real_index_slot, real_element_slot);
2678 1769 : } else if (!subexpr->IsTheHoleLiteral()) {
2679 : // literal[index++] = subexpr
2680 1714 : VisitForAccumulatorValue(subexpr);
2681 : builder()
2682 : ->StoreInArrayLiteral(array, index,
2683 1713 : feedback_index(element_slot.Get()))
2684 1713 : .LoadAccumulatorWithRegister(index);
2685 : // Only increase the index if we are not the last element.
2686 1714 : if (current + 1 != end) {
2687 : builder()
2688 1096 : ->UnaryOperation(Token::INC, feedback_index(index_slot.Get()))
2689 1097 : .StoreAccumulatorInRegister(index);
2690 : }
2691 : } else {
2692 : // literal.length = ++index
2693 : // length_slot is only used when there are holes.
2694 56 : auto length = ast_string_constants()->length_string();
2695 : builder()
2696 56 : ->LoadAccumulatorWithRegister(index)
2697 112 : .UnaryOperation(Token::INC, feedback_index(index_slot.Get()))
2698 56 : .StoreAccumulatorInRegister(index)
2699 : .StoreNamedProperty(array, length, feedback_index(length_slot.Get()),
2700 112 : LanguageMode::kStrict);
2701 : }
2702 : }
2703 :
2704 379565 : builder()->LoadAccumulatorWithRegister(array);
2705 379617 : }
2706 :
2707 379551 : void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
2708 379551 : expr->InitDepthAndFlags();
2709 379566 : BuildCreateArrayLiteral(expr->values(), expr);
2710 379590 : }
2711 :
2712 0 : void BytecodeGenerator::VisitStoreInArrayLiteral(StoreInArrayLiteral* expr) {
2713 : builder()->SetExpressionAsStatementPosition(expr);
2714 : RegisterAllocationScope register_scope(this);
2715 0 : Register array = register_allocator()->NewRegister();
2716 0 : Register index = register_allocator()->NewRegister();
2717 : VisitForRegisterValue(expr->array(), array);
2718 : VisitForRegisterValue(expr->index(), index);
2719 0 : VisitForAccumulatorValue(expr->value());
2720 : builder()->StoreInArrayLiteral(
2721 : array, index,
2722 0 : feedback_index(feedback_spec()->AddStoreInArrayLiteralICSlot()));
2723 0 : }
2724 :
2725 27482127 : void BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) {
2726 : builder()->SetExpressionPosition(proxy);
2727 9160709 : BuildVariableLoad(proxy->var(), proxy->hole_check_mode());
2728 9161115 : }
2729 :
2730 34764669 : void BytecodeGenerator::BuildVariableLoad(Variable* variable,
2731 : HoleCheckMode hole_check_mode,
2732 8330484 : TypeofMode typeof_mode) {
2733 13443502 : switch (variable->location()) {
2734 : case VariableLocation::LOCAL: {
2735 2417320 : Register source(builder()->Local(variable->index()));
2736 : // We need to load the variable into the accumulator, even when in a
2737 : // VisitForRegisterScope, in order to avoid register aliasing if
2738 : // subsequent expressions assign to the same variable.
2739 2417362 : builder()->LoadAccumulatorWithRegister(source);
2740 2417498 : if (hole_check_mode == HoleCheckMode::kRequired) {
2741 2538 : BuildThrowIfHole(variable);
2742 : }
2743 : break;
2744 : }
2745 : case VariableLocation::PARAMETER: {
2746 : Register source;
2747 3675027 : if (variable->IsReceiver()) {
2748 2386311 : source = builder()->Receiver();
2749 : } else {
2750 1288716 : source = builder()->Parameter(variable->index());
2751 : }
2752 : // We need to load the variable into the accumulator, even when in a
2753 : // VisitForRegisterScope, in order to avoid register aliasing if
2754 : // subsequent expressions assign to the same variable.
2755 3675027 : builder()->LoadAccumulatorWithRegister(source);
2756 3675035 : if (hole_check_mode == HoleCheckMode::kRequired) {
2757 2170311 : BuildThrowIfHole(variable);
2758 : }
2759 : break;
2760 : }
2761 : case VariableLocation::UNALLOCATED: {
2762 : // The global identifier "undefined" is immutable. Everything
2763 : // else could be reassigned. For performance, we do a pointer comparison
2764 : // rather than checking if the raw_name is really "undefined".
2765 5943296 : if (variable->raw_name() == ast_string_constants()->undefined_string()) {
2766 81114 : builder()->LoadUndefined();
2767 : } else {
2768 5862182 : FeedbackSlot slot = GetCachedLoadGlobalICSlot(typeof_mode, variable);
2769 : builder()->LoadGlobal(variable->raw_name(), feedback_index(slot),
2770 5862622 : typeof_mode);
2771 : }
2772 : break;
2773 : }
2774 : case VariableLocation::CONTEXT: {
2775 1004860 : int depth = execution_context()->ContextChainDepth(variable->scope());
2776 : ContextScope* context = execution_context()->Previous(depth);
2777 : Register context_reg;
2778 1004850 : if (context) {
2779 971598 : context_reg = context->reg();
2780 : depth = 0;
2781 : } else {
2782 33252 : context_reg = execution_context()->reg();
2783 : }
2784 :
2785 : BytecodeArrayBuilder::ContextSlotMutability immutable =
2786 : (variable->maybe_assigned() == kNotAssigned)
2787 : ? BytecodeArrayBuilder::kImmutableSlot
2788 1004850 : : BytecodeArrayBuilder::kMutableSlot;
2789 :
2790 : builder()->LoadContextSlot(context_reg, variable->index(), depth,
2791 1004850 : immutable);
2792 1004828 : if (hole_check_mode == HoleCheckMode::kRequired) {
2793 241555 : BuildThrowIfHole(variable);
2794 : }
2795 : break;
2796 : }
2797 : case VariableLocation::LOOKUP: {
2798 401970 : switch (variable->mode()) {
2799 : case VariableMode::kDynamicLocal: {
2800 7294 : Variable* local_variable = variable->local_if_not_shadowed();
2801 : int depth =
2802 3647 : execution_context()->ContextChainDepth(local_variable->scope());
2803 : builder()->LoadLookupContextSlot(variable->raw_name(), typeof_mode,
2804 3647 : local_variable->index(), depth);
2805 3647 : if (hole_check_mode == HoleCheckMode::kRequired) {
2806 1531 : BuildThrowIfHole(variable);
2807 : }
2808 : break;
2809 : }
2810 : case VariableMode::kDynamicGlobal: {
2811 : int depth =
2812 372469 : current_scope()->ContextChainLengthUntilOutermostSloppyEval();
2813 372469 : FeedbackSlot slot = GetCachedLoadGlobalICSlot(typeof_mode, variable);
2814 : builder()->LoadLookupGlobalSlot(variable->raw_name(), typeof_mode,
2815 372470 : feedback_index(slot), depth);
2816 : break;
2817 : }
2818 : default:
2819 25854 : builder()->LoadLookupSlot(variable->raw_name(), typeof_mode);
2820 : }
2821 : break;
2822 : }
2823 : case VariableLocation::MODULE: {
2824 1362 : int depth = execution_context()->ContextChainDepth(variable->scope());
2825 1362 : builder()->LoadModuleVariable(variable->index(), depth);
2826 1362 : if (hole_check_mode == HoleCheckMode::kRequired) {
2827 849 : BuildThrowIfHole(variable);
2828 : }
2829 : break;
2830 : }
2831 : }
2832 13444038 : }
2833 :
2834 4201028 : void BytecodeGenerator::BuildVariableLoadForAccumulatorValue(
2835 : Variable* variable, HoleCheckMode hole_check_mode, TypeofMode typeof_mode) {
2836 : ValueResultScope accumulator_result(this);
2837 4201028 : BuildVariableLoad(variable, hole_check_mode, typeof_mode);
2838 4201124 : }
2839 :
2840 7324479 : void BytecodeGenerator::BuildReturn(int source_position) {
2841 2441493 : if (FLAG_trace) {
2842 : RegisterAllocationScope register_scope(this);
2843 0 : Register result = register_allocator()->NewRegister();
2844 : // Runtime returns {result} value, preserving accumulator.
2845 0 : builder()->StoreAccumulatorInRegister(result).CallRuntime(
2846 0 : Runtime::kTraceExit, result);
2847 : }
2848 2441493 : if (info()->collect_type_profile()) {
2849 85 : builder()->CollectTypeProfile(info()->literal()->return_position());
2850 : }
2851 2441493 : builder()->SetReturnPosition(source_position, info()->literal());
2852 2441727 : builder()->Return();
2853 2441954 : }
2854 :
2855 20338 : void BytecodeGenerator::BuildAsyncReturn(int source_position) {
2856 : RegisterAllocationScope register_scope(this);
2857 :
2858 14262 : if (IsAsyncGeneratorFunction(info()->literal()->kind())) {
2859 1055 : RegisterList args = register_allocator()->NewRegisterList(3);
2860 : builder()
2861 1055 : ->MoveRegister(generator_object(), args[0]) // generator
2862 1055 : .StoreAccumulatorInRegister(args[1]) // value
2863 1055 : .LoadTrue()
2864 1055 : .StoreAccumulatorInRegister(args[2]) // done
2865 1055 : .CallRuntime(Runtime::kInlineAsyncGeneratorResolve, args);
2866 : } else {
2867 : DCHECK(IsAsyncFunction(info()->literal()->kind()));
2868 6076 : RegisterList args = register_allocator()->NewRegisterList(3);
2869 : builder()
2870 6076 : ->MoveRegister(generator_object(), args[0]) // generator
2871 6076 : .StoreAccumulatorInRegister(args[1]) // value
2872 18228 : .LoadBoolean(info()->literal()->CanSuspend())
2873 6076 : .StoreAccumulatorInRegister(args[2]) // can_suspend
2874 6076 : .CallRuntime(Runtime::kInlineAsyncFunctionResolve, args);
2875 : }
2876 :
2877 7131 : BuildReturn(source_position);
2878 7131 : }
2879 :
2880 37448 : void BytecodeGenerator::BuildReThrow() { builder()->ReThrow(); }
2881 :
2882 2735793 : void BytecodeGenerator::BuildThrowIfHole(Variable* variable) {
2883 2453145 : if (variable->is_this()) {
2884 : DCHECK(variable->mode() == VariableMode::kConst);
2885 2170497 : builder()->ThrowSuperNotCalledIfHole();
2886 : } else {
2887 282648 : builder()->ThrowReferenceErrorIfHole(variable->raw_name());
2888 : }
2889 2453151 : }
2890 :
2891 38900 : void BytecodeGenerator::BuildHoleCheckForVariableAssignment(Variable* variable,
2892 : Token::Value op) {
2893 41431 : if (variable->is_this() && variable->mode() == VariableMode::kConst &&
2894 : op == Token::INIT) {
2895 : // Perform an initialization check for 'this'. 'this' variable is the
2896 : // only variable able to trigger bind operations outside the TDZ
2897 : // via 'super' calls.
2898 2531 : builder()->ThrowSuperAlreadyCalledIfNotHole();
2899 : } else {
2900 : // Perform an initialization check for let/const declared variables.
2901 : // E.g. let x = (x = 20); is not allowed.
2902 : DCHECK(IsLexicalVariableMode(variable->mode()));
2903 36369 : BuildThrowIfHole(variable);
2904 : }
2905 38900 : }
2906 :
2907 5726329 : void BytecodeGenerator::BuildVariableAssignment(
2908 13234512 : Variable* variable, Token::Value op, HoleCheckMode hole_check_mode,
2909 3517219 : LookupHoistingMode lookup_hoisting_mode) {
2910 : VariableMode mode = variable->mode();
2911 : RegisterAllocationScope assignment_register_scope(this);
2912 : BytecodeLabel end_label;
2913 5726329 : switch (variable->location()) {
2914 : case VariableLocation::PARAMETER:
2915 : case VariableLocation::LOCAL: {
2916 : Register destination;
2917 2491568 : if (VariableLocation::PARAMETER == variable->location()) {
2918 30303 : if (variable->IsReceiver()) {
2919 2375 : destination = builder()->Receiver();
2920 : } else {
2921 27928 : destination = builder()->Parameter(variable->index());
2922 : }
2923 : } else {
2924 2461265 : destination = builder()->Local(variable->index());
2925 : }
2926 :
2927 2491641 : if (hole_check_mode == HoleCheckMode::kRequired) {
2928 : // Load destination to check for hole.
2929 4960 : Register value_temp = register_allocator()->NewRegister();
2930 : builder()
2931 4960 : ->StoreAccumulatorInRegister(value_temp)
2932 4960 : .LoadAccumulatorWithRegister(destination);
2933 :
2934 4960 : BuildHoleCheckForVariableAssignment(variable, op);
2935 4960 : builder()->LoadAccumulatorWithRegister(value_temp);
2936 : }
2937 :
2938 2491641 : if (mode != VariableMode::kConst || op == Token::INIT) {
2939 2486771 : builder()->StoreAccumulatorInRegister(destination);
2940 4870 : } else if (variable->throw_on_const_assignment(language_mode())) {
2941 4837 : builder()->CallRuntime(Runtime::kThrowConstAssignError);
2942 : }
2943 : break;
2944 : }
2945 : case VariableLocation::UNALLOCATED: {
2946 1421094 : FeedbackSlot slot = GetCachedStoreGlobalICSlot(language_mode(), variable);
2947 1421251 : builder()->StoreGlobal(variable->raw_name(), feedback_index(slot));
2948 : break;
2949 : }
2950 : case VariableLocation::CONTEXT: {
2951 1741232 : int depth = execution_context()->ContextChainDepth(variable->scope());
2952 : ContextScope* context = execution_context()->Previous(depth);
2953 : Register context_reg;
2954 :
2955 1741252 : if (context) {
2956 1729213 : context_reg = context->reg();
2957 : depth = 0;
2958 : } else {
2959 12039 : context_reg = execution_context()->reg();
2960 : }
2961 :
2962 1741252 : if (hole_check_mode == HoleCheckMode::kRequired) {
2963 : // Load destination to check for hole.
2964 33870 : Register value_temp = register_allocator()->NewRegister();
2965 : builder()
2966 33870 : ->StoreAccumulatorInRegister(value_temp)
2967 : .LoadContextSlot(context_reg, variable->index(), depth,
2968 33870 : BytecodeArrayBuilder::kMutableSlot);
2969 :
2970 33870 : BuildHoleCheckForVariableAssignment(variable, op);
2971 33870 : builder()->LoadAccumulatorWithRegister(value_temp);
2972 : }
2973 :
2974 1741252 : if (mode != VariableMode::kConst || op == Token::INIT) {
2975 1713179 : builder()->StoreContextSlot(context_reg, variable->index(), depth);
2976 28073 : } else if (variable->throw_on_const_assignment(language_mode())) {
2977 28051 : builder()->CallRuntime(Runtime::kThrowConstAssignError);
2978 : }
2979 : break;
2980 : }
2981 : case VariableLocation::LOOKUP: {
2982 : builder()->StoreLookupSlot(variable->raw_name(), language_mode(),
2983 37543 : lookup_hoisting_mode);
2984 37542 : break;
2985 : }
2986 : case VariableLocation::MODULE: {
2987 : DCHECK(IsDeclaredVariableMode(mode));
2988 :
2989 34845 : if (mode == VariableMode::kConst && op != Token::INIT) {
2990 110 : builder()->CallRuntime(Runtime::kThrowConstAssignError);
2991 110 : break;
2992 : }
2993 :
2994 : // If we don't throw above, we know that we're dealing with an
2995 : // export because imports are const and we do not generate initializing
2996 : // assignments for them.
2997 : DCHECK(variable->IsExport());
2998 :
2999 34735 : int depth = execution_context()->ContextChainDepth(variable->scope());
3000 34735 : if (hole_check_mode == HoleCheckMode::kRequired) {
3001 70 : Register value_temp = register_allocator()->NewRegister();
3002 : builder()
3003 70 : ->StoreAccumulatorInRegister(value_temp)
3004 70 : .LoadModuleVariable(variable->index(), depth);
3005 70 : BuildHoleCheckForVariableAssignment(variable, op);
3006 70 : builder()->LoadAccumulatorWithRegister(value_temp);
3007 : }
3008 34735 : builder()->StoreModuleVariable(variable->index(), depth);
3009 34735 : break;
3010 : }
3011 5726761 : }
3012 5726094 : }
3013 :
3014 2369088 : void BytecodeGenerator::BuildLoadNamedProperty(const Expression* object_expr,
3015 : Register object,
3016 : const AstRawString* name) {
3017 2369088 : if (ShouldOptimizeAsOneShot()) {
3018 1257013 : builder()->LoadNamedPropertyNoFeedback(object, name);
3019 : } else {
3020 1112216 : FeedbackSlot slot = GetCachedLoadICSlot(object_expr, name);
3021 1112200 : builder()->LoadNamedProperty(object, name, feedback_index(slot));
3022 : }
3023 2369285 : }
3024 :
3025 2391720 : void BytecodeGenerator::BuildStoreNamedProperty(const Expression* object_expr,
3026 : Register object,
3027 4783535 : const AstRawString* name) {
3028 : Register value;
3029 2391720 : if (!execution_result()->IsEffect()) {
3030 8514 : value = register_allocator()->NewRegister();
3031 8515 : builder()->StoreAccumulatorInRegister(value);
3032 : }
3033 :
3034 2391721 : if (ShouldOptimizeAsOneShot()) {
3035 114700 : builder()->StoreNamedPropertyNoFeedback(object, name, language_mode());
3036 : } else {
3037 2277056 : FeedbackSlot slot = GetCachedStoreICSlot(object_expr, name);
3038 : builder()->StoreNamedProperty(object, name, feedback_index(slot),
3039 2277059 : language_mode());
3040 : }
3041 :
3042 2391815 : if (!execution_result()->IsEffect()) {
3043 8515 : builder()->LoadAccumulatorWithRegister(value);
3044 : }
3045 2391815 : }
3046 :
3047 : // static
3048 : BytecodeGenerator::AssignmentLhsData
3049 0 : BytecodeGenerator::AssignmentLhsData::NonProperty(Expression* expr) {
3050 : return AssignmentLhsData(NON_PROPERTY, expr, RegisterList(), Register(),
3051 0 : Register(), nullptr, nullptr);
3052 : }
3053 : // static
3054 : BytecodeGenerator::AssignmentLhsData
3055 0 : BytecodeGenerator::AssignmentLhsData::NamedProperty(Expression* object_expr,
3056 : Register object,
3057 : const AstRawString* name) {
3058 : return AssignmentLhsData(NAMED_PROPERTY, nullptr, RegisterList(), object,
3059 0 : Register(), object_expr, name);
3060 : }
3061 : // static
3062 : BytecodeGenerator::AssignmentLhsData
3063 0 : BytecodeGenerator::AssignmentLhsData::KeyedProperty(Register object,
3064 : Register key) {
3065 : return AssignmentLhsData(KEYED_PROPERTY, nullptr, RegisterList(), object, key,
3066 0 : nullptr, nullptr);
3067 : }
3068 : // static
3069 : BytecodeGenerator::AssignmentLhsData
3070 0 : BytecodeGenerator::AssignmentLhsData::NamedSuperProperty(
3071 : RegisterList super_property_args) {
3072 : return AssignmentLhsData(NAMED_SUPER_PROPERTY, nullptr, super_property_args,
3073 0 : Register(), Register(), nullptr, nullptr);
3074 : }
3075 : // static
3076 : BytecodeGenerator::AssignmentLhsData
3077 0 : BytecodeGenerator::AssignmentLhsData::KeyedSuperProperty(
3078 : RegisterList super_property_args) {
3079 : return AssignmentLhsData(KEYED_SUPER_PROPERTY, nullptr, super_property_args,
3080 0 : Register(), Register(), nullptr, nullptr);
3081 : }
3082 :
3083 7608061 : BytecodeGenerator::AssignmentLhsData BytecodeGenerator::PrepareAssignmentLhs(
3084 : Expression* lhs, AccumulatorPreservingMode accumulator_preserving_mode) {
3085 : // Left-hand side can only be a property, a global or a variable slot.
3086 14848065 : Property* property = lhs->AsProperty();
3087 7608112 : AssignType assign_type = Property::GetAssignType(property);
3088 :
3089 : // Evaluate LHS expression.
3090 7608111 : switch (assign_type) {
3091 : case NON_PROPERTY:
3092 : return AssignmentLhsData::NonProperty(lhs);
3093 : case NAMED_PROPERTY: {
3094 2391763 : AccumulatorPreservingScope scope(this, accumulator_preserving_mode);
3095 2391766 : Register object = VisitForRegisterValue(property->obj());
3096 : const AstRawString* name =
3097 4783719 : property->key()->AsLiteral()->AsRawPropertyName();
3098 : return AssignmentLhsData::NamedProperty(property->obj(), object, name);
3099 : }
3100 : case KEYED_PROPERTY: {
3101 31692 : AccumulatorPreservingScope scope(this, accumulator_preserving_mode);
3102 31701 : Register object = VisitForRegisterValue(property->obj());
3103 31698 : Register key = VisitForRegisterValue(property->key());
3104 : return AssignmentLhsData::KeyedProperty(object, key);
3105 : }
3106 : case NAMED_SUPER_PROPERTY: {
3107 220 : AccumulatorPreservingScope scope(this, accumulator_preserving_mode);
3108 : RegisterList super_property_args =
3109 220 : register_allocator()->NewRegisterList(4);
3110 440 : SuperPropertyReference* super_property =
3111 220 : property->obj()->AsSuperPropertyReference();
3112 : VisitForRegisterValue(super_property->this_var(), 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 680 : SuperPropertyReference* super_property =
3125 340 : property->obj()->AsSuperPropertyReference();
3126 : VisitForRegisterValue(super_property->this_var(), super_property_args[0]);
3127 : VisitForRegisterValue(super_property->home_object(),
3128 : super_property_args[1]);
3129 : VisitForRegisterValue(property->key(), super_property_args[2]);
3130 : return AssignmentLhsData::KeyedSuperProperty(super_property_args);
3131 : }
3132 : }
3133 0 : UNREACHABLE();
3134 : }
3135 :
3136 : // Build the iteration finalizer called in the finally block of an iteration
3137 : // protocol execution. This closes the iterator if needed, and suppresses any
3138 : // exception it throws if necessary.
3139 : //
3140 : // In pseudo-code, this builds:
3141 : //
3142 : // if (!done) {
3143 : // let method = iterator.return
3144 : // if (method !== null && method !== undefined) {
3145 : // if (typeof(method) !== "function") throw TypeError
3146 : // try {
3147 : // let return_val = method.call(iterator)
3148 : // if (!%IsObject(return_val)) throw TypeError
3149 : // } catch (e) {
3150 : // if (iteration_continuation != RETHROW)
3151 : // rethrow e
3152 : // }
3153 : // }
3154 : // }
3155 : //
3156 : // For async iterators, iterator.close() becomes await iterator.close().
3157 40729 : void BytecodeGenerator::BuildFinalizeIteration(
3158 : IteratorRecord iterator, Register done,
3159 122211 : Register iteration_continuation_token) {
3160 : RegisterAllocationScope register_scope(this);
3161 : BytecodeLabels iterator_is_done(zone());
3162 :
3163 : // if (!done) {
3164 40737 : builder()->LoadAccumulatorWithRegister(done).JumpIfTrue(
3165 81470 : ToBooleanMode::kConvertToBoolean, iterator_is_done.New());
3166 :
3167 : // method = iterator.return
3168 : // if (method !== null && method !== undefined) {
3169 40741 : Register method = register_allocator()->NewRegister();
3170 : builder()
3171 : ->LoadNamedProperty(iterator.object(),
3172 : ast_string_constants()->return_string(),
3173 81480 : feedback_index(feedback_spec()->AddLoadICSlot()))
3174 40739 : .StoreAccumulatorInRegister(method)
3175 81475 : .JumpIfUndefined(iterator_is_done.New())
3176 81480 : .JumpIfNull(iterator_is_done.New());
3177 :
3178 : // if (typeof(method) !== "function") throw TypeError
3179 : BytecodeLabel if_callable;
3180 : builder()
3181 40739 : ->CompareTypeOf(TestTypeOfFlags::LiteralFlag::kFunction)
3182 40741 : .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &if_callable);
3183 : {
3184 : // throw %NewTypeError(kReturnMethodNotCallable)
3185 : RegisterAllocationScope register_scope(this);
3186 40741 : RegisterList new_type_error_args = register_allocator()->NewRegisterList(2);
3187 : builder()
3188 40741 : ->LoadLiteral(Smi::FromEnum(MessageTemplate::kReturnMethodNotCallable))
3189 40739 : .StoreAccumulatorInRegister(new_type_error_args[0])
3190 81480 : .LoadLiteral(ast_string_constants()->empty_string())
3191 40740 : .StoreAccumulatorInRegister(new_type_error_args[1])
3192 40740 : .CallRuntime(Runtime::kNewTypeError, new_type_error_args)
3193 40742 : .Throw();
3194 : }
3195 40739 : builder()->Bind(&if_callable);
3196 :
3197 : {
3198 : RegisterAllocationScope register_scope(this);
3199 : BuildTryCatch(
3200 : // try {
3201 : // let return_val = method.call(iterator)
3202 : // if (!%IsObject(return_val)) throw TypeError
3203 : // }
3204 40732 : [&]() {
3205 81473 : RegisterList args(iterator.object());
3206 : builder()->CallProperty(
3207 122200 : method, args, feedback_index(feedback_spec()->AddCallICSlot()));
3208 81482 : if (iterator.type() == IteratorType::kAsync) {
3209 337 : BuildAwait();
3210 : }
3211 40741 : builder()->JumpIfJSReceiver(iterator_is_done.New());
3212 : {
3213 : // Throw this exception inside the try block so that it is
3214 : // suppressed by the iteration continuation if necessary.
3215 40743 : RegisterAllocationScope register_scope(this);
3216 40743 : Register return_result = register_allocator()->NewRegister();
3217 : builder()
3218 40739 : ->StoreAccumulatorInRegister(return_result)
3219 : .CallRuntime(Runtime::kThrowIteratorResultNotAnObject,
3220 40741 : return_result);
3221 : }
3222 40742 : },
3223 :
3224 : // catch (e) {
3225 : // if (iteration_continuation != RETHROW)
3226 : // rethrow e
3227 : // }
3228 40733 : [&](Register context) {
3229 : // Reuse context register to store the exception.
3230 40733 : Register close_exception = context;
3231 40733 : builder()->StoreAccumulatorInRegister(close_exception);
3232 :
3233 : BytecodeLabel suppress_close_exception;
3234 : builder()
3235 : ->LoadLiteral(
3236 40738 : Smi::FromInt(ControlScope::DeferredCommands::kRethrowToken))
3237 81478 : .CompareReference(iteration_continuation_token)
3238 : .JumpIfTrue(ToBooleanMode::kAlreadyBoolean,
3239 40742 : &suppress_close_exception)
3240 40742 : .LoadAccumulatorWithRegister(close_exception)
3241 40743 : .ReThrow()
3242 40741 : .Bind(&suppress_close_exception);
3243 40740 : },
3244 40740 : HandlerTable::UNCAUGHT);
3245 : }
3246 :
3247 81480 : iterator_is_done.Bind(builder());
3248 40741 : }
3249 :
3250 : // Get the default value of a destructuring target. Will mutate the
3251 : // destructuring target expression if there is a default value.
3252 : //
3253 : // For
3254 : // a = b
3255 : // in
3256 : // let {a = b} = c
3257 : // returns b and mutates the input into a.
3258 22553 : Expression* BytecodeGenerator::GetDestructuringDefaultValue(
3259 : Expression** target) {
3260 : Expression* default_value = nullptr;
3261 45106 : if ((*target)->IsAssignment()) {
3262 3792 : Assignment* default_init = (*target)->AsAssignment();
3263 : DCHECK_EQ(default_init->op(), Token::ASSIGN);
3264 : default_value = default_init->value();
3265 1896 : *target = default_init->target();
3266 : DCHECK((*target)->IsValidReferenceExpression() || (*target)->IsPattern());
3267 : }
3268 22553 : return default_value;
3269 : }
3270 :
3271 : // Convert a destructuring assignment to an array literal into a sequence of
3272 : // iterator accesses into the value being assigned (in the accumulator).
3273 : //
3274 : // [a().x, ...b] = accumulator
3275 : //
3276 : // becomes
3277 : //
3278 : // iterator = %GetIterator(accumulator)
3279 : // try {
3280 : //
3281 : // // Individual assignments read off the value from iterator.next() This gets
3282 : // // repeated per destructuring element.
3283 : // if (!done) {
3284 : // // Make sure we are considered 'done' if .next(), .done or .value fail.
3285 : // done = true
3286 : // var next_result = iterator.next()
3287 : // var tmp_done = next_result.done
3288 : // if (!tmp_done) {
3289 : // value = next_result.value
3290 : // done = false
3291 : // }
3292 : // }
3293 : // if (done)
3294 : // value = undefined
3295 : // a().x = value
3296 : //
3297 : // // A spread receives the remaining items in the iterator.
3298 : // var array = []
3299 : // var index = 0
3300 : // %FillArrayWithIterator(iterator, array, index, done)
3301 : // done = true
3302 : // b = array
3303 : //
3304 : // } catch(e) {
3305 : // iteration_continuation = RETHROW
3306 : // } finally {
3307 : // %FinalizeIteration(iterator, done, iteration_continuation)
3308 : // }
3309 2689 : void BytecodeGenerator::BuildDestructuringArrayAssignment(
3310 : ArrayLiteral* pattern, Token::Value op,
3311 2689 : LookupHoistingMode lookup_hoisting_mode) {
3312 : RegisterAllocationScope scope(this);
3313 :
3314 2689 : Register value = register_allocator()->NewRegister();
3315 2689 : builder()->StoreAccumulatorInRegister(value);
3316 :
3317 : // Store the iterator in a dedicated register so that it can be closed on
3318 : // exit, and the 'done' value in a dedicated register so that it can be
3319 : // changed and accessed independently of the iteration result.
3320 2689 : IteratorRecord iterator = BuildGetIteratorRecord(IteratorType::kNormal);
3321 2689 : Register done = register_allocator()->NewRegister();
3322 2689 : builder()->LoadFalse();
3323 2689 : builder()->StoreAccumulatorInRegister(done);
3324 :
3325 : BuildTryFinally(
3326 : // Try block.
3327 2689 : [&]() {
3328 13297 : Register next_result = register_allocator()->NewRegister();
3329 5378 : FeedbackSlot next_value_load_slot = feedback_spec()->AddLoadICSlot();
3330 5378 : FeedbackSlot next_done_load_slot = feedback_spec()->AddLoadICSlot();
3331 :
3332 583 : Spread* spread = nullptr;
3333 8914 : for (Expression* target : *pattern->values()) {
3334 4119 : if (target->IsSpread()) {
3335 583 : spread = target->AsSpread();
3336 583 : break;
3337 : }
3338 :
3339 3536 : Expression* default_value = GetDestructuringDefaultValue(&target);
3340 7072 : if (!target->IsPattern()) {
3341 3190 : builder()->SetExpressionAsStatementPosition(target);
3342 : }
3343 :
3344 3536 : AssignmentLhsData lhs_data = PrepareAssignmentLhs(target);
3345 :
3346 : // if (!done) {
3347 : // // Make sure we are considered done if .next(), .done or .value
3348 : // // fail.
3349 : // done = true
3350 : // var next_result = iterator.next()
3351 : // var tmp_done = next_result.done
3352 : // if (!tmp_done) {
3353 : // value = next_result.value
3354 : // done = false
3355 : // }
3356 : // }
3357 : // if (done)
3358 : // value = undefined
3359 3536 : BytecodeLabels is_done(zone());
3360 :
3361 3536 : builder()->LoadAccumulatorWithRegister(done);
3362 : builder()->JumpIfTrue(ToBooleanMode::kConvertToBoolean,
3363 3536 : is_done.New());
3364 :
3365 3535 : builder()->LoadTrue().StoreAccumulatorInRegister(done);
3366 3536 : BuildIteratorNext(iterator, next_result);
3367 : builder()
3368 : ->LoadNamedProperty(next_result,
3369 : ast_string_constants()->done_string(),
3370 7072 : feedback_index(next_done_load_slot))
3371 7072 : .JumpIfTrue(ToBooleanMode::kConvertToBoolean, is_done.New())
3372 : .LoadNamedProperty(next_result,
3373 : ast_string_constants()->value_string(),
3374 10608 : feedback_index(next_value_load_slot))
3375 3536 : .StoreAccumulatorInRegister(next_result)
3376 3536 : .LoadFalse()
3377 7072 : .StoreAccumulatorInRegister(done)
3378 3536 : .LoadAccumulatorWithRegister(next_result);
3379 :
3380 : // Only do the assignment if this is not a hole (i.e. 'elided').
3381 3536 : if (!target->IsTheHoleLiteral()) {
3382 : // [<pattern> = <init>] = <value>
3383 : // becomes (roughly)
3384 : // temp = <value>.next();
3385 : // <pattern> = temp === undefined ? <init> : temp;
3386 : BytecodeLabel do_assignment;
3387 3425 : if (default_value) {
3388 461 : builder()->JumpIfNotUndefined(&do_assignment);
3389 : // Since done == true => temp == undefined, jump directly to using
3390 : // the default value for that case.
3391 461 : is_done.Bind(builder());
3392 461 : VisitForAccumulatorValue(default_value);
3393 : } else {
3394 2964 : builder()->Jump(&do_assignment);
3395 2964 : is_done.Bind(builder());
3396 2964 : builder()->LoadUndefined();
3397 : }
3398 3425 : builder()->Bind(&do_assignment);
3399 :
3400 3425 : BuildAssignment(lhs_data, op, lookup_hoisting_mode);
3401 : } else {
3402 : DCHECK_EQ(lhs_data.assign_type(), NON_PROPERTY);
3403 111 : is_done.Bind(builder());
3404 : }
3405 : }
3406 :
3407 2689 : if (spread) {
3408 583 : RegisterAllocationScope scope(this);
3409 :
3410 : // A spread is turned into a loop over the remainer of the iterator.
3411 : Expression* target = spread->expression();
3412 :
3413 583 : if (!target->IsPattern()) {
3414 : builder()->SetExpressionAsStatementPosition(spread);
3415 : }
3416 :
3417 583 : AssignmentLhsData lhs_data = PrepareAssignmentLhs(target);
3418 :
3419 : // var array = [];
3420 583 : Register array = register_allocator()->NewRegister();
3421 : builder()->CreateEmptyArrayLiteral(
3422 1749 : feedback_index(feedback_spec()->AddLiteralSlot()));
3423 583 : builder()->StoreAccumulatorInRegister(array);
3424 :
3425 : // var index = 0;
3426 583 : Register index = register_allocator()->NewRegister();
3427 583 : builder()->LoadLiteral(Smi::zero());
3428 583 : builder()->StoreAccumulatorInRegister(index);
3429 :
3430 : // Set done to true, since it's guaranteed to be true by the time the
3431 : // array fill completes.
3432 583 : builder()->LoadTrue().StoreAccumulatorInRegister(done);
3433 :
3434 : // Fill the array with the iterator.
3435 : FeedbackSlot element_slot =
3436 1749 : feedback_spec()->AddStoreInArrayLiteralICSlot();
3437 1749 : FeedbackSlot index_slot = feedback_spec()->AddBinaryOpICSlot();
3438 : BuildFillArrayWithIterator(iterator, array, index, next_result,
3439 : next_value_load_slot, next_done_load_slot,
3440 583 : index_slot, element_slot);
3441 :
3442 : // Assign the array to the LHS.
3443 583 : builder()->LoadAccumulatorWithRegister(array);
3444 583 : BuildAssignment(lhs_data, op, lookup_hoisting_mode);
3445 : }
3446 2689 : },
3447 : // Finally block.
3448 : [&](Register iteration_continuation_token) {
3449 : // Finish the iteration in the finally block.
3450 2689 : BuildFinalizeIteration(iterator, done, iteration_continuation_token);
3451 : },
3452 2689 : HandlerTable::UNCAUGHT);
3453 :
3454 2689 : if (!execution_result()->IsEffect()) {
3455 266 : builder()->LoadAccumulatorWithRegister(value);
3456 2689 : }
3457 2689 : }
3458 :
3459 : // Convert a destructuring assignment to an object literal into a sequence of
3460 : // property accesses into the value being assigned (in the accumulator).
3461 : //
3462 : // { y, [x++]: a(), ...b.c } = value
3463 : //
3464 : // becomes
3465 : //
3466 : // var rest_runtime_callargs = new Array(3);
3467 : // rest_runtime_callargs[0] = value;
3468 : //
3469 : // rest_runtime_callargs[1] = value;
3470 : // y = value.y;
3471 : //
3472 : // var temp1 = %ToName(x++);
3473 : // rest_runtime_callargs[2] = temp1;
3474 : // a() = value[temp1];
3475 : //
3476 : // b.c = %CopyDataPropertiesWithExcludedProperties.call(rest_runtime_callargs);
3477 10991 : void BytecodeGenerator::BuildDestructuringObjectAssignment(
3478 29803 : ObjectLiteral* pattern, Token::Value op,
3479 10992 : LookupHoistingMode lookup_hoisting_mode) {
3480 : RegisterAllocationScope scope(this);
3481 :
3482 : // if (value === null || value === undefined)
3483 : // throw new TypeError(kNonCoercible);
3484 : //
3485 : // TODO(leszeks): Eliminate check if value is known to be non-null (e.g.
3486 : // an object literal).
3487 : BytecodeLabel is_null_or_undefined, not_null_or_undefined;
3488 : builder()
3489 10991 : ->JumpIfNull(&is_null_or_undefined)
3490 10991 : .JumpIfNotUndefined(¬_null_or_undefined);
3491 :
3492 : {
3493 10992 : builder()->Bind(&is_null_or_undefined);
3494 : builder()->SetExpressionPosition(pattern);
3495 10992 : builder()->CallRuntime(Runtime::kThrowPatternAssignmentNonCoercible);
3496 : }
3497 :
3498 : // Store the assignment value in a register.
3499 : Register value;
3500 : RegisterList rest_runtime_callargs;
3501 10991 : if (pattern->has_rest_property()) {
3502 : rest_runtime_callargs =
3503 205 : register_allocator()->NewRegisterList(pattern->properties()->length());
3504 205 : value = rest_runtime_callargs[0];
3505 : } else {
3506 10786 : value = register_allocator()->NewRegister();
3507 : }
3508 10992 : builder()->Bind(¬_null_or_undefined).StoreAccumulatorInRegister(value);
3509 :
3510 : int i = 0;
3511 79035 : for (ObjectLiteralProperty* pattern_property : *pattern->properties()) {
3512 : RegisterAllocationScope scope(this);
3513 :
3514 : // The key of the pattern becomes the key into the RHS value, and the value
3515 : // of the pattern becomes the target of the assignment.
3516 : //
3517 : // e.g. { a: b } = o becomes b = o.a
3518 19017 : Expression* pattern_key = pattern_property->key();
3519 19017 : Expression* target = pattern_property->value();
3520 19017 : Expression* default_value = GetDestructuringDefaultValue(&target);
3521 :
3522 38034 : if (!target->IsPattern()) {
3523 : builder()->SetExpressionAsStatementPosition(target);
3524 : }
3525 :
3526 : // Calculate this property's key into the assignment RHS value, additionally
3527 : // storing the key for rest_runtime_callargs if needed.
3528 : //
3529 : // The RHS is accessed using the key either by LoadNamedProperty (if
3530 : // value_name is valid) or by LoadKeyedProperty (otherwise).
3531 : const AstRawString* value_name = nullptr;
3532 : Register value_key;
3533 :
3534 19017 : if (pattern_property->kind() != ObjectLiteralProperty::Kind::SPREAD) {
3535 18812 : if (pattern_key->IsPropertyName()) {
3536 37008 : value_name = pattern_key->AsLiteral()->AsRawPropertyName();
3537 : }
3538 18812 : if (pattern->has_rest_property() || !value_name) {
3539 371 : if (pattern->has_rest_property()) {
3540 129 : value_key = rest_runtime_callargs[i + 1];
3541 : } else {
3542 242 : value_key = register_allocator()->NewRegister();
3543 : }
3544 371 : if (pattern_property->is_computed_name()) {
3545 : // { [a()]: b().x } = c
3546 : // becomes
3547 : // var tmp = a()
3548 : // b().x = c[tmp]
3549 : DCHECK(!pattern_key->IsPropertyName() ||
3550 : !pattern_key->IsNumberLiteral());
3551 264 : VisitForAccumulatorValue(pattern_key);
3552 264 : builder()->ToName(value_key);
3553 : } else {
3554 : // We only need the key for non-computed properties when it is numeric
3555 : // or is being saved for the rest_runtime_callargs.
3556 : DCHECK(
3557 : pattern_key->IsNumberLiteral() ||
3558 : (pattern->has_rest_property() && pattern_key->IsPropertyName()));
3559 : VisitForRegisterValue(pattern_key, value_key);
3560 : }
3561 : }
3562 : }
3563 :
3564 19017 : AssignmentLhsData lhs_data = PrepareAssignmentLhs(target);
3565 :
3566 : // Get the value from the RHS.
3567 19018 : if (pattern_property->kind() == ObjectLiteralProperty::Kind::SPREAD) {
3568 : DCHECK_EQ(i, pattern->properties()->length() - 1);
3569 : DCHECK(!value_key.is_valid());
3570 : DCHECK_NULL(value_name);
3571 : builder()->CallRuntime(Runtime::kCopyDataPropertiesWithExcludedProperties,
3572 205 : rest_runtime_callargs);
3573 18813 : } else if (value_name) {
3574 : builder()->LoadNamedProperty(
3575 37010 : value, value_name, feedback_index(feedback_spec()->AddLoadICSlot()));
3576 : } else {
3577 : DCHECK(value_key.is_valid());
3578 308 : builder()->LoadAccumulatorWithRegister(value_key).LoadKeyedProperty(
3579 616 : value, feedback_index(feedback_spec()->AddKeyedLoadICSlot()));
3580 : }
3581 :
3582 : // {<pattern> = <init>} = <value>
3583 : // becomes
3584 : // temp = <value>;
3585 : // <pattern> = temp === undefined ? <init> : temp;
3586 19018 : if (default_value) {
3587 : BytecodeLabel value_not_undefined;
3588 1435 : builder()->JumpIfNotUndefined(&value_not_undefined);
3589 1435 : VisitForAccumulatorValue(default_value);
3590 1435 : builder()->Bind(&value_not_undefined);
3591 : }
3592 :
3593 19018 : BuildAssignment(lhs_data, op, lookup_hoisting_mode);
3594 :
3595 19018 : i++;
3596 19018 : }
3597 :
3598 10992 : if (!execution_result()->IsEffect()) {
3599 193 : builder()->LoadAccumulatorWithRegister(value);
3600 10992 : }
3601 10991 : }
3602 :
3603 7607618 : void BytecodeGenerator::BuildAssignment(
3604 15183030 : const AssignmentLhsData& lhs_data, Token::Value op,
3605 63411 : LookupHoistingMode lookup_hoisting_mode) {
3606 : // Assign the value to the LHS.
3607 7607618 : switch (lhs_data.assign_type()) {
3608 : case NON_PROPERTY: {
3609 10367308 : if (ObjectLiteral* pattern = lhs_data.expr()->AsObjectLiteral()) {
3610 : // Split object literals into destructuring.
3611 10992 : BuildDestructuringObjectAssignment(pattern, op, lookup_hoisting_mode);
3612 5172660 : } else if (ArrayLiteral* pattern = lhs_data.expr()->AsArrayLiteral()) {
3613 : // Split object literals into destructuring.
3614 2689 : BuildDestructuringArrayAssignment(pattern, op, lookup_hoisting_mode);
3615 : } else {
3616 : DCHECK(lhs_data.expr()->IsVariableProxy());
3617 10339942 : VariableProxy* proxy = lhs_data.expr()->AsVariableProxy();
3618 : BuildVariableAssignment(proxy->var(), op, proxy->hole_check_mode(),
3619 10339942 : lookup_hoisting_mode);
3620 : }
3621 : break;
3622 : }
3623 : case NAMED_PROPERTY: {
3624 : BuildStoreNamedProperty(lhs_data.object_expr(), lhs_data.object(),
3625 2391756 : lhs_data.name());
3626 2391804 : break;
3627 : }
3628 : case KEYED_PROPERTY: {
3629 31701 : FeedbackSlot slot = feedback_spec()->AddKeyedStoreICSlot(language_mode());
3630 : Register value;
3631 31704 : if (!execution_result()->IsEffect()) {
3632 1976 : value = register_allocator()->NewRegister();
3633 1976 : builder()->StoreAccumulatorInRegister(value);
3634 : }
3635 : builder()->StoreKeyedProperty(lhs_data.object(), lhs_data.key(),
3636 31695 : feedback_index(slot), language_mode());
3637 31707 : if (!execution_result()->IsEffect()) {
3638 1976 : builder()->LoadAccumulatorWithRegister(value);
3639 : }
3640 : break;
3641 : }
3642 : case NAMED_SUPER_PROPERTY: {
3643 : builder()
3644 220 : ->StoreAccumulatorInRegister(lhs_data.super_property_args()[3])
3645 220 : .CallRuntime(StoreToSuperRuntimeId(), lhs_data.super_property_args());
3646 220 : break;
3647 : }
3648 : case KEYED_SUPER_PROPERTY: {
3649 : builder()
3650 340 : ->StoreAccumulatorInRegister(lhs_data.super_property_args()[3])
3651 : .CallRuntime(StoreKeyedToSuperRuntimeId(),
3652 340 : lhs_data.super_property_args());
3653 340 : break;
3654 : }
3655 : }
3656 7607431 : }
3657 :
3658 22378789 : void BytecodeGenerator::VisitAssignment(Assignment* expr) {
3659 7459596 : AssignmentLhsData lhs_data = PrepareAssignmentLhs(expr->target());
3660 :
3661 7459794 : VisitForAccumulatorValue(expr->value());
3662 :
3663 : builder()->SetExpressionPosition(expr);
3664 7459399 : BuildAssignment(lhs_data, expr->op(), expr->lookup_hoisting_mode());
3665 7459086 : }
3666 :
3667 82566 : void BytecodeGenerator::VisitCompoundAssignment(CompoundAssignment* expr) {
3668 411435 : AssignmentLhsData lhs_data = PrepareAssignmentLhs(expr->target());
3669 :
3670 : // Evaluate the value and potentially handle compound assignments by loading
3671 : // the left-hand side value and performing a binary operation.
3672 82568 : switch (lhs_data.assign_type()) {
3673 : case NON_PROPERTY: {
3674 243481 : VariableProxy* proxy = expr->target()->AsVariableProxy();
3675 81162 : BuildVariableLoad(proxy->var(), proxy->hole_check_mode());
3676 81163 : break;
3677 : }
3678 : case NAMED_PROPERTY: {
3679 527 : BuildLoadNamedProperty(lhs_data.object_expr(), lhs_data.object(),
3680 1054 : lhs_data.name());
3681 527 : break;
3682 : }
3683 : case KEYED_PROPERTY: {
3684 821 : FeedbackSlot slot = feedback_spec()->AddKeyedLoadICSlot();
3685 : builder()
3686 821 : ->LoadAccumulatorWithRegister(lhs_data.key())
3687 821 : .LoadKeyedProperty(lhs_data.object(), feedback_index(slot));
3688 : break;
3689 : }
3690 : case NAMED_SUPER_PROPERTY: {
3691 : builder()->CallRuntime(Runtime::kLoadFromSuper,
3692 20 : lhs_data.super_property_args().Truncate(3));
3693 20 : break;
3694 : }
3695 : case KEYED_SUPER_PROPERTY: {
3696 : builder()->CallRuntime(Runtime::kLoadKeyedFromSuper,
3697 40 : lhs_data.super_property_args().Truncate(3));
3698 40 : break;
3699 : }
3700 : }
3701 247715 : BinaryOperation* binop = expr->AsCompoundAssignment()->binary_operation();
3702 82570 : FeedbackSlot slot = feedback_spec()->AddBinaryOpICSlot();
3703 82570 : if (expr->value()->IsSmiLiteral()) {
3704 : builder()->BinaryOperationSmiLiteral(
3705 : binop->op(), expr->value()->AsLiteral()->AsSmiLiteral(),
3706 63788 : feedback_index(slot));
3707 : } else {
3708 61306 : Register old_value = register_allocator()->NewRegister();
3709 61307 : builder()->StoreAccumulatorInRegister(old_value);
3710 61309 : VisitForAccumulatorValue(expr->value());
3711 61307 : builder()->BinaryOperation(binop->op(), old_value, feedback_index(slot));
3712 : }
3713 :
3714 : builder()->SetExpressionPosition(expr);
3715 82571 : BuildAssignment(lhs_data, expr->op(), expr->lookup_hoisting_mode());
3716 82572 : }
3717 :
3718 : // Suspends the generator to resume at the next suspend_id, with output stored
3719 : // in the accumulator. When the generator is resumed, the sent value is loaded
3720 : // in the accumulator.
3721 23635 : void BytecodeGenerator::BuildSuspendPoint(int position) {
3722 23635 : const int suspend_id = suspend_count_++;
3723 :
3724 23635 : RegisterList registers = register_allocator()->AllLiveRegisters();
3725 :
3726 : // Save context, registers, and state. This bytecode then returns the value
3727 : // in the accumulator.
3728 : builder()->SetExpressionPosition(position);
3729 23635 : builder()->SuspendGenerator(generator_object(), registers, suspend_id);
3730 :
3731 : // Upon resume, we continue here.
3732 23635 : builder()->Bind(generator_jump_table_, suspend_id);
3733 :
3734 : // Clobbers all registers and sets the accumulator to the
3735 : // [[input_or_debug_pos]] slot of the generator object.
3736 23635 : builder()->ResumeGenerator(generator_object(), registers);
3737 23634 : }
3738 :
3739 16956 : void BytecodeGenerator::VisitYield(Yield* expr) {
3740 : builder()->SetExpressionPosition(expr);
3741 16572 : VisitForAccumulatorValue(expr->expression());
3742 :
3743 : // If this is not the first yield
3744 8286 : if (suspend_count_ > 0) {
3745 3449 : if (IsAsyncGeneratorFunction(function_kind())) {
3746 : // AsyncGenerator yields (with the exception of the initial yield)
3747 : // delegate work to the AsyncGeneratorYield stub, which Awaits the operand
3748 : // and on success, wraps the value in an IteratorResult.
3749 : RegisterAllocationScope register_scope(this);
3750 384 : RegisterList args = register_allocator()->NewRegisterList(3);
3751 : builder()
3752 384 : ->MoveRegister(generator_object(), args[0]) // generator
3753 384 : .StoreAccumulatorInRegister(args[1]) // value
3754 768 : .LoadBoolean(catch_prediction() != HandlerTable::ASYNC_AWAIT)
3755 384 : .StoreAccumulatorInRegister(args[2]) // is_caught
3756 384 : .CallRuntime(Runtime::kInlineAsyncGeneratorYield, args);
3757 : } else {
3758 : // Generator yields (with the exception of the initial yield) wrap the
3759 : // value into IteratorResult.
3760 : RegisterAllocationScope register_scope(this);
3761 3065 : RegisterList args = register_allocator()->NewRegisterList(2);
3762 : builder()
3763 3065 : ->StoreAccumulatorInRegister(args[0]) // value
3764 3065 : .LoadFalse()
3765 3065 : .StoreAccumulatorInRegister(args[1]) // done
3766 3065 : .CallRuntime(Runtime::kInlineCreateIterResultObject, args);
3767 : }
3768 : }
3769 :
3770 8286 : BuildSuspendPoint(expr->position());
3771 : // At this point, the generator has been resumed, with the received value in
3772 : // the accumulator.
3773 :
3774 : // TODO(caitp): remove once yield* desugaring for async generators is handled
3775 : // in BytecodeGenerator.
3776 8286 : if (expr->on_abrupt_resume() == Yield::kNoControl) {
3777 : DCHECK(IsAsyncGeneratorFunction(function_kind()));
3778 0 : return;
3779 : }
3780 :
3781 8286 : Register input = register_allocator()->NewRegister();
3782 8286 : builder()->StoreAccumulatorInRegister(input).CallRuntime(
3783 8286 : Runtime::kInlineGeneratorGetResumeMode, generator_object());
3784 :
3785 : // Now dispatch on resume mode.
3786 : STATIC_ASSERT(JSGeneratorObject::kNext + 1 == JSGeneratorObject::kReturn);
3787 : BytecodeJumpTable* jump_table =
3788 8286 : builder()->AllocateJumpTable(2, JSGeneratorObject::kNext);
3789 :
3790 8286 : builder()->SwitchOnSmiNoFeedback(jump_table);
3791 :
3792 : {
3793 : // Resume with throw (switch fallthrough).
3794 : // TODO(leszeks): Add a debug-only check that the accumulator is
3795 : // JSGeneratorObject::kThrow.
3796 : builder()->SetExpressionPosition(expr);
3797 8286 : builder()->LoadAccumulatorWithRegister(input);
3798 8286 : builder()->Throw();
3799 : }
3800 :
3801 : {
3802 : // Resume with return.
3803 8286 : builder()->Bind(jump_table, JSGeneratorObject::kReturn);
3804 8286 : builder()->LoadAccumulatorWithRegister(input);
3805 8286 : if (IsAsyncGeneratorFunction(function_kind())) {
3806 : execution_control()->AsyncReturnAccumulator();
3807 : } else {
3808 : execution_control()->ReturnAccumulator();
3809 : }
3810 : }
3811 :
3812 : {
3813 : // Resume with next.
3814 8286 : builder()->Bind(jump_table, JSGeneratorObject::kNext);
3815 : BuildIncrementBlockCoverageCounterIfEnabled(expr,
3816 : SourceRangeKind::kContinuation);
3817 8286 : builder()->LoadAccumulatorWithRegister(input);
3818 : }
3819 : }
3820 :
3821 : // Desugaring of (yield* iterable)
3822 : //
3823 : // do {
3824 : // const kNext = 0;
3825 : // const kReturn = 1;
3826 : // const kThrow = 2;
3827 : //
3828 : // let output; // uninitialized
3829 : //
3830 : // let iteratorRecord = GetIterator(iterable);
3831 : // let iterator = iteratorRecord.[[Iterator]];
3832 : // let next = iteratorRecord.[[NextMethod]];
3833 : // let input = undefined;
3834 : // let resumeMode = kNext;
3835 : //
3836 : // while (true) {
3837 : // // From the generator to the iterator:
3838 : // // Forward input according to resumeMode and obtain output.
3839 : // switch (resumeMode) {
3840 : // case kNext:
3841 : // output = next.[[Call]](iterator, « »);;
3842 : // break;
3843 : // case kReturn:
3844 : // let iteratorReturn = iterator.return;
3845 : // if (IS_NULL_OR_UNDEFINED(iteratorReturn)) return input;
3846 : // output = iteratorReturn.[[Call]](iterator, «input»);
3847 : // break;
3848 : // case kThrow:
3849 : // let iteratorThrow = iterator.throw;
3850 : // if (IS_NULL_OR_UNDEFINED(iteratorThrow)) {
3851 : // let iteratorReturn = iterator.return;
3852 : // if (!IS_NULL_OR_UNDEFINED(iteratorReturn)) {
3853 : // output = iteratorReturn.[[Call]](iterator, « »);
3854 : // if (IS_ASYNC_GENERATOR) output = await output;
3855 : // if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
3856 : // }
3857 : // throw MakeTypeError(kThrowMethodMissing);
3858 : // }
3859 : // output = iteratorThrow.[[Call]](iterator, «input»);
3860 : // break;
3861 : // }
3862 : //
3863 : // if (IS_ASYNC_GENERATOR) output = await output;
3864 : // if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
3865 : // if (output.done) break;
3866 : //
3867 : // // From the generator to its user:
3868 : // // Forward output, receive new input, and determine resume mode.
3869 : // if (IS_ASYNC_GENERATOR) {
3870 : // // AsyncGeneratorYield abstract operation awaits the operand before
3871 : // // resolving the promise for the current AsyncGeneratorRequest.
3872 : // %_AsyncGeneratorYield(output.value)
3873 : // }
3874 : // input = Suspend(output);
3875 : // resumeMode = %GeneratorGetResumeMode();
3876 : // }
3877 : //
3878 : // if (resumeMode === kReturn) {
3879 : // return output.value;
3880 : // }
3881 : // output.value
3882 : // }
3883 2020 : void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
3884 200 : Register output = register_allocator()->NewRegister();
3885 200 : Register resume_mode = register_allocator()->NewRegister();
3886 : IteratorType iterator_type = IsAsyncGeneratorFunction(function_kind())
3887 : ? IteratorType::kAsync
3888 200 : : IteratorType::kNormal;
3889 :
3890 : {
3891 : RegisterAllocationScope register_scope(this);
3892 200 : RegisterList iterator_and_input = register_allocator()->NewRegisterList(2);
3893 200 : VisitForAccumulatorValue(expr->expression());
3894 : IteratorRecord iterator = BuildGetIteratorRecord(
3895 : register_allocator()->NewRegister() /* next method */,
3896 200 : iterator_and_input[0], iterator_type);
3897 :
3898 200 : Register input = iterator_and_input[1];
3899 200 : builder()->LoadUndefined().StoreAccumulatorInRegister(input);
3900 : builder()
3901 200 : ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kNext))
3902 200 : .StoreAccumulatorInRegister(resume_mode);
3903 :
3904 : {
3905 : // This loop builder does not construct counters as the loop is not
3906 : // visible to the user, and we therefore neither pass the block coverage
3907 : // builder nor the expression.
3908 : //
3909 : // In addition to the normal suspend for yield*, a yield* in an async
3910 : // generator has 2 additional suspends:
3911 : // - One for awaiting the iterator result of closing the generator when
3912 : // resumed with a "throw" completion, and a throw method is not
3913 : // present on the delegated iterator
3914 : // - One for awaiting the iterator result yielded by the delegated
3915 : // iterator
3916 :
3917 200 : LoopBuilder loop(builder(), nullptr, nullptr);
3918 200 : loop.LoopHeader();
3919 :
3920 : {
3921 : BytecodeLabels after_switch(zone());
3922 : BytecodeJumpTable* switch_jump_table =
3923 200 : builder()->AllocateJumpTable(2, 1);
3924 :
3925 : builder()
3926 200 : ->LoadAccumulatorWithRegister(resume_mode)
3927 200 : .SwitchOnSmiNoFeedback(switch_jump_table);
3928 :
3929 : // Fallthrough to default case.
3930 : // TODO(tebbi): Add debug code to check that {resume_mode} really is
3931 : // {JSGeneratorObject::kNext} in this case.
3932 : STATIC_ASSERT(JSGeneratorObject::kNext == 0);
3933 : {
3934 200 : FeedbackSlot slot = feedback_spec()->AddCallICSlot();
3935 : builder()->CallProperty(iterator.next(), iterator_and_input,
3936 200 : feedback_index(slot));
3937 200 : builder()->Jump(after_switch.New());
3938 : }
3939 :
3940 : STATIC_ASSERT(JSGeneratorObject::kReturn == 1);
3941 200 : builder()->Bind(switch_jump_table, JSGeneratorObject::kReturn);
3942 : {
3943 : const AstRawString* return_string =
3944 200 : ast_string_constants()->return_string();
3945 : BytecodeLabels no_return_method(zone());
3946 :
3947 : BuildCallIteratorMethod(iterator.object(), return_string,
3948 : iterator_and_input, after_switch.New(),
3949 200 : &no_return_method);
3950 200 : no_return_method.Bind(builder());
3951 200 : builder()->LoadAccumulatorWithRegister(input);
3952 200 : if (iterator_type == IteratorType::kAsync) {
3953 : execution_control()->AsyncReturnAccumulator();
3954 : } else {
3955 : execution_control()->ReturnAccumulator();
3956 : }
3957 : }
3958 :
3959 : STATIC_ASSERT(JSGeneratorObject::kThrow == 2);
3960 200 : builder()->Bind(switch_jump_table, JSGeneratorObject::kThrow);
3961 : {
3962 : const AstRawString* throw_string =
3963 200 : ast_string_constants()->throw_string();
3964 : BytecodeLabels no_throw_method(zone());
3965 : BuildCallIteratorMethod(iterator.object(), throw_string,
3966 : iterator_and_input, after_switch.New(),
3967 200 : &no_throw_method);
3968 :
3969 : // If there is no "throw" method, perform IteratorClose, and finally
3970 : // throw a TypeError.
3971 200 : no_throw_method.Bind(builder());
3972 200 : BuildIteratorClose(iterator, expr);
3973 200 : builder()->CallRuntime(Runtime::kThrowThrowMethodMissing);
3974 : }
3975 :
3976 200 : after_switch.Bind(builder());
3977 : }
3978 :
3979 200 : if (iterator_type == IteratorType::kAsync) {
3980 : // Await the result of the method invocation.
3981 210 : BuildAwait(expr->position());
3982 : }
3983 :
3984 : // Check that output is an object.
3985 : BytecodeLabel check_if_done;
3986 : builder()
3987 200 : ->StoreAccumulatorInRegister(output)
3988 200 : .JumpIfJSReceiver(&check_if_done)
3989 200 : .CallRuntime(Runtime::kThrowIteratorResultNotAnObject, output);
3990 :
3991 200 : builder()->Bind(&check_if_done);
3992 : // Break once output.done is true.
3993 : builder()->LoadNamedProperty(
3994 : output, ast_string_constants()->done_string(),
3995 400 : feedback_index(feedback_spec()->AddLoadICSlot()));
3996 :
3997 : loop.BreakIfTrue(ToBooleanMode::kConvertToBoolean);
3998 :
3999 : // Suspend the current generator.
4000 200 : if (iterator_type == IteratorType::kNormal) {
4001 190 : builder()->LoadAccumulatorWithRegister(output);
4002 : } else {
4003 : RegisterAllocationScope register_scope(this);
4004 : DCHECK_EQ(iterator_type, IteratorType::kAsync);
4005 : // If generatorKind is async, perform AsyncGeneratorYield(output.value),
4006 : // which will await `output.value` before resolving the current
4007 : // AsyncGeneratorRequest's promise.
4008 : builder()->LoadNamedProperty(
4009 : output, ast_string_constants()->value_string(),
4010 20 : feedback_index(feedback_spec()->AddLoadICSlot()));
4011 :
4012 10 : RegisterList args = register_allocator()->NewRegisterList(3);
4013 : builder()
4014 10 : ->MoveRegister(generator_object(), args[0]) // generator
4015 10 : .StoreAccumulatorInRegister(args[1]) // value
4016 20 : .LoadBoolean(catch_prediction() != HandlerTable::ASYNC_AWAIT)
4017 10 : .StoreAccumulatorInRegister(args[2]) // is_caught
4018 10 : .CallRuntime(Runtime::kInlineAsyncGeneratorYield, args);
4019 : }
4020 :
4021 200 : BuildSuspendPoint(expr->position());
4022 200 : builder()->StoreAccumulatorInRegister(input);
4023 : builder()
4024 : ->CallRuntime(Runtime::kInlineGeneratorGetResumeMode,
4025 200 : generator_object())
4026 200 : .StoreAccumulatorInRegister(resume_mode);
4027 :
4028 200 : loop.BindContinueTarget();
4029 200 : loop.JumpToHeader(loop_depth_);
4030 200 : }
4031 : }
4032 :
4033 : // Decide if we trigger a return or if the yield* expression should just
4034 : // produce a value.
4035 : BytecodeLabel completion_is_output_value;
4036 200 : Register output_value = register_allocator()->NewRegister();
4037 : builder()
4038 : ->LoadNamedProperty(output, ast_string_constants()->value_string(),
4039 400 : feedback_index(feedback_spec()->AddLoadICSlot()))
4040 200 : .StoreAccumulatorInRegister(output_value)
4041 200 : .LoadLiteral(Smi::FromInt(JSGeneratorObject::kReturn))
4042 200 : .CompareReference(resume_mode)
4043 200 : .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &completion_is_output_value)
4044 200 : .LoadAccumulatorWithRegister(output_value);
4045 200 : if (iterator_type == IteratorType::kAsync) {
4046 : execution_control()->AsyncReturnAccumulator();
4047 : } else {
4048 : execution_control()->ReturnAccumulator();
4049 : }
4050 :
4051 200 : builder()->Bind(&completion_is_output_value);
4052 : BuildIncrementBlockCoverageCounterIfEnabled(expr,
4053 : SourceRangeKind::kContinuation);
4054 200 : builder()->LoadAccumulatorWithRegister(output_value);
4055 200 : }
4056 :
4057 30298 : void BytecodeGenerator::BuildAwait(int position) {
4058 : // Rather than HandlerTable::UNCAUGHT, async functions use
4059 : // HandlerTable::ASYNC_AWAIT to communicate that top-level exceptions are
4060 : // transformed into promise rejections. This is necessary to prevent emitting
4061 : // multiple debug events for the same uncaught exception. There is no point
4062 : // in the body of an async function where catch prediction is
4063 : // HandlerTable::UNCAUGHT.
4064 : DCHECK(catch_prediction() != HandlerTable::UNCAUGHT);
4065 :
4066 : {
4067 : // Await(operand) and suspend.
4068 : RegisterAllocationScope register_scope(this);
4069 :
4070 : Runtime::FunctionId await_intrinsic_id;
4071 15149 : if (IsAsyncGeneratorFunction(function_kind())) {
4072 : await_intrinsic_id = catch_prediction() == HandlerTable::ASYNC_AWAIT
4073 : ? Runtime::kInlineAsyncGeneratorAwaitUncaught
4074 1308 : : Runtime::kInlineAsyncGeneratorAwaitCaught;
4075 : } else {
4076 : await_intrinsic_id = catch_prediction() == HandlerTable::ASYNC_AWAIT
4077 : ? Runtime::kInlineAsyncFunctionAwaitUncaught
4078 13841 : : Runtime::kInlineAsyncFunctionAwaitCaught;
4079 : }
4080 15149 : RegisterList args = register_allocator()->NewRegisterList(2);
4081 : builder()
4082 15149 : ->MoveRegister(generator_object(), args[0])
4083 15149 : .StoreAccumulatorInRegister(args[1])
4084 15149 : .CallRuntime(await_intrinsic_id, args);
4085 : }
4086 :
4087 15149 : BuildSuspendPoint(position);
4088 :
4089 15148 : Register input = register_allocator()->NewRegister();
4090 15149 : Register resume_mode = register_allocator()->NewRegister();
4091 :
4092 : // Now dispatch on resume mode.
4093 : BytecodeLabel resume_next;
4094 : builder()
4095 15149 : ->StoreAccumulatorInRegister(input)
4096 15148 : .CallRuntime(Runtime::kInlineGeneratorGetResumeMode, generator_object())
4097 15148 : .StoreAccumulatorInRegister(resume_mode)
4098 15148 : .LoadLiteral(Smi::FromInt(JSGeneratorObject::kNext))
4099 15148 : .CompareReference(resume_mode)
4100 15148 : .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &resume_next);
4101 :
4102 : // Resume with "throw" completion (rethrow the received value).
4103 : // TODO(leszeks): Add a debug-only check that the accumulator is
4104 : // JSGeneratorObject::kThrow.
4105 15148 : builder()->LoadAccumulatorWithRegister(input).ReThrow();
4106 :
4107 : // Resume with next.
4108 15148 : builder()->Bind(&resume_next);
4109 15149 : builder()->LoadAccumulatorWithRegister(input);
4110 15149 : }
4111 :
4112 14455 : void BytecodeGenerator::VisitAwait(Await* expr) {
4113 : builder()->SetExpressionPosition(expr);
4114 14455 : VisitForAccumulatorValue(expr->expression());
4115 14455 : BuildAwait(expr->position());
4116 : BuildIncrementBlockCoverageCounterIfEnabled(expr,
4117 : SourceRangeKind::kContinuation);
4118 14455 : }
4119 :
4120 38720 : void BytecodeGenerator::VisitThrow(Throw* expr) {
4121 : AllocateBlockCoverageSlotIfEnabled(expr, SourceRangeKind::kContinuation);
4122 19360 : VisitForAccumulatorValue(expr->exception());
4123 : builder()->SetExpressionPosition(expr);
4124 19363 : builder()->Throw();
4125 19365 : }
4126 :
4127 7377985 : void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* property) {
4128 2504987 : AssignType property_kind = Property::GetAssignType(property);
4129 2505128 : switch (property_kind) {
4130 : case NON_PROPERTY:
4131 0 : UNREACHABLE();
4132 : case NAMED_PROPERTY: {
4133 : builder()->SetExpressionPosition(property);
4134 : const AstRawString* name =
4135 4737343 : property->key()->AsLiteral()->AsRawPropertyName();
4136 2368628 : BuildLoadNamedProperty(property->obj(), obj, name);
4137 2368754 : break;
4138 : }
4139 : case KEYED_PROPERTY: {
4140 135655 : VisitForAccumulatorValue(property->key());
4141 : builder()->SetExpressionPosition(property);
4142 : builder()->LoadKeyedProperty(
4143 271313 : obj, feedback_index(feedback_spec()->AddKeyedLoadICSlot()));
4144 135654 : break;
4145 : }
4146 : case NAMED_SUPER_PROPERTY:
4147 417 : VisitNamedSuperPropertyLoad(property, Register::invalid_value());
4148 417 : break;
4149 : case KEYED_SUPER_PROPERTY:
4150 360 : VisitKeyedSuperPropertyLoad(property, Register::invalid_value());
4151 360 : break;
4152 : }
4153 2505166 : }
4154 :
4155 805388 : void BytecodeGenerator::VisitPropertyLoadForRegister(Register obj,
4156 : Property* expr,
4157 : Register destination) {
4158 : ValueResultScope result_scope(this);
4159 805388 : VisitPropertyLoad(obj, expr);
4160 805446 : builder()->StoreAccumulatorInRegister(destination);
4161 805445 : }
4162 :
4163 2658 : void BytecodeGenerator::VisitNamedSuperPropertyLoad(Property* property,
4164 : Register opt_receiver_out) {
4165 : RegisterAllocationScope register_scope(this);
4166 1772 : SuperPropertyReference* super_property =
4167 886 : property->obj()->AsSuperPropertyReference();
4168 886 : RegisterList args = register_allocator()->NewRegisterList(3);
4169 : VisitForRegisterValue(super_property->this_var(), args[0]);
4170 : VisitForRegisterValue(super_property->home_object(), args[1]);
4171 :
4172 : builder()->SetExpressionPosition(property);
4173 : builder()
4174 1772 : ->LoadLiteral(property->key()->AsLiteral()->AsRawPropertyName())
4175 886 : .StoreAccumulatorInRegister(args[2])
4176 886 : .CallRuntime(Runtime::kLoadFromSuper, args);
4177 :
4178 886 : if (opt_receiver_out.is_valid()) {
4179 469 : builder()->MoveRegister(args[0], opt_receiver_out);
4180 886 : }
4181 886 : }
4182 :
4183 1200 : void BytecodeGenerator::VisitKeyedSuperPropertyLoad(Property* property,
4184 : Register opt_receiver_out) {
4185 : RegisterAllocationScope register_scope(this);
4186 800 : SuperPropertyReference* super_property =
4187 400 : property->obj()->AsSuperPropertyReference();
4188 400 : RegisterList args = register_allocator()->NewRegisterList(3);
4189 : VisitForRegisterValue(super_property->this_var(), args[0]);
4190 : VisitForRegisterValue(super_property->home_object(), args[1]);
4191 : VisitForRegisterValue(property->key(), args[2]);
4192 :
4193 : builder()->SetExpressionPosition(property);
4194 400 : builder()->CallRuntime(Runtime::kLoadKeyedFromSuper, args);
4195 :
4196 400 : if (opt_receiver_out.is_valid()) {
4197 40 : builder()->MoveRegister(args[0], opt_receiver_out);
4198 400 : }
4199 400 : }
4200 :
4201 3398440 : void BytecodeGenerator::VisitProperty(Property* expr) {
4202 1699574 : AssignType property_kind = Property::GetAssignType(expr);
4203 1699643 : if (property_kind != NAMED_SUPER_PROPERTY &&
4204 : property_kind != KEYED_SUPER_PROPERTY) {
4205 1698866 : Register obj = VisitForRegisterValue(expr->obj());
4206 1699013 : VisitPropertyLoad(obj, expr);
4207 : } else {
4208 777 : VisitPropertyLoad(Register::invalid_value(), expr);
4209 : }
4210 1699765 : }
4211 :
4212 0 : void BytecodeGenerator::VisitResolvedProperty(ResolvedProperty* expr) {
4213 : // Handled by VisitCall().
4214 0 : UNREACHABLE();
4215 : }
4216 :
4217 16908009 : void BytecodeGenerator::VisitArguments(const ZonePtrList<Expression>* args,
4218 : RegisterList* arg_regs) {
4219 : // Visit arguments.
4220 23083120 : for (int i = 0; i < static_cast<int>(args->length()); i++) {
4221 6175065 : VisitAndPushIntoRegisterList(args->at(i), arg_regs);
4222 : }
4223 5366495 : }
4224 :
4225 10436281 : void BytecodeGenerator::VisitCall(Call* expr) {
4226 : Expression* callee_expr = expr->expression();
4227 5167262 : Call::CallType call_type = expr->GetCallType();
4228 :
4229 5167271 : if (call_type == Call::SUPER_CALL) {
4230 5172596 : return VisitCallSuper(expr);
4231 : }
4232 :
4233 : // Grow the args list as we visit receiver / arguments to avoid allocating all
4234 : // the registers up-front. Otherwise these registers are unavailable during
4235 : // receiver / argument visiting and we can end up with memory leaks due to
4236 : // registers keeping objects alive.
4237 5161982 : Register callee = register_allocator()->NewRegister();
4238 5161917 : RegisterList args = register_allocator()->NewGrowableRegisterList();
4239 :
4240 : bool implicit_undefined_receiver = false;
4241 : // When a call contains a spread, a Call AST node is only created if there is
4242 : // exactly one spread, and it is the last argument.
4243 5161917 : bool is_spread_call = expr->only_last_arg_is_spread();
4244 5161923 : bool optimize_as_one_shot = ShouldOptimizeAsOneShot();
4245 :
4246 : // TODO(petermarshall): We have a lot of call bytecodes that are very similar,
4247 : // see if we can reduce the number by adding a separate argument which
4248 : // specifies the call type (e.g., property, spread, tailcall, etc.).
4249 :
4250 : // Prepare the callee and the receiver to the function call. This depends on
4251 : // the semantics of the underlying call type.
4252 5162012 : switch (call_type) {
4253 : case Call::NAMED_PROPERTY_CALL:
4254 : case Call::KEYED_PROPERTY_CALL: {
4255 1610759 : Property* property = callee_expr->AsProperty();
4256 805371 : VisitAndPushIntoRegisterList(property->obj(), &args);
4257 805431 : VisitPropertyLoadForRegister(args.last_register(), property, callee);
4258 805408 : break;
4259 : }
4260 : case Call::RESOLVED_PROPERTY_CALL: {
4261 0 : ResolvedProperty* resolved = callee_expr->AsResolvedProperty();
4262 0 : VisitAndPushIntoRegisterList(resolved->object(), &args);
4263 0 : VisitForAccumulatorValue(resolved->property());
4264 0 : builder()->StoreAccumulatorInRegister(callee);
4265 0 : break;
4266 : }
4267 : case Call::GLOBAL_CALL: {
4268 : // Receiver is undefined for global calls.
4269 3829291 : if (!is_spread_call && !optimize_as_one_shot) {
4270 : implicit_undefined_receiver = true;
4271 : } else {
4272 : // TODO(leszeks): There's no special bytecode for tail calls or spread
4273 : // calls with an undefined receiver, so just push undefined ourselves.
4274 715480 : BuildPushUndefinedIntoRegisterList(&args);
4275 : }
4276 : // Load callee as a global variable.
4277 11488078 : VariableProxy* proxy = callee_expr->AsVariableProxy();
4278 : BuildVariableLoadForAccumulatorValue(proxy->var(),
4279 3829328 : proxy->hole_check_mode());
4280 3829206 : builder()->StoreAccumulatorInRegister(callee);
4281 3829306 : break;
4282 : }
4283 : case Call::WITH_CALL: {
4284 4587 : Register receiver = register_allocator()->GrowRegisterList(&args);
4285 : DCHECK(callee_expr->AsVariableProxy()->var()->IsLookupSlot());
4286 : {
4287 : RegisterAllocationScope inner_register_scope(this);
4288 4587 : Register name = register_allocator()->NewRegister();
4289 :
4290 : // Call %LoadLookupSlotForCall to get the callee and receiver.
4291 4587 : RegisterList result_pair = register_allocator()->NewRegisterList(2);
4292 13761 : Variable* variable = callee_expr->AsVariableProxy()->var();
4293 : builder()
4294 4587 : ->LoadLiteral(variable->raw_name())
4295 4587 : .StoreAccumulatorInRegister(name)
4296 : .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, name,
4297 4587 : result_pair)
4298 4587 : .MoveRegister(result_pair[0], callee)
4299 4587 : .MoveRegister(result_pair[1], receiver);
4300 : }
4301 : break;
4302 : }
4303 : case Call::OTHER_CALL: {
4304 : // Receiver is undefined for other calls.
4305 522355 : if (!is_spread_call && !optimize_as_one_shot) {
4306 : implicit_undefined_receiver = true;
4307 : } else {
4308 : // TODO(leszeks): There's no special bytecode for tail calls or spread
4309 : // calls with an undefined receiver, so just push undefined ourselves.
4310 224825 : BuildPushUndefinedIntoRegisterList(&args);
4311 : }
4312 : VisitForRegisterValue(callee_expr, callee);
4313 : break;
4314 : }
4315 : case Call::NAMED_SUPER_PROPERTY_CALL: {
4316 469 : Register receiver = register_allocator()->GrowRegisterList(&args);
4317 469 : Property* property = callee_expr->AsProperty();
4318 469 : VisitNamedSuperPropertyLoad(property, receiver);
4319 469 : builder()->StoreAccumulatorInRegister(callee);
4320 : break;
4321 : }
4322 : case Call::KEYED_SUPER_PROPERTY_CALL: {
4323 40 : Register receiver = register_allocator()->GrowRegisterList(&args);
4324 40 : Property* property = callee_expr->AsProperty();
4325 40 : VisitKeyedSuperPropertyLoad(property, receiver);
4326 40 : builder()->StoreAccumulatorInRegister(callee);
4327 : break;
4328 : }
4329 : case Call::SUPER_CALL:
4330 0 : UNREACHABLE();
4331 : break;
4332 : }
4333 :
4334 : // Evaluate all arguments to the function call and store in sequential args
4335 : // registers.
4336 5162166 : VisitArguments(expr->arguments(), &args);
4337 5161980 : int reciever_arg_count = implicit_undefined_receiver ? 0 : 1;
4338 5161980 : CHECK_EQ(reciever_arg_count + expr->arguments()->length(),
4339 : args.register_count());
4340 :
4341 : // Resolve callee for a potential direct eval call. This block will mutate the
4342 : // callee value.
4343 5161980 : if (expr->is_possibly_eval() && expr->arguments()->length() > 0) {
4344 : RegisterAllocationScope inner_register_scope(this);
4345 : // Set up arguments for ResolvePossiblyDirectEval by copying callee, source
4346 : // strings and function closure, and loading language and
4347 : // position.
4348 214076 : Register first_arg = args[reciever_arg_count];
4349 107038 : RegisterList runtime_call_args = register_allocator()->NewRegisterList(6);
4350 : builder()
4351 107040 : ->MoveRegister(callee, runtime_call_args[0])
4352 107040 : .MoveRegister(first_arg, runtime_call_args[1])
4353 214079 : .MoveRegister(Register::function_closure(), runtime_call_args[2])
4354 107040 : .LoadLiteral(Smi::FromEnum(language_mode()))
4355 107039 : .StoreAccumulatorInRegister(runtime_call_args[3])
4356 214078 : .LoadLiteral(Smi::FromInt(current_scope()->start_position()))
4357 107038 : .StoreAccumulatorInRegister(runtime_call_args[4])
4358 214077 : .LoadLiteral(Smi::FromInt(expr->position()))
4359 107037 : .StoreAccumulatorInRegister(runtime_call_args[5]);
4360 :
4361 : // Call ResolvePossiblyDirectEval and modify the callee.
4362 : builder()
4363 107038 : ->CallRuntime(Runtime::kResolvePossiblyDirectEval, runtime_call_args)
4364 107039 : .StoreAccumulatorInRegister(callee);
4365 : }
4366 :
4367 : builder()->SetExpressionPosition(expr);
4368 :
4369 5161981 : if (is_spread_call) {
4370 : DCHECK(!implicit_undefined_receiver);
4371 : builder()->CallWithSpread(callee, args,
4372 3620 : feedback_index(feedback_spec()->AddCallICSlot()));
4373 5160171 : } else if (optimize_as_one_shot) {
4374 : DCHECK(!implicit_undefined_receiver);
4375 1247187 : builder()->CallNoFeedback(callee, args);
4376 7825968 : } else if (call_type == Call::NAMED_PROPERTY_CALL ||
4377 3912984 : call_type == Call::KEYED_PROPERTY_CALL ||
4378 3912984 : call_type == Call::RESOLVED_PROPERTY_CALL) {
4379 : DCHECK(!implicit_undefined_receiver);
4380 : builder()->CallProperty(callee, args,
4381 996811 : feedback_index(feedback_spec()->AddCallICSlot()));
4382 3414581 : } else if (implicit_undefined_receiver) {
4383 : builder()->CallUndefinedReceiver(
4384 6822470 : callee, args, feedback_index(feedback_spec()->AddCallICSlot()));
4385 : } else {
4386 : builder()->CallAnyReceiver(
4387 6706 : callee, args, feedback_index(feedback_spec()->AddCallICSlot()));
4388 : }
4389 : }
4390 :
4391 21157 : void BytecodeGenerator::VisitCallSuper(Call* expr) {
4392 : RegisterAllocationScope register_scope(this);
4393 18399 : SuperCallReference* super = expr->expression()->AsSuperCallReference();
4394 11189 : const ZonePtrList<Expression>* args = expr->arguments();
4395 :
4396 : int first_spread_index = 0;
4397 11800 : for (; first_spread_index < args->length(); first_spread_index++) {
4398 9148 : if (args->at(first_spread_index)->IsSpread()) break;
4399 : }
4400 :
4401 : // Prepare the constructor to the super call.
4402 5289 : Register this_function = VisitForRegisterValue(super->this_function_var());
4403 5290 : Register constructor = register_allocator()->NewRegister();
4404 : builder()
4405 5290 : ->LoadAccumulatorWithRegister(this_function)
4406 5290 : .GetSuperConstructor(constructor);
4407 :
4408 5290 : if (first_spread_index < expr->arguments()->length() - 1) {
4409 : // We rewrite something like
4410 : // super(1, ...x, 2)
4411 : // to
4412 : // %reflect_construct(constructor, [1, ...x, 2], new_target)
4413 : // That is, we implement (non-last-arg) spreads in super calls via our
4414 : // mechanism for spreads in array literals.
4415 :
4416 : // First generate the array containing all arguments.
4417 30 : BuildCreateArrayLiteral(args, nullptr);
4418 :
4419 : // Now pass that array to %reflect_construct.
4420 30 : RegisterList construct_args = register_allocator()->NewRegisterList(3);
4421 30 : builder()->StoreAccumulatorInRegister(construct_args[1]);
4422 30 : builder()->MoveRegister(constructor, construct_args[0]);
4423 : VisitForRegisterValue(super->new_target_var(), construct_args[2]);
4424 30 : builder()->CallJSRuntime(Context::REFLECT_CONSTRUCT_INDEX, construct_args);
4425 : } else {
4426 5260 : RegisterList args_regs = register_allocator()->NewGrowableRegisterList();
4427 5260 : VisitArguments(args, &args_regs);
4428 : // The new target is loaded into the accumulator from the
4429 : // {new.target} variable.
4430 5260 : VisitForAccumulatorValue(super->new_target_var());
4431 : builder()->SetExpressionPosition(expr);
4432 :
4433 5260 : int feedback_slot_index = feedback_index(feedback_spec()->AddCallICSlot());
4434 :
4435 5260 : if (first_spread_index == expr->arguments()->length() - 1) {
4436 : builder()->ConstructWithSpread(constructor, args_regs,
4437 3934 : feedback_slot_index);
4438 : } else {
4439 : DCHECK_EQ(first_spread_index, expr->arguments()->length());
4440 : // Call construct.
4441 : // TODO(turbofan): For now we do gather feedback on super constructor
4442 : // calls, utilizing the existing machinery to inline the actual call
4443 : // target and the JSCreate for the implicit receiver allocation. This
4444 : // is not an ideal solution for super constructor calls, but it gets
4445 : // the job done for now. In the long run we might want to revisit this
4446 : // and come up with a better way.
4447 1326 : builder()->Construct(constructor, args_regs, feedback_slot_index);
4448 : }
4449 : }
4450 :
4451 : // Explicit calls to the super constructor using super() perform an
4452 : // implicit binding assignment to the 'this' variable.
4453 : //
4454 : // Default constructors don't need have to do the assignment because
4455 : // 'this' isn't accessed in default constructors.
4456 10578 : if (!IsDefaultConstructor(info()->literal()->kind())) {
4457 : BuildVariableAssignment(super->this_var()->var(), Token::INIT,
4458 2531 : HoleCheckMode::kRequired);
4459 : }
4460 :
4461 : // The derived constructor has the correct bit set always, so we
4462 : // don't emit code to load and call the initializer if not
4463 : // required.
4464 : //
4465 : // For the arrow function or eval case, we always emit code to load
4466 : // and call the initializer.
4467 : //
4468 : // TODO(gsathya): In the future, we could tag nested arrow functions
4469 : // or eval with the correct bit so that we do the load conditionally
4470 : // if required.
4471 15680 : if (info()->literal()->requires_instance_members_initializer() ||
4472 5100 : !IsDerivedConstructor(info()->literal()->kind())) {
4473 321 : Register instance = register_allocator()->NewRegister();
4474 321 : builder()->StoreAccumulatorInRegister(instance);
4475 321 : BuildInstanceMemberInitialization(this_function, instance);
4476 321 : builder()->LoadAccumulatorWithRegister(instance);
4477 5290 : }
4478 5290 : }
4479 :
4480 142230 : void BytecodeGenerator::VisitCallNew(CallNew* expr) {
4481 142230 : Register constructor = VisitForRegisterValue(expr->expression());
4482 142291 : RegisterList args = register_allocator()->NewGrowableRegisterList();
4483 142291 : VisitArguments(expr->arguments(), &args);
4484 :
4485 : // The accumulator holds new target which is the same as the
4486 : // constructor for CallNew.
4487 : builder()->SetExpressionPosition(expr);
4488 142264 : builder()->LoadAccumulatorWithRegister(constructor);
4489 :
4490 142283 : int feedback_slot_index = feedback_index(feedback_spec()->AddCallICSlot());
4491 142286 : if (expr->only_last_arg_is_spread()) {
4492 169 : builder()->ConstructWithSpread(constructor, args, feedback_slot_index);
4493 : } else {
4494 142063 : builder()->Construct(constructor, args, feedback_slot_index);
4495 : }
4496 142283 : }
4497 :
4498 113819 : void BytecodeGenerator::VisitCallRuntime(CallRuntime* expr) {
4499 56912 : if (expr->is_jsruntime()) {
4500 383 : RegisterList args = register_allocator()->NewGrowableRegisterList();
4501 383 : VisitArguments(expr->arguments(), &args);
4502 383 : builder()->CallJSRuntime(expr->context_index(), args);
4503 : } else {
4504 : // Evaluate all arguments to the runtime call.
4505 56529 : RegisterList args = register_allocator()->NewGrowableRegisterList();
4506 56529 : VisitArguments(expr->arguments(), &args);
4507 56524 : Runtime::FunctionId function_id = expr->function()->function_id;
4508 56524 : builder()->CallRuntime(function_id, args);
4509 : }
4510 56951 : }
4511 :
4512 3310 : void BytecodeGenerator::VisitVoid(UnaryOperation* expr) {
4513 3310 : VisitForEffect(expr->expression());
4514 3310 : builder()->LoadUndefined();
4515 0 : }
4516 :
4517 144216 : void BytecodeGenerator::VisitForTypeOfValue(Expression* expr) {
4518 144217 : if (expr->IsVariableProxy()) {
4519 : // Typeof does not throw a reference error on global variables, hence we
4520 : // perform a non-contextual load in case the operand is a variable proxy.
4521 415707 : VariableProxy* proxy = expr->AsVariableProxy();
4522 : BuildVariableLoadForAccumulatorValue(proxy->var(), proxy->hole_check_mode(),
4523 138569 : INSIDE_TYPEOF);
4524 : } else {
4525 5648 : VisitForAccumulatorValue(expr);
4526 : }
4527 144218 : }
4528 :
4529 51626 : void BytecodeGenerator::VisitTypeOf(UnaryOperation* expr) {
4530 51626 : VisitForTypeOfValue(expr->expression());
4531 51628 : builder()->TypeOf();
4532 0 : }
4533 :
4534 491193 : void BytecodeGenerator::VisitNot(UnaryOperation* expr) {
4535 233026 : if (execution_result()->IsEffect()) {
4536 165 : VisitForEffect(expr->expression());
4537 232861 : } else if (execution_result()->IsTest()) {
4538 : // No actual logical negation happening, we just swap the control flow, by
4539 : // swapping the target labels and the fallthrough branch, and visit in the
4540 : // same test result context.
4541 : TestResultScope* test_result = execution_result()->AsTest();
4542 : test_result->InvertControlFlow();
4543 207721 : VisitInSameTestExecutionScope(expr->expression());
4544 : } else {
4545 25140 : TypeHint type_hint = VisitForAccumulatorValue(expr->expression());
4546 25141 : builder()->LogicalNot(ToBooleanModeFromTypeHint(type_hint));
4547 : // Always returns a boolean value.
4548 : execution_result()->SetResultIsBoolean();
4549 : }
4550 233035 : }
4551 :
4552 481566 : void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
4553 356431 : switch (expr->op()) {
4554 : case Token::Value::NOT:
4555 233026 : VisitNot(expr);
4556 233033 : break;
4557 : case Token::Value::TYPEOF:
4558 : VisitTypeOf(expr);
4559 : break;
4560 : case Token::Value::VOID:
4561 : VisitVoid(expr);
4562 : break;
4563 : case Token::Value::DELETE:
4564 5903 : VisitDelete(expr);
4565 5903 : break;
4566 : case Token::Value::ADD:
4567 : case Token::Value::SUB:
4568 : case Token::Value::BIT_NOT:
4569 62566 : VisitForAccumulatorValue(expr->expression());
4570 : builder()->SetExpressionPosition(expr);
4571 : builder()->UnaryOperation(
4572 125138 : expr->op(), feedback_index(feedback_spec()->AddBinaryOpICSlot()));
4573 62569 : break;
4574 : default:
4575 0 : UNREACHABLE();
4576 : }
4577 356444 : }
4578 :
4579 5903 : void BytecodeGenerator::VisitDelete(UnaryOperation* expr) {
4580 5903 : if (expr->expression()->IsProperty()) {
4581 : // Delete of an object property is allowed both in sloppy
4582 : // and strict modes.
4583 13095 : Property* property = expr->expression()->AsProperty();
4584 4364 : Register object = VisitForRegisterValue(property->obj());
4585 4367 : VisitForAccumulatorValue(property->key());
4586 4367 : builder()->Delete(object, language_mode());
4587 1539 : } else if (expr->expression()->IsVariableProxy()) {
4588 : // Delete of an unqualified identifier is allowed in sloppy mode but is
4589 : // not allowed in strict mode. Deleting 'this' and 'new.target' is allowed
4590 : // in both modes.
4591 2569 : VariableProxy* proxy = expr->expression()->AsVariableProxy();
4592 : DCHECK(is_sloppy(language_mode()) || proxy->is_this() ||
4593 : proxy->is_new_target());
4594 1698 : if (proxy->is_this() || proxy->is_new_target()) {
4595 80 : builder()->LoadTrue();
4596 : } else {
4597 1437 : Variable* variable = proxy->var();
4598 803 : switch (variable->location()) {
4599 : case VariableLocation::PARAMETER:
4600 : case VariableLocation::LOCAL:
4601 : case VariableLocation::CONTEXT: {
4602 : // Deleting local var/let/const, context variables, and arguments
4603 : // does not have any effect.
4604 169 : builder()->LoadFalse();
4605 169 : break;
4606 : }
4607 : case VariableLocation::UNALLOCATED:
4608 : // TODO(adamk): Falling through to the runtime results in correct
4609 : // behavior, but does unnecessary context-walking (since scope
4610 : // analysis has already proven that the variable doesn't exist in
4611 : // any non-global scope). Consider adding a DeleteGlobal bytecode
4612 : // that knows how to deal with ScriptContexts as well as global
4613 : // object properties.
4614 : case VariableLocation::LOOKUP: {
4615 634 : Register name_reg = register_allocator()->NewRegister();
4616 : builder()
4617 634 : ->LoadLiteral(variable->raw_name())
4618 635 : .StoreAccumulatorInRegister(name_reg)
4619 635 : .CallRuntime(Runtime::kDeleteLookupSlot, name_reg);
4620 : break;
4621 : }
4622 : default:
4623 0 : UNREACHABLE();
4624 : }
4625 : }
4626 : } else {
4627 : // Delete of an unresolvable reference returns true.
4628 656 : VisitForEffect(expr->expression());
4629 656 : builder()->LoadTrue();
4630 : }
4631 5905 : }
4632 :
4633 1381369 : void BytecodeGenerator::VisitCountOperation(CountOperation* expr) {
4634 : DCHECK(expr->expression()->IsValidReferenceExpression());
4635 :
4636 : // Left-hand side can only be a property, a global or a variable slot.
4637 266055 : Property* property = expr->expression()->AsProperty();
4638 240939 : AssignType assign_type = Property::GetAssignType(property);
4639 :
4640 425666 : bool is_postfix = expr->is_postfix() && !execution_result()->IsEffect();
4641 :
4642 : // Evaluate LHS expression and get old value.
4643 : Register object, key, old_value;
4644 : RegisterList super_property_args;
4645 : const AstRawString* name;
4646 240954 : switch (assign_type) {
4647 : case NON_PROPERTY: {
4648 699736 : VariableProxy* proxy = expr->expression()->AsVariableProxy();
4649 : BuildVariableLoadForAccumulatorValue(proxy->var(),
4650 233254 : proxy->hole_check_mode());
4651 233275 : break;
4652 : }
4653 : case NAMED_PROPERTY: {
4654 4871 : object = VisitForRegisterValue(property->obj());
4655 9744 : name = property->key()->AsLiteral()->AsRawPropertyName();
4656 : builder()->LoadNamedProperty(
4657 : object, name,
4658 4872 : feedback_index(GetCachedLoadICSlot(property->obj(), name)));
4659 4872 : break;
4660 : }
4661 : case KEYED_PROPERTY: {
4662 2691 : object = VisitForRegisterValue(property->obj());
4663 : // Use visit for accumulator here since we need the key in the accumulator
4664 : // for the LoadKeyedProperty.
4665 2691 : key = register_allocator()->NewRegister();
4666 2691 : VisitForAccumulatorValue(property->key());
4667 2692 : builder()->StoreAccumulatorInRegister(key).LoadKeyedProperty(
4668 5383 : object, feedback_index(feedback_spec()->AddKeyedLoadICSlot()));
4669 2692 : break;
4670 : }
4671 : case NAMED_SUPER_PROPERTY: {
4672 45 : super_property_args = register_allocator()->NewRegisterList(4);
4673 45 : RegisterList load_super_args = super_property_args.Truncate(3);
4674 90 : SuperPropertyReference* super_property =
4675 45 : property->obj()->AsSuperPropertyReference();
4676 : VisitForRegisterValue(super_property->this_var(), load_super_args[0]);
4677 : VisitForRegisterValue(super_property->home_object(), load_super_args[1]);
4678 : builder()
4679 90 : ->LoadLiteral(property->key()->AsLiteral()->AsRawPropertyName())
4680 45 : .StoreAccumulatorInRegister(load_super_args[2])
4681 45 : .CallRuntime(Runtime::kLoadFromSuper, load_super_args);
4682 : break;
4683 : }
4684 : case KEYED_SUPER_PROPERTY: {
4685 90 : super_property_args = register_allocator()->NewRegisterList(4);
4686 90 : RegisterList load_super_args = super_property_args.Truncate(3);
4687 180 : SuperPropertyReference* super_property =
4688 90 : property->obj()->AsSuperPropertyReference();
4689 : VisitForRegisterValue(super_property->this_var(), 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 241003 : FeedbackSlot count_slot = feedback_spec()->AddBinaryOpICSlot();
4699 240919 : if (is_postfix) {
4700 26919 : 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 26919 : ->ToNumeric(feedback_index(count_slot))
4706 26920 : .StoreAccumulatorInRegister(old_value);
4707 : }
4708 :
4709 : // Perform +1/-1 operation.
4710 240920 : builder()->UnaryOperation(expr->op(), feedback_index(count_slot));
4711 :
4712 : // Store the value.
4713 : builder()->SetExpressionPosition(expr);
4714 240949 : switch (assign_type) {
4715 : case NON_PROPERTY: {
4716 699699 : VariableProxy* proxy = expr->expression()->AsVariableProxy();
4717 : BuildVariableAssignment(proxy->var(), expr->op(),
4718 466466 : proxy->hole_check_mode());
4719 233278 : break;
4720 : }
4721 : case NAMED_PROPERTY: {
4722 4872 : FeedbackSlot slot = GetCachedStoreICSlot(property->obj(), name);
4723 : Register value;
4724 4872 : if (!execution_result()->IsEffect()) {
4725 4465 : value = register_allocator()->NewRegister();
4726 4465 : builder()->StoreAccumulatorInRegister(value);
4727 : }
4728 : builder()->StoreNamedProperty(object, name, feedback_index(slot),
4729 4872 : language_mode());
4730 4872 : if (!execution_result()->IsEffect()) {
4731 4466 : builder()->LoadAccumulatorWithRegister(value);
4732 : }
4733 : break;
4734 : }
4735 : case KEYED_PROPERTY: {
4736 2691 : FeedbackSlot slot = feedback_spec()->AddKeyedStoreICSlot(language_mode());
4737 : Register value;
4738 2691 : if (!execution_result()->IsEffect()) {
4739 481 : value = register_allocator()->NewRegister();
4740 481 : builder()->StoreAccumulatorInRegister(value);
4741 : }
4742 : builder()->StoreKeyedProperty(object, key, feedback_index(slot),
4743 2691 : language_mode());
4744 2692 : if (!execution_result()->IsEffect()) {
4745 481 : builder()->LoadAccumulatorWithRegister(value);
4746 : }
4747 : break;
4748 : }
4749 : case NAMED_SUPER_PROPERTY: {
4750 : builder()
4751 45 : ->StoreAccumulatorInRegister(super_property_args[3])
4752 45 : .CallRuntime(StoreToSuperRuntimeId(), super_property_args);
4753 45 : break;
4754 : }
4755 : case KEYED_SUPER_PROPERTY: {
4756 : builder()
4757 90 : ->StoreAccumulatorInRegister(super_property_args[3])
4758 90 : .CallRuntime(StoreKeyedToSuperRuntimeId(), super_property_args);
4759 90 : break;
4760 : }
4761 : }
4762 :
4763 : // Restore old value for postfix expressions.
4764 240995 : if (is_postfix) {
4765 26920 : builder()->LoadAccumulatorWithRegister(old_value);
4766 : }
4767 240995 : }
4768 :
4769 504550 : void BytecodeGenerator::VisitBinaryOperation(BinaryOperation* binop) {
4770 504550 : switch (binop->op()) {
4771 : case Token::COMMA:
4772 37686 : VisitCommaExpression(binop);
4773 37686 : break;
4774 : case Token::OR:
4775 40775 : VisitLogicalOrExpression(binop);
4776 40774 : break;
4777 : case Token::AND:
4778 68726 : VisitLogicalAndExpression(binop);
4779 68726 : break;
4780 : default:
4781 357363 : VisitArithmeticExpression(binop);
4782 357366 : break;
4783 : }
4784 504552 : }
4785 :
4786 104638 : void BytecodeGenerator::VisitNaryOperation(NaryOperation* expr) {
4787 104638 : switch (expr->op()) {
4788 : case Token::COMMA:
4789 332 : VisitNaryCommaExpression(expr);
4790 332 : break;
4791 : case Token::OR:
4792 19271 : VisitNaryLogicalOrExpression(expr);
4793 19272 : break;
4794 : case Token::AND:
4795 621 : VisitNaryLogicalAndExpression(expr);
4796 621 : break;
4797 : default:
4798 84414 : VisitNaryArithmeticExpression(expr);
4799 84418 : break;
4800 : }
4801 104643 : }
4802 :
4803 44272 : void BytecodeGenerator::BuildLiteralCompareNil(
4804 44272 : Token::Value op, BytecodeArrayBuilder::NilValue nil) {
4805 44272 : if (execution_result()->IsTest()) {
4806 63910 : TestResultScope* test_result = execution_result()->AsTest();
4807 31955 : switch (test_result->fallthrough()) {
4808 : case TestFallthrough::kThen:
4809 30589 : builder()->JumpIfNotNil(test_result->NewElseLabel(), op, nil);
4810 15294 : break;
4811 : case TestFallthrough::kElse:
4812 33322 : builder()->JumpIfNil(test_result->NewThenLabel(), op, nil);
4813 16662 : 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 12317 : builder()->CompareNil(op, nil);
4822 : }
4823 44274 : }
4824 :
4825 4629709 : void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) {
4826 : Expression* sub_expr;
4827 : Literal* literal;
4828 840423 : if (expr->IsLiteralCompareTypeof(&sub_expr, &literal)) {
4829 : // Emit a fast literal comparion for expressions of the form:
4830 : // typeof(x) === 'string'.
4831 92593 : VisitForTypeOfValue(sub_expr);
4832 : builder()->SetExpressionPosition(expr);
4833 : TestTypeOfFlags::LiteralFlag literal_flag =
4834 185178 : TestTypeOfFlags::GetFlagForLiteral(ast_string_constants(), literal);
4835 92588 : if (literal_flag == TestTypeOfFlags::LiteralFlag::kOther) {
4836 231 : builder()->LoadFalse();
4837 : } else {
4838 92357 : builder()->CompareTypeOf(literal_flag);
4839 : }
4840 747875 : } else if (expr->IsLiteralCompareUndefined(&sub_expr)) {
4841 39281 : VisitForAccumulatorValue(sub_expr);
4842 : builder()->SetExpressionPosition(expr);
4843 39282 : BuildLiteralCompareNil(expr->op(), BytecodeArrayBuilder::kUndefinedValue);
4844 708568 : } else if (expr->IsLiteralCompareNull(&sub_expr)) {
4845 4991 : VisitForAccumulatorValue(sub_expr);
4846 : builder()->SetExpressionPosition(expr);
4847 4993 : BuildLiteralCompareNil(expr->op(), BytecodeArrayBuilder::kNullValue);
4848 : } else {
4849 703579 : Register lhs = VisitForRegisterValue(expr->left());
4850 703594 : VisitForAccumulatorValue(expr->right());
4851 : builder()->SetExpressionPosition(expr);
4852 703615 : if (expr->op() == Token::IN) {
4853 2404 : builder()->CompareOperation(expr->op(), lhs);
4854 701211 : } else if (expr->op() == Token::INSTANCEOF) {
4855 14248 : FeedbackSlot slot = feedback_spec()->AddInstanceOfSlot();
4856 14243 : builder()->CompareOperation(expr->op(), lhs, feedback_index(slot));
4857 : } else {
4858 686963 : FeedbackSlot slot = feedback_spec()->AddCompareICSlot();
4859 686923 : builder()->CompareOperation(expr->op(), lhs, feedback_index(slot));
4860 : }
4861 : }
4862 : // Always returns a boolean value.
4863 : execution_result()->SetResultIsBoolean();
4864 840468 : }
4865 :
4866 1582870 : void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) {
4867 357363 : FeedbackSlot slot = feedback_spec()->AddBinaryOpICSlot();
4868 : Expression* subexpr;
4869 357368 : Smi literal;
4870 357368 : if (expr->IsSmiLiteralOperation(&subexpr, &literal)) {
4871 125949 : TypeHint type_hint = VisitForAccumulatorValue(subexpr);
4872 : builder()->SetExpressionPosition(expr);
4873 : builder()->BinaryOperationSmiLiteral(expr->op(), literal,
4874 125962 : feedback_index(slot));
4875 125957 : if (expr->op() == Token::ADD && type_hint == TypeHint::kString) {
4876 : execution_result()->SetResultIsString();
4877 : }
4878 : } else {
4879 231434 : TypeHint lhs_type = VisitForAccumulatorValue(expr->left());
4880 231431 : Register lhs = register_allocator()->NewRegister();
4881 231434 : builder()->StoreAccumulatorInRegister(lhs);
4882 231442 : TypeHint rhs_type = VisitForAccumulatorValue(expr->right());
4883 332564 : if (expr->op() == Token::ADD &&
4884 101123 : (lhs_type == TypeHint::kString || rhs_type == TypeHint::kString)) {
4885 : execution_result()->SetResultIsString();
4886 : }
4887 :
4888 : builder()->SetExpressionPosition(expr);
4889 231441 : builder()->BinaryOperation(expr->op(), lhs, feedback_index(slot));
4890 : }
4891 357393 : }
4892 :
4893 461197 : void BytecodeGenerator::VisitNaryArithmeticExpression(NaryOperation* expr) {
4894 : // TODO(leszeks): Add support for lhs smi in commutative ops.
4895 84414 : TypeHint type_hint = VisitForAccumulatorValue(expr->first());
4896 :
4897 777944 : for (size_t i = 0; i < expr->subsequent_length(); ++i) {
4898 : RegisterAllocationScope register_scope(this);
4899 304546 : 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 178392 : feedback_index(feedback_spec()->AddBinaryOpICSlot()));
4904 : } else {
4905 259951 : Register lhs = register_allocator()->NewRegister();
4906 259947 : builder()->StoreAccumulatorInRegister(lhs);
4907 259950 : TypeHint rhs_hint = VisitForAccumulatorValue(expr->subsequent(i));
4908 259951 : 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 519894 : feedback_index(feedback_spec()->AddBinaryOpICSlot()));
4913 : }
4914 304544 : }
4915 :
4916 120548 : 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 84426 : }
4921 :
4922 : // Note: the actual spreading is performed by the surrounding expression's
4923 : // visitor.
4924 8021 : 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 42589 : void BytecodeGenerator::BuildGetIterator(IteratorType hint) {
4939 42589 : RegisterList args = register_allocator()->NewRegisterList(1);
4940 42602 : Register method = register_allocator()->NewRegister();
4941 42603 : Register obj = args[0];
4942 :
4943 42603 : if (hint == IteratorType::kAsync) {
4944 : // Set method to GetMethod(obj, @@asyncIterator)
4945 347 : builder()->StoreAccumulatorInRegister(obj).LoadAsyncIteratorProperty(
4946 694 : 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 347 : builder()->JumpIfUndefined(&async_iterator_undefined);
4951 347 : builder()->JumpIfNull(&async_iterator_null);
4952 :
4953 : // Let iterator be Call(method, obj)
4954 347 : builder()->StoreAccumulatorInRegister(method).CallProperty(
4955 694 : method, args, feedback_index(feedback_spec()->AddCallICSlot()));
4956 :
4957 : // If Type(iterator) is not Object, throw a TypeError exception.
4958 347 : builder()->JumpIfJSReceiver(&done);
4959 347 : builder()->CallRuntime(Runtime::kThrowSymbolAsyncIteratorInvalid);
4960 :
4961 347 : builder()->Bind(&async_iterator_undefined);
4962 347 : builder()->Bind(&async_iterator_null);
4963 : // If method is undefined,
4964 : // Let syncMethod be GetMethod(obj, @@iterator)
4965 : builder()
4966 : ->LoadIteratorProperty(obj,
4967 694 : feedback_index(feedback_spec()->AddLoadICSlot()))
4968 347 : .StoreAccumulatorInRegister(method);
4969 :
4970 : // Let syncIterator be Call(syncMethod, obj)
4971 : builder()->CallProperty(method, args,
4972 694 : feedback_index(feedback_spec()->AddCallICSlot()));
4973 :
4974 : // Return CreateAsyncFromSyncIterator(syncIterator)
4975 : // alias `method` register as it's no longer used
4976 347 : Register sync_iter = method;
4977 347 : builder()->StoreAccumulatorInRegister(sync_iter).CallRuntime(
4978 347 : Runtime::kInlineCreateAsyncFromSyncIterator, sync_iter);
4979 :
4980 347 : builder()->Bind(&done);
4981 : } else {
4982 : // Let method be GetMethod(obj, @@iterator).
4983 : builder()
4984 42253 : ->StoreAccumulatorInRegister(obj)
4985 : .LoadIteratorProperty(obj,
4986 84511 : feedback_index(feedback_spec()->AddLoadICSlot()))
4987 42256 : .StoreAccumulatorInRegister(method);
4988 :
4989 : // Let iterator be Call(method, obj).
4990 : builder()->CallProperty(method, args,
4991 84514 : feedback_index(feedback_spec()->AddCallICSlot()));
4992 :
4993 : // If Type(iterator) is not Object, throw a TypeError exception.
4994 : BytecodeLabel no_type_error;
4995 42257 : builder()->JumpIfJSReceiver(&no_type_error);
4996 42251 : builder()->CallRuntime(Runtime::kThrowSymbolIteratorInvalid);
4997 42256 : builder()->Bind(&no_type_error);
4998 : }
4999 42597 : }
5000 :
5001 : // Returns an IteratorRecord which is valid for the lifetime of the current
5002 : // register_allocation_scope.
5003 42594 : BytecodeGenerator::IteratorRecord BytecodeGenerator::BuildGetIteratorRecord(
5004 42602 : Register next, Register object, IteratorType hint) {
5005 : DCHECK(next.is_valid() && object.is_valid());
5006 42594 : BuildGetIterator(hint);
5007 :
5008 : builder()
5009 42602 : ->StoreAccumulatorInRegister(object)
5010 : .LoadNamedProperty(object, ast_string_constants()->next_string(),
5011 127807 : feedback_index(feedback_spec()->AddLoadICSlot()))
5012 42604 : .StoreAccumulatorInRegister(next);
5013 42605 : return IteratorRecord(object, next, hint);
5014 : }
5015 :
5016 42395 : BytecodeGenerator::IteratorRecord BytecodeGenerator::BuildGetIteratorRecord(
5017 : IteratorType hint) {
5018 42395 : Register next = register_allocator()->NewRegister();
5019 42396 : Register object = register_allocator()->NewRegister();
5020 42404 : return BuildGetIteratorRecord(next, object, hint);
5021 : }
5022 :
5023 87654 : 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 87645 : feedback_index(feedback_spec()->AddCallICSlot()));
5028 :
5029 43835 : if (iterator.type() == IteratorType::kAsync) {
5030 337 : BuildAwait();
5031 : }
5032 :
5033 : BytecodeLabel is_object;
5034 : builder()
5035 43835 : ->StoreAccumulatorInRegister(next_result)
5036 43835 : .JumpIfJSReceiver(&is_object)
5037 43835 : .CallRuntime(Runtime::kThrowIteratorResultNotAnObject, next_result)
5038 43834 : .Bind(&is_object);
5039 43831 : }
5040 :
5041 600 : 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 600 : Register method = register_allocator()->NewRegister();
5049 600 : FeedbackSlot slot = feedback_spec()->AddLoadICSlot();
5050 : builder()
5051 600 : ->LoadNamedProperty(iterator, method_name, feedback_index(slot))
5052 1200 : .JumpIfUndefined(if_notcalled->New())
5053 1200 : .JumpIfNull(if_notcalled->New())
5054 600 : .StoreAccumulatorInRegister(method)
5055 : .CallProperty(method, receiver_and_args,
5056 1200 : feedback_index(feedback_spec()->AddCallICSlot()))
5057 600 : .Jump(if_called);
5058 600 : }
5059 :
5060 400 : void BytecodeGenerator::BuildIteratorClose(const IteratorRecord& iterator,
5061 400 : 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 200 : &if_called, &done);
5069 200 : builder()->Bind(&if_called);
5070 :
5071 200 : if (iterator.type() == IteratorType::kAsync) {
5072 : DCHECK_NOT_NULL(expr);
5073 10 : BuildAwait(expr->position());
5074 : }
5075 :
5076 200 : builder()->JumpIfJSReceiver(done.New());
5077 : {
5078 : RegisterAllocationScope register_scope(this);
5079 200 : Register return_result = register_allocator()->NewRegister();
5080 : builder()
5081 200 : ->StoreAccumulatorInRegister(return_result)
5082 200 : .CallRuntime(Runtime::kThrowIteratorResultNotAnObject, return_result);
5083 : }
5084 :
5085 400 : done.Bind(builder());
5086 200 : }
5087 :
5088 2043 : void BytecodeGenerator::VisitGetTemplateObject(GetTemplateObject* expr) {
5089 : builder()->SetExpressionPosition(expr);
5090 2043 : size_t entry = builder()->AllocateDeferredConstantPoolEntry();
5091 4086 : template_objects_.push_back(std::make_pair(expr, entry));
5092 2043 : FeedbackSlot literal_slot = feedback_spec()->AddLiteralSlot();
5093 2043 : builder()->GetTemplateObject(entry, feedback_index(literal_slot));
5094 2043 : }
5095 :
5096 7145 : void BytecodeGenerator::VisitTemplateLiteral(TemplateLiteral* expr) {
5097 10601 : const ZonePtrList<const AstRawString>& parts = *expr->string_parts();
5098 28350 : 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 7145 : FeedbackSlot slot = feedback_spec()->AddBinaryOpICSlot();
5107 7145 : Register last_part = register_allocator()->NewRegister();
5108 : bool last_part_valid = false;
5109 :
5110 : builder()->SetExpressionPosition(expr);
5111 28347 : for (int i = 0; i < substitutions.length(); ++i) {
5112 10601 : if (i != 0) {
5113 3456 : builder()->StoreAccumulatorInRegister(last_part);
5114 : last_part_valid = true;
5115 : }
5116 :
5117 21202 : if (!parts[i]->IsEmpty()) {
5118 7335 : builder()->LoadLiteral(parts[i]);
5119 7337 : if (last_part_valid) {
5120 3385 : builder()->BinaryOperation(Token::ADD, last_part, feedback_index(slot));
5121 : }
5122 7337 : builder()->StoreAccumulatorInRegister(last_part);
5123 : last_part_valid = true;
5124 : }
5125 :
5126 10604 : TypeHint type_hint = VisitForAccumulatorValue(substitutions[i]);
5127 10604 : if (type_hint != TypeHint::kString) {
5128 10592 : builder()->ToString();
5129 : }
5130 10603 : if (last_part_valid) {
5131 7408 : builder()->BinaryOperation(Token::ADD, last_part, feedback_index(slot));
5132 : }
5133 : last_part_valid = false;
5134 : }
5135 :
5136 14290 : if (!parts.last()->IsEmpty()) {
5137 2904 : builder()->StoreAccumulatorInRegister(last_part);
5138 2904 : builder()->LoadLiteral(parts.last());
5139 2904 : builder()->BinaryOperation(Token::ADD, last_part, feedback_index(slot));
5140 : }
5141 7145 : }
5142 :
5143 0 : void BytecodeGenerator::VisitThisFunction(ThisFunction* expr) {
5144 0 : builder()->LoadAccumulatorWithRegister(Register::function_closure());
5145 0 : }
5146 :
5147 0 : void BytecodeGenerator::VisitSuperCallReference(SuperCallReference* expr) {
5148 : // Handled by VisitCall().
5149 0 : UNREACHABLE();
5150 : }
5151 :
5152 0 : void BytecodeGenerator::VisitSuperPropertyReference(
5153 : SuperPropertyReference* expr) {
5154 17 : builder()->CallRuntime(Runtime::kThrowUnsupportedSuperError);
5155 0 : }
5156 :
5157 75372 : void BytecodeGenerator::VisitCommaExpression(BinaryOperation* binop) {
5158 37686 : VisitForEffect(binop->left());
5159 37686 : Visit(binop->right());
5160 37686 : }
5161 :
5162 332 : void BytecodeGenerator::VisitNaryCommaExpression(NaryOperation* expr) {
5163 : DCHECK_GT(expr->subsequent_length(), 0);
5164 :
5165 332 : VisitForEffect(expr->first());
5166 5221144 : for (size_t i = 0; i < expr->subsequent_length() - 1; ++i) {
5167 2610240 : VisitForEffect(expr->subsequent(i));
5168 : }
5169 332 : Visit(expr->subsequent(expr->subsequent_length() - 1));
5170 332 : }
5171 :
5172 127458 : void BytecodeGenerator::VisitLogicalTestSubExpression(
5173 : Token::Value token, Expression* expr, BytecodeLabels* then_labels,
5174 127458 : BytecodeLabels* else_labels, int coverage_slot) {
5175 : DCHECK(token == Token::OR || token == Token::AND);
5176 :
5177 : BytecodeLabels test_next(zone());
5178 127458 : if (token == Token::OR) {
5179 87913 : VisitForTest(expr, then_labels, &test_next, TestFallthrough::kElse);
5180 : } else {
5181 : DCHECK_EQ(Token::AND, token);
5182 39545 : VisitForTest(expr, &test_next, else_labels, TestFallthrough::kThen);
5183 : }
5184 127461 : test_next.Bind(builder());
5185 :
5186 127461 : BuildIncrementBlockCoverageCounterIfEnabled(coverage_slot);
5187 127461 : }
5188 :
5189 53905 : void BytecodeGenerator::VisitLogicalTest(Token::Value token, Expression* left,
5190 : Expression* right,
5191 53905 : int right_coverage_slot) {
5192 : DCHECK(token == Token::OR || token == Token::AND);
5193 53905 : TestResultScope* test_result = execution_result()->AsTest();
5194 : BytecodeLabels* then_labels = test_result->then_labels();
5195 : BytecodeLabels* else_labels = test_result->else_labels();
5196 : TestFallthrough fallthrough = test_result->fallthrough();
5197 :
5198 : VisitLogicalTestSubExpression(token, left, then_labels, else_labels,
5199 53905 : right_coverage_slot);
5200 : // The last test has the same then, else and fallthrough as the parent test.
5201 53907 : VisitForTest(right, then_labels, else_labels, fallthrough);
5202 53906 : }
5203 :
5204 19306 : void BytecodeGenerator::VisitNaryLogicalTest(
5205 19306 : Token::Value token, NaryOperation* expr,
5206 19306 : const NaryCodeCoverageSlots* coverage_slots) {
5207 : DCHECK(token == Token::OR || token == Token::AND);
5208 : DCHECK_GT(expr->subsequent_length(), 0);
5209 :
5210 19306 : TestResultScope* test_result = execution_result()->AsTest();
5211 : BytecodeLabels* then_labels = test_result->then_labels();
5212 : BytecodeLabels* else_labels = test_result->else_labels();
5213 : TestFallthrough fallthrough = test_result->fallthrough();
5214 :
5215 : VisitLogicalTestSubExpression(token, expr->first(), then_labels, else_labels,
5216 19306 : coverage_slots->GetSlotFor(0));
5217 92859 : for (size_t i = 0; i < expr->subsequent_length() - 1; ++i) {
5218 : VisitLogicalTestSubExpression(token, expr->subsequent(i), then_labels,
5219 : else_labels,
5220 108494 : coverage_slots->GetSlotFor(i + 1));
5221 : }
5222 : // The last test has the same then, else and fallthrough as the parent test.
5223 : VisitForTest(expr->subsequent(expr->subsequent_length() - 1), then_labels,
5224 19306 : else_labels, fallthrough);
5225 19306 : }
5226 :
5227 21960 : bool BytecodeGenerator::VisitLogicalOrSubExpression(Expression* expr,
5228 : BytecodeLabels* end_labels,
5229 : int coverage_slot) {
5230 21960 : if (expr->ToBooleanIsTrue()) {
5231 1730 : VisitForAccumulatorValue(expr);
5232 1730 : end_labels->Bind(builder());
5233 1730 : return true;
5234 20231 : } else if (!expr->ToBooleanIsFalse()) {
5235 20040 : TypeHint type_hint = VisitForAccumulatorValue(expr);
5236 : builder()->JumpIfTrue(ToBooleanModeFromTypeHint(type_hint),
5237 40085 : end_labels->New());
5238 : }
5239 :
5240 20233 : BuildIncrementBlockCoverageCounterIfEnabled(coverage_slot);
5241 :
5242 20233 : return false;
5243 : }
5244 :
5245 30861 : bool BytecodeGenerator::VisitLogicalAndSubExpression(Expression* expr,
5246 : BytecodeLabels* end_labels,
5247 : int coverage_slot) {
5248 30861 : if (expr->ToBooleanIsFalse()) {
5249 175 : VisitForAccumulatorValue(expr);
5250 175 : end_labels->Bind(builder());
5251 175 : return true;
5252 30686 : } else if (!expr->ToBooleanIsTrue()) {
5253 28944 : TypeHint type_hint = VisitForAccumulatorValue(expr);
5254 : builder()->JumpIfFalse(ToBooleanModeFromTypeHint(type_hint),
5255 57886 : end_labels->New());
5256 : }
5257 :
5258 30686 : BuildIncrementBlockCoverageCounterIfEnabled(coverage_slot);
5259 :
5260 30686 : return false;
5261 : }
5262 :
5263 103210 : void BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) {
5264 : Expression* left = binop->left();
5265 : Expression* right = binop->right();
5266 :
5267 : int right_coverage_slot =
5268 : AllocateBlockCoverageSlotIfEnabled(binop, SourceRangeKind::kRight);
5269 :
5270 40776 : if (execution_result()->IsTest()) {
5271 4340 : TestResultScope* test_result = execution_result()->AsTest();
5272 19115 : if (left->ToBooleanIsTrue()) {
5273 4340 : builder()->Jump(test_result->NewThenLabel());
5274 14774 : } else if (left->ToBooleanIsFalse() && right->ToBooleanIsFalse()) {
5275 0 : BuildIncrementBlockCoverageCounterIfEnabled(right_coverage_slot);
5276 0 : builder()->Jump(test_result->NewElseLabel());
5277 : } else {
5278 14774 : VisitLogicalTest(Token::OR, left, right, right_coverage_slot);
5279 : }
5280 : test_result->SetResultConsumedByTest();
5281 : } else {
5282 : BytecodeLabels end_labels(zone());
5283 21661 : if (VisitLogicalOrSubExpression(left, &end_labels, right_coverage_slot)) {
5284 40775 : return;
5285 : }
5286 19967 : VisitForAccumulatorValue(right);
5287 19970 : end_labels.Bind(builder());
5288 : }
5289 : }
5290 :
5291 38691 : void BytecodeGenerator::VisitNaryLogicalOrExpression(NaryOperation* expr) {
5292 : Expression* first = expr->first();
5293 : DCHECK_GT(expr->subsequent_length(), 0);
5294 :
5295 19271 : NaryCodeCoverageSlots coverage_slots(this, expr);
5296 :
5297 19271 : if (execution_result()->IsTest()) {
5298 0 : TestResultScope* test_result = execution_result()->AsTest();
5299 19122 : if (first->ToBooleanIsTrue()) {
5300 0 : builder()->Jump(test_result->NewThenLabel());
5301 : } else {
5302 19123 : VisitNaryLogicalTest(Token::OR, expr, &coverage_slots);
5303 : }
5304 : test_result->SetResultConsumedByTest();
5305 : } else {
5306 : BytecodeLabels end_labels(zone());
5307 149 : if (VisitLogicalOrSubExpression(first, &end_labels,
5308 : coverage_slots.GetSlotFor(0))) {
5309 : return;
5310 : }
5311 264 : for (size_t i = 0; i < expr->subsequent_length() - 1; ++i) {
5312 151 : if (VisitLogicalOrSubExpression(expr->subsequent(i), &end_labels,
5313 151 : coverage_slots.GetSlotFor(i + 1))) {
5314 : return;
5315 : }
5316 : }
5317 : // We have to visit the last value even if it's true, because we need its
5318 : // actual value.
5319 113 : VisitForAccumulatorValue(expr->subsequent(expr->subsequent_length() - 1));
5320 113 : end_labels.Bind(builder());
5321 : }
5322 : }
5323 :
5324 167032 : void BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) {
5325 : Expression* left = binop->left();
5326 : Expression* right = binop->right();
5327 :
5328 : int right_coverage_slot =
5329 : AllocateBlockCoverageSlotIfEnabled(binop, SourceRangeKind::kRight);
5330 :
5331 68725 : if (execution_result()->IsTest()) {
5332 10 : TestResultScope* test_result = execution_result()->AsTest();
5333 39143 : if (left->ToBooleanIsFalse()) {
5334 10 : builder()->Jump(test_result->NewElseLabel());
5335 39133 : } else if (left->ToBooleanIsTrue() && right->ToBooleanIsTrue()) {
5336 0 : BuildIncrementBlockCoverageCounterIfEnabled(right_coverage_slot);
5337 0 : builder()->Jump(test_result->NewThenLabel());
5338 : } else {
5339 39133 : VisitLogicalTest(Token::AND, left, right, right_coverage_slot);
5340 : }
5341 : test_result->SetResultConsumedByTest();
5342 : } else {
5343 : BytecodeLabels end_labels(zone());
5344 29582 : if (VisitLogicalAndSubExpression(left, &end_labels, right_coverage_slot)) {
5345 68726 : return;
5346 : }
5347 29426 : VisitForAccumulatorValue(right);
5348 29427 : end_labels.Bind(builder());
5349 : }
5350 : }
5351 :
5352 1680 : void BytecodeGenerator::VisitNaryLogicalAndExpression(NaryOperation* expr) {
5353 : Expression* first = expr->first();
5354 : DCHECK_GT(expr->subsequent_length(), 0);
5355 :
5356 621 : NaryCodeCoverageSlots coverage_slots(this, expr);
5357 :
5358 621 : if (execution_result()->IsTest()) {
5359 0 : TestResultScope* test_result = execution_result()->AsTest();
5360 183 : if (first->ToBooleanIsFalse()) {
5361 0 : builder()->Jump(test_result->NewElseLabel());
5362 : } else {
5363 183 : VisitNaryLogicalTest(Token::AND, expr, &coverage_slots);
5364 : }
5365 : test_result->SetResultConsumedByTest();
5366 : } else {
5367 : BytecodeLabels end_labels(zone());
5368 438 : if (VisitLogicalAndSubExpression(first, &end_labels,
5369 : coverage_slots.GetSlotFor(0))) {
5370 : return;
5371 : }
5372 1260 : for (size_t i = 0; i < expr->subsequent_length() - 1; ++i) {
5373 842 : if (VisitLogicalAndSubExpression(expr->subsequent(i), &end_labels,
5374 842 : coverage_slots.GetSlotFor(i + 1))) {
5375 : return;
5376 : }
5377 : }
5378 : // We have to visit the last value even if it's false, because we need its
5379 : // actual value.
5380 418 : VisitForAccumulatorValue(expr->subsequent(expr->subsequent_length() - 1));
5381 418 : end_labels.Bind(builder());
5382 : }
5383 : }
5384 :
5385 383272 : void BytecodeGenerator::BuildNewLocalActivationContext() {
5386 : ValueResultScope value_execution_result(this);
5387 368596 : Scope* scope = closure_scope();
5388 : DCHECK_EQ(current_scope(), closure_scope());
5389 :
5390 : // Create the appropriate context.
5391 191636 : if (scope->is_script_scope()) {
5392 13578 : Register scope_reg = register_allocator()->NewRegister();
5393 : builder()
5394 13579 : ->LoadLiteral(scope)
5395 13578 : .StoreAccumulatorInRegister(scope_reg)
5396 13578 : .CallRuntime(Runtime::kNewScriptContext, scope_reg);
5397 178058 : } else if (scope->is_module_scope()) {
5398 : // We don't need to do anything for the outer script scope.
5399 : DCHECK(scope->outer_scope()->is_script_scope());
5400 :
5401 : // A JSFunction representing a module is called with the module object as
5402 : // its sole argument.
5403 1098 : RegisterList args = register_allocator()->NewRegisterList(2);
5404 : builder()
5405 1098 : ->MoveRegister(builder()->Parameter(0), args[0])
5406 1098 : .LoadLiteral(scope)
5407 1098 : .StoreAccumulatorInRegister(args[1])
5408 1098 : .CallRuntime(Runtime::kPushModuleContext, args);
5409 : } else {
5410 : DCHECK(scope->is_function_scope() || scope->is_eval_scope());
5411 176960 : int slot_count = scope->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
5412 176960 : if (slot_count <= ConstructorBuiltins::MaximumFunctionContextSlots()) {
5413 176943 : switch (scope->scope_type()) {
5414 : case EVAL_SCOPE:
5415 42320 : builder()->CreateEvalContext(scope, slot_count);
5416 42320 : break;
5417 : case FUNCTION_SCOPE:
5418 134623 : builder()->CreateFunctionContext(scope, slot_count);
5419 134622 : break;
5420 : default:
5421 0 : UNREACHABLE();
5422 : }
5423 : } else {
5424 17 : Register arg = register_allocator()->NewRegister();
5425 17 : builder()->LoadLiteral(scope).StoreAccumulatorInRegister(arg).CallRuntime(
5426 17 : Runtime::kNewFunctionContext, arg);
5427 : }
5428 : }
5429 191630 : }
5430 :
5431 338551 : void BytecodeGenerator::BuildLocalActivationContextInitialization() {
5432 428483 : DeclarationScope* scope = closure_scope();
5433 :
5434 322729 : if (scope->has_this_declaration() && scope->receiver()->IsContextSlot()) {
5435 105752 : Variable* variable = scope->receiver();
5436 105752 : Register receiver(builder()->Receiver());
5437 : // Context variable (at bottom of the context chain).
5438 : DCHECK_EQ(0, scope->ContextChainLength(variable->scope()));
5439 105752 : builder()->LoadAccumulatorWithRegister(receiver).StoreContextSlot(
5440 105754 : execution_context()->reg(), variable->index(), 0);
5441 : }
5442 :
5443 : // Copy parameters into context if necessary.
5444 : int num_parameters = scope->num_parameters();
5445 259412 : for (int i = 0; i < num_parameters; i++) {
5446 41180 : Variable* variable = scope->parameter(i);
5447 94400 : if (!variable->IsContextSlot()) continue;
5448 :
5449 41180 : Register parameter(builder()->Parameter(i));
5450 : // Context variable (at bottom of the context chain).
5451 : DCHECK_EQ(0, scope->ContextChainLength(variable->scope()));
5452 41180 : builder()->LoadAccumulatorWithRegister(parameter).StoreContextSlot(
5453 41180 : execution_context()->reg(), variable->index(), 0);
5454 : }
5455 191622 : }
5456 :
5457 58330 : void BytecodeGenerator::BuildNewLocalBlockContext(Scope* scope) {
5458 : ValueResultScope value_execution_result(this);
5459 : DCHECK(scope->is_block_scope());
5460 :
5461 58330 : builder()->CreateBlockContext(scope);
5462 58320 : }
5463 :
5464 2955 : void BytecodeGenerator::BuildNewLocalWithContext(Scope* scope) {
5465 : ValueResultScope value_execution_result(this);
5466 :
5467 2955 : Register extension_object = register_allocator()->NewRegister();
5468 :
5469 2955 : builder()->ToObject(extension_object);
5470 2956 : builder()->CreateWithContext(extension_object, scope);
5471 2956 : }
5472 :
5473 69598 : void BytecodeGenerator::BuildNewLocalCatchContext(Scope* scope) {
5474 : ValueResultScope value_execution_result(this);
5475 : DCHECK(scope->catch_variable()->IsContextSlot());
5476 :
5477 69598 : Register exception = register_allocator()->NewRegister();
5478 69606 : builder()->StoreAccumulatorInRegister(exception);
5479 69619 : builder()->CreateCatchContext(exception, scope);
5480 69614 : }
5481 :
5482 9259 : void BytecodeGenerator::VisitObjectLiteralAccessor(
5483 : Register home_object, ObjectLiteralProperty* property, Register value_out) {
5484 9259 : if (property == nullptr) {
5485 3918 : builder()->LoadNull().StoreAccumulatorInRegister(value_out);
5486 : } else {
5487 5341 : VisitForRegisterValue(property->value(), value_out);
5488 5342 : VisitSetHomeObject(value_out, home_object, property);
5489 : }
5490 9259 : }
5491 :
5492 11292 : void BytecodeGenerator::VisitSetHomeObject(Register value, Register home_object,
5493 11292 : LiteralProperty* property) {
5494 : Expression* expr = property->value();
5495 11292 : if (FunctionLiteral::NeedsHomeObject(expr)) {
5496 659 : FeedbackSlot slot = feedback_spec()->AddStoreICSlot(language_mode());
5497 : builder()
5498 659 : ->LoadAccumulatorWithRegister(home_object)
5499 659 : .StoreHomeObjectProperty(value, feedback_index(slot), language_mode());
5500 : }
5501 11294 : }
5502 :
5503 2210370 : void BytecodeGenerator::VisitArgumentsObject(Variable* variable) {
5504 4219444 : if (variable == nullptr) return;
5505 :
5506 : DCHECK(variable->IsContextSlot() || variable->IsStackAllocated());
5507 :
5508 : // Allocate and initialize a new arguments object and assign to the
5509 : // {arguments} variable.
5510 100648 : builder()->CreateArguments(closure_scope()->GetArgumentsType());
5511 100647 : BuildVariableAssignment(variable, Token::ASSIGN, HoleCheckMode::kElided);
5512 : }
5513 :
5514 2109727 : void BytecodeGenerator::VisitRestArgumentsArray(Variable* rest) {
5515 4219454 : if (rest == nullptr) return;
5516 :
5517 : // Allocate and initialize a new rest parameter and assign to the {rest}
5518 : // variable.
5519 5166 : builder()->CreateArguments(CreateArgumentsType::kRestParameter);
5520 : DCHECK(rest->IsContextSlot() || rest->IsStackAllocated());
5521 5166 : BuildVariableAssignment(rest, Token::ASSIGN, HoleCheckMode::kElided);
5522 : }
5523 :
5524 4219459 : void BytecodeGenerator::VisitThisFunctionVariable(Variable* variable) {
5525 8438918 : if (variable == nullptr) return;
5526 :
5527 : // Store the closure we were called with in the given variable.
5528 34588 : builder()->LoadAccumulatorWithRegister(Register::function_closure());
5529 34588 : BuildVariableAssignment(variable, Token::INIT, HoleCheckMode::kElided);
5530 : }
5531 :
5532 2310863 : void BytecodeGenerator::VisitNewTargetVariable(Variable* variable) {
5533 2109723 : if (variable == nullptr) return;
5534 :
5535 : // The generator resume trampoline abuses the new.target register
5536 : // to pass in the generator object. In ordinary calls, new.target is always
5537 : // undefined because generator functions are non-constructible, so don't
5538 : // assign anything to the new.target variable.
5539 100827 : if (IsResumableFunction(info()->literal()->kind())) return;
5540 :
5541 100313 : if (variable->location() == VariableLocation::LOCAL) {
5542 : // The new.target register was already assigned by entry trampoline.
5543 : DCHECK_EQ(incoming_new_target_or_generator_.index(),
5544 : GetRegisterForLocalVariable(variable).index());
5545 : return;
5546 : }
5547 :
5548 : // Store the new target we were called with in the given variable.
5549 94864 : builder()->LoadAccumulatorWithRegister(incoming_new_target_or_generator_);
5550 94864 : BuildVariableAssignment(variable, Token::INIT, HoleCheckMode::kElided);
5551 : }
5552 :
5553 28810 : void BytecodeGenerator::BuildGeneratorObjectVariableInitialization() {
5554 : DCHECK(IsResumableFunction(info()->literal()->kind()));
5555 :
5556 10864 : Variable* generator_object_var = closure_scope()->generator_object_var();
5557 : RegisterAllocationScope register_scope(this);
5558 10864 : RegisterList args = register_allocator()->NewRegisterList(2);
5559 : Runtime::FunctionId function_id =
5560 17946 : (IsAsyncFunction(info()->literal()->kind()) &&
5561 7082 : !IsAsyncGeneratorFunction(info()->literal()->kind()))
5562 : ? Runtime::kInlineAsyncFunctionEnter
5563 10864 : : Runtime::kInlineCreateJSGeneratorObject;
5564 : builder()
5565 10864 : ->MoveRegister(Register::function_closure(), args[0])
5566 21728 : .MoveRegister(builder()->Receiver(), args[1])
5567 10864 : .CallRuntime(function_id, args)
5568 10864 : .StoreAccumulatorInRegister(generator_object());
5569 :
5570 10864 : if (generator_object_var->location() == VariableLocation::LOCAL) {
5571 : // The generator object register is already set to the variable's local
5572 : // register.
5573 : DCHECK_EQ(generator_object().index(),
5574 : GetRegisterForLocalVariable(generator_object_var).index());
5575 : } else {
5576 : BuildVariableAssignment(generator_object_var, Token::INIT,
5577 0 : HoleCheckMode::kElided);
5578 10864 : }
5579 10864 : }
5580 :
5581 940230 : void BytecodeGenerator::BuildPushUndefinedIntoRegisterList(
5582 : RegisterList* reg_list) {
5583 940230 : Register reg = register_allocator()->GrowRegisterList(reg_list);
5584 940378 : builder()->LoadUndefined().StoreAccumulatorInRegister(reg);
5585 940582 : }
5586 :
5587 9946 : void BytecodeGenerator::BuildLoadPropertyKey(LiteralProperty* property,
5588 : Register out_reg) {
5589 9946 : if (property->key()->IsStringLiteral()) {
5590 : builder()
5591 4348 : ->LoadLiteral(property->key()->AsLiteral()->AsRawString())
5592 2174 : .StoreAccumulatorInRegister(out_reg);
5593 : } else {
5594 7774 : VisitForAccumulatorValue(property->key());
5595 7774 : builder()->ToName(out_reg);
5596 : }
5597 9947 : }
5598 :
5599 0 : int BytecodeGenerator::AllocateBlockCoverageSlotIfEnabled(
5600 : AstNode* node, SourceRangeKind kind) {
5601 2240286 : return (block_coverage_builder_ == nullptr)
5602 : ? BlockCoverageBuilder::kNoCoverageArraySlot
5603 2240286 : : block_coverage_builder_->AllocateBlockCoverageSlot(node, kind);
5604 : }
5605 :
5606 0 : int BytecodeGenerator::AllocateNaryBlockCoverageSlotIfEnabled(
5607 : NaryOperation* node, size_t index) {
5608 305 : return (block_coverage_builder_ == nullptr)
5609 : ? BlockCoverageBuilder::kNoCoverageArraySlot
5610 : : block_coverage_builder_->AllocateNaryBlockCoverageSlot(node,
5611 305 : index);
5612 : }
5613 :
5614 0 : void BytecodeGenerator::BuildIncrementBlockCoverageCounterIfEnabled(
5615 : AstNode* node, SourceRangeKind kind) {
5616 22941 : if (block_coverage_builder_ == nullptr) return;
5617 190 : block_coverage_builder_->IncrementBlockCounter(node, kind);
5618 : }
5619 :
5620 178379 : void BytecodeGenerator::BuildIncrementBlockCoverageCounterIfEnabled(
5621 : int coverage_array_slot) {
5622 178379 : if (block_coverage_builder_ != nullptr) {
5623 : block_coverage_builder_->IncrementBlockCounter(coverage_array_slot);
5624 : }
5625 178379 : }
5626 :
5627 : // Visits the expression |expr| and places the result in the accumulator.
5628 17374227 : BytecodeGenerator::TypeHint BytecodeGenerator::VisitForAccumulatorValue(
5629 : Expression* expr) {
5630 : ValueResultScope accumulator_scope(this);
5631 17374227 : Visit(expr);
5632 34748535 : return accumulator_scope.type_hint();
5633 : }
5634 :
5635 41021 : void BytecodeGenerator::VisitForAccumulatorValueOrTheHole(Expression* expr) {
5636 41021 : if (expr == nullptr) {
5637 33066 : builder()->LoadTheHole();
5638 : } else {
5639 7955 : VisitForAccumulatorValue(expr);
5640 : }
5641 41024 : }
5642 :
5643 : // Visits the expression |expr| and discards the result.
5644 12807917 : void BytecodeGenerator::VisitForEffect(Expression* expr) {
5645 : EffectResultScope effect_scope(this);
5646 12807917 : Visit(expr);
5647 12807108 : }
5648 :
5649 : // Visits the expression |expr| and returns the register containing
5650 : // the expression result.
5651 5031512 : Register BytecodeGenerator::VisitForRegisterValue(Expression* expr) {
5652 5031512 : VisitForAccumulatorValue(expr);
5653 5031804 : Register result = register_allocator()->NewRegister();
5654 5031794 : builder()->StoreAccumulatorInRegister(result);
5655 5031879 : return result;
5656 : }
5657 :
5658 : // Visits the expression |expr| and stores the expression result in
5659 : // |destination|.
5660 : void BytecodeGenerator::VisitForRegisterValue(Expression* expr,
5661 : Register destination) {
5662 848844 : ValueResultScope register_scope(this);
5663 848817 : Visit(expr);
5664 848783 : builder()->StoreAccumulatorInRegister(destination);
5665 : }
5666 :
5667 : // Visits the expression |expr| and pushes the result into a new register
5668 : // added to the end of |reg_list|.
5669 6980013 : void BytecodeGenerator::VisitAndPushIntoRegisterList(Expression* expr,
5670 : RegisterList* reg_list) {
5671 : {
5672 : ValueResultScope register_scope(this);
5673 6980013 : Visit(expr);
5674 : }
5675 : // Grow the register list after visiting the expression to avoid reserving
5676 : // the register across the expression evaluation, which could cause memory
5677 : // leaks for deep expressions due to dead objects being kept alive by pointers
5678 : // in registers.
5679 6980065 : Register destination = register_allocator()->GrowRegisterList(reg_list);
5680 6979991 : builder()->StoreAccumulatorInRegister(destination);
5681 6980130 : }
5682 :
5683 862981 : void BytecodeGenerator::BuildTest(ToBooleanMode mode,
5684 : BytecodeLabels* then_labels,
5685 : BytecodeLabels* else_labels,
5686 : TestFallthrough fallthrough) {
5687 862981 : switch (fallthrough) {
5688 : case TestFallthrough::kThen:
5689 599414 : builder()->JumpIfFalse(mode, else_labels->New());
5690 599428 : break;
5691 : case TestFallthrough::kElse:
5692 263571 : builder()->JumpIfTrue(mode, then_labels->New());
5693 263575 : break;
5694 : case TestFallthrough::kNone:
5695 0 : builder()->JumpIfTrue(mode, then_labels->New());
5696 0 : builder()->Jump(else_labels->New());
5697 0 : break;
5698 : }
5699 862999 : }
5700 :
5701 : // Visits the expression |expr| for testing its boolean value and jumping to the
5702 : // |then| or |other| label depending on value and short-circuit semantics
5703 972473 : void BytecodeGenerator::VisitForTest(Expression* expr,
5704 : BytecodeLabels* then_labels,
5705 : BytecodeLabels* else_labels,
5706 : TestFallthrough fallthrough) {
5707 : bool result_consumed;
5708 : TypeHint type_hint;
5709 : {
5710 : // To make sure that all temporary registers are returned before generating
5711 : // jumps below, we ensure that the result scope is deleted before doing so.
5712 : // Dead registers might be materialized otherwise.
5713 : TestResultScope test_result(this, then_labels, else_labels, fallthrough);
5714 972473 : Visit(expr);
5715 972511 : result_consumed = test_result.result_consumed_by_test();
5716 972511 : type_hint = test_result.type_hint();
5717 : // Labels and fallthrough might have been mutated, so update based on
5718 : // TestResultScope.
5719 972511 : then_labels = test_result.then_labels();
5720 972511 : else_labels = test_result.else_labels();
5721 972511 : fallthrough = test_result.fallthrough();
5722 : }
5723 972517 : if (!result_consumed) {
5724 : BuildTest(ToBooleanModeFromTypeHint(type_hint), then_labels, else_labels,
5725 672250 : fallthrough);
5726 : }
5727 972520 : }
5728 :
5729 415450 : void BytecodeGenerator::VisitInSameTestExecutionScope(Expression* expr) {
5730 : DCHECK(execution_result()->IsTest());
5731 : {
5732 : RegisterAllocationScope reg_scope(this);
5733 207721 : Visit(expr);
5734 : }
5735 207729 : if (!execution_result()->AsTest()->result_consumed_by_test()) {
5736 190750 : TestResultScope* result_scope = execution_result()->AsTest();
5737 : BuildTest(ToBooleanModeFromTypeHint(result_scope->type_hint()),
5738 : result_scope->then_labels(), result_scope->else_labels(),
5739 381500 : result_scope->fallthrough());
5740 : result_scope->SetResultConsumedByTest();
5741 : }
5742 207729 : }
5743 :
5744 72549 : void BytecodeGenerator::VisitInScope(Statement* stmt, Scope* scope) {
5745 : DCHECK(scope->declarations()->is_empty());
5746 : CurrentScope current_scope(this, scope);
5747 145125 : ContextScope context_scope(this, scope);
5748 72575 : Visit(stmt);
5749 72564 : }
5750 :
5751 16313 : Register BytecodeGenerator::GetRegisterForLocalVariable(Variable* variable) {
5752 : DCHECK_EQ(VariableLocation::LOCAL, variable->location());
5753 16313 : return builder()->Local(variable->index());
5754 : }
5755 :
5756 2136859 : FunctionKind BytecodeGenerator::function_kind() const {
5757 2136859 : return info()->literal()->kind();
5758 : }
5759 :
5760 6425926 : LanguageMode BytecodeGenerator::language_mode() const {
5761 : return current_scope()->language_mode();
5762 : }
5763 :
5764 : Register BytecodeGenerator::generator_object() const {
5765 : DCHECK(IsResumableFunction(info()->literal()->kind()));
5766 : return incoming_new_target_or_generator_;
5767 : }
5768 :
5769 17934869 : FeedbackVectorSpec* BytecodeGenerator::feedback_spec() {
5770 : return info()->feedback_vector_spec();
5771 : }
5772 :
5773 : int BytecodeGenerator::feedback_index(FeedbackSlot slot) const {
5774 : DCHECK(!slot.IsInvalid());
5775 : return FeedbackVector::GetIndex(slot);
5776 : }
5777 :
5778 7724567 : FeedbackSlot BytecodeGenerator::GetCachedLoadGlobalICSlot(
5779 10823546 : TypeofMode typeof_mode, Variable* variable) {
5780 : FeedbackSlotKind slot_kind =
5781 : typeof_mode == INSIDE_TYPEOF
5782 : ? FeedbackSlotKind::kLoadGlobalInsideTypeof
5783 7724567 : : FeedbackSlotKind::kLoadGlobalNotInsideTypeof;
5784 : FeedbackSlot slot = feedback_slot_cache()->Get(slot_kind, variable);
5785 7725047 : if (!slot.IsInvalid()) {
5786 4626095 : return slot;
5787 : }
5788 3098952 : slot = feedback_spec()->AddLoadGlobalICSlot(typeof_mode);
5789 : feedback_slot_cache()->Put(slot_kind, variable, slot);
5790 3099269 : return slot;
5791 : }
5792 :
5793 1421051 : FeedbackSlot BytecodeGenerator::GetCachedStoreGlobalICSlot(
5794 2577168 : LanguageMode language_mode, Variable* variable) {
5795 : FeedbackSlotKind slot_kind = is_strict(language_mode)
5796 : ? FeedbackSlotKind::kStoreGlobalStrict
5797 1421051 : : FeedbackSlotKind::kStoreGlobalSloppy;
5798 : FeedbackSlot slot = feedback_slot_cache()->Get(slot_kind, variable);
5799 1421231 : if (!slot.IsInvalid()) {
5800 265162 : return slot;
5801 : }
5802 1156069 : slot = feedback_spec()->AddStoreGlobalICSlot(language_mode);
5803 : feedback_slot_cache()->Put(slot_kind, variable, slot);
5804 1156093 : return slot;
5805 : }
5806 :
5807 1117062 : FeedbackSlot BytecodeGenerator::GetCachedLoadICSlot(const Expression* expr,
5808 1539183 : const AstRawString* name) {
5809 1117062 : if (!FLAG_ignition_share_named_property_feedback) {
5810 0 : return feedback_spec()->AddLoadICSlot();
5811 : }
5812 : FeedbackSlotKind slot_kind = FeedbackSlotKind::kLoadProperty;
5813 1117074 : if (!expr->IsVariableProxy()) {
5814 203504 : return feedback_spec()->AddLoadICSlot();
5815 : }
5816 2452753 : const VariableProxy* proxy = expr->AsVariableProxy();
5817 : FeedbackSlot slot =
5818 913570 : feedback_slot_cache()->Get(slot_kind, proxy->var()->index(), name);
5819 913569 : if (!slot.IsInvalid()) {
5820 287961 : return slot;
5821 : }
5822 625608 : slot = feedback_spec()->AddLoadICSlot();
5823 625613 : feedback_slot_cache()->Put(slot_kind, proxy->var()->index(), name, slot);
5824 625601 : return slot;
5825 : }
5826 :
5827 2281928 : FeedbackSlot BytecodeGenerator::GetCachedStoreICSlot(const Expression* expr,
5828 2459236 : const AstRawString* name) {
5829 2281928 : if (!FLAG_ignition_share_named_property_feedback) {
5830 0 : return feedback_spec()->AddStoreICSlot(language_mode());
5831 : }
5832 : FeedbackSlotKind slot_kind = is_strict(language_mode())
5833 : ? FeedbackSlotKind::kStoreNamedStrict
5834 2281928 : : FeedbackSlotKind::kStoreNamedSloppy;
5835 2281926 : if (!expr->IsVariableProxy()) {
5836 2314 : return feedback_spec()->AddStoreICSlot(language_mode());
5837 : }
5838 4738848 : const VariableProxy* proxy = expr->AsVariableProxy();
5839 : FeedbackSlot slot =
5840 2279612 : feedback_slot_cache()->Get(slot_kind, proxy->var()->index(), name);
5841 2279616 : if (!slot.IsInvalid()) {
5842 2099993 : return slot;
5843 : }
5844 179623 : slot = feedback_spec()->AddStoreICSlot(language_mode());
5845 179624 : feedback_slot_cache()->Put(slot_kind, proxy->var()->index(), name, slot);
5846 179623 : return slot;
5847 : }
5848 :
5849 2854753 : FeedbackSlot BytecodeGenerator::GetCachedCreateClosureSlot(
5850 5709678 : FunctionLiteral* literal) {
5851 : FeedbackSlotKind slot_kind = FeedbackSlotKind::kCreateClosure;
5852 : FeedbackSlot slot = feedback_slot_cache()->Get(slot_kind, literal);
5853 2854842 : if (!slot.IsInvalid()) {
5854 0 : return slot;
5855 : }
5856 2854842 : slot = feedback_spec()->AddCreateClosureSlot();
5857 : feedback_slot_cache()->Put(slot_kind, literal, slot);
5858 2855031 : return slot;
5859 : }
5860 :
5861 0 : FeedbackSlot BytecodeGenerator::GetDummyCompareICSlot() {
5862 1671 : return dummy_feedback_slot_.Get();
5863 : }
5864 :
5865 : Runtime::FunctionId BytecodeGenerator::StoreToSuperRuntimeId() {
5866 : return is_strict(language_mode()) ? Runtime::kStoreToSuper_Strict
5867 265 : : Runtime::kStoreToSuper_Sloppy;
5868 : }
5869 :
5870 : Runtime::FunctionId BytecodeGenerator::StoreKeyedToSuperRuntimeId() {
5871 : return is_strict(language_mode()) ? Runtime::kStoreKeyedToSuper_Strict
5872 430 : : Runtime::kStoreKeyedToSuper_Sloppy;
5873 : }
5874 :
5875 : } // namespace interpreter
5876 : } // namespace internal
5877 183867 : } // namespace v8
|