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/ast/ast-source-ranges.h"
8 : #include "src/ast/compile-time-value.h"
9 : #include "src/ast/scopes.h"
10 : #include "src/builtins/builtins-constructor.h"
11 : #include "src/code-stubs.h"
12 : #include "src/compilation-info.h"
13 : #include "src/compiler.h"
14 : #include "src/interpreter/bytecode-flags.h"
15 : #include "src/interpreter/bytecode-jump-table.h"
16 : #include "src/interpreter/bytecode-label.h"
17 : #include "src/interpreter/bytecode-register-allocator.h"
18 : #include "src/interpreter/control-flow-builders.h"
19 : #include "src/objects-inl.h"
20 : #include "src/objects/debug-objects.h"
21 : #include "src/parsing/parse-info.h"
22 : #include "src/parsing/token.h"
23 :
24 : namespace v8 {
25 : namespace internal {
26 : namespace interpreter {
27 :
28 : // Scoped class tracking context objects created by the visitor. Represents
29 : // mutations of the context chain within the function body, allowing pushing and
30 : // popping of the current {context_register} during visitation.
31 : class BytecodeGenerator::ContextScope BASE_EMBEDDED {
32 : public:
33 2469053 : ContextScope(BytecodeGenerator* generator, Scope* scope)
34 : : generator_(generator),
35 : scope_(scope),
36 2806786 : outer_(generator_->execution_context()),
37 : register_(Register::current_context()),
38 4938106 : depth_(0) {
39 : DCHECK(scope->NeedsContext() || outer_ == nullptr);
40 2469058 : if (outer_) {
41 337733 : depth_ = outer_->depth_ + 1;
42 :
43 : // Push the outer context into a new context register.
44 : Register outer_context_reg =
45 675466 : generator_->register_allocator()->NewRegister();
46 337733 : outer_->set_register(outer_context_reg);
47 675466 : generator_->builder()->PushContext(outer_context_reg);
48 : }
49 2469058 : generator_->set_execution_context(this);
50 2469058 : }
51 :
52 2469057 : ~ContextScope() {
53 2469057 : if (outer_) {
54 : DCHECK_EQ(register_.index(), Register::current_context().index());
55 337733 : generator_->builder()->PopContext(outer_->reg());
56 337733 : outer_->set_register(register_);
57 : }
58 2469057 : generator_->set_execution_context(outer_);
59 2469057 : }
60 :
61 : // Returns the depth of the given |scope| for the current execution context.
62 : int ContextChainDepth(Scope* scope) {
63 4336596 : return scope_->ContextChainLength(scope);
64 : }
65 :
66 : // Returns the execution context at |depth| in the current context chain if it
67 : // is a function local execution context, otherwise returns nullptr.
68 : ContextScope* Previous(int depth) {
69 4296625 : if (depth > depth_) {
70 : return nullptr;
71 : }
72 :
73 : ContextScope* previous = this;
74 71182 : for (int i = depth; i > 0; --i) {
75 71182 : previous = previous->outer_;
76 : }
77 : return previous;
78 : }
79 :
80 : Register reg() const { return register_; }
81 :
82 : private:
83 : const BytecodeArrayBuilder* builder() const { return generator_->builder(); }
84 :
85 675466 : void set_register(Register reg) { register_ = reg; }
86 :
87 : BytecodeGenerator* generator_;
88 : Scope* scope_;
89 : ContextScope* outer_;
90 : Register register_;
91 : int depth_;
92 : };
93 :
94 : // Scoped class for tracking control statements entered by the
95 : // visitor. The pattern derives AstGraphBuilder::ControlScope.
96 : class BytecodeGenerator::ControlScope BASE_EMBEDDED {
97 : public:
98 15312392 : explicit ControlScope(BytecodeGenerator* generator)
99 : : generator_(generator), outer_(generator->execution_control()),
100 22968588 : context_(generator->execution_context()) {
101 : generator_->set_execution_control(this);
102 : }
103 7656196 : virtual ~ControlScope() { generator_->set_execution_control(outer()); }
104 :
105 : void Break(Statement* stmt) {
106 67991 : PerformCommand(CMD_BREAK, stmt, kNoSourcePosition);
107 : }
108 : void Continue(Statement* stmt) {
109 8726 : PerformCommand(CMD_CONTINUE, stmt, kNoSourcePosition);
110 : }
111 : void ReturnAccumulator(int source_position = kNoSourcePosition) {
112 2177983 : PerformCommand(CMD_RETURN, nullptr, source_position);
113 : }
114 : void AsyncReturnAccumulator(int source_position = kNoSourcePosition) {
115 3830 : PerformCommand(CMD_ASYNC_RETURN, nullptr, source_position);
116 : }
117 :
118 : class DeferredCommands;
119 :
120 : protected:
121 : enum Command {
122 : CMD_BREAK,
123 : CMD_CONTINUE,
124 : CMD_RETURN,
125 : CMD_ASYNC_RETURN,
126 : CMD_RETHROW
127 : };
128 : static constexpr bool CommandUsesAccumulator(Command command) {
129 : return command != CMD_BREAK && command != CMD_CONTINUE;
130 : }
131 :
132 : void PerformCommand(Command command, Statement* statement,
133 : int source_position);
134 : virtual bool Execute(Command command, Statement* statement,
135 : int source_position) = 0;
136 :
137 : // Helper to pop the context chain to a depth expected by this control scope.
138 : // Note that it is the responsibility of each individual {Execute} method to
139 : // trigger this when commands are handled and control-flow continues locally.
140 : void PopContextToExpectedDepth();
141 :
142 : BytecodeGenerator* generator() const { return generator_; }
143 : ControlScope* outer() const { return outer_; }
144 : ContextScope* context() const { return context_; }
145 :
146 : private:
147 : BytecodeGenerator* generator_;
148 : ControlScope* outer_;
149 : ContextScope* context_;
150 :
151 : DISALLOW_COPY_AND_ASSIGN(ControlScope);
152 : };
153 :
154 : // Helper class for a try-finally control scope. It can record intercepted
155 : // control-flow commands that cause entry into a finally-block, and re-apply
156 : // them after again leaving that block. Special tokens are used to identify
157 : // paths going through the finally-block to dispatch after leaving the block.
158 : class BytecodeGenerator::ControlScope::DeferredCommands final {
159 : public:
160 36312 : DeferredCommands(BytecodeGenerator* generator, Register token_register,
161 : Register result_register)
162 : : generator_(generator),
163 : deferred_(generator->zone()),
164 : token_register_(token_register),
165 : result_register_(result_register),
166 : return_token_(-1),
167 : async_return_token_(-1),
168 72624 : rethrow_token_(-1) {}
169 :
170 : // One recorded control-flow command.
171 : struct Entry {
172 : Command command; // The command type being applied on this path.
173 : Statement* statement; // The target statement for the command or {nullptr}.
174 : int token; // A token identifying this particular path.
175 : };
176 :
177 : // Records a control-flow command while entering the finally-block. This also
178 : // generates a new dispatch token that identifies one particular path. This
179 : // expects the result to be in the accumulator.
180 215376 : void RecordCommand(Command command, Statement* statement) {
181 53844 : int token = GetTokenForCommand(command, statement);
182 :
183 : DCHECK_LT(token, deferred_.size());
184 : DCHECK_EQ(deferred_[token].command, command);
185 : DCHECK_EQ(deferred_[token].statement, statement);
186 : DCHECK_EQ(deferred_[token].token, token);
187 :
188 53844 : if (CommandUsesAccumulator(command)) {
189 53568 : builder()->StoreAccumulatorInRegister(result_register_);
190 : }
191 53844 : builder()->LoadLiteral(Smi::FromInt(token));
192 53844 : builder()->StoreAccumulatorInRegister(token_register_);
193 53844 : if (!CommandUsesAccumulator(command)) {
194 : // If we're not saving the accumulator in the result register, shove a
195 : // harmless value there instead so that it is still considered "killed" in
196 : // the liveness analysis. Normally we would LdaUndefined first, but the
197 : // Smi token value is just as good, and by reusing it we save a bytecode.
198 276 : builder()->StoreAccumulatorInRegister(result_register_);
199 : }
200 53844 : }
201 :
202 : // Records the dispatch token to be used to identify the re-throw path when
203 : // the finally-block has been entered through the exception handler. This
204 : // expects the exception to be in the accumulator.
205 : void RecordHandlerReThrowPath() {
206 : // The accumulator contains the exception object.
207 36312 : RecordCommand(CMD_RETHROW, nullptr);
208 : }
209 :
210 : // Records the dispatch token to be used to identify the implicit fall-through
211 : // path at the end of a try-block into the corresponding finally-block.
212 108936 : void RecordFallThroughPath() {
213 36312 : builder()->LoadLiteral(Smi::FromInt(-1));
214 36312 : builder()->StoreAccumulatorInRegister(token_register_);
215 : // Since we're not saving the accumulator in the result register, shove a
216 : // harmless value there instead so that it is still considered "killed" in
217 : // the liveness analysis. Normally we would LdaUndefined first, but the Smi
218 : // token value is just as good, and by reusing it we save a bytecode.
219 36312 : builder()->StoreAccumulatorInRegister(result_register_);
220 36312 : }
221 :
222 : // Applies all recorded control-flow commands after the finally-block again.
223 : // This generates a dynamic dispatch on the token from the entry point.
224 239518 : void ApplyDeferredCommands() {
225 72624 : if (deferred_.size() == 0) return;
226 :
227 : BytecodeLabel fall_through;
228 :
229 36312 : if (deferred_.size() == 1) {
230 : // For a single entry, just jump to the fallthrough if we don't match the
231 : // entry token.
232 : const Entry& entry = deferred_[0];
233 :
234 : builder()
235 52484 : ->LoadLiteral(Smi::FromInt(entry.token))
236 26242 : .CompareOperation(Token::EQ_STRICT, token_register_)
237 26242 : .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &fall_through);
238 :
239 26242 : if (CommandUsesAccumulator(entry.command)) {
240 26242 : builder()->LoadAccumulatorWithRegister(result_register_);
241 : }
242 : execution_control()->PerformCommand(entry.command, entry.statement,
243 52484 : kNoSourcePosition);
244 : } else {
245 : // For multiple entries, build a jump table and switch on the token,
246 : // jumping to the fallthrough if none of them match.
247 :
248 : BytecodeJumpTable* jump_table =
249 20140 : builder()->AllocateJumpTable(static_cast<int>(deferred_.size()), 0);
250 : builder()
251 10070 : ->LoadAccumulatorWithRegister(token_register_)
252 10070 : .SwitchOnSmiNoFeedback(jump_table)
253 10070 : .Jump(&fall_through);
254 42908 : for (const Entry& entry : deferred_) {
255 45536 : builder()->Bind(jump_table, entry.token);
256 :
257 22768 : if (CommandUsesAccumulator(entry.command)) {
258 22492 : builder()->LoadAccumulatorWithRegister(result_register_);
259 : }
260 : execution_control()->PerformCommand(entry.command, entry.statement,
261 45536 : kNoSourcePosition);
262 : }
263 : }
264 :
265 36312 : builder()->Bind(&fall_through);
266 : }
267 :
268 424664 : BytecodeArrayBuilder* builder() { return generator_->builder(); }
269 49010 : ControlScope* execution_control() { return generator_->execution_control(); }
270 :
271 : private:
272 53844 : int GetTokenForCommand(Command command, Statement* statement) {
273 53844 : switch (command) {
274 : case CMD_RETURN:
275 13101 : return GetReturnToken();
276 : case CMD_ASYNC_RETURN:
277 4074 : return GetAsyncReturnToken();
278 : case CMD_RETHROW:
279 36393 : return GetRethrowToken();
280 : default:
281 : // TODO(leszeks): We could also search for entries with the same
282 : // command and statement.
283 276 : return GetNewTokenForCommand(command, statement);
284 : }
285 : }
286 :
287 13101 : int GetReturnToken() {
288 13101 : if (return_token_ == -1) {
289 9574 : return_token_ = GetNewTokenForCommand(CMD_RETURN, nullptr);
290 : }
291 13101 : return return_token_;
292 : }
293 :
294 4074 : int GetAsyncReturnToken() {
295 4074 : if (async_return_token_ == -1) {
296 2848 : async_return_token_ = GetNewTokenForCommand(CMD_ASYNC_RETURN, nullptr);
297 : }
298 4074 : return async_return_token_;
299 : }
300 :
301 36393 : int GetRethrowToken() {
302 36393 : if (rethrow_token_ == -1) {
303 36312 : rethrow_token_ = GetNewTokenForCommand(CMD_RETHROW, nullptr);
304 : }
305 36393 : return rethrow_token_;
306 : }
307 :
308 : int GetNewTokenForCommand(Command command, Statement* statement) {
309 98020 : int token = static_cast<int>(deferred_.size());
310 98020 : deferred_.push_back({command, statement, token});
311 : return token;
312 : }
313 :
314 : BytecodeGenerator* generator_;
315 : ZoneVector<Entry> deferred_;
316 : Register token_register_;
317 : Register result_register_;
318 :
319 : // Tokens for commands that don't need a statement.
320 : int return_token_;
321 : int async_return_token_;
322 : int rethrow_token_;
323 : };
324 :
325 : // Scoped class for dealing with control flow reaching the function level.
326 2131325 : class BytecodeGenerator::ControlScopeForTopLevel final
327 : : public BytecodeGenerator::ControlScope {
328 : public:
329 : explicit ControlScopeForTopLevel(BytecodeGenerator* generator)
330 2131325 : : ControlScope(generator) {}
331 :
332 : protected:
333 2208738 : bool Execute(Command command, Statement* statement,
334 : int source_position) override {
335 2208738 : switch (command) {
336 : case CMD_BREAK: // We should never see break/continue in top-level.
337 : case CMD_CONTINUE:
338 0 : UNREACHABLE();
339 : case CMD_RETURN:
340 : // No need to pop contexts, execution leaves the method body.
341 2208739 : generator()->BuildReturn(source_position);
342 2174456 : return true;
343 : case CMD_ASYNC_RETURN:
344 : // No need to pop contexts, execution leaves the method body.
345 2604 : generator()->BuildAsyncReturn(source_position);
346 2604 : return true;
347 : case CMD_RETHROW:
348 : // No need to pop contexts, execution leaves the method body.
349 : generator()->BuildReThrow();
350 31681 : return true;
351 : }
352 : return false;
353 : }
354 : };
355 :
356 : // Scoped class for enabling break inside blocks and switch blocks.
357 5163438 : class BytecodeGenerator::ControlScopeForBreakable final
358 : : public BytecodeGenerator::ControlScope {
359 : public:
360 : ControlScopeForBreakable(BytecodeGenerator* generator,
361 : BreakableStatement* statement,
362 : BreakableControlFlowBuilder* control_builder)
363 : : ControlScope(generator),
364 : statement_(statement),
365 5163438 : control_builder_(control_builder) {}
366 :
367 : protected:
368 594221 : bool Execute(Command command, Statement* statement,
369 : int source_position) override {
370 594221 : control_builder_->set_needs_continuation_counter();
371 594221 : if (statement != statement_) return false;
372 36151 : switch (command) {
373 : case CMD_BREAK:
374 36151 : PopContextToExpectedDepth();
375 36151 : control_builder_->Break();
376 36151 : return true;
377 : case CMD_CONTINUE:
378 : case CMD_RETURN:
379 : case CMD_ASYNC_RETURN:
380 : case CMD_RETHROW:
381 : break;
382 : }
383 : return false;
384 : }
385 :
386 : private:
387 : Statement* statement_;
388 : BreakableControlFlowBuilder* control_builder_;
389 : };
390 :
391 : // Scoped class for enabling 'break' and 'continue' in iteration
392 : // constructs, e.g. do...while, while..., for...
393 : class BytecodeGenerator::ControlScopeForIteration final
394 : : public BytecodeGenerator::ControlScope {
395 : public:
396 : ControlScopeForIteration(BytecodeGenerator* generator,
397 : IterationStatement* statement,
398 : LoopBuilder* loop_builder)
399 : : ControlScope(generator),
400 : statement_(statement),
401 222999 : loop_builder_(loop_builder) {
402 222999 : generator->loop_depth_++;
403 : }
404 222999 : ~ControlScopeForIteration() { generator()->loop_depth_--; }
405 :
406 : protected:
407 90846 : bool Execute(Command command, Statement* statement,
408 : int source_position) override {
409 90846 : if (statement != statement_) return false;
410 40566 : switch (command) {
411 : case CMD_BREAK:
412 31840 : PopContextToExpectedDepth();
413 31840 : loop_builder_->Break();
414 31840 : return true;
415 : case CMD_CONTINUE:
416 8726 : PopContextToExpectedDepth();
417 8726 : loop_builder_->Continue();
418 8726 : return true;
419 : case CMD_RETURN:
420 : case CMD_ASYNC_RETURN:
421 : case CMD_RETHROW:
422 : break;
423 : }
424 : return false;
425 : }
426 :
427 : private:
428 : Statement* statement_;
429 : LoopBuilder* loop_builder_;
430 : };
431 :
432 : // Scoped class for enabling 'throw' in try-catch constructs.
433 102122 : class BytecodeGenerator::ControlScopeForTryCatch final
434 : : public BytecodeGenerator::ControlScope {
435 : public:
436 : ControlScopeForTryCatch(BytecodeGenerator* generator,
437 : TryCatchBuilder* try_catch_builder)
438 102122 : : ControlScope(generator) {}
439 :
440 : protected:
441 32747 : bool Execute(Command command, Statement* statement,
442 : int source_position) override {
443 32747 : switch (command) {
444 : case CMD_BREAK:
445 : case CMD_CONTINUE:
446 : case CMD_RETURN:
447 : case CMD_ASYNC_RETURN:
448 : break;
449 : case CMD_RETHROW:
450 : // No need to pop contexts, execution re-enters the method body via the
451 : // stack unwinding mechanism which itself restores contexts correctly.
452 4550 : generator()->BuildReThrow();
453 4550 : return true;
454 : }
455 : return false;
456 : }
457 : };
458 :
459 : // Scoped class for enabling control flow through try-finally constructs.
460 36312 : class BytecodeGenerator::ControlScopeForTryFinally final
461 : : public BytecodeGenerator::ControlScope {
462 : public:
463 : ControlScopeForTryFinally(BytecodeGenerator* generator,
464 : TryFinallyBuilder* try_finally_builder,
465 : DeferredCommands* commands)
466 : : ControlScope(generator),
467 : try_finally_builder_(try_finally_builder),
468 36312 : commands_(commands) {}
469 :
470 : protected:
471 17532 : bool Execute(Command command, Statement* statement,
472 : int source_position) override {
473 17532 : switch (command) {
474 : case CMD_BREAK:
475 : case CMD_CONTINUE:
476 : case CMD_RETURN:
477 : case CMD_ASYNC_RETURN:
478 : case CMD_RETHROW:
479 17532 : PopContextToExpectedDepth();
480 : // We don't record source_position here since we don't generate return
481 : // bytecode right here and will generate it later as part of finally
482 : // block. Each return bytecode generated in finally block will get own
483 : // return source position from corresponded return statement or we'll
484 : // use end of function if no return statement is presented.
485 17532 : commands_->RecordCommand(command, statement);
486 17532 : try_finally_builder_->LeaveTry();
487 17532 : return true;
488 : }
489 : return false;
490 : }
491 :
492 : private:
493 : TryFinallyBuilder* try_finally_builder_;
494 : DeferredCommands* commands_;
495 : };
496 :
497 2307539 : void BytecodeGenerator::ControlScope::PerformCommand(Command command,
498 : Statement* statement,
499 : int source_position) {
500 636547 : ControlScope* current = this;
501 636547 : do {
502 2944086 : if (current->Execute(command, statement, source_position)) {
503 2307540 : return;
504 : }
505 : current = current->outer();
506 : } while (current != nullptr);
507 0 : UNREACHABLE();
508 : }
509 :
510 188498 : void BytecodeGenerator::ControlScope::PopContextToExpectedDepth() {
511 : // Pop context to the expected depth. Note that this can in fact pop multiple
512 : // contexts at once because the {PopContext} bytecode takes a saved register.
513 188498 : if (generator()->execution_context() != context()) {
514 16294 : generator()->builder()->PopContext(context()->reg());
515 : }
516 94249 : }
517 :
518 : class BytecodeGenerator::RegisterAllocationScope final {
519 : public:
520 : explicit RegisterAllocationScope(BytecodeGenerator* generator)
521 : : generator_(generator),
522 : outer_next_register_index_(
523 149152268 : generator->register_allocator()->next_register_index()) {}
524 :
525 74576017 : ~RegisterAllocationScope() {
526 : generator_->register_allocator()->ReleaseRegisters(
527 74576017 : outer_next_register_index_);
528 74576009 : }
529 :
530 : private:
531 : BytecodeGenerator* generator_;
532 : int outer_next_register_index_;
533 :
534 : DISALLOW_COPY_AND_ASSIGN(RegisterAllocationScope);
535 : };
536 :
537 : // Scoped base class for determining how the result of an expression will be
538 : // used.
539 : class BytecodeGenerator::ExpressionResultScope {
540 : public:
541 42382378 : ExpressionResultScope(BytecodeGenerator* generator, Expression::Context kind)
542 : : generator_(generator),
543 : outer_(generator->execution_result()),
544 : allocator_(generator),
545 : kind_(kind),
546 127147134 : type_hint_(TypeHint::kAny) {
547 : generator_->set_execution_result(this);
548 : }
549 :
550 84764786 : virtual ~ExpressionResultScope() {
551 42382393 : generator_->set_execution_result(outer_);
552 0 : }
553 :
554 : bool IsEffect() const { return kind_ == Expression::kEffect; }
555 : bool IsValue() const { return kind_ == Expression::kValue; }
556 : bool IsTest() const { return kind_ == Expression::kTest; }
557 :
558 : TestResultScope* AsTest() {
559 : DCHECK(IsTest());
560 : return reinterpret_cast<TestResultScope*>(this);
561 : }
562 :
563 : // Specify expression always returns a Boolean result value.
564 : void SetResultIsBoolean() {
565 : DCHECK_EQ(type_hint_, TypeHint::kAny);
566 1554144 : type_hint_ = TypeHint::kBoolean;
567 : }
568 :
569 : TypeHint type_hint() const { return type_hint_; }
570 :
571 : private:
572 : BytecodeGenerator* generator_;
573 : ExpressionResultScope* outer_;
574 : RegisterAllocationScope allocator_;
575 : Expression::Context kind_;
576 : TypeHint type_hint_;
577 :
578 : DISALLOW_COPY_AND_ASSIGN(ExpressionResultScope);
579 : };
580 :
581 : // Scoped class used when the result of the current expression is not
582 : // expected to produce a result.
583 9541610 : class BytecodeGenerator::EffectResultScope final
584 : : public ExpressionResultScope {
585 : public:
586 : explicit EffectResultScope(BytecodeGenerator* generator)
587 9541607 : : ExpressionResultScope(generator, Expression::kEffect) {}
588 : };
589 :
590 : // Scoped class used when the result of the current expression to be
591 : // evaluated should go into the interpreter's accumulator.
592 33027719 : class BytecodeGenerator::ValueResultScope final : public ExpressionResultScope {
593 : public:
594 1543406 : explicit ValueResultScope(BytecodeGenerator* generator)
595 33027704 : : ExpressionResultScope(generator, Expression::kValue) {}
596 : };
597 :
598 : // Scoped class used when the result of the current expression to be
599 : // evaluated is only tested with jumps to two branches.
600 1356472 : class BytecodeGenerator::TestResultScope final : public ExpressionResultScope {
601 : public:
602 : TestResultScope(BytecodeGenerator* generator, BytecodeLabels* then_labels,
603 : BytecodeLabels* else_labels, TestFallthrough fallthrough)
604 : : ExpressionResultScope(generator, Expression::kTest),
605 : result_consumed_by_test_(false),
606 : fallthrough_(fallthrough),
607 : then_labels_(then_labels),
608 1356473 : else_labels_(else_labels) {}
609 :
610 : // Used when code special cases for TestResultScope and consumes any
611 : // possible value by testing and jumping to a then/else label.
612 : void SetResultConsumedByTest() {
613 640399 : result_consumed_by_test_ = true;
614 : }
615 : bool result_consumed_by_test() { return result_consumed_by_test_; }
616 :
617 : // Inverts the control flow of the operation, swapping the then and else
618 : // labels and the fallthrough.
619 283388 : void InvertControlFlow() {
620 : std::swap(then_labels_, else_labels_);
621 283388 : fallthrough_ = inverted_fallthrough();
622 : }
623 :
624 48364 : BytecodeLabel* NewThenLabel() { return then_labels_->New(); }
625 78572 : BytecodeLabel* NewElseLabel() { return else_labels_->New(); }
626 :
627 : BytecodeLabels* then_labels() const { return then_labels_; }
628 : BytecodeLabels* else_labels() const { return else_labels_; }
629 :
630 : void set_then_labels(BytecodeLabels* then_labels) {
631 68068 : then_labels_ = then_labels;
632 : }
633 : void set_else_labels(BytecodeLabels* else_labels) {
634 110283 : else_labels_ = else_labels;
635 : }
636 :
637 : TestFallthrough fallthrough() const { return fallthrough_; }
638 : TestFallthrough inverted_fallthrough() const {
639 283388 : switch (fallthrough_) {
640 : case TestFallthrough::kThen:
641 : return TestFallthrough::kElse;
642 : case TestFallthrough::kElse:
643 : return TestFallthrough::kThen;
644 : default:
645 : return TestFallthrough::kNone;
646 : }
647 : }
648 : void set_fallthrough(TestFallthrough fallthrough) {
649 178351 : fallthrough_ = fallthrough;
650 : }
651 :
652 : private:
653 : bool result_consumed_by_test_;
654 : TestFallthrough fallthrough_;
655 : BytecodeLabels* then_labels_;
656 : BytecodeLabels* else_labels_;
657 :
658 : DISALLOW_COPY_AND_ASSIGN(TestResultScope);
659 : };
660 :
661 : // Used to build a list of global declaration initial value pairs.
662 : class BytecodeGenerator::GlobalDeclarationsBuilder final : public ZoneObject {
663 : public:
664 2220196 : explicit GlobalDeclarationsBuilder(Zone* zone)
665 : : declarations_(0, zone),
666 : constant_pool_entry_(0),
667 2220197 : has_constant_pool_entry_(false) {}
668 :
669 : void AddFunctionDeclaration(const AstRawString* name, FeedbackSlot slot,
670 : FeedbackSlot literal_slot,
671 : FunctionLiteral* func) {
672 : DCHECK(!slot.IsInvalid());
673 377512 : declarations_.push_back(Declaration(name, slot, literal_slot, func));
674 : }
675 :
676 : void AddUndefinedDeclaration(const AstRawString* name, FeedbackSlot slot) {
677 : DCHECK(!slot.IsInvalid());
678 1822390 : declarations_.push_back(Declaration(name, slot, nullptr));
679 : }
680 :
681 2188886 : Handle<FixedArray> AllocateDeclarations(CompilationInfo* info,
682 : Handle<Script> script) {
683 : DCHECK(has_constant_pool_entry_);
684 : int array_index = 0;
685 : Handle<FixedArray> data = info->isolate()->factory()->NewFixedArray(
686 266610 : static_cast<int>(declarations_.size() * 4), TENURED);
687 1277691 : for (const Declaration& declaration : declarations_) {
688 1099951 : FunctionLiteral* func = declaration.func;
689 : Handle<Object> initial_value;
690 1099951 : if (func == nullptr) {
691 : initial_value = info->isolate()->factory()->undefined_value();
692 : } else {
693 : initial_value =
694 188756 : Compiler::GetSharedFunctionInfo(func, script, info->isolate());
695 : }
696 :
697 : // Return a null handle if any initial values can't be created. Caller
698 : // will set stack overflow.
699 1099951 : if (initial_value.is_null()) return Handle<FixedArray>();
700 :
701 3299853 : data->set(array_index++, *declaration.name->string());
702 1099951 : data->set(array_index++, Smi::FromInt(declaration.slot.ToInt()));
703 : Object* undefined_or_literal_slot;
704 1099951 : if (declaration.literal_slot.IsInvalid()) {
705 911195 : undefined_or_literal_slot = info->isolate()->heap()->undefined_value();
706 : } else {
707 : undefined_or_literal_slot =
708 : Smi::FromInt(declaration.literal_slot.ToInt());
709 : }
710 2199902 : data->set(array_index++, undefined_or_literal_slot);
711 2199902 : data->set(array_index++, *initial_value);
712 : }
713 88870 : return data;
714 : }
715 :
716 : size_t constant_pool_entry() {
717 : DCHECK(has_constant_pool_entry_);
718 : return constant_pool_entry_;
719 : }
720 :
721 : void set_constant_pool_entry(size_t constant_pool_entry) {
722 : DCHECK(!empty());
723 : DCHECK(!has_constant_pool_entry_);
724 88870 : constant_pool_entry_ = constant_pool_entry;
725 88870 : has_constant_pool_entry_ = true;
726 : }
727 :
728 : bool empty() { return declarations_.empty(); }
729 :
730 : private:
731 : struct Declaration {
732 4440392 : Declaration() : slot(FeedbackSlot::Invalid()), func(nullptr) {}
733 : Declaration(const AstRawString* name, FeedbackSlot slot,
734 : FeedbackSlot literal_slot, FunctionLiteral* func)
735 188756 : : name(name), slot(slot), literal_slot(literal_slot), func(func) {}
736 : Declaration(const AstRawString* name, FeedbackSlot slot,
737 : FunctionLiteral* func)
738 : : name(name),
739 : slot(slot),
740 : literal_slot(FeedbackSlot::Invalid()),
741 911195 : func(func) {}
742 :
743 : const AstRawString* name;
744 : FeedbackSlot slot;
745 : FeedbackSlot literal_slot;
746 : FunctionLiteral* func;
747 : };
748 : ZoneVector<Declaration> declarations_;
749 : size_t constant_pool_entry_;
750 : bool has_constant_pool_entry_;
751 : };
752 :
753 : class BytecodeGenerator::CurrentScope final {
754 : public:
755 5311257 : CurrentScope(BytecodeGenerator* generator, Scope* scope)
756 : : generator_(generator), outer_scope_(generator->current_scope()) {
757 5311257 : if (scope != nullptr) {
758 : DCHECK_EQ(outer_scope_, scope->outer_scope());
759 : generator_->set_current_scope(scope);
760 : }
761 : }
762 : ~CurrentScope() {
763 5311257 : if (outer_scope_ != generator_->current_scope()) {
764 : generator_->set_current_scope(outer_scope_);
765 : }
766 : }
767 :
768 : private:
769 : BytecodeGenerator* generator_;
770 : Scope* outer_scope_;
771 : };
772 :
773 : class BytecodeGenerator::FeedbackSlotCache : public ZoneObject {
774 : public:
775 : typedef std::pair<TypeofMode, void*> Key;
776 :
777 : explicit FeedbackSlotCache(Zone* zone) : map_(zone) {}
778 :
779 : void Put(TypeofMode typeof_mode, Variable* variable, FeedbackSlot slot) {
780 : Key key = std::make_pair(typeof_mode, variable);
781 : auto entry = std::make_pair(key, slot);
782 : map_.insert(entry);
783 : }
784 : void Put(AstNode* node, FeedbackSlot slot) {
785 : Key key = std::make_pair(NOT_INSIDE_TYPEOF, node);
786 : auto entry = std::make_pair(key, slot);
787 : map_.insert(entry);
788 : }
789 :
790 3897155 : FeedbackSlot Get(TypeofMode typeof_mode, Variable* variable) const {
791 : Key key = std::make_pair(typeof_mode, variable);
792 : auto iter = map_.find(key);
793 3897155 : if (iter != map_.end()) {
794 1480892 : return iter->second;
795 : }
796 2416263 : return FeedbackSlot();
797 : }
798 4157075 : FeedbackSlot Get(AstNode* node) const {
799 : Key key = std::make_pair(NOT_INSIDE_TYPEOF, node);
800 : auto iter = map_.find(key);
801 4157074 : if (iter != map_.end()) {
802 0 : return iter->second;
803 : }
804 4157074 : return FeedbackSlot();
805 : }
806 :
807 : private:
808 : ZoneMap<Key, FeedbackSlot> map_;
809 : };
810 :
811 27708035 : BytecodeGenerator::BytecodeGenerator(CompilationInfo* info)
812 : : zone_(info->zone()),
813 : builder_(new (zone()) BytecodeArrayBuilder(
814 : info->isolate(), info->zone(), info->num_parameters_including_this(),
815 2131327 : info->scope()->num_stack_slots(), info->feedback_vector_spec(),
816 2131325 : info->SourcePositionRecordingMode())),
817 : info_(info),
818 2131328 : ast_string_constants_(info->isolate()->ast_string_constants()),
819 2131328 : closure_scope_(info->scope()),
820 2131329 : current_scope_(info->scope()),
821 : feedback_slot_cache_(new (zone()) FeedbackSlotCache(zone())),
822 2131329 : globals_builder_(new (zone()) GlobalDeclarationsBuilder(zone())),
823 : block_coverage_builder_(nullptr),
824 : global_declarations_(0, zone()),
825 : function_literals_(0, zone()),
826 : native_function_literals_(0, zone()),
827 : object_literals_(0, zone()),
828 : array_literals_(0, zone()),
829 : template_objects_(0, zone()),
830 : execution_control_(nullptr),
831 : execution_context_(nullptr),
832 : execution_result_(nullptr),
833 : incoming_new_target_or_generator_(),
834 : generator_jump_table_(nullptr),
835 : generator_state_(),
836 : loop_depth_(0),
837 25575928 : catch_prediction_(HandlerTable::UNCAUGHT) {
838 : DCHECK_EQ(closure_scope(), closure_scope()->GetClosureScope());
839 2131326 : if (info->has_source_range_map()) {
840 : block_coverage_builder_ = new (zone())
841 781 : BlockCoverageBuilder(zone(), builder(), info->source_range_map());
842 : }
843 2131326 : }
844 :
845 2131307 : Handle<BytecodeArray> BytecodeGenerator::FinalizeBytecode(
846 4263395 : Isolate* isolate, Handle<Script> script) {
847 : DCHECK(ThreadId::Current().Equals(isolate->thread_id()));
848 :
849 2131307 : AllocateDeferredConstants(isolate, script);
850 :
851 2131307 : if (block_coverage_builder_) {
852 : info()->set_coverage_info(
853 781 : isolate->factory()->NewCoverageInfo(block_coverage_builder_->slots()));
854 781 : if (FLAG_trace_block_coverage) {
855 0 : info()->coverage_info()->Print(info()->shared_info()->name());
856 : }
857 : }
858 :
859 2131307 : if (HasStackOverflow()) return Handle<BytecodeArray>();
860 2131307 : Handle<BytecodeArray> bytecode_array = builder()->ToBytecodeArray(isolate);
861 :
862 2131308 : if (incoming_new_target_or_generator_.is_valid()) {
863 : bytecode_array->set_incoming_new_target_or_generator_register(
864 : incoming_new_target_or_generator_);
865 : }
866 :
867 2131308 : return bytecode_array;
868 : }
869 :
870 2131307 : void BytecodeGenerator::AllocateDeferredConstants(Isolate* isolate,
871 4517328 : Handle<Script> script) {
872 : // Build global declaration pair arrays.
873 4440354 : for (GlobalDeclarationsBuilder* globals_builder : global_declarations_) {
874 : Handle<FixedArray> declarations =
875 88870 : globals_builder->AllocateDeclarations(info(), script);
876 88870 : if (declarations.is_null()) return SetStackOverflow();
877 : builder()->SetDeferredConstantPoolEntry(
878 88870 : globals_builder->constant_pool_entry(), declarations);
879 : }
880 :
881 : // Find or build shared function infos.
882 8230928 : for (std::pair<FunctionLiteral*, size_t> literal : function_literals_) {
883 : FunctionLiteral* expr = literal.first;
884 : Handle<SharedFunctionInfo> shared_info =
885 3968314 : Compiler::GetSharedFunctionInfo(expr, script, isolate);
886 3968314 : if (shared_info.is_null()) return SetStackOverflow();
887 3968314 : builder()->SetDeferredConstantPoolEntry(literal.second, shared_info);
888 : }
889 :
890 : // Find or build shared function infos for the native function templates.
891 4264292 : for (std::pair<NativeFunctionLiteral*, size_t> literal :
892 1678 : native_function_literals_) {
893 3356 : NativeFunctionLiteral* expr = literal.first;
894 : Handle<SharedFunctionInfo> shared_info =
895 : Compiler::GetSharedFunctionInfoForNative(expr->extension(),
896 1678 : expr->name());
897 1678 : if (shared_info.is_null()) return SetStackOverflow();
898 1678 : builder()->SetDeferredConstantPoolEntry(literal.second, shared_info);
899 : }
900 :
901 : // Build object literal constant properties
902 4519312 : for (std::pair<ObjectLiteral*, size_t> literal : object_literals_) {
903 256698 : ObjectLiteral* object_literal = literal.first;
904 256698 : if (object_literal->properties_count() > 0) {
905 : // If constant properties is an empty fixed array, we've already added it
906 : // to the constant pool when visiting the object literal.
907 : Handle<BoilerplateDescription> constant_properties =
908 : object_literal->GetOrBuildConstantProperties(isolate);
909 :
910 : builder()->SetDeferredConstantPoolEntry(literal.second,
911 256698 : constant_properties);
912 : }
913 : }
914 :
915 : // Build array literal constant elements
916 4374073 : for (std::pair<ArrayLiteral*, size_t> literal : array_literals_) {
917 : ArrayLiteral* array_literal = literal.first;
918 : Handle<ConstantElementsPair> constant_elements =
919 : array_literal->GetOrBuildConstantElements(isolate);
920 111459 : builder()->SetDeferredConstantPoolEntry(literal.second, constant_elements);
921 : }
922 :
923 : // Build template literals.
924 4264053 : for (std::pair<GetTemplateObject*, size_t> literal : template_objects_) {
925 : GetTemplateObject* get_template_object = literal.first;
926 : Handle<TemplateObjectDescription> description =
927 1439 : get_template_object->GetOrBuildDescription(isolate);
928 1439 : builder()->SetDeferredConstantPoolEntry(literal.second, description);
929 : }
930 : }
931 :
932 8701340 : void BytecodeGenerator::GenerateBytecode(uintptr_t stack_limit) {
933 : DisallowHeapAllocation no_allocation;
934 : DisallowHandleAllocation no_handles;
935 : DisallowHandleDereference no_deref;
936 :
937 : InitializeAstVisitor(stack_limit);
938 :
939 : // Initialize the incoming context.
940 2131320 : ContextScope incoming_context(this, closure_scope());
941 :
942 : // Initialize control scope.
943 : ControlScopeForTopLevel control(this);
944 :
945 2131326 : RegisterAllocationScope register_scope(this);
946 :
947 2131325 : AllocateTopLevelRegisters();
948 :
949 4262642 : if (info()->literal()->CanSuspend()) {
950 8286 : BuildGeneratorPrologue();
951 : }
952 :
953 2131323 : if (closure_scope()->NeedsContext()) {
954 : // Push a new inner context scope for the function.
955 176056 : BuildNewLocalActivationContext();
956 176056 : ContextScope local_function_context(this, closure_scope());
957 176056 : BuildLocalActivationContextInitialization();
958 176056 : GenerateBytecodeBody();
959 : } else {
960 1955267 : GenerateBytecodeBody();
961 : }
962 :
963 : // Check that we are not falling off the end.
964 2131325 : DCHECK(!builder()->RequiresImplicitReturn());
965 2131325 : }
966 :
967 23445004 : void BytecodeGenerator::GenerateBytecodeBody() {
968 : // Build the arguments object if it is used.
969 2131321 : VisitArgumentsObject(closure_scope()->arguments());
970 :
971 : // Build rest arguments array if it is used.
972 : Variable* rest_parameter = closure_scope()->rest_parameter();
973 2131323 : VisitRestArgumentsArray(rest_parameter);
974 :
975 : // Build assignment to {.this_function} variable if it is used.
976 2131323 : VisitThisFunctionVariable(closure_scope()->this_function_var());
977 :
978 : // Build assignment to {new.target} variable if it is used.
979 2131324 : VisitNewTargetVariable(closure_scope()->new_target_var());
980 :
981 : // Create a generator object if necessary and initialize the
982 : // {.generator_object} variable.
983 4262646 : if (info()->literal()->CanSuspend()) {
984 8286 : BuildGeneratorObjectVariableInitialization();
985 : }
986 :
987 : // Emit tracing call if requested to do so.
988 2131323 : if (FLAG_trace) builder()->CallRuntime(Runtime::kTraceEnter);
989 :
990 : // Emit type profile call.
991 2131323 : if (info()->collect_type_profile()) {
992 85 : feedback_spec()->AddTypeProfileSlot();
993 : int num_parameters = closure_scope()->num_parameters();
994 205 : for (int i = 0; i < num_parameters; i++) {
995 120 : Register parameter(builder()->Parameter(i));
996 120 : builder()->LoadAccumulatorWithRegister(parameter).CollectTypeProfile(
997 240 : closure_scope()->parameter(i)->initializer_position());
998 : }
999 : }
1000 :
1001 : // Visit declarations within the function scope.
1002 2131323 : VisitDeclarations(closure_scope()->declarations());
1003 :
1004 : // Emit initializing assignments for module namespace imports (if any).
1005 2131325 : VisitModuleNamespaceImports();
1006 :
1007 : // Perform a stack-check before the body.
1008 4262648 : builder()->StackCheck(info()->literal()->start_position());
1009 :
1010 : // Visit statements in the function body.
1011 2131325 : VisitStatements(info()->literal()->body());
1012 :
1013 : // Emit an implicit return instruction in case control flow can fall off the
1014 : // end of the function without an explicit return being present on all paths.
1015 2131326 : if (builder()->RequiresImplicitReturn()) {
1016 409670 : builder()->LoadUndefined();
1017 409670 : BuildReturn();
1018 : }
1019 2131326 : }
1020 :
1021 4262640 : void BytecodeGenerator::AllocateTopLevelRegisters() {
1022 4262640 : if (info()->literal()->CanSuspend()) {
1023 : // Allocate a register for generator_state_.
1024 8286 : generator_state_ = register_allocator()->NewRegister();
1025 : // Either directly use generator_object_var or allocate a new register for
1026 : // the incoming generator object.
1027 8286 : Variable* generator_object_var = closure_scope()->generator_object_var();
1028 8286 : if (generator_object_var->location() == VariableLocation::LOCAL) {
1029 : incoming_new_target_or_generator_ =
1030 7219 : GetRegisterForLocalVariable(generator_object_var);
1031 : } else {
1032 1067 : incoming_new_target_or_generator_ = register_allocator()->NewRegister();
1033 : }
1034 2123034 : } else if (closure_scope()->new_target_var()) {
1035 : // Either directly use new_target_var or allocate a new register for
1036 : // the incoming new target object.
1037 102885 : Variable* new_target_var = closure_scope()->new_target_var();
1038 102885 : if (new_target_var->location() == VariableLocation::LOCAL) {
1039 : incoming_new_target_or_generator_ =
1040 14261 : GetRegisterForLocalVariable(new_target_var);
1041 : } else {
1042 88624 : incoming_new_target_or_generator_ = register_allocator()->NewRegister();
1043 : }
1044 : }
1045 2131320 : }
1046 :
1047 222629 : void BytecodeGenerator::VisitIterationHeader(IterationStatement* stmt,
1048 : LoopBuilder* loop_builder) {
1049 : VisitIterationHeader(stmt->first_suspend_id(), stmt->suspend_count(),
1050 222629 : loop_builder);
1051 0 : }
1052 :
1053 222872 : void BytecodeGenerator::VisitIterationHeader(int first_suspend_id,
1054 : int suspend_count,
1055 4344 : LoopBuilder* loop_builder) {
1056 : // Recall that suspend_count is always zero inside ordinary (i.e.
1057 : // non-generator) functions.
1058 222872 : if (suspend_count == 0) {
1059 221786 : loop_builder->LoopHeader();
1060 : } else {
1061 : loop_builder->LoopHeaderInGenerator(&generator_jump_table_,
1062 1086 : first_suspend_id, suspend_count);
1063 :
1064 : // Perform state dispatch on the generator state, assuming this is a resume.
1065 : builder()
1066 1086 : ->LoadAccumulatorWithRegister(generator_state_)
1067 2172 : .SwitchOnSmiNoFeedback(generator_jump_table_);
1068 :
1069 : // We fall through when the generator state is not in the jump table. If we
1070 : // are not resuming, we want to fall through to the loop body.
1071 : // TODO(leszeks): Only generate this test for debug builds, we can skip it
1072 : // entirely in release assuming that the generator states is always valid.
1073 : BytecodeLabel not_resuming;
1074 : builder()
1075 1086 : ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting))
1076 1086 : .CompareOperation(Token::Value::EQ_STRICT, generator_state_)
1077 1086 : .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, ¬_resuming);
1078 :
1079 : // Otherwise this is an error.
1080 1086 : builder()->Abort(BailoutReason::kInvalidJumpTableIndex);
1081 :
1082 1086 : builder()->Bind(¬_resuming);
1083 : }
1084 222872 : }
1085 :
1086 49716 : void BytecodeGenerator::BuildGeneratorPrologue() {
1087 : DCHECK_GT(info()->literal()->suspend_count(), 0);
1088 : DCHECK(generator_state_.is_valid());
1089 : DCHECK(generator_object().is_valid());
1090 : generator_jump_table_ =
1091 16572 : builder()->AllocateJumpTable(info()->literal()->suspend_count(), 0);
1092 :
1093 : BytecodeLabel regular_call;
1094 : builder()
1095 8286 : ->LoadAccumulatorWithRegister(generator_object())
1096 8286 : .JumpIfUndefined(®ular_call);
1097 :
1098 : // This is a resume call. Restore the current context and the registers,
1099 : // then perform state dispatch.
1100 : {
1101 : RegisterAllocationScope register_scope(this);
1102 8286 : Register generator_context = register_allocator()->NewRegister();
1103 : builder()
1104 8286 : ->CallRuntime(Runtime::kInlineGeneratorGetContext, generator_object())
1105 8286 : .PushContext(generator_context)
1106 8286 : .RestoreGeneratorState(generator_object())
1107 8286 : .StoreAccumulatorInRegister(generator_state_)
1108 16572 : .SwitchOnSmiNoFeedback(generator_jump_table_);
1109 : }
1110 : // We fall through when the generator state is not in the jump table.
1111 : // TODO(leszeks): Only generate this for debug builds.
1112 8286 : builder()->Abort(BailoutReason::kInvalidJumpTableIndex);
1113 :
1114 : // This is a regular call.
1115 : builder()
1116 8286 : ->Bind(®ular_call)
1117 8286 : .LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting))
1118 8286 : .StoreAccumulatorInRegister(generator_state_);
1119 : // Now fall through to the ordinary function prologue, after which we will run
1120 : // into the generator object creation and other extra code inserted by the
1121 : // parser.
1122 8286 : }
1123 :
1124 10314960 : void BytecodeGenerator::VisitBlock(Block* stmt) {
1125 : // Visit declarations and statements.
1126 : CurrentScope current_scope(this, stmt->scope());
1127 5297794 : if (stmt->scope() != nullptr && stmt->scope()->NeedsContext()) {
1128 21426 : BuildNewLocalBlockContext(stmt->scope());
1129 21426 : ContextScope scope(this, stmt->scope());
1130 21426 : VisitBlockDeclarationsAndStatements(stmt);
1131 : } else {
1132 5125341 : VisitBlockDeclarationsAndStatements(stmt);
1133 : }
1134 5146767 : }
1135 :
1136 15440301 : void BytecodeGenerator::VisitBlockDeclarationsAndStatements(Block* stmt) {
1137 5146767 : BlockBuilder block_builder(builder(), block_coverage_builder_, stmt);
1138 : ControlScopeForBreakable execution_control(this, stmt, &block_builder);
1139 5146767 : if (stmt->scope() != nullptr) {
1140 151027 : VisitDeclarations(stmt->scope()->declarations());
1141 : }
1142 5146767 : VisitStatements(stmt->statements());
1143 5146766 : }
1144 :
1145 5605855 : void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) {
1146 5585697 : Variable* variable = decl->proxy()->var();
1147 3996868 : switch (variable->location()) {
1148 : case VariableLocation::UNALLOCATED: {
1149 : DCHECK(!variable->binding_needs_init());
1150 : FeedbackSlot slot =
1151 911195 : GetCachedLoadGlobalICSlot(NOT_INSIDE_TYPEOF, variable);
1152 : globals_builder()->AddUndefinedDeclaration(variable->raw_name(), slot);
1153 : break;
1154 : }
1155 : case VariableLocation::LOCAL:
1156 1463470 : if (variable->binding_needs_init()) {
1157 3153 : Register destination(builder()->Local(variable->index()));
1158 3153 : builder()->LoadTheHole().StoreAccumulatorInRegister(destination);
1159 : }
1160 : break;
1161 : case VariableLocation::PARAMETER:
1162 690 : if (variable->binding_needs_init()) {
1163 0 : Register destination(builder()->Parameter(variable->index()));
1164 0 : builder()->LoadTheHole().StoreAccumulatorInRegister(destination);
1165 : }
1166 : break;
1167 : case VariableLocation::CONTEXT:
1168 1320958 : if (variable->binding_needs_init()) {
1169 : DCHECK_EQ(0, execution_context()->ContextChainDepth(variable->scope()));
1170 391513 : builder()->LoadTheHole().StoreContextSlot(execution_context()->reg(),
1171 391513 : variable->index(), 0);
1172 : }
1173 : break;
1174 : case VariableLocation::LOOKUP: {
1175 : DCHECK_EQ(VAR, variable->mode());
1176 : DCHECK(!variable->binding_needs_init());
1177 :
1178 282968 : Register name = register_allocator()->NewRegister();
1179 :
1180 : builder()
1181 282968 : ->LoadLiteral(variable->raw_name())
1182 282968 : .StoreAccumulatorInRegister(name)
1183 282968 : .CallRuntime(Runtime::kDeclareEvalVar, name);
1184 : break;
1185 : }
1186 : case VariableLocation::MODULE:
1187 17587 : if (variable->IsExport() && variable->binding_needs_init()) {
1188 17005 : builder()->LoadTheHole();
1189 17005 : BuildVariableAssignment(variable, Token::INIT, HoleCheckMode::kElided);
1190 : }
1191 : // Nothing to do for imports.
1192 : break;
1193 : }
1194 3996868 : }
1195 :
1196 2490676 : void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) {
1197 1504229 : Variable* variable = decl->proxy()->var();
1198 : DCHECK(variable->mode() == LET || variable->mode() == VAR);
1199 789870 : switch (variable->location()) {
1200 : case VariableLocation::UNALLOCATED: {
1201 : FeedbackSlot slot =
1202 188756 : GetCachedLoadGlobalICSlot(NOT_INSIDE_TYPEOF, variable);
1203 188756 : FeedbackSlot literal_slot = GetCachedCreateClosureSlot(decl->fun());
1204 : globals_builder()->AddFunctionDeclaration(variable->raw_name(), slot,
1205 : literal_slot, decl->fun());
1206 : break;
1207 : }
1208 : case VariableLocation::PARAMETER:
1209 : case VariableLocation::LOCAL: {
1210 75175 : VisitForAccumulatorValue(decl->fun());
1211 75175 : BuildVariableAssignment(variable, Token::INIT, HoleCheckMode::kElided);
1212 75175 : break;
1213 : }
1214 : case VariableLocation::CONTEXT: {
1215 : DCHECK_EQ(0, execution_context()->ContextChainDepth(variable->scope()));
1216 517782 : VisitForAccumulatorValue(decl->fun());
1217 : builder()->StoreContextSlot(execution_context()->reg(), variable->index(),
1218 517782 : 0);
1219 517782 : break;
1220 : }
1221 : case VariableLocation::LOOKUP: {
1222 7821 : RegisterList args = register_allocator()->NewRegisterList(2);
1223 : builder()
1224 7821 : ->LoadLiteral(variable->raw_name())
1225 7821 : .StoreAccumulatorInRegister(args[0]);
1226 7821 : VisitForAccumulatorValue(decl->fun());
1227 7821 : builder()->StoreAccumulatorInRegister(args[1]).CallRuntime(
1228 7821 : Runtime::kDeclareEvalFunction, args);
1229 : break;
1230 : }
1231 : case VariableLocation::MODULE:
1232 : DCHECK_EQ(variable->mode(), LET);
1233 : DCHECK(variable->IsExport());
1234 336 : VisitForAccumulatorValue(decl->fun());
1235 336 : BuildVariableAssignment(variable, Token::INIT, HoleCheckMode::kElided);
1236 336 : break;
1237 : }
1238 789870 : }
1239 :
1240 2132571 : void BytecodeGenerator::VisitModuleNamespaceImports() {
1241 4261581 : if (!closure_scope()->is_module_scope()) return;
1242 :
1243 : RegisterAllocationScope register_scope(this);
1244 1067 : Register module_request = register_allocator()->NewRegister();
1245 :
1246 1067 : ModuleDescriptor* descriptor = closure_scope()->AsModuleScope()->module();
1247 2224 : for (auto entry : descriptor->namespace_imports()) {
1248 : builder()
1249 180 : ->LoadLiteral(Smi::FromInt(entry->module_request))
1250 90 : .StoreAccumulatorInRegister(module_request)
1251 90 : .CallRuntime(Runtime::kGetModuleNamespace, module_request);
1252 180 : Variable* var = closure_scope()->LookupLocal(entry->local_name);
1253 : DCHECK_NOT_NULL(var);
1254 90 : BuildVariableAssignment(var, Token::INIT, HoleCheckMode::kElided);
1255 1067 : }
1256 : }
1257 :
1258 5305479 : void BytecodeGenerator::VisitDeclarations(Declaration::List* declarations) {
1259 : RegisterAllocationScope register_scope(this);
1260 : DCHECK(globals_builder()->empty());
1261 9470126 : for (Declaration* decl : *declarations) {
1262 : RegisterAllocationScope register_scope(this);
1263 4786737 : Visit(decl);
1264 4786738 : }
1265 4594520 : if (globals_builder()->empty()) return;
1266 :
1267 : globals_builder()->set_constant_pool_entry(
1268 88870 : builder()->AllocateDeferredConstantPoolEntry());
1269 88870 : int encoded_flags = info()->GetDeclareGlobalsFlags();
1270 :
1271 : // Emit code to declare globals.
1272 88870 : RegisterList args = register_allocator()->NewRegisterList(3);
1273 : builder()
1274 177740 : ->LoadConstantPoolEntry(globals_builder()->constant_pool_entry())
1275 88870 : .StoreAccumulatorInRegister(args[0])
1276 88870 : .LoadLiteral(Smi::FromInt(encoded_flags))
1277 88870 : .StoreAccumulatorInRegister(args[1])
1278 177740 : .MoveRegister(Register::function_closure(), args[2])
1279 88870 : .CallRuntime(Runtime::kDeclareGlobalsForInterpreter, args);
1280 :
1281 : // Push and reset globals builder.
1282 177740 : global_declarations_.push_back(globals_builder());
1283 88870 : globals_builder_ = new (zone()) GlobalDeclarationsBuilder(zone());
1284 : }
1285 :
1286 28984316 : void BytecodeGenerator::VisitStatements(ZoneList<Statement*>* statements) {
1287 43211236 : for (int i = 0; i < statements->length(); i++) {
1288 : // Allocate an outer register allocations scope for the statement.
1289 : RegisterAllocationScope allocation_scope(this);
1290 16256450 : Statement* stmt = statements->at(i);
1291 16256450 : Visit(stmt);
1292 16256456 : if (stmt->IsJump()) break;
1293 14226921 : }
1294 7378704 : }
1295 :
1296 18694546 : void BytecodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
1297 : builder()->SetStatementPosition(stmt);
1298 9347273 : VisitForEffect(stmt->expression());
1299 9347276 : }
1300 :
1301 0 : void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
1302 0 : }
1303 :
1304 7004593 : void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) {
1305 : ConditionalControlFlowBuilder conditional_builder(
1306 1935326 : builder(), block_coverage_builder_, stmt);
1307 : builder()->SetStatementPosition(stmt);
1308 :
1309 967663 : if (stmt->condition()->ToBooleanIsTrue()) {
1310 : // Generate then block unconditionally as always true.
1311 332 : conditional_builder.Then();
1312 332 : Visit(stmt->then_statement());
1313 967331 : } else if (stmt->condition()->ToBooleanIsFalse()) {
1314 : // Generate else block unconditionally if it exists.
1315 8355 : if (stmt->HasElseStatement()) {
1316 7058 : conditional_builder.Else();
1317 7058 : Visit(stmt->else_statement());
1318 : }
1319 : } else {
1320 : // TODO(oth): If then statement is BreakStatement or
1321 : // ContinueStatement we can reduce number of generated
1322 : // jump/jump_ifs here. See BasicLoops test.
1323 : VisitForTest(stmt->condition(), conditional_builder.then_labels(),
1324 958976 : conditional_builder.else_labels(), TestFallthrough::kThen);
1325 :
1326 958975 : conditional_builder.Then();
1327 958975 : Visit(stmt->then_statement());
1328 :
1329 958975 : if (stmt->HasElseStatement()) {
1330 241269 : conditional_builder.JumpToEnd();
1331 241269 : conditional_builder.Else();
1332 241269 : Visit(stmt->else_statement());
1333 : }
1334 967662 : }
1335 967663 : }
1336 :
1337 3409 : void BytecodeGenerator::VisitSloppyBlockFunctionStatement(
1338 3409 : SloppyBlockFunctionStatement* stmt) {
1339 3409 : Visit(stmt->statement());
1340 3409 : }
1341 :
1342 26178 : void BytecodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
1343 : AllocateBlockCoverageSlotIfEnabled(stmt, SourceRangeKind::kContinuation);
1344 : builder()->SetStatementPosition(stmt);
1345 : execution_control()->Continue(stmt->target());
1346 8726 : }
1347 :
1348 203973 : void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
1349 : AllocateBlockCoverageSlotIfEnabled(stmt, SourceRangeKind::kContinuation);
1350 : builder()->SetStatementPosition(stmt);
1351 : execution_control()->Break(stmt->target());
1352 67991 : }
1353 :
1354 8689275 : void BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
1355 : AllocateBlockCoverageSlotIfEnabled(stmt, SourceRangeKind::kContinuation);
1356 : builder()->SetStatementPosition(stmt);
1357 2172318 : VisitForAccumulatorValue(stmt->expression());
1358 2172321 : if (stmt->is_async_return()) {
1359 : execution_control()->AsyncReturnAccumulator(stmt->end_position());
1360 : } else {
1361 : execution_control()->ReturnAccumulator(stmt->end_position());
1362 : }
1363 2172321 : }
1364 :
1365 12096 : void BytecodeGenerator::VisitWithStatement(WithStatement* stmt) {
1366 : builder()->SetStatementPosition(stmt);
1367 3024 : VisitForAccumulatorValue(stmt->expression());
1368 3024 : BuildNewLocalWithContext(stmt->scope());
1369 3024 : VisitInScope(stmt->statement(), stmt->scope());
1370 3024 : }
1371 :
1372 159953 : void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
1373 : // We need this scope because we visit for register values. We have to
1374 : // maintain a execution result scope where registers can be allocated.
1375 251229 : ZoneList<CaseClause*>* clauses = stmt->cases();
1376 : SwitchBuilder switch_builder(builder(), block_coverage_builder_, stmt,
1377 33342 : clauses->length());
1378 : ControlScopeForBreakable scope(this, stmt, &switch_builder);
1379 : int default_index = -1;
1380 :
1381 : builder()->SetStatementPosition(stmt);
1382 :
1383 : // Keep the switch value in a register until a case matches.
1384 16671 : Register tag = VisitForRegisterValue(stmt->tag());
1385 :
1386 : // Iterate over all cases and create nodes for label comparison.
1387 234558 : for (int i = 0; i < clauses->length(); i++) {
1388 100608 : CaseClause* clause = clauses->at(i);
1389 :
1390 : // The default is not a test, remember index.
1391 100608 : if (clause->is_default()) {
1392 : default_index = i;
1393 : continue;
1394 : }
1395 :
1396 : // Perform label comparison as if via '===' with tag.
1397 93269 : VisitForAccumulatorValue(clause->label());
1398 : builder()->CompareOperation(
1399 : Token::Value::EQ_STRICT, tag,
1400 186538 : feedback_index(feedback_spec()->AddCompareICSlot()));
1401 93269 : switch_builder.Case(ToBooleanMode::kAlreadyBoolean, i);
1402 : }
1403 :
1404 16671 : if (default_index >= 0) {
1405 : // Emit default jump if there is a default case.
1406 7339 : switch_builder.DefaultAt(default_index);
1407 : } else {
1408 : // Otherwise if we have reached here none of the cases matched, so jump to
1409 : // the end.
1410 : switch_builder.Break();
1411 : }
1412 :
1413 : // Iterate over all cases and create the case bodies.
1414 217887 : for (int i = 0; i < clauses->length(); i++) {
1415 201216 : CaseClause* clause = clauses->at(i);
1416 100608 : switch_builder.SetCaseTarget(i, clause);
1417 100608 : VisitStatements(clause->statements());
1418 16671 : }
1419 16671 : }
1420 :
1421 445998 : void BytecodeGenerator::VisitIterationBody(IterationStatement* stmt,
1422 222999 : LoopBuilder* loop_builder) {
1423 222999 : loop_builder->LoopBody();
1424 : ControlScopeForIteration execution_control(this, stmt, loop_builder);
1425 445998 : builder()->StackCheck(stmt->position());
1426 222999 : Visit(stmt->body());
1427 222999 : loop_builder->BindContinueTarget();
1428 222999 : }
1429 :
1430 19186 : void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
1431 5896 : LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt);
1432 2948 : if (stmt->cond()->ToBooleanIsFalse()) {
1433 370 : VisitIterationBody(stmt, &loop_builder);
1434 2578 : } else if (stmt->cond()->ToBooleanIsTrue()) {
1435 : VisitIterationHeader(stmt, &loop_builder);
1436 637 : VisitIterationBody(stmt, &loop_builder);
1437 637 : loop_builder.JumpToHeader(loop_depth_);
1438 : } else {
1439 : VisitIterationHeader(stmt, &loop_builder);
1440 1941 : VisitIterationBody(stmt, &loop_builder);
1441 : builder()->SetExpressionAsStatementPosition(stmt->cond());
1442 : BytecodeLabels loop_backbranch(zone());
1443 : VisitForTest(stmt->cond(), &loop_backbranch, loop_builder.break_labels(),
1444 1941 : TestFallthrough::kThen);
1445 1941 : loop_backbranch.Bind(builder());
1446 1941 : loop_builder.JumpToHeader(loop_depth_);
1447 2948 : }
1448 2948 : }
1449 :
1450 126069 : void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
1451 34794 : LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt);
1452 :
1453 17397 : if (stmt->cond()->ToBooleanIsFalse()) {
1454 : // If the condition is false there is no need to generate the loop.
1455 103 : return;
1456 : }
1457 :
1458 : VisitIterationHeader(stmt, &loop_builder);
1459 17294 : if (!stmt->cond()->ToBooleanIsTrue()) {
1460 : builder()->SetExpressionAsStatementPosition(stmt->cond());
1461 : BytecodeLabels loop_body(zone());
1462 : VisitForTest(stmt->cond(), &loop_body, loop_builder.break_labels(),
1463 14146 : TestFallthrough::kThen);
1464 14146 : loop_body.Bind(builder());
1465 : }
1466 17294 : VisitIterationBody(stmt, &loop_builder);
1467 17294 : loop_builder.JumpToHeader(loop_depth_);
1468 : }
1469 :
1470 2011976 : void BytecodeGenerator::VisitForStatement(ForStatement* stmt) {
1471 375458 : LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt);
1472 :
1473 187729 : if (stmt->init() != nullptr) {
1474 133175 : Visit(stmt->init());
1475 : }
1476 187729 : if (stmt->cond() && stmt->cond()->ToBooleanIsFalse()) {
1477 : // If the condition is known to be false there is no need to generate
1478 : // body, next or condition blocks. Init block should be generated.
1479 15464 : return;
1480 : }
1481 :
1482 : VisitIterationHeader(stmt, &loop_builder);
1483 172265 : if (stmt->cond() && !stmt->cond()->ToBooleanIsTrue()) {
1484 : builder()->SetExpressionAsStatementPosition(stmt->cond());
1485 : BytecodeLabels loop_body(zone());
1486 : VisitForTest(stmt->cond(), &loop_body, loop_builder.break_labels(),
1487 155482 : TestFallthrough::kThen);
1488 155482 : loop_body.Bind(builder());
1489 : }
1490 172265 : VisitIterationBody(stmt, &loop_builder);
1491 172265 : if (stmt->next() != nullptr) {
1492 : builder()->SetStatementPosition(stmt->next());
1493 147301 : Visit(stmt->next());
1494 : }
1495 172265 : loop_builder.JumpToHeader(loop_depth_);
1496 : }
1497 :
1498 6501 : void BytecodeGenerator::VisitForInAssignment(Expression* expr) {
1499 : DCHECK(expr->IsValidReferenceExpression());
1500 :
1501 : // Evaluate assignment starting with the value to be stored in the
1502 : // accumulator.
1503 6368 : Property* property = expr->AsProperty();
1504 6072 : LhsKind assign_type = Property::GetAssignType(property);
1505 6072 : switch (assign_type) {
1506 : case VARIABLE: {
1507 11848 : VariableProxy* proxy = expr->AsVariableProxy();
1508 : BuildVariableAssignment(proxy->var(), Token::ASSIGN,
1509 5924 : proxy->hole_check_mode());
1510 5924 : break;
1511 : }
1512 : case NAMED_PROPERTY: {
1513 : RegisterAllocationScope register_scope(this);
1514 23 : Register value = register_allocator()->NewRegister();
1515 23 : builder()->StoreAccumulatorInRegister(value);
1516 23 : Register object = VisitForRegisterValue(property->obj());
1517 : const AstRawString* name =
1518 46 : property->key()->AsLiteral()->AsRawPropertyName();
1519 23 : builder()->LoadAccumulatorWithRegister(value);
1520 23 : FeedbackSlot slot = feedback_spec()->AddStoreICSlot(language_mode());
1521 : builder()->StoreNamedProperty(object, name, feedback_index(slot),
1522 23 : language_mode());
1523 23 : break;
1524 : }
1525 : case KEYED_PROPERTY: {
1526 : RegisterAllocationScope register_scope(this);
1527 110 : Register value = register_allocator()->NewRegister();
1528 110 : builder()->StoreAccumulatorInRegister(value);
1529 110 : Register object = VisitForRegisterValue(property->obj());
1530 110 : Register key = VisitForRegisterValue(property->key());
1531 110 : builder()->LoadAccumulatorWithRegister(value);
1532 110 : FeedbackSlot slot = feedback_spec()->AddKeyedStoreICSlot(language_mode());
1533 : builder()->StoreKeyedProperty(object, key, feedback_index(slot),
1534 110 : language_mode());
1535 110 : break;
1536 : }
1537 : case NAMED_SUPER_PROPERTY: {
1538 : RegisterAllocationScope register_scope(this);
1539 5 : RegisterList args = register_allocator()->NewRegisterList(4);
1540 5 : builder()->StoreAccumulatorInRegister(args[3]);
1541 10 : SuperPropertyReference* super_property =
1542 5 : property->obj()->AsSuperPropertyReference();
1543 : VisitForRegisterValue(super_property->this_var(), args[0]);
1544 : VisitForRegisterValue(super_property->home_object(), args[1]);
1545 : builder()
1546 15 : ->LoadLiteral(property->key()->AsLiteral()->AsRawPropertyName())
1547 5 : .StoreAccumulatorInRegister(args[2])
1548 5 : .CallRuntime(StoreToSuperRuntimeId(), args);
1549 5 : break;
1550 : }
1551 : case KEYED_SUPER_PROPERTY: {
1552 : RegisterAllocationScope register_scope(this);
1553 10 : RegisterList args = register_allocator()->NewRegisterList(4);
1554 10 : builder()->StoreAccumulatorInRegister(args[3]);
1555 20 : SuperPropertyReference* super_property =
1556 10 : property->obj()->AsSuperPropertyReference();
1557 : VisitForRegisterValue(super_property->this_var(), args[0]);
1558 : VisitForRegisterValue(super_property->home_object(), args[1]);
1559 : VisitForRegisterValue(property->key(), args[2]);
1560 10 : builder()->CallRuntime(StoreKeyedToSuperRuntimeId(), args);
1561 10 : break;
1562 : }
1563 : }
1564 6072 : }
1565 :
1566 121530 : void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) {
1567 12234 : if (stmt->subject()->IsNullLiteral() ||
1568 6100 : stmt->subject()->IsUndefinedLiteral()) {
1569 : // ForIn generates lots of code, skip if it wouldn't produce any effects.
1570 62 : return;
1571 : }
1572 :
1573 : BytecodeLabel subject_null_label, subject_undefined_label;
1574 6072 : FeedbackSlot slot = feedback_spec()->AddForInSlot();
1575 :
1576 : // Prepare the state for executing ForIn.
1577 : builder()->SetExpressionAsStatementPosition(stmt->subject());
1578 6072 : VisitForAccumulatorValue(stmt->subject());
1579 6072 : builder()->JumpIfUndefined(&subject_undefined_label);
1580 6072 : builder()->JumpIfNull(&subject_null_label);
1581 6072 : Register receiver = register_allocator()->NewRegister();
1582 6072 : builder()->ToObject(receiver);
1583 :
1584 : // Used as kRegTriple and kRegPair in ForInPrepare and ForInNext.
1585 6072 : RegisterList triple = register_allocator()->NewRegisterList(3);
1586 6072 : Register cache_length = triple[2];
1587 6072 : builder()->ForInEnumerate(receiver);
1588 6072 : builder()->ForInPrepare(triple, feedback_index(slot));
1589 :
1590 : // Set up loop counter
1591 6072 : Register index = register_allocator()->NewRegister();
1592 6072 : builder()->LoadLiteral(Smi::kZero);
1593 6072 : builder()->StoreAccumulatorInRegister(index);
1594 :
1595 : // The loop
1596 : {
1597 12144 : LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt);
1598 : VisitIterationHeader(stmt, &loop_builder);
1599 : builder()->SetExpressionAsStatementPosition(stmt->each());
1600 6072 : builder()->ForInContinue(index, cache_length);
1601 : loop_builder.BreakIfFalse(ToBooleanMode::kAlreadyBoolean);
1602 : builder()->ForInNext(receiver, index, triple.Truncate(2),
1603 6072 : feedback_index(slot));
1604 : loop_builder.ContinueIfUndefined();
1605 6072 : VisitForInAssignment(stmt->each());
1606 6072 : VisitIterationBody(stmt, &loop_builder);
1607 6072 : builder()->ForInStep(index);
1608 6072 : builder()->StoreAccumulatorInRegister(index);
1609 6072 : loop_builder.JumpToHeader(loop_depth_);
1610 : }
1611 6072 : builder()->Bind(&subject_null_label);
1612 6072 : builder()->Bind(&subject_undefined_label);
1613 : }
1614 :
1615 195360 : void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
1616 48840 : LoopBuilder loop_builder(builder(), block_coverage_builder_, stmt);
1617 :
1618 : builder()->SetExpressionAsStatementPosition(stmt->assign_iterator());
1619 24420 : VisitForEffect(stmt->assign_iterator());
1620 :
1621 : VisitIterationHeader(stmt, &loop_builder);
1622 : builder()->SetExpressionAsStatementPosition(stmt->next_result());
1623 24420 : VisitForEffect(stmt->next_result());
1624 24420 : TypeHint type_hint = VisitForAccumulatorValue(stmt->result_done());
1625 : loop_builder.BreakIfTrue(ToBooleanModeFromTypeHint(type_hint));
1626 :
1627 24420 : VisitForEffect(stmt->assign_each());
1628 24420 : VisitIterationBody(stmt, &loop_builder);
1629 24420 : loop_builder.JumpToHeader(loop_depth_);
1630 24420 : }
1631 :
1632 894701 : void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
1633 : // Update catch prediction tracking. The updated catch_prediction value lasts
1634 : // until the end of the try_block in the AST node, and does not apply to the
1635 : // catch_block.
1636 : HandlerTable::CatchPrediction outer_catch_prediction = catch_prediction();
1637 : set_catch_prediction(stmt->GetCatchPrediction(outer_catch_prediction));
1638 :
1639 : TryCatchBuilder try_control_builder(builder(), catch_prediction());
1640 :
1641 : // Preserve the context in a dedicated register, so that it can be restored
1642 : // when the handler is entered by the stack-unwinding machinery.
1643 : // TODO(mstarzinger): Be smarter about register allocation.
1644 102122 : Register context = register_allocator()->NewRegister();
1645 204244 : builder()->MoveRegister(Register::current_context(), context);
1646 :
1647 : // Evaluate the try-block inside a control scope. This simulates a handler
1648 : // that is intercepting 'throw' control commands.
1649 102122 : try_control_builder.BeginTry(context);
1650 : {
1651 : ControlScopeForTryCatch scope(this, &try_control_builder);
1652 102122 : Visit(stmt->try_block());
1653 : set_catch_prediction(outer_catch_prediction);
1654 : }
1655 102122 : try_control_builder.EndTry();
1656 :
1657 : // Create a catch scope that binds the exception.
1658 102122 : BuildNewLocalCatchContext(stmt->scope());
1659 102122 : builder()->StoreAccumulatorInRegister(context);
1660 :
1661 : // If requested, clear message object as we enter the catch block.
1662 102122 : if (stmt->ShouldClearPendingException(outer_catch_prediction)) {
1663 77725 : builder()->LoadTheHole().SetPendingMessage();
1664 : }
1665 :
1666 : // Load the catch context into the accumulator.
1667 102122 : builder()->LoadAccumulatorWithRegister(context);
1668 :
1669 : // Evaluate the catch-block.
1670 : BuildIncrementBlockCoverageCounterIfEnabled(stmt, SourceRangeKind::kCatch);
1671 102122 : VisitInScope(stmt->catch_block(), stmt->scope());
1672 102122 : try_control_builder.EndCatch();
1673 : BuildIncrementBlockCoverageCounterIfEnabled(stmt,
1674 : SourceRangeKind::kContinuation);
1675 102122 : }
1676 :
1677 181560 : void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
1678 : // We can't know whether the finally block will override ("catch") an
1679 : // exception thrown in the try block, so we just adopt the outer prediction.
1680 36312 : TryFinallyBuilder try_control_builder(builder(), catch_prediction());
1681 :
1682 : // We keep a record of all paths that enter the finally-block to be able to
1683 : // dispatch to the correct continuation point after the statements in the
1684 : // finally-block have been evaluated.
1685 : //
1686 : // The try-finally construct can enter the finally-block in three ways:
1687 : // 1. By exiting the try-block normally, falling through at the end.
1688 : // 2. By exiting the try-block with a function-local control flow transfer
1689 : // (i.e. through break/continue/return statements).
1690 : // 3. By exiting the try-block with a thrown exception.
1691 : //
1692 : // The result register semantics depend on how the block was entered:
1693 : // - ReturnStatement: It represents the return value being returned.
1694 : // - ThrowStatement: It represents the exception being thrown.
1695 : // - BreakStatement/ContinueStatement: Undefined and not used.
1696 : // - Falling through into finally-block: Undefined and not used.
1697 36312 : Register token = register_allocator()->NewRegister();
1698 36312 : Register result = register_allocator()->NewRegister();
1699 : ControlScope::DeferredCommands commands(this, token, result);
1700 :
1701 : // Preserve the context in a dedicated register, so that it can be restored
1702 : // when the handler is entered by the stack-unwinding machinery.
1703 : // TODO(mstarzinger): Be smarter about register allocation.
1704 36312 : Register context = register_allocator()->NewRegister();
1705 72624 : builder()->MoveRegister(Register::current_context(), context);
1706 :
1707 : // Evaluate the try-block inside a control scope. This simulates a handler
1708 : // that is intercepting all control commands.
1709 36312 : try_control_builder.BeginTry(context);
1710 : {
1711 : ControlScopeForTryFinally scope(this, &try_control_builder, &commands);
1712 36312 : Visit(stmt->try_block());
1713 : }
1714 36312 : try_control_builder.EndTry();
1715 :
1716 : // Record fall-through and exception cases.
1717 36312 : commands.RecordFallThroughPath();
1718 36312 : try_control_builder.LeaveTry();
1719 36312 : try_control_builder.BeginHandler();
1720 : commands.RecordHandlerReThrowPath();
1721 :
1722 : // Pending message object is saved on entry.
1723 36312 : try_control_builder.BeginFinally();
1724 36312 : Register message = context; // Reuse register.
1725 :
1726 : // Clear message object as we enter the finally block.
1727 36312 : builder()->LoadTheHole().SetPendingMessage().StoreAccumulatorInRegister(
1728 36312 : message);
1729 :
1730 : // Evaluate the finally-block.
1731 : BuildIncrementBlockCoverageCounterIfEnabled(stmt, SourceRangeKind::kFinally);
1732 36312 : Visit(stmt->finally_block());
1733 36312 : try_control_builder.EndFinally();
1734 :
1735 : // Pending message object is restored on exit.
1736 36312 : builder()->LoadAccumulatorWithRegister(message).SetPendingMessage();
1737 :
1738 : // Dynamic dispatch after the finally-block.
1739 36312 : commands.ApplyDeferredCommands();
1740 : BuildIncrementBlockCoverageCounterIfEnabled(stmt,
1741 : SourceRangeKind::kContinuation);
1742 36312 : }
1743 :
1744 12608 : void BytecodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
1745 : builder()->SetStatementPosition(stmt);
1746 6304 : builder()->Debugger();
1747 0 : }
1748 :
1749 11904950 : void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
1750 : DCHECK_EQ(expr->scope()->outer_scope(), current_scope());
1751 : uint8_t flags = CreateClosureFlags::Encode(
1752 11904951 : expr->pretenure(), closure_scope()->is_function_scope());
1753 3968317 : size_t entry = builder()->AllocateDeferredConstantPoolEntry();
1754 3968319 : FeedbackSlot slot = GetCachedCreateClosureSlot(expr);
1755 7936632 : builder()->CreateClosure(entry, feedback_index(slot), flags);
1756 7936637 : function_literals_.push_back(std::make_pair(expr, entry));
1757 3968319 : }
1758 :
1759 534917 : void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr) {
1760 59344 : VisitDeclarations(expr->scope()->declarations());
1761 59344 : Register constructor = VisitForRegisterValue(expr->constructor());
1762 : {
1763 : RegisterAllocationScope register_scope(this);
1764 59344 : RegisterList args = register_allocator()->NewRegisterList(4);
1765 59344 : VisitForAccumulatorValueOrTheHole(expr->extends());
1766 : builder()
1767 59344 : ->StoreAccumulatorInRegister(args[0])
1768 59344 : .MoveRegister(constructor, args[1])
1769 59344 : .LoadLiteral(Smi::FromInt(expr->start_position()))
1770 59344 : .StoreAccumulatorInRegister(args[2])
1771 59344 : .LoadLiteral(Smi::FromInt(expr->end_position()))
1772 59344 : .StoreAccumulatorInRegister(args[3])
1773 59344 : .CallRuntime(Runtime::kDefineClass, args);
1774 : }
1775 59344 : Register prototype = register_allocator()->NewRegister();
1776 59344 : builder()->StoreAccumulatorInRegister(prototype);
1777 :
1778 59344 : if (FunctionLiteral::NeedsHomeObject(expr->constructor())) {
1779 : // Prototype is already in the accumulator.
1780 821 : FeedbackSlot slot = feedback_spec()->AddStoreICSlot(language_mode());
1781 : builder()->StoreHomeObjectProperty(constructor, feedback_index(slot),
1782 821 : language_mode());
1783 : }
1784 :
1785 59344 : VisitClassLiteralProperties(expr, constructor, prototype);
1786 59344 : BuildClassLiteralNameProperty(expr, constructor);
1787 59344 : builder()->CallRuntime(Runtime::kToFastProperties, constructor);
1788 : // Assign to class variable.
1789 59344 : if (expr->class_variable() != nullptr) {
1790 : DCHECK(expr->class_variable()->IsStackLocal() ||
1791 : expr->class_variable()->IsContextSlot());
1792 : BuildVariableAssignment(expr->class_variable(), Token::INIT,
1793 53563 : HoleCheckMode::kElided);
1794 : }
1795 59344 : }
1796 :
1797 153793 : void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr) {
1798 : CurrentScope current_scope(this, expr->scope());
1799 : DCHECK_NOT_NULL(expr->scope());
1800 59344 : if (expr->scope()->NeedsContext()) {
1801 35105 : BuildNewLocalBlockContext(expr->scope());
1802 35105 : ContextScope scope(this, expr->scope());
1803 35105 : BuildClassLiteral(expr);
1804 : } else {
1805 24239 : BuildClassLiteral(expr);
1806 : }
1807 59344 : }
1808 :
1809 515636 : void BytecodeGenerator::VisitClassLiteralProperties(ClassLiteral* expr,
1810 : Register constructor,
1811 490181 : Register prototype) {
1812 : RegisterAllocationScope register_scope(this);
1813 59344 : RegisterList args = register_allocator()->NewRegisterList(4);
1814 178032 : Register receiver = args[0], key = args[1], value = args[2], attr = args[3];
1815 :
1816 : bool attr_assigned = false;
1817 : Register old_receiver = Register::invalid_value();
1818 :
1819 : // Create nodes to store method values into the literal.
1820 912584 : for (int i = 0; i < expr->properties()->length(); i++) {
1821 1190844 : ClassLiteral::Property* property = expr->properties()->at(i);
1822 :
1823 : // Set-up receiver.
1824 396948 : Register new_receiver = property->is_static() ? constructor : prototype;
1825 396948 : if (new_receiver != old_receiver) {
1826 45368 : builder()->MoveRegister(new_receiver, receiver);
1827 : old_receiver = new_receiver;
1828 : }
1829 :
1830 396948 : BuildLoadPropertyKey(property, key);
1831 793896 : if (property->is_static() && property->is_computed_name()) {
1832 : // The static prototype property is read only. We handle the non computed
1833 : // property name case in the parser. Since this is the only case where we
1834 : // need to check for an own read only property we special case this so we
1835 : // do not need to do this for every property.
1836 : BytecodeLabel done;
1837 : builder()
1838 2798 : ->LoadLiteral(ast_string_constants()->prototype_string())
1839 1399 : .CompareOperation(Token::Value::EQ_STRICT, key)
1840 1399 : .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &done)
1841 1399 : .CallRuntime(Runtime::kThrowStaticPrototypeError)
1842 1399 : .Bind(&done);
1843 : }
1844 :
1845 : VisitForRegisterValue(property->value(), value);
1846 396948 : VisitSetHomeObject(value, receiver, property);
1847 :
1848 396948 : if (!attr_assigned) {
1849 : builder()
1850 45067 : ->LoadLiteral(Smi::FromInt(DONT_ENUM))
1851 45067 : .StoreAccumulatorInRegister(attr);
1852 : attr_assigned = true;
1853 : }
1854 :
1855 396948 : switch (property->kind()) {
1856 : case ClassLiteral::Property::METHOD: {
1857 : DataPropertyInLiteralFlags flags = DataPropertyInLiteralFlag::kDontEnum;
1858 388365 : if (property->NeedsSetFunctionName()) {
1859 : flags |= DataPropertyInLiteralFlag::kSetFunctionName;
1860 : }
1861 :
1862 : FeedbackSlot slot =
1863 388365 : feedback_spec()->AddStoreDataPropertyInLiteralICSlot();
1864 : builder()
1865 388365 : ->LoadAccumulatorWithRegister(value)
1866 : .StoreDataPropertyInLiteral(receiver, key, flags,
1867 388365 : feedback_index(slot));
1868 : break;
1869 : }
1870 : case ClassLiteral::Property::GETTER: {
1871 5712 : builder()->CallRuntime(Runtime::kDefineGetterPropertyUnchecked, args);
1872 5712 : break;
1873 : }
1874 : case ClassLiteral::Property::SETTER: {
1875 2871 : builder()->CallRuntime(Runtime::kDefineSetterPropertyUnchecked, args);
1876 2871 : break;
1877 : }
1878 : case ClassLiteral::Property::FIELD: {
1879 0 : UNREACHABLE();
1880 : break;
1881 : }
1882 : }
1883 59344 : }
1884 59344 : }
1885 :
1886 118601 : void BytecodeGenerator::BuildClassLiteralNameProperty(ClassLiteral* expr,
1887 53854 : Register literal) {
1888 118601 : if (!expr->has_name_static_property() &&
1889 59257 : expr->constructor()->has_shared_name()) {
1890 : Runtime::FunctionId runtime_id =
1891 : expr->has_static_computed_names()
1892 : ? Runtime::kInstallClassNameAccessorWithCheck
1893 53854 : : Runtime::kInstallClassNameAccessor;
1894 53854 : builder()->CallRuntime(runtime_id, literal);
1895 : }
1896 59344 : }
1897 :
1898 1678 : void BytecodeGenerator::VisitNativeFunctionLiteral(
1899 3356 : NativeFunctionLiteral* expr) {
1900 1678 : size_t entry = builder()->AllocateDeferredConstantPoolEntry();
1901 1678 : FeedbackSlot slot = feedback_spec()->AddCreateClosureSlot();
1902 1678 : builder()->CreateClosure(entry, feedback_index(slot), NOT_TENURED);
1903 3356 : native_function_literals_.push_back(std::make_pair(expr, entry));
1904 1678 : }
1905 :
1906 3862 : void BytecodeGenerator::VisitDoExpression(DoExpression* expr) {
1907 1931 : VisitBlock(expr->block());
1908 1931 : VisitVariableProxy(expr->result());
1909 1931 : }
1910 :
1911 334568 : void BytecodeGenerator::VisitConditional(Conditional* expr) {
1912 : ConditionalControlFlowBuilder conditional_builder(
1913 95862 : builder(), block_coverage_builder_, expr);
1914 :
1915 47931 : if (expr->condition()->ToBooleanIsTrue()) {
1916 : // Generate then block unconditionally as always true.
1917 241 : conditional_builder.Then();
1918 241 : VisitForAccumulatorValue(expr->then_expression());
1919 47690 : } else if (expr->condition()->ToBooleanIsFalse()) {
1920 : // Generate else block unconditionally if it exists.
1921 113 : conditional_builder.Else();
1922 113 : VisitForAccumulatorValue(expr->else_expression());
1923 : } else {
1924 : VisitForTest(expr->condition(), conditional_builder.then_labels(),
1925 47577 : conditional_builder.else_labels(), TestFallthrough::kThen);
1926 :
1927 47577 : conditional_builder.Then();
1928 47577 : VisitForAccumulatorValue(expr->then_expression());
1929 47577 : conditional_builder.JumpToEnd();
1930 :
1931 47577 : conditional_builder.Else();
1932 47577 : VisitForAccumulatorValue(expr->else_expression());
1933 47931 : }
1934 47931 : }
1935 :
1936 17637644 : void BytecodeGenerator::VisitLiteral(Literal* expr) {
1937 9310551 : if (!execution_result()->IsEffect()) {
1938 7996440 : const AstValue* raw_value = expr->raw_value();
1939 7996443 : builder()->LoadLiteral(raw_value);
1940 15873236 : if (raw_value->IsTrue() || raw_value->IsFalse()) {
1941 : execution_result()->SetResultIsBoolean();
1942 : }
1943 : }
1944 9310548 : }
1945 :
1946 115174 : void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
1947 : // Materialize a regular expression literal.
1948 : builder()->CreateRegExpLiteral(
1949 57587 : expr->raw_pattern(), feedback_index(feedback_spec()->AddLiteralSlot()),
1950 57587 : expr->flags());
1951 57587 : }
1952 :
1953 1742701 : void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
1954 : // Fast path for the empty object literal which doesn't need an
1955 : // AllocationSite.
1956 3619334 : if (expr->IsEmptyObjectLiteral()) {
1957 : DCHECK(expr->IsFastCloningSupported());
1958 40224 : builder()->CreateEmptyObjectLiteral();
1959 344009 : return;
1960 : }
1961 :
1962 263561 : int literal_index = feedback_index(feedback_spec()->AddLiteralSlot());
1963 : // Deep-copy the literal boilerplate.
1964 : uint8_t flags = CreateObjectLiteralFlags::Encode(
1965 263561 : expr->ComputeFlags(), expr->IsFastCloningSupported());
1966 :
1967 263561 : Register literal = register_allocator()->NewRegister();
1968 : size_t entry;
1969 : // If constant properties is an empty fixed array, use a cached empty fixed
1970 : // array to ensure it's only added to the constant pool once.
1971 263561 : if (expr->properties_count() == 0) {
1972 6863 : entry = builder()->EmptyFixedArrayConstantPoolEntry();
1973 : } else {
1974 256698 : entry = builder()->AllocateDeferredConstantPoolEntry();
1975 513396 : object_literals_.push_back(std::make_pair(expr, entry));
1976 : }
1977 : // TODO(cbruni): Directly generate runtime call for literals we cannot
1978 : // optimize once the CreateShallowObjectLiteral stub is in sync with the TF
1979 : // optimizations.
1980 527122 : builder()->CreateObjectLiteral(entry, literal_index, flags, literal);
1981 :
1982 : // Store computed values into the literal.
1983 : int property_index = 0;
1984 : AccessorTable accessor_table(zone());
1985 5305431 : for (; property_index < expr->properties()->length(); property_index++) {
1986 2879075 : ObjectLiteral::Property* property = expr->properties()->at(property_index);
1987 3537399 : if (property->is_computed_name()) break;
1988 4685692 : if (property->IsCompileTimeValue()) continue;
1989 :
1990 : RegisterAllocationScope inner_register_scope(this);
1991 684146 : Literal* key = property->key()->AsLiteral();
1992 356178 : switch (property->kind()) {
1993 : case ObjectLiteral::Property::SPREAD:
1994 : case ObjectLiteral::Property::CONSTANT:
1995 0 : UNREACHABLE();
1996 : case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1997 : DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value()));
1998 : // Fall through.
1999 : case ObjectLiteral::Property::COMPUTED: {
2000 : // It is safe to use [[Put]] here because the boilerplate already
2001 : // contains computed properties with an uninitialized value.
2002 328695 : if (key->IsStringLiteral()) {
2003 : DCHECK(key->IsPropertyName());
2004 328114 : if (property->emit_store()) {
2005 327968 : VisitForAccumulatorValue(property->value());
2006 327968 : FeedbackSlot slot = feedback_spec()->AddStoreOwnICSlot();
2007 327968 : if (FunctionLiteral::NeedsHomeObject(property->value())) {
2008 : RegisterAllocationScope register_scope(this);
2009 464 : Register value = register_allocator()->NewRegister();
2010 464 : builder()->StoreAccumulatorInRegister(value);
2011 : builder()->StoreNamedOwnProperty(
2012 928 : literal, key->AsRawPropertyName(), feedback_index(slot));
2013 464 : VisitSetHomeObject(value, literal, property);
2014 : } else {
2015 : builder()->StoreNamedOwnProperty(
2016 655008 : literal, key->AsRawPropertyName(), feedback_index(slot));
2017 : }
2018 : } else {
2019 146 : VisitForEffect(property->value());
2020 : }
2021 : } else {
2022 581 : RegisterList args = register_allocator()->NewRegisterList(4);
2023 :
2024 581 : builder()->MoveRegister(literal, args[0]);
2025 : VisitForRegisterValue(property->key(), args[1]);
2026 : VisitForRegisterValue(property->value(), args[2]);
2027 581 : if (property->emit_store()) {
2028 : builder()
2029 546 : ->LoadLiteral(Smi::FromEnum(LanguageMode::kSloppy))
2030 546 : .StoreAccumulatorInRegister(args[3])
2031 546 : .CallRuntime(Runtime::kSetProperty, args);
2032 546 : Register value = args[2];
2033 546 : VisitSetHomeObject(value, literal, property);
2034 : }
2035 : }
2036 : break;
2037 : }
2038 : case ObjectLiteral::Property::PROTOTYPE: {
2039 : // __proto__:null is handled by CreateObjectLiteral.
2040 22747 : if (property->IsNullPrototype()) break;
2041 : DCHECK(property->emit_store());
2042 : DCHECK(!property->NeedsSetFunctionName());
2043 1080 : RegisterList args = register_allocator()->NewRegisterList(2);
2044 1080 : builder()->MoveRegister(literal, args[0]);
2045 : VisitForRegisterValue(property->value(), args[1]);
2046 1080 : builder()->CallRuntime(Runtime::kInternalSetPrototype, args);
2047 1080 : break;
2048 : }
2049 : case ObjectLiteral::Property::GETTER:
2050 2829 : if (property->emit_store()) {
2051 2751 : accessor_table.lookup(key)->second->getter = property;
2052 : }
2053 : break;
2054 : case ObjectLiteral::Property::SETTER:
2055 1907 : if (property->emit_store()) {
2056 1841 : accessor_table.lookup(key)->second->setter = property;
2057 : }
2058 : break;
2059 : }
2060 356178 : }
2061 :
2062 : // Define accessors, using only a single call to the runtime for each pair of
2063 : // corresponding getters and setters.
2064 531122 : for (AccessorTable::Iterator it = accessor_table.begin();
2065 : it != accessor_table.end(); ++it) {
2066 : RegisterAllocationScope inner_register_scope(this);
2067 4000 : RegisterList args = register_allocator()->NewRegisterList(5);
2068 4000 : builder()->MoveRegister(literal, args[0]);
2069 4000 : VisitForRegisterValue(it->first, args[1]);
2070 4000 : VisitObjectLiteralAccessor(literal, it->second->getter, args[2]);
2071 4000 : VisitObjectLiteralAccessor(literal, it->second->setter, args[3]);
2072 : builder()
2073 4000 : ->LoadLiteral(Smi::FromInt(NONE))
2074 4000 : .StoreAccumulatorInRegister(args[4])
2075 4000 : .CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, args);
2076 4000 : }
2077 :
2078 : // Object literals have two parts. The "static" part on the left contains no
2079 : // computed property names, and so we can compute its map ahead of time; see
2080 : // Runtime_CreateObjectLiteralBoilerplate. The second "dynamic" part starts
2081 : // with the first computed property name and continues with all properties to
2082 : // its right. All the code from above initializes the static component of the
2083 : // object literal, and arranges for the map of the result to reflect the
2084 : // static order in which the keys appear. For the dynamic properties, we
2085 : // compile them into a series of "SetOwnProperty" runtime calls. This will
2086 : // preserve insertion order.
2087 271423 : for (; property_index < expr->properties()->length(); property_index++) {
2088 4213 : ObjectLiteral::Property* property = expr->properties()->at(property_index);
2089 : RegisterAllocationScope inner_register_scope(this);
2090 :
2091 3931 : if (property->IsPrototype()) {
2092 : // __proto__:null is handled by CreateObjectLiteral.
2093 46 : if (property->IsNullPrototype()) continue;
2094 : DCHECK(property->emit_store());
2095 : DCHECK(!property->NeedsSetFunctionName());
2096 40 : RegisterList args = register_allocator()->NewRegisterList(2);
2097 40 : builder()->MoveRegister(literal, args[0]);
2098 3925 : VisitForRegisterValue(property->value(), args[1]);
2099 40 : builder()->CallRuntime(Runtime::kInternalSetPrototype, args);
2100 40 : continue;
2101 : }
2102 :
2103 3885 : switch (property->kind()) {
2104 : case ObjectLiteral::Property::CONSTANT:
2105 : case ObjectLiteral::Property::COMPUTED:
2106 : case ObjectLiteral::Property::MATERIALIZED_LITERAL: {
2107 3403 : Register key = register_allocator()->NewRegister();
2108 3403 : BuildLoadPropertyKey(property, key);
2109 3403 : Register value = VisitForRegisterValue(property->value());
2110 3403 : VisitSetHomeObject(value, literal, property);
2111 :
2112 : DataPropertyInLiteralFlags data_property_flags =
2113 : DataPropertyInLiteralFlag::kNoFlags;
2114 3403 : if (property->NeedsSetFunctionName()) {
2115 : data_property_flags |= DataPropertyInLiteralFlag::kSetFunctionName;
2116 : }
2117 :
2118 : FeedbackSlot slot =
2119 3403 : feedback_spec()->AddStoreDataPropertyInLiteralICSlot();
2120 : builder()
2121 3403 : ->LoadAccumulatorWithRegister(value)
2122 : .StoreDataPropertyInLiteral(literal, key, data_property_flags,
2123 3403 : feedback_index(slot));
2124 : break;
2125 : }
2126 : case ObjectLiteral::Property::GETTER:
2127 : case ObjectLiteral::Property::SETTER: {
2128 282 : RegisterList args = register_allocator()->NewRegisterList(4);
2129 282 : builder()->MoveRegister(literal, args[0]);
2130 282 : BuildLoadPropertyKey(property, args[1]);
2131 : VisitForRegisterValue(property->value(), args[2]);
2132 282 : VisitSetHomeObject(args[2], literal, property);
2133 : builder()
2134 282 : ->LoadLiteral(Smi::FromInt(NONE))
2135 282 : .StoreAccumulatorInRegister(args[3]);
2136 : Runtime::FunctionId function_id =
2137 : property->kind() == ObjectLiteral::Property::GETTER
2138 : ? Runtime::kDefineGetterPropertyUnchecked
2139 282 : : Runtime::kDefineSetterPropertyUnchecked;
2140 282 : builder()->CallRuntime(function_id, args);
2141 : break;
2142 : }
2143 : case ObjectLiteral::Property::SPREAD: {
2144 200 : RegisterList args = register_allocator()->NewRegisterList(2);
2145 200 : builder()->MoveRegister(literal, args[0]);
2146 : VisitForRegisterValue(property->value(), args[1]);
2147 200 : builder()->CallRuntime(Runtime::kCopyDataProperties, args);
2148 : break;
2149 : }
2150 : case ObjectLiteral::Property::PROTOTYPE:
2151 0 : UNREACHABLE(); // Handled specially above.
2152 : break;
2153 : }
2154 3885 : }
2155 :
2156 263561 : builder()->LoadAccumulatorWithRegister(literal);
2157 : }
2158 :
2159 1308345 : void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
2160 : // Deep-copy the literal boilerplate.
2161 248665 : int literal_index = feedback_index(feedback_spec()->AddLiteralSlot());
2162 8292316 : if (expr->is_empty()) {
2163 : // Empty array literal fast-path.
2164 : DCHECK(expr->IsFastCloningSupported());
2165 137206 : builder()->CreateEmptyArrayLiteral(literal_index);
2166 385871 : return;
2167 : }
2168 :
2169 : uint8_t flags = CreateArrayLiteralFlags::Encode(
2170 111459 : expr->IsFastCloningSupported(), expr->ComputeFlags());
2171 111459 : size_t entry = builder()->AllocateDeferredConstantPoolEntry();
2172 222918 : builder()->CreateArrayLiteral(entry, literal_index, flags);
2173 222918 : array_literals_.push_back(std::make_pair(expr, entry));
2174 :
2175 : Register index, literal;
2176 :
2177 : // We'll reuse the same literal slot for all of the non-constant
2178 : // subexpressions that use a keyed store IC.
2179 :
2180 : // Evaluate all the non-constant subexpressions and store them into the
2181 : // newly cloned array.
2182 : bool literal_in_accumulator = true;
2183 : FeedbackSlot slot;
2184 16087302 : for (int array_index = 0; array_index < expr->values()->length();
2185 : array_index++) {
2186 7932192 : Expression* subexpr = expr->values()->at(array_index);
2187 7932192 : if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
2188 : DCHECK(!subexpr->IsSpread());
2189 :
2190 285376 : if (literal_in_accumulator) {
2191 64402 : index = register_allocator()->NewRegister();
2192 64402 : literal = register_allocator()->NewRegister();
2193 64402 : builder()->StoreAccumulatorInRegister(literal);
2194 : literal_in_accumulator = false;
2195 : }
2196 285376 : if (slot.IsInvalid()) {
2197 64402 : slot = feedback_spec()->AddKeyedStoreICSlot(language_mode());
2198 : }
2199 :
2200 : builder()
2201 285376 : ->LoadLiteral(Smi::FromInt(array_index))
2202 285376 : .StoreAccumulatorInRegister(index);
2203 285376 : VisitForAccumulatorValue(subexpr);
2204 : builder()->StoreKeyedProperty(literal, index, feedback_index(slot),
2205 285376 : language_mode());
2206 : }
2207 :
2208 111459 : if (!literal_in_accumulator) {
2209 : // Restore literal array into accumulator.
2210 64402 : builder()->LoadAccumulatorWithRegister(literal);
2211 : }
2212 : }
2213 :
2214 30352524 : void BytecodeGenerator::VisitVariableProxy(VariableProxy* proxy) {
2215 : builder()->SetExpressionPosition(proxy);
2216 10117508 : BuildVariableLoad(proxy->var(), proxy->hole_check_mode());
2217 10117509 : }
2218 :
2219 31312784 : void BytecodeGenerator::BuildVariableLoad(Variable* variable,
2220 : HoleCheckMode hole_check_mode,
2221 26126140 : TypeofMode typeof_mode) {
2222 11699929 : switch (variable->location()) {
2223 : case VariableLocation::LOCAL: {
2224 3585893 : Register source(builder()->Local(variable->index()));
2225 : // We need to load the variable into the accumulator, even when in a
2226 : // VisitForRegisterScope, in order to avoid register aliasing if
2227 : // subsequent expressions assign to the same variable.
2228 3585895 : builder()->LoadAccumulatorWithRegister(source);
2229 3585895 : if (hole_check_mode == HoleCheckMode::kRequired) {
2230 2470 : BuildThrowIfHole(variable);
2231 : }
2232 : break;
2233 : }
2234 : case VariableLocation::PARAMETER: {
2235 : Register source;
2236 2485107 : if (variable->IsReceiver()) {
2237 396365 : source = builder()->Receiver();
2238 : } else {
2239 2088742 : source = builder()->Parameter(variable->index());
2240 : }
2241 : // We need to load the variable into the accumulator, even when in a
2242 : // VisitForRegisterScope, in order to avoid register aliasing if
2243 : // subsequent expressions assign to the same variable.
2244 2485107 : builder()->LoadAccumulatorWithRegister(source);
2245 2485108 : if (hole_check_mode == HoleCheckMode::kRequired) {
2246 16267 : BuildThrowIfHole(variable);
2247 : }
2248 : break;
2249 : }
2250 : case VariableLocation::UNALLOCATED: {
2251 : // The global identifier "undefined" is immutable. Everything
2252 : // else could be reassigned. For performance, we do a pointer comparison
2253 : // rather than checking if the raw_name is really "undefined".
2254 2507969 : if (variable->raw_name() == ast_string_constants()->undefined_string()) {
2255 76524 : builder()->LoadUndefined();
2256 : } else {
2257 2431445 : FeedbackSlot slot = GetCachedLoadGlobalICSlot(typeof_mode, variable);
2258 : builder()->LoadGlobal(variable->raw_name(), feedback_index(slot),
2259 2431445 : typeof_mode);
2260 : }
2261 : break;
2262 : }
2263 : case VariableLocation::CONTEXT: {
2264 2738083 : int depth = execution_context()->ContextChainDepth(variable->scope());
2265 : ContextScope* context = execution_context()->Previous(depth);
2266 : Register context_reg;
2267 2738083 : if (context) {
2268 2710060 : context_reg = context->reg();
2269 : depth = 0;
2270 : } else {
2271 28023 : context_reg = execution_context()->reg();
2272 : }
2273 :
2274 : BytecodeArrayBuilder::ContextSlotMutability immutable =
2275 : (variable->maybe_assigned() == kNotAssigned)
2276 : ? BytecodeArrayBuilder::kImmutableSlot
2277 2738083 : : BytecodeArrayBuilder::kMutableSlot;
2278 :
2279 : builder()->LoadContextSlot(context_reg, variable->index(), depth,
2280 2738083 : immutable);
2281 2738082 : if (hole_check_mode == HoleCheckMode::kRequired) {
2282 170472 : BuildThrowIfHole(variable);
2283 : }
2284 : break;
2285 : }
2286 : case VariableLocation::LOOKUP: {
2287 381402 : switch (variable->mode()) {
2288 : case DYNAMIC_LOCAL: {
2289 7664 : Variable* local_variable = variable->local_if_not_shadowed();
2290 : int depth =
2291 3832 : execution_context()->ContextChainDepth(local_variable->scope());
2292 : builder()->LoadLookupContextSlot(variable->raw_name(), typeof_mode,
2293 3832 : local_variable->index(), depth);
2294 3832 : if (hole_check_mode == HoleCheckMode::kRequired) {
2295 1768 : BuildThrowIfHole(variable);
2296 : }
2297 : break;
2298 : }
2299 : case DYNAMIC_GLOBAL: {
2300 : int depth =
2301 365759 : closure_scope()->ContextChainLengthUntilOutermostSloppyEval();
2302 365759 : FeedbackSlot slot = GetCachedLoadGlobalICSlot(typeof_mode, variable);
2303 : builder()->LoadLookupGlobalSlot(variable->raw_name(), typeof_mode,
2304 365759 : feedback_index(slot), depth);
2305 : break;
2306 : }
2307 : default:
2308 11811 : builder()->LoadLookupSlot(variable->raw_name(), typeof_mode);
2309 : }
2310 : break;
2311 : }
2312 : case VariableLocation::MODULE: {
2313 1479 : int depth = execution_context()->ContextChainDepth(variable->scope());
2314 1479 : builder()->LoadModuleVariable(variable->index(), depth);
2315 1479 : if (hole_check_mode == HoleCheckMode::kRequired) {
2316 881 : BuildThrowIfHole(variable);
2317 : }
2318 : break;
2319 : }
2320 : }
2321 11699930 : }
2322 :
2323 1481524 : void BytecodeGenerator::BuildVariableLoadForAccumulatorValue(
2324 : Variable* variable, HoleCheckMode hole_check_mode, TypeofMode typeof_mode) {
2325 : ValueResultScope accumulator_result(this);
2326 1481524 : BuildVariableLoad(variable, hole_check_mode, typeof_mode);
2327 1481524 : }
2328 :
2329 12933715 : void BytecodeGenerator::BuildReturn(int source_position) {
2330 2586726 : if (FLAG_trace) {
2331 : RegisterAllocationScope register_scope(this);
2332 0 : Register result = register_allocator()->NewRegister();
2333 : // Runtime returns {result} value, preserving accumulator.
2334 0 : builder()->StoreAccumulatorInRegister(result).CallRuntime(
2335 0 : Runtime::kTraceExit, result);
2336 : }
2337 2586726 : if (info()->collect_type_profile()) {
2338 170 : builder()->CollectTypeProfile(info()->literal()->return_position());
2339 : }
2340 5173452 : builder()->SetReturnPosition(source_position, info()->literal());
2341 2586726 : builder()->Return();
2342 2586730 : }
2343 :
2344 11042 : void BytecodeGenerator::BuildAsyncReturn(int source_position) {
2345 : RegisterAllocationScope register_scope(this);
2346 :
2347 5208 : if (IsAsyncGeneratorFunction(info()->literal()->kind())) {
2348 989 : RegisterList args = register_allocator()->NewRegisterList(3);
2349 : builder()
2350 989 : ->MoveRegister(generator_object(), args[0]) // generator
2351 989 : .StoreAccumulatorInRegister(args[1]) // value
2352 989 : .LoadTrue()
2353 989 : .StoreAccumulatorInRegister(args[2]) // done
2354 989 : .CallRuntime(Runtime::kInlineAsyncGeneratorResolve, args);
2355 : } else {
2356 : DCHECK(IsAsyncFunction(info()->literal()->kind()));
2357 1615 : RegisterList args = register_allocator()->NewRegisterList(2);
2358 1615 : Register promise = args[0];
2359 1615 : Register return_value = args[1];
2360 1615 : builder()->StoreAccumulatorInRegister(return_value);
2361 :
2362 : Variable* var_promise = closure_scope()->promise_var();
2363 : DCHECK_NOT_NULL(var_promise);
2364 1615 : BuildVariableLoad(var_promise, HoleCheckMode::kElided);
2365 : builder()
2366 1615 : ->StoreAccumulatorInRegister(promise)
2367 1615 : .CallJSRuntime(Context::PROMISE_RESOLVE_INDEX, args)
2368 1615 : .LoadAccumulatorWithRegister(promise);
2369 : }
2370 :
2371 2604 : BuildReturn(source_position);
2372 2604 : }
2373 :
2374 36231 : void BytecodeGenerator::BuildReThrow() { builder()->ReThrow(); }
2375 :
2376 452116 : void BytecodeGenerator::BuildThrowIfHole(Variable* variable) {
2377 226058 : if (variable->is_this()) {
2378 : DCHECK(variable->mode() == CONST);
2379 16387 : builder()->ThrowSuperNotCalledIfHole();
2380 : } else {
2381 209671 : builder()->ThrowReferenceErrorIfHole(variable->raw_name());
2382 : }
2383 226058 : }
2384 :
2385 36315 : void BytecodeGenerator::BuildHoleCheckForVariableAssignment(Variable* variable,
2386 2115 : Token::Value op) {
2387 38430 : if (variable->is_this() && variable->mode() == CONST && op == Token::INIT) {
2388 : // Perform an initialization check for 'this'. 'this' variable is the
2389 : // only variable able to trigger bind operations outside the TDZ
2390 : // via 'super' calls.
2391 2115 : builder()->ThrowSuperAlreadyCalledIfNotHole();
2392 : } else {
2393 : // Perform an initialization check for let/const declared variables.
2394 : // E.g. let x = (x = 20); is not allowed.
2395 : DCHECK(IsLexicalVariableMode(variable->mode()));
2396 34200 : BuildThrowIfHole(variable);
2397 : }
2398 36315 : }
2399 :
2400 5583038 : void BytecodeGenerator::BuildVariableAssignment(
2401 12762731 : Variable* variable, Token::Value op, HoleCheckMode hole_check_mode,
2402 8776291 : LookupHoistingMode lookup_hoisting_mode) {
2403 : VariableMode mode = variable->mode();
2404 : RegisterAllocationScope assignment_register_scope(this);
2405 : BytecodeLabel end_label;
2406 5583038 : switch (variable->location()) {
2407 : case VariableLocation::PARAMETER:
2408 : case VariableLocation::LOCAL: {
2409 : Register destination;
2410 2893984 : if (VariableLocation::PARAMETER == variable->location()) {
2411 32248 : if (variable->IsReceiver()) {
2412 2043 : destination = builder()->Receiver();
2413 : } else {
2414 30205 : destination = builder()->Parameter(variable->index());
2415 : }
2416 : } else {
2417 2861736 : destination = builder()->Local(variable->index());
2418 : }
2419 :
2420 2893985 : if (hole_check_mode == HoleCheckMode::kRequired) {
2421 : // Load destination to check for hole.
2422 4640 : Register value_temp = register_allocator()->NewRegister();
2423 : builder()
2424 4640 : ->StoreAccumulatorInRegister(value_temp)
2425 4640 : .LoadAccumulatorWithRegister(destination);
2426 :
2427 4640 : BuildHoleCheckForVariableAssignment(variable, op);
2428 4640 : builder()->LoadAccumulatorWithRegister(value_temp);
2429 : }
2430 :
2431 2893985 : if (mode != CONST || op == Token::INIT) {
2432 2889094 : builder()->StoreAccumulatorInRegister(destination);
2433 4891 : } else if (variable->throw_on_const_assignment(language_mode())) {
2434 4858 : builder()->CallRuntime(Runtime::kThrowConstAssignError);
2435 : }
2436 : break;
2437 : }
2438 : case VariableLocation::UNALLOCATED: {
2439 : // TODO(ishell): consider using FeedbackSlotCache for variables here.
2440 : FeedbackSlot slot =
2441 1064785 : feedback_spec()->AddStoreGlobalICSlot(language_mode());
2442 : builder()->StoreGlobal(variable->raw_name(), feedback_index(slot),
2443 1064785 : language_mode());
2444 : break;
2445 : }
2446 : case VariableLocation::CONTEXT: {
2447 1558542 : int depth = execution_context()->ContextChainDepth(variable->scope());
2448 : ContextScope* context = execution_context()->Previous(depth);
2449 : Register context_reg;
2450 :
2451 1558542 : if (context) {
2452 1549696 : context_reg = context->reg();
2453 : depth = 0;
2454 : } else {
2455 8846 : context_reg = execution_context()->reg();
2456 : }
2457 :
2458 1558542 : if (hole_check_mode == HoleCheckMode::kRequired) {
2459 : // Load destination to check for hole.
2460 31591 : Register value_temp = register_allocator()->NewRegister();
2461 : builder()
2462 31591 : ->StoreAccumulatorInRegister(value_temp)
2463 : .LoadContextSlot(context_reg, variable->index(), depth,
2464 31591 : BytecodeArrayBuilder::kMutableSlot);
2465 :
2466 31591 : BuildHoleCheckForVariableAssignment(variable, op);
2467 31591 : builder()->LoadAccumulatorWithRegister(value_temp);
2468 : }
2469 :
2470 1558542 : if (mode != CONST || op == Token::INIT) {
2471 1530452 : builder()->StoreContextSlot(context_reg, variable->index(), depth);
2472 28090 : } else if (variable->throw_on_const_assignment(language_mode())) {
2473 28068 : builder()->CallRuntime(Runtime::kThrowConstAssignError);
2474 : }
2475 : break;
2476 : }
2477 : case VariableLocation::LOOKUP: {
2478 : builder()->StoreLookupSlot(variable->raw_name(), language_mode(),
2479 30935 : lookup_hoisting_mode);
2480 30935 : break;
2481 : }
2482 : case VariableLocation::MODULE: {
2483 : DCHECK(IsDeclaredVariableMode(mode));
2484 :
2485 34792 : if (mode == CONST && op != Token::INIT) {
2486 132 : builder()->CallRuntime(Runtime::kThrowConstAssignError);
2487 132 : break;
2488 : }
2489 :
2490 : // If we don't throw above, we know that we're dealing with an
2491 : // export because imports are const and we do not generate initializing
2492 : // assignments for them.
2493 : DCHECK(variable->IsExport());
2494 :
2495 34660 : int depth = execution_context()->ContextChainDepth(variable->scope());
2496 34660 : if (hole_check_mode == HoleCheckMode::kRequired) {
2497 84 : Register value_temp = register_allocator()->NewRegister();
2498 : builder()
2499 84 : ->StoreAccumulatorInRegister(value_temp)
2500 84 : .LoadModuleVariable(variable->index(), depth);
2501 84 : BuildHoleCheckForVariableAssignment(variable, op);
2502 84 : builder()->LoadAccumulatorWithRegister(value_temp);
2503 : }
2504 34660 : builder()->StoreModuleVariable(variable->index(), depth);
2505 34660 : break;
2506 : }
2507 5583039 : }
2508 5583039 : }
2509 :
2510 38555807 : void BytecodeGenerator::VisitAssignment(Assignment* expr) {
2511 : DCHECK(expr->target()->IsValidReferenceExpression() ||
2512 : (expr->op() == Token::INIT && expr->target()->IsVariableProxy() &&
2513 : expr->target()->AsVariableProxy()->is_this()));
2514 : Register object, key;
2515 : RegisterList super_property_args;
2516 : const AstRawString* name;
2517 :
2518 : // Left-hand side can only be a property, a global or a variable slot.
2519 9807430 : Property* property = expr->target()->AsProperty();
2520 6628060 : LhsKind assign_type = Property::GetAssignType(property);
2521 :
2522 : // Evaluate LHS expression.
2523 6628062 : switch (assign_type) {
2524 : case VARIABLE:
2525 : // Nothing to do to evaluate variable assignment LHS.
2526 : break;
2527 : case NAMED_PROPERTY: {
2528 1529450 : object = VisitForRegisterValue(property->obj());
2529 3058900 : name = property->key()->AsLiteral()->AsRawPropertyName();
2530 1529450 : break;
2531 : }
2532 : case KEYED_PROPERTY: {
2533 59687 : object = VisitForRegisterValue(property->obj());
2534 59687 : key = VisitForRegisterValue(property->key());
2535 59687 : break;
2536 : }
2537 : case NAMED_SUPER_PROPERTY: {
2538 217 : super_property_args = register_allocator()->NewRegisterList(4);
2539 434 : SuperPropertyReference* super_property =
2540 217 : property->obj()->AsSuperPropertyReference();
2541 : VisitForRegisterValue(super_property->this_var(), super_property_args[0]);
2542 : VisitForRegisterValue(super_property->home_object(),
2543 : super_property_args[1]);
2544 : builder()
2545 651 : ->LoadLiteral(property->key()->AsLiteral()->AsRawPropertyName())
2546 217 : .StoreAccumulatorInRegister(super_property_args[2]);
2547 217 : break;
2548 : }
2549 : case KEYED_SUPER_PROPERTY: {
2550 331 : super_property_args = register_allocator()->NewRegisterList(4);
2551 662 : SuperPropertyReference* super_property =
2552 331 : property->obj()->AsSuperPropertyReference();
2553 : VisitForRegisterValue(super_property->this_var(), super_property_args[0]);
2554 : VisitForRegisterValue(super_property->home_object(),
2555 : super_property_args[1]);
2556 : VisitForRegisterValue(property->key(), super_property_args[2]);
2557 : break;
2558 : }
2559 : }
2560 :
2561 : // Evaluate the value and potentially handle compound assignments by loading
2562 : // the left-hand side value and performing a binary operation.
2563 6628062 : if (expr->IsCompoundAssignment()) {
2564 100697 : switch (assign_type) {
2565 : case VARIABLE: {
2566 297840 : VariableProxy* proxy = expr->target()->AsVariableProxy();
2567 99280 : BuildVariableLoad(proxy->var(), proxy->hole_check_mode());
2568 99280 : break;
2569 : }
2570 : case NAMED_PROPERTY: {
2571 527 : FeedbackSlot slot = feedback_spec()->AddLoadICSlot();
2572 527 : builder()->LoadNamedProperty(object, name, feedback_index(slot));
2573 : break;
2574 : }
2575 : case KEYED_PROPERTY: {
2576 : // Key is already in accumulator at this point due to evaluating the
2577 : // LHS above.
2578 830 : FeedbackSlot slot = feedback_spec()->AddKeyedLoadICSlot();
2579 830 : builder()->LoadKeyedProperty(object, feedback_index(slot));
2580 : break;
2581 : }
2582 : case NAMED_SUPER_PROPERTY: {
2583 : builder()->CallRuntime(Runtime::kLoadFromSuper,
2584 20 : super_property_args.Truncate(3));
2585 20 : break;
2586 : }
2587 : case KEYED_SUPER_PROPERTY: {
2588 : builder()->CallRuntime(Runtime::kLoadKeyedFromSuper,
2589 40 : super_property_args.Truncate(3));
2590 40 : break;
2591 : }
2592 : }
2593 302091 : BinaryOperation* binop = expr->AsCompoundAssignment()->binary_operation();
2594 100697 : FeedbackSlot slot = feedback_spec()->AddBinaryOpICSlot();
2595 100697 : if (expr->value()->IsSmiLiteral()) {
2596 : builder()->BinaryOperationSmiLiteral(
2597 : binop->op(), expr->value()->AsLiteral()->AsSmiLiteral(),
2598 51756 : feedback_index(slot));
2599 : } else {
2600 74819 : Register old_value = register_allocator()->NewRegister();
2601 74819 : builder()->StoreAccumulatorInRegister(old_value);
2602 74819 : VisitForAccumulatorValue(expr->value());
2603 74819 : builder()->BinaryOperation(binop->op(), old_value, feedback_index(slot));
2604 : }
2605 : } else {
2606 6527365 : VisitForAccumulatorValue(expr->value());
2607 : }
2608 :
2609 : // Store the value.
2610 : builder()->SetExpressionPosition(expr);
2611 6628061 : switch (assign_type) {
2612 : case VARIABLE: {
2613 : // TODO(oth): The BuildVariableAssignment() call is hard to reason about.
2614 : // Is the value in the accumulator safe? Yes, but scary.
2615 15115128 : VariableProxy* proxy = expr->target()->AsVariableProxy();
2616 : BuildVariableAssignment(proxy->var(), expr->op(),
2617 : proxy->hole_check_mode(),
2618 5038376 : expr->lookup_hoisting_mode());
2619 5038377 : break;
2620 : }
2621 : case NAMED_PROPERTY: {
2622 1529450 : FeedbackSlot slot = feedback_spec()->AddStoreICSlot(language_mode());
2623 : builder()->StoreNamedProperty(object, name, feedback_index(slot),
2624 1529450 : language_mode());
2625 : break;
2626 : }
2627 : case KEYED_PROPERTY: {
2628 59687 : FeedbackSlot slot = feedback_spec()->AddKeyedStoreICSlot(language_mode());
2629 : builder()->StoreKeyedProperty(object, key, feedback_index(slot),
2630 59687 : language_mode());
2631 : break;
2632 : }
2633 : case NAMED_SUPER_PROPERTY: {
2634 : builder()
2635 217 : ->StoreAccumulatorInRegister(super_property_args[3])
2636 217 : .CallRuntime(StoreToSuperRuntimeId(), super_property_args);
2637 217 : break;
2638 : }
2639 : case KEYED_SUPER_PROPERTY: {
2640 : builder()
2641 331 : ->StoreAccumulatorInRegister(super_property_args[3])
2642 331 : .CallRuntime(StoreKeyedToSuperRuntimeId(), super_property_args);
2643 331 : break;
2644 : }
2645 : }
2646 6628062 : }
2647 :
2648 100697 : void BytecodeGenerator::VisitCompoundAssignment(CompoundAssignment* expr) {
2649 100697 : VisitAssignment(expr);
2650 100697 : }
2651 :
2652 : // Suspends the generator to resume at |suspend_id|, with output stored in the
2653 : // accumulator. When the generator is resumed, the sent value is loaded in the
2654 : // accumulator.
2655 160368 : void BytecodeGenerator::BuildSuspendPoint(int suspend_id) {
2656 20046 : RegisterList registers(0, register_allocator()->next_register_index());
2657 :
2658 : // Save context, registers, and state. Then return.
2659 20046 : builder()->SuspendGenerator(generator_object(), registers, suspend_id);
2660 :
2661 40092 : builder()->SetReturnPosition(kNoSourcePosition, info()->literal());
2662 20046 : builder()->Return(); // Hard return (ignore any finally blocks).
2663 :
2664 : // Upon resume, we continue here.
2665 40092 : builder()->Bind(generator_jump_table_, suspend_id);
2666 :
2667 : // Clobbers all registers.
2668 20046 : builder()->RestoreGeneratorRegisters(generator_object(), registers);
2669 :
2670 : // Update state to indicate that we have finished resuming. Loop headers
2671 : // rely on this.
2672 : builder()
2673 20046 : ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting))
2674 20046 : .StoreAccumulatorInRegister(generator_state_);
2675 :
2676 : // When resuming execution of a generator, module or async function, the sent
2677 : // value is in the [[input_or_debug_pos]] slot.
2678 : builder()->CallRuntime(Runtime::kInlineGeneratorGetInputOrDebugPos,
2679 20046 : generator_object());
2680 20046 : }
2681 :
2682 112161 : void BytecodeGenerator::VisitYield(Yield* expr) {
2683 : builder()->SetExpressionPosition(expr);
2684 27018 : VisitForAccumulatorValue(expr->expression());
2685 :
2686 9006 : if (!expr->IsInitialYield()) {
2687 3729 : if (IsAsyncGeneratorFunction(function_kind())) {
2688 : // AsyncGenerator yields (with the exception of the initial yield)
2689 : // delegate work to the AsyncGeneratorYield stub, which Awaits the operand
2690 : // and on success, wraps the value in an IteratorResult.
2691 : RegisterAllocationScope register_scope(this);
2692 360 : RegisterList args = register_allocator()->NewRegisterList(3);
2693 : builder()
2694 360 : ->MoveRegister(generator_object(), args[0]) // generator
2695 360 : .StoreAccumulatorInRegister(args[1]) // value
2696 720 : .LoadBoolean(catch_prediction() != HandlerTable::ASYNC_AWAIT)
2697 360 : .StoreAccumulatorInRegister(args[2]) // is_caught
2698 360 : .CallRuntime(Runtime::kInlineAsyncGeneratorYield, args);
2699 : } else {
2700 : // Generator yields (with the exception of the initial yield) wrap the
2701 : // value into IteratorResult.
2702 : RegisterAllocationScope register_scope(this);
2703 3369 : RegisterList args = register_allocator()->NewRegisterList(2);
2704 : builder()
2705 3369 : ->StoreAccumulatorInRegister(args[0]) // value
2706 3369 : .LoadFalse()
2707 3369 : .StoreAccumulatorInRegister(args[1]) // done
2708 3369 : .CallRuntime(Runtime::kInlineCreateIterResultObject, args);
2709 : }
2710 : }
2711 :
2712 9006 : BuildSuspendPoint(expr->suspend_id());
2713 : // At this point, the generator has been resumed, with the received value in
2714 : // the accumulator.
2715 :
2716 : // TODO(caitp): remove once yield* desugaring for async generators is handled
2717 : // in BytecodeGenerator.
2718 9006 : if (expr->on_abrupt_resume() == Yield::kNoControl) {
2719 : DCHECK(IsAsyncGeneratorFunction(function_kind()));
2720 0 : return;
2721 : }
2722 :
2723 9006 : Register input = register_allocator()->NewRegister();
2724 9006 : builder()->StoreAccumulatorInRegister(input).CallRuntime(
2725 9006 : Runtime::kInlineGeneratorGetResumeMode, generator_object());
2726 :
2727 : // Now dispatch on resume mode.
2728 : STATIC_ASSERT(JSGeneratorObject::kNext + 1 == JSGeneratorObject::kReturn);
2729 : BytecodeJumpTable* jump_table =
2730 9006 : builder()->AllocateJumpTable(2, JSGeneratorObject::kNext);
2731 :
2732 9006 : builder()->SwitchOnSmiNoFeedback(jump_table);
2733 :
2734 : {
2735 : // Resume with throw (switch fallthrough).
2736 : // TODO(leszeks): Add a debug-only check that the accumulator is
2737 : // JSGeneratorObject::kThrow.
2738 : builder()->SetExpressionPosition(expr);
2739 9006 : builder()->LoadAccumulatorWithRegister(input);
2740 9006 : builder()->Throw();
2741 : }
2742 :
2743 : {
2744 : // Resume with return.
2745 9006 : builder()->Bind(jump_table, JSGeneratorObject::kReturn);
2746 9006 : builder()->LoadAccumulatorWithRegister(input);
2747 9006 : if (IsAsyncGeneratorFunction(function_kind())) {
2748 : execution_control()->AsyncReturnAccumulator();
2749 : } else {
2750 : execution_control()->ReturnAccumulator();
2751 : }
2752 : }
2753 :
2754 : {
2755 : // Resume with next.
2756 9006 : builder()->Bind(jump_table, JSGeneratorObject::kNext);
2757 : BuildIncrementBlockCoverageCounterIfEnabled(expr,
2758 : SourceRangeKind::kContinuation);
2759 9006 : builder()->LoadAccumulatorWithRegister(input);
2760 : }
2761 : }
2762 :
2763 : // Desugaring of (yield* iterable)
2764 : //
2765 : // do {
2766 : // const kNext = 0;
2767 : // const kReturn = 1;
2768 : // const kThrow = 2;
2769 : //
2770 : // let output; // uninitialized
2771 : //
2772 : // let iterator = GetIterator(iterable);
2773 : // let input = undefined;
2774 : // let resumeMode = kNext;
2775 : //
2776 : // while (true) {
2777 : // // From the generator to the iterator:
2778 : // // Forward input according to resumeMode and obtain output.
2779 : // switch (resumeMode) {
2780 : // case kNext:
2781 : // output = iterator.next(input);
2782 : // break;
2783 : // case kReturn:
2784 : // let iteratorReturn = iterator.return;
2785 : // if (IS_NULL_OR_UNDEFINED(iteratorReturn)) return input;
2786 : // output = %_Call(iteratorReturn, iterator, input);
2787 : // break;
2788 : // case kThrow:
2789 : // let iteratorThrow = iterator.throw;
2790 : // if (IS_NULL_OR_UNDEFINED(iteratorThrow)) {
2791 : // let iteratorReturn = iterator.return;
2792 : // if (!IS_NULL_OR_UNDEFINED(iteratorReturn)) {
2793 : // output = %_Call(iteratorReturn, iterator);
2794 : // if (IS_ASYNC_GENERATOR) output = await output;
2795 : // if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
2796 : // }
2797 : // throw MakeTypeError(kThrowMethodMissing);
2798 : // }
2799 : // output = %_Call(iteratorThrow, iterator, input);
2800 : // break;
2801 : // }
2802 : //
2803 : // if (IS_ASYNC_GENERATOR) output = await output;
2804 : // if (!IS_RECEIVER(output)) %ThrowIterResultNotAnObject(output);
2805 : // if (output.done) break;
2806 : //
2807 : // // From the generator to its user:
2808 : // // Forward output, receive new input, and determine resume mode.
2809 : // if (IS_ASYNC_GENERATOR) {
2810 : // // AsyncGeneratorYield abstract operation awaits the operand before
2811 : // // resolving the promise for the current AsyncGeneratorRequest.
2812 : // %_AsyncGeneratorYield(output.value)
2813 : // }
2814 : // input = Suspend(output);
2815 : // resumeMode = %GeneratorGetResumeMode();
2816 : // }
2817 : //
2818 : // if (resumeMode === kReturn) {
2819 : // return output.value;
2820 : // }
2821 : // output.value
2822 : // }
2823 10758 : void BytecodeGenerator::VisitYieldStar(YieldStar* expr) {
2824 243 : Register output = register_allocator()->NewRegister();
2825 243 : Register resume_mode = register_allocator()->NewRegister();
2826 : IteratorType iterator_type = IsAsyncGeneratorFunction(function_kind())
2827 : ? IteratorType::kAsync
2828 243 : : IteratorType::kNormal;
2829 :
2830 : {
2831 : RegisterAllocationScope register_scope(this);
2832 :
2833 243 : RegisterList iterator_and_input = register_allocator()->NewRegisterList(2);
2834 :
2835 : Register iterator = iterator_and_input[0];
2836 :
2837 729 : BuildGetIterator(expr->expression(), iterator_type);
2838 243 : builder()->StoreAccumulatorInRegister(iterator);
2839 243 : Register input = iterator_and_input[1];
2840 243 : builder()->LoadUndefined().StoreAccumulatorInRegister(input);
2841 : builder()
2842 243 : ->LoadLiteral(Smi::FromInt(JSGeneratorObject::kNext))
2843 243 : .StoreAccumulatorInRegister(resume_mode);
2844 :
2845 : {
2846 : // This loop builder does not construct counters as the loop is not
2847 : // visible to the user, and we therefore neither pass the block coverage
2848 : // builder nor the expression.
2849 : //
2850 : // YieldStar in AsyncGenerator functions includes 3 suspend points, rather
2851 : // than 1. These are documented in the YieldStar AST node.
2852 243 : LoopBuilder loop(builder(), nullptr, nullptr);
2853 243 : VisitIterationHeader(expr->suspend_id(), expr->suspend_count(), &loop);
2854 :
2855 : {
2856 : BytecodeLabels after_switch(zone());
2857 : BytecodeJumpTable* switch_jump_table =
2858 243 : builder()->AllocateJumpTable(2, 1);
2859 :
2860 : builder()
2861 243 : ->LoadAccumulatorWithRegister(resume_mode)
2862 243 : .SwitchOnSmiNoFeedback(switch_jump_table);
2863 :
2864 : // Fallthrough to default case.
2865 : // TODO(tebbi): Add debug code to check that {resume_mode} really is
2866 : // {JSGeneratorObject::kNext} in this case.
2867 : STATIC_ASSERT(JSGeneratorObject::kNext == 0);
2868 : {
2869 : RegisterAllocationScope register_scope(this);
2870 : // output = iterator.next(input);
2871 243 : Register iterator_next = register_allocator()->NewRegister();
2872 243 : FeedbackSlot load_slot = feedback_spec()->AddLoadICSlot();
2873 243 : FeedbackSlot call_slot = feedback_spec()->AddCallICSlot();
2874 : builder()
2875 : ->LoadNamedProperty(iterator,
2876 : ast_string_constants()->next_string(),
2877 486 : feedback_index(load_slot))
2878 243 : .StoreAccumulatorInRegister(iterator_next)
2879 : .CallProperty(iterator_next, iterator_and_input,
2880 243 : feedback_index(call_slot))
2881 486 : .Jump(after_switch.New());
2882 : }
2883 :
2884 : STATIC_ASSERT(JSGeneratorObject::kReturn == 1);
2885 243 : builder()->Bind(switch_jump_table, JSGeneratorObject::kReturn);
2886 : {
2887 : RegisterAllocationScope register_scope(this);
2888 : BytecodeLabels return_input(zone());
2889 : // Trigger return from within the inner iterator.
2890 243 : Register iterator_return = register_allocator()->NewRegister();
2891 243 : FeedbackSlot load_slot = feedback_spec()->AddLoadICSlot();
2892 243 : FeedbackSlot call_slot = feedback_spec()->AddCallICSlot();
2893 : builder()
2894 : ->LoadNamedProperty(iterator,
2895 : ast_string_constants()->return_string(),
2896 486 : feedback_index(load_slot))
2897 486 : .JumpIfUndefined(return_input.New())
2898 486 : .JumpIfNull(return_input.New())
2899 243 : .StoreAccumulatorInRegister(iterator_return)
2900 : .CallProperty(iterator_return, iterator_and_input,
2901 243 : feedback_index(call_slot))
2902 486 : .Jump(after_switch.New());
2903 :
2904 243 : return_input.Bind(builder());
2905 : {
2906 243 : builder()->LoadAccumulatorWithRegister(input);
2907 243 : if (iterator_type == IteratorType::kAsync) {
2908 : execution_control()->AsyncReturnAccumulator();
2909 : } else {
2910 : execution_control()->ReturnAccumulator();
2911 : }
2912 243 : }
2913 : }
2914 :
2915 : STATIC_ASSERT(JSGeneratorObject::kThrow == 2);
2916 243 : builder()->Bind(switch_jump_table, JSGeneratorObject::kThrow);
2917 : {
2918 : BytecodeLabels iterator_throw_is_undefined(zone());
2919 : {
2920 : RegisterAllocationScope register_scope(this);
2921 : // If the inner iterator has a throw method, use it to trigger an
2922 : // exception inside.
2923 243 : Register iterator_throw = register_allocator()->NewRegister();
2924 243 : FeedbackSlot load_slot = feedback_spec()->AddLoadICSlot();
2925 243 : FeedbackSlot call_slot = feedback_spec()->AddCallICSlot();
2926 : builder()
2927 : ->LoadNamedProperty(iterator,
2928 : ast_string_constants()->throw_string(),
2929 486 : feedback_index(load_slot))
2930 486 : .JumpIfUndefined(iterator_throw_is_undefined.New())
2931 486 : .JumpIfNull(iterator_throw_is_undefined.New())
2932 243 : .StoreAccumulatorInRegister(iterator_throw);
2933 : builder()
2934 : ->CallProperty(iterator_throw, iterator_and_input,
2935 243 : feedback_index(call_slot))
2936 486 : .Jump(after_switch.New());
2937 : }
2938 :
2939 243 : iterator_throw_is_undefined.Bind(builder());
2940 : {
2941 : RegisterAllocationScope register_scope(this);
2942 : BytecodeLabels throw_throw_method_missing(zone());
2943 243 : Register iterator_return = register_allocator()->NewRegister();
2944 : // If iterator.throw does not exist, try to use iterator.return to
2945 : // inform the iterator that it should stop.
2946 243 : FeedbackSlot load_slot = feedback_spec()->AddLoadICSlot();
2947 243 : FeedbackSlot call_slot = feedback_spec()->AddCallICSlot();
2948 : builder()
2949 : ->LoadNamedProperty(iterator,
2950 : ast_string_constants()->return_string(),
2951 486 : feedback_index(load_slot))
2952 243 : .StoreAccumulatorInRegister(iterator_return);
2953 : builder()
2954 486 : ->JumpIfUndefined(throw_throw_method_missing.New())
2955 486 : .JumpIfNull(throw_throw_method_missing.New())
2956 : .CallProperty(iterator_return, RegisterList(iterator),
2957 243 : feedback_index(call_slot));
2958 :
2959 243 : if (iterator_type == IteratorType::kAsync) {
2960 : // For async generators, await the result of the .return() call.
2961 11 : BuildAwait(expr->await_iterator_close_suspend_id());
2962 11 : builder()->StoreAccumulatorInRegister(output);
2963 : }
2964 :
2965 : builder()
2966 486 : ->JumpIfJSReceiver(throw_throw_method_missing.New())
2967 243 : .CallRuntime(Runtime::kThrowIteratorResultNotAnObject, output);
2968 :
2969 243 : throw_throw_method_missing.Bind(builder());
2970 486 : builder()->CallRuntime(Runtime::kThrowThrowMethodMissing);
2971 : }
2972 : }
2973 :
2974 243 : after_switch.Bind(builder());
2975 : }
2976 :
2977 243 : if (iterator_type == IteratorType::kAsync) {
2978 : // Await the result of the method invocation.
2979 11 : BuildAwait(expr->await_delegated_iterator_output_suspend_id());
2980 : }
2981 :
2982 : // Check that output is an object.
2983 : BytecodeLabel check_if_done;
2984 : builder()
2985 243 : ->StoreAccumulatorInRegister(output)
2986 243 : .JumpIfJSReceiver(&check_if_done)
2987 243 : .CallRuntime(Runtime::kThrowIteratorResultNotAnObject, output);
2988 :
2989 243 : builder()->Bind(&check_if_done);
2990 : // Break once output.done is true.
2991 : builder()->LoadNamedProperty(
2992 : output, ast_string_constants()->done_string(),
2993 729 : feedback_index(feedback_spec()->AddLoadICSlot()));
2994 :
2995 : loop.BreakIfTrue(ToBooleanMode::kConvertToBoolean);
2996 :
2997 : // Suspend the current generator.
2998 243 : if (iterator_type == IteratorType::kNormal) {
2999 232 : builder()->LoadAccumulatorWithRegister(output);
3000 : } else {
3001 : RegisterAllocationScope register_scope(this);
3002 : DCHECK_EQ(iterator_type, IteratorType::kAsync);
3003 : // If generatorKind is async, perform AsyncGeneratorYield(output.value),
3004 : // which will await `output.value` before resolving the current
3005 : // AsyncGeneratorRequest's promise.
3006 : builder()->LoadNamedProperty(
3007 : output, ast_string_constants()->value_string(),
3008 33 : feedback_index(feedback_spec()->AddLoadICSlot()));
3009 :
3010 11 : RegisterList args = register_allocator()->NewRegisterList(3);
3011 : builder()
3012 11 : ->MoveRegister(generator_object(), args[0]) // generator
3013 11 : .StoreAccumulatorInRegister(args[1]) // value
3014 22 : .LoadBoolean(catch_prediction() != HandlerTable::ASYNC_AWAIT)
3015 11 : .StoreAccumulatorInRegister(args[2]) // is_caught
3016 11 : .CallRuntime(Runtime::kInlineAsyncGeneratorYield, args);
3017 : }
3018 :
3019 243 : BuildSuspendPoint(expr->suspend_id());
3020 243 : builder()->StoreAccumulatorInRegister(input);
3021 : builder()
3022 : ->CallRuntime(Runtime::kInlineGeneratorGetResumeMode,
3023 243 : generator_object())
3024 243 : .StoreAccumulatorInRegister(resume_mode);
3025 :
3026 243 : loop.BindContinueTarget();
3027 243 : loop.JumpToHeader(loop_depth_);
3028 243 : }
3029 : }
3030 :
3031 : // Decide if we trigger a return or if the yield* expression should just
3032 : // produce a value.
3033 : BytecodeLabel completion_is_output_value;
3034 243 : Register output_value = register_allocator()->NewRegister();
3035 : builder()
3036 : ->LoadNamedProperty(output, ast_string_constants()->value_string(),
3037 729 : feedback_index(feedback_spec()->AddLoadICSlot()))
3038 243 : .StoreAccumulatorInRegister(output_value)
3039 243 : .LoadLiteral(Smi::FromInt(JSGeneratorObject::kReturn))
3040 243 : .CompareOperation(Token::EQ_STRICT, resume_mode)
3041 243 : .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &completion_is_output_value)
3042 243 : .LoadAccumulatorWithRegister(output_value);
3043 243 : if (iterator_type == IteratorType::kAsync) {
3044 : execution_control()->AsyncReturnAccumulator();
3045 : } else {
3046 : execution_control()->ReturnAccumulator();
3047 : }
3048 :
3049 243 : builder()->Bind(&completion_is_output_value);
3050 : BuildIncrementBlockCoverageCounterIfEnabled(expr,
3051 : SourceRangeKind::kContinuation);
3052 243 : builder()->LoadAccumulatorWithRegister(output_value);
3053 243 : }
3054 :
3055 105508 : void BytecodeGenerator::BuildAwait(int suspend_id) {
3056 : // Rather than HandlerTable::UNCAUGHT, async functions use
3057 : // HandlerTable::ASYNC_AWAIT to communicate that top-level exceptions are
3058 : // transformed into promise rejections. This is necessary to prevent emitting
3059 : // multiple debug events for the same uncaught exception. There is no point
3060 : // in the body of an async function where catch prediction is
3061 : // HandlerTable::UNCAUGHT.
3062 : DCHECK(catch_prediction() != HandlerTable::UNCAUGHT);
3063 :
3064 : {
3065 : // Await(operand) and suspend.
3066 : RegisterAllocationScope register_scope(this);
3067 :
3068 : int await_builtin_context_index;
3069 : RegisterList args;
3070 10797 : if (IsAsyncGeneratorFunction(function_kind())) {
3071 : await_builtin_context_index =
3072 : catch_prediction() == HandlerTable::ASYNC_AWAIT
3073 : ? Context::ASYNC_GENERATOR_AWAIT_UNCAUGHT
3074 1231 : : Context::ASYNC_GENERATOR_AWAIT_CAUGHT;
3075 1231 : args = register_allocator()->NewRegisterList(2);
3076 : builder()
3077 1231 : ->MoveRegister(generator_object(), args[0])
3078 1231 : .StoreAccumulatorInRegister(args[1]);
3079 : } else {
3080 : await_builtin_context_index =
3081 : catch_prediction() == HandlerTable::ASYNC_AWAIT
3082 : ? Context::ASYNC_FUNCTION_AWAIT_UNCAUGHT_INDEX
3083 9566 : : Context::ASYNC_FUNCTION_AWAIT_CAUGHT_INDEX;
3084 9566 : args = register_allocator()->NewRegisterList(3);
3085 : builder()
3086 9566 : ->MoveRegister(generator_object(), args[0])
3087 9566 : .StoreAccumulatorInRegister(args[1]);
3088 :
3089 : // AsyncFunction Await builtins require a 3rd parameter to hold the outer
3090 : // promise.
3091 : Variable* var_promise = closure_scope()->promise_var();
3092 9566 : BuildVariableLoadForAccumulatorValue(var_promise, HoleCheckMode::kElided);
3093 9566 : builder()->StoreAccumulatorInRegister(args[2]);
3094 : }
3095 :
3096 10797 : builder()->CallJSRuntime(await_builtin_context_index, args);
3097 : }
3098 :
3099 10797 : BuildSuspendPoint(suspend_id);
3100 :
3101 10797 : Register input = register_allocator()->NewRegister();
3102 10797 : Register resume_mode = register_allocator()->NewRegister();
3103 :
3104 : // Now dispatch on resume mode.
3105 : BytecodeLabel resume_next;
3106 : builder()
3107 10797 : ->StoreAccumulatorInRegister(input)
3108 10797 : .CallRuntime(Runtime::kInlineGeneratorGetResumeMode, generator_object())
3109 10797 : .StoreAccumulatorInRegister(resume_mode)
3110 10797 : .LoadLiteral(Smi::FromInt(JSGeneratorObject::kNext))
3111 10797 : .CompareOperation(Token::EQ_STRICT, resume_mode)
3112 10797 : .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &resume_next);
3113 :
3114 : // Resume with "throw" completion (rethrow the received value).
3115 : // TODO(leszeks): Add a debug-only check that the accumulator is
3116 : // JSGeneratorObject::kThrow.
3117 10797 : builder()->LoadAccumulatorWithRegister(input).ReThrow();
3118 :
3119 : // Resume with next.
3120 10797 : builder()->Bind(&resume_next);
3121 10797 : builder()->LoadAccumulatorWithRegister(input);
3122 10797 : }
3123 :
3124 10775 : void BytecodeGenerator::VisitAwait(Await* expr) {
3125 : builder()->SetExpressionPosition(expr);
3126 10775 : VisitForAccumulatorValue(expr->expression());
3127 10775 : BuildAwait(expr->suspend_id());
3128 : BuildIncrementBlockCoverageCounterIfEnabled(expr,
3129 : SourceRangeKind::kContinuation);
3130 10775 : }
3131 :
3132 281976 : void BytecodeGenerator::VisitThrow(Throw* expr) {
3133 : AllocateBlockCoverageSlotIfEnabled(expr, SourceRangeKind::kContinuation);
3134 70494 : VisitForAccumulatorValue(expr->exception());
3135 : builder()->SetExpressionPosition(expr);
3136 70494 : builder()->Throw();
3137 70494 : }
3138 :
3139 14894717 : void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* property) {
3140 3724230 : LhsKind property_kind = Property::GetAssignType(property);
3141 3724231 : switch (property_kind) {
3142 : case VARIABLE:
3143 0 : UNREACHABLE();
3144 : case NAMED_PROPERTY: {
3145 : builder()->SetExpressionPosition(property);
3146 : builder()->LoadNamedProperty(
3147 : obj, property->key()->AsLiteral()->AsRawPropertyName(),
3148 14030699 : feedback_index(feedback_spec()->AddLoadICSlot()));
3149 3507675 : break;
3150 : }
3151 : case KEYED_PROPERTY: {
3152 215821 : VisitForAccumulatorValue(property->key());
3153 : builder()->SetExpressionPosition(property);
3154 : builder()->LoadKeyedProperty(
3155 431642 : obj, feedback_index(feedback_spec()->AddKeyedLoadICSlot()));
3156 215821 : break;
3157 : }
3158 : case NAMED_SUPER_PROPERTY:
3159 386 : VisitNamedSuperPropertyLoad(property, Register::invalid_value());
3160 386 : break;
3161 : case KEYED_SUPER_PROPERTY:
3162 350 : VisitKeyedSuperPropertyLoad(property, Register::invalid_value());
3163 350 : break;
3164 : }
3165 3724232 : }
3166 :
3167 835465 : void BytecodeGenerator::VisitPropertyLoadForRegister(Register obj,
3168 : Property* expr,
3169 835465 : Register destination) {
3170 : ValueResultScope result_scope(this);
3171 835465 : VisitPropertyLoad(obj, expr);
3172 835465 : builder()->StoreAccumulatorInRegister(destination);
3173 835465 : }
3174 :
3175 2286 : void BytecodeGenerator::VisitNamedSuperPropertyLoad(Property* property,
3176 1900 : Register opt_receiver_out) {
3177 : RegisterAllocationScope register_scope(this);
3178 1524 : SuperPropertyReference* super_property =
3179 762 : property->obj()->AsSuperPropertyReference();
3180 762 : RegisterList args = register_allocator()->NewRegisterList(3);
3181 : VisitForRegisterValue(super_property->this_var(), args[0]);
3182 : VisitForRegisterValue(super_property->home_object(), args[1]);
3183 :
3184 : builder()->SetExpressionPosition(property);
3185 : builder()
3186 2286 : ->LoadLiteral(property->key()->AsLiteral()->AsRawPropertyName())
3187 762 : .StoreAccumulatorInRegister(args[2])
3188 762 : .CallRuntime(Runtime::kLoadFromSuper, args);
3189 :
3190 762 : if (opt_receiver_out.is_valid()) {
3191 376 : builder()->MoveRegister(args[0], opt_receiver_out);
3192 762 : }
3193 762 : }
3194 :
3195 1146 : void BytecodeGenerator::VisitKeyedSuperPropertyLoad(Property* property,
3196 796 : Register opt_receiver_out) {
3197 : RegisterAllocationScope register_scope(this);
3198 764 : SuperPropertyReference* super_property =
3199 382 : property->obj()->AsSuperPropertyReference();
3200 382 : RegisterList args = register_allocator()->NewRegisterList(3);
3201 : VisitForRegisterValue(super_property->this_var(), args[0]);
3202 : VisitForRegisterValue(super_property->home_object(), args[1]);
3203 : VisitForRegisterValue(property->key(), args[2]);
3204 :
3205 : builder()->SetExpressionPosition(property);
3206 382 : builder()->CallRuntime(Runtime::kLoadKeyedFromSuper, args);
3207 :
3208 382 : if (opt_receiver_out.is_valid()) {
3209 32 : builder()->MoveRegister(args[0], opt_receiver_out);
3210 382 : }
3211 382 : }
3212 :
3213 5776798 : void BytecodeGenerator::VisitProperty(Property* expr) {
3214 2888767 : LhsKind property_kind = Property::GetAssignType(expr);
3215 2888767 : if (property_kind != NAMED_SUPER_PROPERTY &&
3216 : property_kind != KEYED_SUPER_PROPERTY) {
3217 2888031 : Register obj = VisitForRegisterValue(expr->obj());
3218 2888031 : VisitPropertyLoad(obj, expr);
3219 : } else {
3220 736 : VisitPropertyLoad(Register::invalid_value(), expr);
3221 : }
3222 2888766 : }
3223 :
3224 13955615 : void BytecodeGenerator::VisitArguments(ZoneList<Expression*>* args,
3225 : RegisterList* arg_regs) {
3226 : // Visit arguments.
3227 21296998 : for (int i = 0; i < static_cast<int>(args->length()); i++) {
3228 7341382 : VisitAndPushIntoRegisterList(args->at(i), arg_regs);
3229 : }
3230 3307117 : }
3231 :
3232 20046961 : void BytecodeGenerator::VisitCall(Call* expr) {
3233 : Expression* callee_expr = expr->expression();
3234 2665847 : Call::CallType call_type = expr->GetCallType();
3235 :
3236 2665849 : if (call_type == Call::SUPER_CALL) {
3237 2669611 : return VisitCallSuper(expr);
3238 : }
3239 :
3240 : // Grow the args list as we visit receiver / arguments to avoid allocating all
3241 : // the registers up-front. Otherwise these registers are unavailable during
3242 : // receiver / argument visiting and we can end up with memory leaks due to
3243 : // registers keeping objects alive.
3244 2662087 : Register callee = register_allocator()->NewRegister();
3245 2662086 : RegisterList args = register_allocator()->NewGrowableRegisterList();
3246 :
3247 : bool implicit_undefined_receiver = false;
3248 : // When a call contains a spread, a Call AST node is only created if there is
3249 : // exactly one spread, and it is the last argument.
3250 2662086 : bool is_spread_call = expr->only_last_arg_is_spread();
3251 :
3252 : // TODO(petermarshall): We have a lot of call bytecodes that are very similar,
3253 : // see if we can reduce the number by adding a separate argument which
3254 : // specifies the call type (e.g., property, spread, tailcall, etc.).
3255 :
3256 : // Prepare the callee and the receiver to the function call. This depends on
3257 : // the semantics of the underlying call type.
3258 2662086 : switch (call_type) {
3259 : case Call::NAMED_PROPERTY_CALL:
3260 : case Call::KEYED_PROPERTY_CALL: {
3261 1670930 : Property* property = callee_expr->AsProperty();
3262 835465 : VisitAndPushIntoRegisterList(property->obj(), &args);
3263 835465 : VisitPropertyLoadForRegister(args.last_register(), property, callee);
3264 835465 : break;
3265 : }
3266 : case Call::GLOBAL_CALL: {
3267 : // Receiver is undefined for global calls.
3268 1087090 : if (!is_spread_call) {
3269 : implicit_undefined_receiver = true;
3270 : } else {
3271 : // TODO(leszeks): There's no special bytecode for tail calls or spread
3272 : // calls with an undefined receiver, so just push undefined ourselves.
3273 17 : BuildPushUndefinedIntoRegisterList(&args);
3274 : }
3275 : // Load callee as a global variable.
3276 3261270 : VariableProxy* proxy = callee_expr->AsVariableProxy();
3277 : BuildVariableLoadForAccumulatorValue(proxy->var(),
3278 1087090 : proxy->hole_check_mode());
3279 1087090 : builder()->StoreAccumulatorInRegister(callee);
3280 1087090 : break;
3281 : }
3282 : case Call::WITH_CALL: {
3283 2141 : Register receiver = register_allocator()->GrowRegisterList(&args);
3284 : DCHECK(callee_expr->AsVariableProxy()->var()->IsLookupSlot());
3285 : {
3286 : RegisterAllocationScope inner_register_scope(this);
3287 2141 : Register name = register_allocator()->NewRegister();
3288 :
3289 : // Call %LoadLookupSlotForCall to get the callee and receiver.
3290 : DCHECK(Register::AreContiguous(callee, receiver));
3291 : RegisterList result_pair(callee.index(), 2);
3292 : USE(receiver);
3293 :
3294 4282 : Variable* variable = callee_expr->AsVariableProxy()->var();
3295 : builder()
3296 2141 : ->LoadLiteral(variable->raw_name())
3297 2141 : .StoreAccumulatorInRegister(name)
3298 : .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, name,
3299 2141 : result_pair);
3300 : }
3301 : break;
3302 : }
3303 : case Call::OTHER_CALL: {
3304 : // Receiver is undefined for other calls.
3305 736981 : if (!is_spread_call) {
3306 : implicit_undefined_receiver = true;
3307 : } else {
3308 : // TODO(leszeks): There's no special bytecode for tail calls or spread
3309 : // calls with an undefined receiver, so just push undefined ourselves.
3310 579 : BuildPushUndefinedIntoRegisterList(&args);
3311 : }
3312 : VisitForRegisterValue(callee_expr, callee);
3313 : break;
3314 : }
3315 : case Call::NAMED_SUPER_PROPERTY_CALL: {
3316 376 : Register receiver = register_allocator()->GrowRegisterList(&args);
3317 376 : Property* property = callee_expr->AsProperty();
3318 376 : VisitNamedSuperPropertyLoad(property, receiver);
3319 376 : builder()->StoreAccumulatorInRegister(callee);
3320 : break;
3321 : }
3322 : case Call::KEYED_SUPER_PROPERTY_CALL: {
3323 32 : Register receiver = register_allocator()->GrowRegisterList(&args);
3324 32 : Property* property = callee_expr->AsProperty();
3325 32 : VisitKeyedSuperPropertyLoad(property, receiver);
3326 32 : builder()->StoreAccumulatorInRegister(callee);
3327 : break;
3328 : }
3329 : case Call::SUPER_CALL:
3330 0 : UNREACHABLE();
3331 : break;
3332 : }
3333 :
3334 : // Evaluate all arguments to the function call and store in sequential args
3335 : // registers.
3336 2662088 : VisitArguments(expr->arguments(), &args);
3337 2662083 : int reciever_arg_count = implicit_undefined_receiver ? 0 : 1;
3338 5324166 : CHECK_EQ(reciever_arg_count + expr->arguments()->length(),
3339 : args.register_count());
3340 :
3341 : // Resolve callee for a potential direct eval call. This block will mutate the
3342 : // callee value.
3343 2662083 : if (expr->is_possibly_eval() && expr->arguments()->length() > 0) {
3344 : RegisterAllocationScope inner_register_scope(this);
3345 : // Set up arguments for ResolvePossiblyDirectEval by copying callee, source
3346 : // strings and function closure, and loading language and
3347 : // position.
3348 212644 : Register first_arg = args[reciever_arg_count];
3349 106322 : RegisterList runtime_call_args = register_allocator()->NewRegisterList(6);
3350 : builder()
3351 106322 : ->MoveRegister(callee, runtime_call_args[0])
3352 106322 : .MoveRegister(first_arg, runtime_call_args[1])
3353 212644 : .MoveRegister(Register::function_closure(), runtime_call_args[2])
3354 106322 : .LoadLiteral(Smi::FromEnum(language_mode()))
3355 106322 : .StoreAccumulatorInRegister(runtime_call_args[3])
3356 212644 : .LoadLiteral(Smi::FromInt(current_scope()->start_position()))
3357 106322 : .StoreAccumulatorInRegister(runtime_call_args[4])
3358 212644 : .LoadLiteral(Smi::FromInt(expr->position()))
3359 106322 : .StoreAccumulatorInRegister(runtime_call_args[5]);
3360 :
3361 : // Call ResolvePossiblyDirectEval and modify the callee.
3362 : builder()
3363 106322 : ->CallRuntime(Runtime::kResolvePossiblyDirectEval, runtime_call_args)
3364 106322 : .StoreAccumulatorInRegister(callee);
3365 : }
3366 :
3367 : builder()->SetExpressionPosition(expr);
3368 :
3369 2662083 : int feedback_slot_index = feedback_index(feedback_spec()->AddCallICSlot());
3370 :
3371 2662086 : if (is_spread_call) {
3372 : DCHECK(!implicit_undefined_receiver);
3373 1491 : builder()->CallWithSpread(callee, args, feedback_slot_index);
3374 2660595 : } else if (call_type == Call::NAMED_PROPERTY_CALL ||
3375 : call_type == Call::KEYED_PROPERTY_CALL) {
3376 : DCHECK(!implicit_undefined_receiver);
3377 834595 : builder()->CallProperty(callee, args, feedback_slot_index);
3378 1826000 : } else if (implicit_undefined_receiver) {
3379 1823476 : builder()->CallUndefinedReceiver(callee, args, feedback_slot_index);
3380 : } else {
3381 2524 : builder()->CallAnyReceiver(callee, args, feedback_slot_index);
3382 : }
3383 : }
3384 :
3385 26334 : void BytecodeGenerator::VisitCallSuper(Call* expr) {
3386 : RegisterAllocationScope register_scope(this);
3387 11286 : SuperCallReference* super = expr->expression()->AsSuperCallReference();
3388 :
3389 : // Prepare the constructor to the super call.
3390 3762 : VisitForAccumulatorValue(super->this_function_var());
3391 3762 : Register constructor = register_allocator()->NewRegister();
3392 3762 : builder()->GetSuperConstructor(constructor);
3393 :
3394 : ZoneList<Expression*>* args = expr->arguments();
3395 3762 : RegisterList args_regs = register_allocator()->NewGrowableRegisterList();
3396 3762 : VisitArguments(args, &args_regs);
3397 : // The new target is loaded into the accumulator from the
3398 : // {new.target} variable.
3399 3762 : VisitForAccumulatorValue(super->new_target_var());
3400 : builder()->SetExpressionPosition(expr);
3401 :
3402 3762 : int feedback_slot_index = feedback_index(feedback_spec()->AddCallICSlot());
3403 :
3404 : // When a super call contains a spread, a CallSuper AST node is only created
3405 : // if there is exactly one spread, and it is the last argument.
3406 3762 : if (expr->only_last_arg_is_spread()) {
3407 2849 : builder()->ConstructWithSpread(constructor, args_regs, feedback_slot_index);
3408 : } else {
3409 : // Call construct.
3410 : // TODO(turbofan): For now we do gather feedback on super constructor
3411 : // calls, utilizing the existing machinery to inline the actual call
3412 : // target and the JSCreate for the implicit receiver allocation. This
3413 : // is not an ideal solution for super constructor calls, but it gets
3414 : // the job done for now. In the long run we might want to revisit this
3415 : // and come up with a better way.
3416 913 : builder()->Construct(constructor, args_regs, feedback_slot_index);
3417 3762 : }
3418 3762 : }
3419 :
3420 937416 : void BytecodeGenerator::VisitCallNew(CallNew* expr) {
3421 156236 : Register constructor = VisitForRegisterValue(expr->expression());
3422 156236 : RegisterList args = register_allocator()->NewGrowableRegisterList();
3423 156236 : VisitArguments(expr->arguments(), &args);
3424 :
3425 : // The accumulator holds new target which is the same as the
3426 : // constructor for CallNew.
3427 : builder()->SetExpressionPosition(expr);
3428 156236 : builder()->LoadAccumulatorWithRegister(constructor);
3429 :
3430 156236 : int feedback_slot_index = feedback_index(feedback_spec()->AddCallICSlot());
3431 156236 : if (expr->only_last_arg_is_spread()) {
3432 122 : builder()->ConstructWithSpread(constructor, args, feedback_slot_index);
3433 : } else {
3434 156114 : builder()->Construct(constructor, args, feedback_slot_index);
3435 : }
3436 156236 : }
3437 :
3438 1862200 : void BytecodeGenerator::VisitCallRuntime(CallRuntime* expr) {
3439 485034 : if (expr->is_jsruntime()) {
3440 77936 : RegisterList args = register_allocator()->NewGrowableRegisterList();
3441 77936 : VisitArguments(expr->arguments(), &args);
3442 77936 : builder()->CallJSRuntime(expr->context_index(), args);
3443 : } else {
3444 : // Evaluate all arguments to the runtime call.
3445 407098 : RegisterList args = register_allocator()->NewGrowableRegisterList();
3446 407098 : VisitArguments(expr->arguments(), &args);
3447 407098 : Runtime::FunctionId function_id = expr->function()->function_id;
3448 407098 : builder()->CallRuntime(function_id, args);
3449 : }
3450 485034 : }
3451 :
3452 21964 : void BytecodeGenerator::VisitVoid(UnaryOperation* expr) {
3453 10982 : VisitForEffect(expr->expression());
3454 10982 : builder()->LoadUndefined();
3455 0 : }
3456 :
3457 203426 : void BytecodeGenerator::VisitForTypeOfValue(Expression* expr) {
3458 203426 : if (expr->IsVariableProxy()) {
3459 : // Typeof does not throw a reference error on global variables, hence we
3460 : // perform a non-contextual load in case the operand is a variable proxy.
3461 569292 : VariableProxy* proxy = expr->AsVariableProxy();
3462 : BuildVariableLoadForAccumulatorValue(proxy->var(), proxy->hole_check_mode(),
3463 189764 : INSIDE_TYPEOF);
3464 : } else {
3465 13662 : VisitForAccumulatorValue(expr);
3466 : }
3467 203426 : }
3468 :
3469 115648 : void BytecodeGenerator::VisitTypeOf(UnaryOperation* expr) {
3470 57824 : VisitForTypeOfValue(expr->expression());
3471 57824 : builder()->TypeOf();
3472 0 : }
3473 :
3474 811564 : void BytecodeGenerator::VisitNot(UnaryOperation* expr) {
3475 344653 : if (execution_result()->IsEffect()) {
3476 136 : VisitForEffect(expr->expression());
3477 344517 : } else if (execution_result()->IsTest()) {
3478 : // No actual logical negation happening, we just swap the control flow, by
3479 : // swapping the target labels and the fallthrough branch, and visit in the
3480 : // same test result context.
3481 : TestResultScope* test_result = execution_result()->AsTest();
3482 : test_result->InvertControlFlow();
3483 283388 : VisitInSameTestExecutionScope(expr->expression());
3484 : } else {
3485 61129 : TypeHint type_hint = VisitForAccumulatorValue(expr->expression());
3486 61129 : builder()->LogicalNot(ToBooleanModeFromTypeHint(type_hint));
3487 : // Always returns a boolean value.
3488 : execution_result()->SetResultIsBoolean();
3489 : }
3490 344653 : }
3491 :
3492 671069 : void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
3493 473709 : switch (expr->op()) {
3494 : case Token::Value::NOT:
3495 344653 : VisitNot(expr);
3496 344653 : break;
3497 : case Token::Value::TYPEOF:
3498 : VisitTypeOf(expr);
3499 : break;
3500 : case Token::Value::VOID:
3501 : VisitVoid(expr);
3502 : break;
3503 : case Token::Value::DELETE:
3504 10910 : VisitDelete(expr);
3505 10910 : break;
3506 : case Token::Value::ADD:
3507 : case Token::Value::SUB:
3508 : case Token::Value::BIT_NOT:
3509 49340 : VisitForAccumulatorValue(expr->expression());
3510 : builder()->SetExpressionPosition(expr);
3511 : builder()->UnaryOperation(
3512 98680 : expr->op(), feedback_index(feedback_spec()->AddBinaryOpICSlot()));
3513 49340 : break;
3514 : default:
3515 0 : UNREACHABLE();
3516 : }
3517 473709 : }
3518 :
3519 34134 : void BytecodeGenerator::VisitDelete(UnaryOperation* expr) {
3520 10910 : if (expr->expression()->IsProperty()) {
3521 : // Delete of an object property is allowed both in sloppy
3522 : // and strict modes.
3523 28518 : Property* property = expr->expression()->AsProperty();
3524 9506 : Register object = VisitForRegisterValue(property->obj());
3525 9506 : VisitForAccumulatorValue(property->key());
3526 9506 : builder()->Delete(object, language_mode());
3527 1404 : } else if (expr->expression()->IsVariableProxy()) {
3528 : // Delete of an unqualified identifier is allowed in sloppy mode but is
3529 : // not allowed in strict mode. Deleting 'this' and 'new.target' is allowed
3530 : // in both modes.
3531 2725 : VariableProxy* proxy = expr->expression()->AsVariableProxy();
3532 : DCHECK(is_sloppy(language_mode()) || proxy->is_this() ||
3533 : proxy->is_new_target());
3534 1798 : if (proxy->is_this() || proxy->is_new_target()) {
3535 86 : builder()->LoadTrue();
3536 : } else {
3537 1526 : Variable* variable = proxy->var();
3538 851 : switch (variable->location()) {
3539 : case VariableLocation::PARAMETER:
3540 : case VariableLocation::LOCAL:
3541 : case VariableLocation::CONTEXT: {
3542 : // Deleting local var/let/const, context variables, and arguments
3543 : // does not have any effect.
3544 176 : builder()->LoadFalse();
3545 176 : break;
3546 : }
3547 : case VariableLocation::UNALLOCATED:
3548 : // TODO(adamk): Falling through to the runtime results in correct
3549 : // behavior, but does unnecessary context-walking (since scope
3550 : // analysis has already proven that the variable doesn't exist in
3551 : // any non-global scope). Consider adding a DeleteGlobal bytecode
3552 : // that knows how to deal with ScriptContexts as well as global
3553 : // object properties.
3554 : case VariableLocation::LOOKUP: {
3555 675 : Register name_reg = register_allocator()->NewRegister();
3556 : builder()
3557 675 : ->LoadLiteral(variable->raw_name())
3558 675 : .StoreAccumulatorInRegister(name_reg)
3559 675 : .CallRuntime(Runtime::kDeleteLookupSlot, name_reg);
3560 : break;
3561 : }
3562 : default:
3563 0 : UNREACHABLE();
3564 : }
3565 : }
3566 : } else {
3567 : // Delete of an unresolvable reference returns true.
3568 467 : VisitForEffect(expr->expression());
3569 467 : builder()->LoadTrue();
3570 : }
3571 10910 : }
3572 :
3573 1635494 : void BytecodeGenerator::VisitCountOperation(CountOperation* expr) {
3574 : DCHECK(expr->expression()->IsValidReferenceExpression());
3575 :
3576 : // Left-hand side can only be a property, a global or a variable slot.
3577 222791 : Property* property = expr->expression()->AsProperty();
3578 204333 : LhsKind assign_type = Property::GetAssignType(property);
3579 :
3580 360615 : bool is_postfix = expr->is_postfix() && !execution_result()->IsEffect();
3581 :
3582 : // Evaluate LHS expression and get old value.
3583 : Register object, key, old_value;
3584 : RegisterList super_property_args;
3585 : const AstRawString* name;
3586 204333 : switch (assign_type) {
3587 : case VARIABLE: {
3588 585312 : VariableProxy* proxy = expr->expression()->AsVariableProxy();
3589 : BuildVariableLoadForAccumulatorValue(proxy->var(),
3590 195104 : proxy->hole_check_mode());
3591 195104 : break;
3592 : }
3593 : case NAMED_PROPERTY: {
3594 8317 : object = VisitForRegisterValue(property->obj());
3595 16634 : name = property->key()->AsLiteral()->AsRawPropertyName();
3596 : builder()->LoadNamedProperty(
3597 16634 : object, name, feedback_index(feedback_spec()->AddLoadICSlot()));
3598 8317 : break;
3599 : }
3600 : case KEYED_PROPERTY: {
3601 774 : object = VisitForRegisterValue(property->obj());
3602 : // Use visit for accumulator here since we need the key in the accumulator
3603 : // for the LoadKeyedProperty.
3604 774 : key = register_allocator()->NewRegister();
3605 774 : VisitForAccumulatorValue(property->key());
3606 774 : builder()->StoreAccumulatorInRegister(key).LoadKeyedProperty(
3607 1548 : object, feedback_index(feedback_spec()->AddKeyedLoadICSlot()));
3608 774 : break;
3609 : }
3610 : case NAMED_SUPER_PROPERTY: {
3611 46 : super_property_args = register_allocator()->NewRegisterList(4);
3612 46 : RegisterList load_super_args = super_property_args.Truncate(3);
3613 92 : SuperPropertyReference* super_property =
3614 46 : property->obj()->AsSuperPropertyReference();
3615 : VisitForRegisterValue(super_property->this_var(), load_super_args[0]);
3616 : VisitForRegisterValue(super_property->home_object(), load_super_args[1]);
3617 : builder()
3618 138 : ->LoadLiteral(property->key()->AsLiteral()->AsRawPropertyName())
3619 46 : .StoreAccumulatorInRegister(load_super_args[2])
3620 46 : .CallRuntime(Runtime::kLoadFromSuper, load_super_args);
3621 : break;
3622 : }
3623 : case KEYED_SUPER_PROPERTY: {
3624 92 : super_property_args = register_allocator()->NewRegisterList(4);
3625 92 : RegisterList load_super_args = super_property_args.Truncate(3);
3626 184 : SuperPropertyReference* super_property =
3627 92 : property->obj()->AsSuperPropertyReference();
3628 : VisitForRegisterValue(super_property->this_var(), load_super_args[0]);
3629 : VisitForRegisterValue(super_property->home_object(), load_super_args[1]);
3630 : VisitForRegisterValue(property->key(), load_super_args[2]);
3631 92 : builder()->CallRuntime(Runtime::kLoadKeyedFromSuper, load_super_args);
3632 : break;
3633 : }
3634 : }
3635 :
3636 : // Save result for postfix expressions.
3637 204333 : FeedbackSlot count_slot = feedback_spec()->AddBinaryOpICSlot();
3638 204333 : if (is_postfix) {
3639 29055 : old_value = register_allocator()->NewRegister();
3640 : // Convert old value into a number before saving it.
3641 : // TODO(ignition): Think about adding proper PostInc/PostDec bytecodes
3642 : // instead of this ToNumber + Inc/Dec dance.
3643 : builder()
3644 29055 : ->ToNumeric(feedback_index(count_slot))
3645 29055 : .StoreAccumulatorInRegister(old_value);
3646 : }
3647 :
3648 : // Perform +1/-1 operation.
3649 204333 : builder()->UnaryOperation(expr->op(), feedback_index(count_slot));
3650 :
3651 : // Store the value.
3652 : builder()->SetExpressionPosition(expr);
3653 204333 : switch (assign_type) {
3654 : case VARIABLE: {
3655 585312 : VariableProxy* proxy = expr->expression()->AsVariableProxy();
3656 : BuildVariableAssignment(proxy->var(), expr->op(),
3657 195104 : proxy->hole_check_mode());
3658 195104 : break;
3659 : }
3660 : case NAMED_PROPERTY: {
3661 8317 : FeedbackSlot slot = feedback_spec()->AddStoreICSlot(language_mode());
3662 : builder()->StoreNamedProperty(object, name, feedback_index(slot),
3663 8317 : language_mode());
3664 : break;
3665 : }
3666 : case KEYED_PROPERTY: {
3667 774 : FeedbackSlot slot = feedback_spec()->AddKeyedStoreICSlot(language_mode());
3668 : builder()->StoreKeyedProperty(object, key, feedback_index(slot),
3669 774 : language_mode());
3670 : break;
3671 : }
3672 : case NAMED_SUPER_PROPERTY: {
3673 : builder()
3674 46 : ->StoreAccumulatorInRegister(super_property_args[3])
3675 46 : .CallRuntime(StoreToSuperRuntimeId(), super_property_args);
3676 46 : break;
3677 : }
3678 : case KEYED_SUPER_PROPERTY: {
3679 : builder()
3680 92 : ->StoreAccumulatorInRegister(super_property_args[3])
3681 92 : .CallRuntime(StoreKeyedToSuperRuntimeId(), super_property_args);
3682 92 : break;
3683 : }
3684 : }
3685 :
3686 : // Restore old value for postfix expressions.
3687 204333 : if (is_postfix) {
3688 29055 : builder()->LoadAccumulatorWithRegister(old_value);
3689 : }
3690 204333 : }
3691 :
3692 1163699 : void BytecodeGenerator::VisitBinaryOperation(BinaryOperation* binop) {
3693 1163699 : switch (binop->op()) {
3694 : case Token::COMMA:
3695 109343 : VisitCommaExpression(binop);
3696 109343 : break;
3697 : case Token::OR:
3698 147247 : VisitLogicalOrExpression(binop);
3699 147247 : break;
3700 : case Token::AND:
3701 140625 : VisitLogicalAndExpression(binop);
3702 140625 : break;
3703 : default:
3704 766484 : VisitArithmeticExpression(binop);
3705 766484 : break;
3706 : }
3707 1163699 : }
3708 :
3709 268858 : void BytecodeGenerator::BuildLiteralCompareNil(Token::Value op, NilValue nil) {
3710 134429 : if (execution_result()->IsTest()) {
3711 245180 : TestResultScope* test_result = execution_result()->AsTest();
3712 122590 : switch (test_result->fallthrough()) {
3713 : case TestFallthrough::kThen:
3714 78567 : builder()->JumpIfNotNil(test_result->NewElseLabel(), op, nil);
3715 78567 : break;
3716 : case TestFallthrough::kElse:
3717 44023 : builder()->JumpIfNil(test_result->NewThenLabel(), op, nil);
3718 44023 : break;
3719 : case TestFallthrough::kNone:
3720 : builder()
3721 0 : ->JumpIfNil(test_result->NewThenLabel(), op, nil)
3722 0 : .Jump(test_result->NewElseLabel());
3723 : }
3724 : test_result->SetResultConsumedByTest();
3725 : } else {
3726 11839 : builder()->CompareNil(op, nil);
3727 : }
3728 134429 : }
3729 :
3730 8296015 : void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) {
3731 : Expression* sub_expr;
3732 : Literal* literal;
3733 1162365 : if (expr->IsLiteralCompareTypeof(&sub_expr, &literal)) {
3734 : // Emit a fast literal comparion for expressions of the form:
3735 : // typeof(x) === 'string'.
3736 145602 : VisitForTypeOfValue(sub_expr);
3737 : builder()->SetExpressionPosition(expr);
3738 : TestTypeOfFlags::LiteralFlag literal_flag =
3739 291204 : TestTypeOfFlags::GetFlagForLiteral(ast_string_constants(), literal);
3740 145602 : if (literal_flag == TestTypeOfFlags::LiteralFlag::kOther) {
3741 228 : builder()->LoadFalse();
3742 : } else {
3743 145374 : builder()->CompareTypeOf(literal_flag);
3744 : }
3745 1016763 : } else if (expr->IsLiteralCompareUndefined(&sub_expr)) {
3746 79695 : VisitForAccumulatorValue(sub_expr);
3747 : builder()->SetExpressionPosition(expr);
3748 79695 : BuildLiteralCompareNil(expr->op(), kUndefinedValue);
3749 937068 : } else if (expr->IsLiteralCompareNull(&sub_expr)) {
3750 54734 : VisitForAccumulatorValue(sub_expr);
3751 : builder()->SetExpressionPosition(expr);
3752 54734 : BuildLiteralCompareNil(expr->op(), kNullValue);
3753 : } else {
3754 882334 : Register lhs = VisitForRegisterValue(expr->left());
3755 882334 : VisitForAccumulatorValue(expr->right());
3756 : builder()->SetExpressionPosition(expr);
3757 882334 : if (expr->op() == Token::INSTANCEOF || expr->op() == Token::IN) {
3758 28383 : builder()->CompareOperation(expr->op(), lhs);
3759 : } else {
3760 853951 : FeedbackSlot slot = feedback_spec()->AddCompareICSlot();
3761 853951 : builder()->CompareOperation(expr->op(), lhs, feedback_index(slot));
3762 : }
3763 : }
3764 : // Always returns a boolean value.
3765 : execution_result()->SetResultIsBoolean();
3766 1162365 : }
3767 :
3768 4236067 : void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) {
3769 766484 : FeedbackSlot slot = feedback_spec()->AddBinaryOpICSlot();
3770 : Expression* subexpr;
3771 : Smi* literal;
3772 766484 : if (expr->IsSmiLiteralOperation(&subexpr, &literal)) {
3773 181417 : VisitForAccumulatorValue(subexpr);
3774 : builder()->SetExpressionPosition(expr);
3775 : builder()->BinaryOperationSmiLiteral(expr->op(), literal,
3776 362834 : feedback_index(slot));
3777 : } else {
3778 585067 : Register lhs = VisitForRegisterValue(expr->left());
3779 585067 : VisitForAccumulatorValue(expr->right());
3780 : builder()->SetExpressionPosition(expr);
3781 585066 : builder()->BinaryOperation(expr->op(), lhs, feedback_index(slot));
3782 : }
3783 766484 : }
3784 :
3785 4462 : void BytecodeGenerator::VisitSpread(Spread* expr) { Visit(expr->expression()); }
3786 :
3787 0 : void BytecodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) {
3788 0 : UNREACHABLE();
3789 : }
3790 :
3791 696 : void BytecodeGenerator::VisitImportCallExpression(ImportCallExpression* expr) {
3792 232 : RegisterList args = register_allocator()->NewRegisterList(2);
3793 : VisitForRegisterValue(expr->argument(), args[1]);
3794 : builder()
3795 464 : ->MoveRegister(Register::function_closure(), args[0])
3796 232 : .CallRuntime(Runtime::kDynamicImportCall, args);
3797 232 : }
3798 :
3799 26721 : void BytecodeGenerator::BuildGetIterator(Expression* iterable,
3800 135915 : IteratorType hint) {
3801 26721 : RegisterList args = register_allocator()->NewRegisterList(1);
3802 26721 : Register method = register_allocator()->NewRegister();
3803 26721 : Register obj = args[0];
3804 :
3805 26721 : VisitForAccumulatorValue(iterable);
3806 :
3807 26721 : if (hint == IteratorType::kAsync) {
3808 : // Set method to GetMethod(obj, @@asyncIterator)
3809 330 : builder()->StoreAccumulatorInRegister(obj).LoadAsyncIteratorProperty(
3810 660 : obj, feedback_index(feedback_spec()->AddLoadICSlot()));
3811 :
3812 : BytecodeLabel async_iterator_undefined, async_iterator_null, done;
3813 : // TODO(ignition): Add a single opcode for JumpIfNullOrUndefined
3814 330 : builder()->JumpIfUndefined(&async_iterator_undefined);
3815 330 : builder()->JumpIfNull(&async_iterator_null);
3816 :
3817 : // Let iterator be Call(method, obj)
3818 330 : builder()->StoreAccumulatorInRegister(method).CallProperty(
3819 660 : method, args, feedback_index(feedback_spec()->AddCallICSlot()));
3820 :
3821 : // If Type(iterator) is not Object, throw a TypeError exception.
3822 330 : builder()->JumpIfJSReceiver(&done);
3823 330 : builder()->CallRuntime(Runtime::kThrowSymbolAsyncIteratorInvalid);
3824 :
3825 330 : builder()->Bind(&async_iterator_undefined);
3826 330 : builder()->Bind(&async_iterator_null);
3827 : // If method is undefined,
3828 : // Let syncMethod be GetMethod(obj, @@iterator)
3829 : builder()
3830 : ->LoadIteratorProperty(obj,
3831 660 : feedback_index(feedback_spec()->AddLoadICSlot()))
3832 330 : .StoreAccumulatorInRegister(method);
3833 :
3834 : // Let syncIterator be Call(syncMethod, obj)
3835 : builder()->CallProperty(method, args,
3836 660 : feedback_index(feedback_spec()->AddCallICSlot()));
3837 :
3838 : // Return CreateAsyncFromSyncIterator(syncIterator)
3839 : // alias `method` register as it's no longer used
3840 330 : Register sync_iter = method;
3841 330 : builder()->StoreAccumulatorInRegister(sync_iter).CallRuntime(
3842 330 : Runtime::kInlineCreateAsyncFromSyncIterator, sync_iter);
3843 :
3844 330 : builder()->Bind(&done);
3845 : } else {
3846 : // Let method be GetMethod(obj, @@iterator).
3847 : builder()
3848 26391 : ->StoreAccumulatorInRegister(obj)
3849 : .LoadIteratorProperty(obj,
3850 52782 : feedback_index(feedback_spec()->AddLoadICSlot()))
3851 26391 : .StoreAccumulatorInRegister(method);
3852 :
3853 : // Let iterator be Call(method, obj).
3854 : builder()->CallProperty(method, args,
3855 52782 : feedback_index(feedback_spec()->AddCallICSlot()));
3856 :
3857 : // If Type(iterator) is not Object, throw a TypeError exception.
3858 : BytecodeLabel no_type_error;
3859 26391 : builder()->JumpIfJSReceiver(&no_type_error);
3860 26391 : builder()->CallRuntime(Runtime::kThrowSymbolIteratorInvalid);
3861 26391 : builder()->Bind(&no_type_error);
3862 : }
3863 26721 : }
3864 :
3865 52956 : void BytecodeGenerator::VisitGetIterator(GetIterator* expr) {
3866 : builder()->SetExpressionPosition(expr);
3867 26478 : BuildGetIterator(expr->iterable(), expr->hint());
3868 26478 : }
3869 :
3870 4317 : void BytecodeGenerator::VisitGetTemplateObject(GetTemplateObject* expr) {
3871 : builder()->SetExpressionPosition(expr);
3872 1439 : size_t entry = builder()->AllocateDeferredConstantPoolEntry();
3873 2878 : template_objects_.push_back(std::make_pair(expr, entry));
3874 1439 : builder()->GetTemplateObject(entry);
3875 1439 : }
3876 :
3877 68806 : void BytecodeGenerator::VisitThisFunction(ThisFunction* expr) {
3878 137612 : builder()->LoadAccumulatorWithRegister(Register::function_closure());
3879 0 : }
3880 :
3881 0 : void BytecodeGenerator::VisitSuperCallReference(SuperCallReference* expr) {
3882 : // Handled by VisitCall().
3883 0 : UNREACHABLE();
3884 : }
3885 :
3886 0 : void BytecodeGenerator::VisitSuperPropertyReference(
3887 18 : SuperPropertyReference* expr) {
3888 18 : builder()->CallRuntime(Runtime::kThrowUnsupportedSuperError);
3889 0 : }
3890 :
3891 218686 : void BytecodeGenerator::VisitCommaExpression(BinaryOperation* binop) {
3892 109343 : VisitForEffect(binop->left());
3893 109343 : Visit(binop->right());
3894 109343 : }
3895 :
3896 178351 : void BytecodeGenerator::BuildLogicalTest(Token::Value token, Expression* left,
3897 535053 : Expression* right) {
3898 : DCHECK(token == Token::OR || token == Token::AND);
3899 178351 : TestResultScope* test_result = execution_result()->AsTest();
3900 : BytecodeLabels* then_labels = test_result->then_labels();
3901 : BytecodeLabels* else_labels = test_result->else_labels();
3902 : TestFallthrough fallthrough = test_result->fallthrough();
3903 : {
3904 : // Visit the left side using current TestResultScope.
3905 : BytecodeLabels test_right(zone());
3906 178351 : if (token == Token::OR) {
3907 : test_result->set_fallthrough(TestFallthrough::kElse);
3908 : test_result->set_else_labels(&test_right);
3909 : } else {
3910 : DCHECK_EQ(Token::AND, token);
3911 : test_result->set_fallthrough(TestFallthrough::kThen);
3912 : test_result->set_then_labels(&test_right);
3913 : }
3914 178351 : VisitInSameTestExecutionScope(left);
3915 178351 : test_right.Bind(builder());
3916 : }
3917 : // Visit the right side in a new TestResultScope.
3918 178351 : VisitForTest(right, then_labels, else_labels, fallthrough);
3919 178351 : }
3920 :
3921 213174 : void BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) {
3922 : Expression* left = binop->left();
3923 : Expression* right = binop->right();
3924 :
3925 147247 : if (execution_result()->IsTest()) {
3926 4341 : TestResultScope* test_result = execution_result()->AsTest();
3927 114624 : if (left->ToBooleanIsTrue()) {
3928 4341 : builder()->Jump(test_result->NewThenLabel());
3929 110283 : } else if (left->ToBooleanIsFalse() && right->ToBooleanIsFalse()) {
3930 0 : builder()->Jump(test_result->NewElseLabel());
3931 : } else {
3932 110283 : BuildLogicalTest(Token::OR, left, right);
3933 : }
3934 : test_result->SetResultConsumedByTest();
3935 : } else {
3936 32623 : if (left->ToBooleanIsTrue()) {
3937 1683 : VisitForAccumulatorValue(left);
3938 30940 : } else if (left->ToBooleanIsFalse()) {
3939 147 : VisitForAccumulatorValue(right);
3940 : } else {
3941 : BytecodeLabel end_label;
3942 30793 : TypeHint type_hint = VisitForAccumulatorValue(left);
3943 30793 : builder()->JumpIfTrue(ToBooleanModeFromTypeHint(type_hint), &end_label);
3944 30793 : VisitForAccumulatorValue(right);
3945 30793 : builder()->Bind(&end_label);
3946 : }
3947 : }
3948 147247 : }
3949 :
3950 282042 : void BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) {
3951 : Expression* left = binop->left();
3952 : Expression* right = binop->right();
3953 :
3954 140625 : if (execution_result()->IsTest()) {
3955 5 : TestResultScope* test_result = execution_result()->AsTest();
3956 68073 : if (left->ToBooleanIsFalse()) {
3957 5 : builder()->Jump(test_result->NewElseLabel());
3958 68068 : } else if (left->ToBooleanIsTrue() && right->ToBooleanIsTrue()) {
3959 0 : builder()->Jump(test_result->NewThenLabel());
3960 : } else {
3961 68068 : BuildLogicalTest(Token::AND, left, right);
3962 : }
3963 : test_result->SetResultConsumedByTest();
3964 : } else {
3965 72552 : if (left->ToBooleanIsFalse()) {
3966 147 : VisitForAccumulatorValue(left);
3967 72405 : } else if (left->ToBooleanIsTrue()) {
3968 1699 : VisitForAccumulatorValue(right);
3969 : } else {
3970 : BytecodeLabel end_label;
3971 70706 : TypeHint type_hint = VisitForAccumulatorValue(left);
3972 70706 : builder()->JumpIfFalse(ToBooleanModeFromTypeHint(type_hint), &end_label);
3973 70706 : VisitForAccumulatorValue(right);
3974 70706 : builder()->Bind(&end_label);
3975 : }
3976 : }
3977 140625 : }
3978 :
3979 1354 : void BytecodeGenerator::VisitRewritableExpression(RewritableExpression* expr) {
3980 1354 : Visit(expr->expression());
3981 1354 : }
3982 :
3983 361844 : void BytecodeGenerator::BuildNewLocalActivationContext() {
3984 : ValueResultScope value_execution_result(this);
3985 343459 : Scope* scope = closure_scope();
3986 :
3987 : // Create the appropriate context.
3988 176056 : if (scope->is_script_scope()) {
3989 7592 : RegisterList args = register_allocator()->NewRegisterList(2);
3990 : builder()
3991 15184 : ->LoadAccumulatorWithRegister(Register::function_closure())
3992 7592 : .StoreAccumulatorInRegister(args[0])
3993 7592 : .LoadLiteral(scope)
3994 7592 : .StoreAccumulatorInRegister(args[1])
3995 7592 : .CallRuntime(Runtime::kNewScriptContext, args);
3996 168464 : } else if (scope->is_module_scope()) {
3997 : // We don't need to do anything for the outer script scope.
3998 : DCHECK(scope->outer_scope()->is_script_scope());
3999 :
4000 : // A JSFunction representing a module is called with the module object as
4001 : // its sole argument, which we pass on to PushModuleContext.
4002 1067 : RegisterList args = register_allocator()->NewRegisterList(3);
4003 : builder()
4004 2134 : ->MoveRegister(builder()->Parameter(0), args[0])
4005 2134 : .LoadAccumulatorWithRegister(Register::function_closure())
4006 1067 : .StoreAccumulatorInRegister(args[1])
4007 1067 : .LoadLiteral(scope)
4008 1067 : .StoreAccumulatorInRegister(args[2])
4009 1067 : .CallRuntime(Runtime::kPushModuleContext, args);
4010 : } else {
4011 : DCHECK(scope->is_function_scope() || scope->is_eval_scope());
4012 167397 : int slot_count = scope->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
4013 167397 : if (slot_count <= ConstructorBuiltins::MaximumFunctionContextSlots()) {
4014 167391 : switch (scope->scope_type()) {
4015 : case EVAL_SCOPE:
4016 20739 : builder()->CreateEvalContext(slot_count);
4017 20739 : break;
4018 : case FUNCTION_SCOPE:
4019 146652 : builder()->CreateFunctionContext(slot_count);
4020 146652 : break;
4021 : default:
4022 0 : UNREACHABLE();
4023 : }
4024 : } else {
4025 6 : RegisterList args = register_allocator()->NewRegisterList(2);
4026 : builder()
4027 12 : ->MoveRegister(Register::function_closure(), args[0])
4028 6 : .LoadLiteral(Smi::FromInt(scope->scope_type()))
4029 6 : .StoreAccumulatorInRegister(args[1])
4030 6 : .CallRuntime(Runtime::kNewFunctionContext, args);
4031 : }
4032 : }
4033 176056 : }
4034 :
4035 488216 : void BytecodeGenerator::BuildLocalActivationContextInitialization() {
4036 242584 : DeclarationScope* scope = closure_scope();
4037 :
4038 320325 : if (scope->has_this_declaration() && scope->receiver()->IsContextSlot()) {
4039 98315 : Variable* variable = scope->receiver();
4040 98315 : Register receiver(builder()->Receiver());
4041 : // Context variable (at bottom of the context chain).
4042 : DCHECK_EQ(0, scope->ContextChainLength(variable->scope()));
4043 98315 : builder()->LoadAccumulatorWithRegister(receiver).StoreContextSlot(
4044 98315 : execution_context()->reg(), variable->index(), 0);
4045 : }
4046 :
4047 : // Copy parameters into context if necessary.
4048 : int num_parameters = scope->num_parameters();
4049 293807 : for (int i = 0; i < num_parameters; i++) {
4050 57765 : Variable* variable = scope->parameter(i);
4051 177737 : if (!variable->IsContextSlot()) continue;
4052 :
4053 57765 : Register parameter(builder()->Parameter(i));
4054 : // Context variable (at bottom of the context chain).
4055 : DCHECK_EQ(0, scope->ContextChainLength(variable->scope()));
4056 57765 : builder()->LoadAccumulatorWithRegister(parameter).StoreContextSlot(
4057 57765 : execution_context()->reg(), variable->index(), 0);
4058 : }
4059 176056 : }
4060 :
4061 113062 : void BytecodeGenerator::BuildNewLocalBlockContext(Scope* scope) {
4062 : ValueResultScope value_execution_result(this);
4063 : DCHECK(scope->is_block_scope());
4064 :
4065 56531 : VisitFunctionClosureForContext();
4066 56531 : builder()->CreateBlockContext(scope);
4067 56531 : }
4068 :
4069 9072 : void BytecodeGenerator::BuildNewLocalWithContext(Scope* scope) {
4070 : ValueResultScope value_execution_result(this);
4071 :
4072 3024 : Register extension_object = register_allocator()->NewRegister();
4073 :
4074 3024 : builder()->ToObject(extension_object);
4075 3024 : VisitFunctionClosureForContext();
4076 3024 : builder()->CreateWithContext(extension_object, scope);
4077 3024 : }
4078 :
4079 306366 : void BytecodeGenerator::BuildNewLocalCatchContext(Scope* scope) {
4080 : ValueResultScope value_execution_result(this);
4081 : DCHECK(scope->catch_variable()->IsContextSlot());
4082 :
4083 102122 : Register exception = register_allocator()->NewRegister();
4084 102122 : builder()->StoreAccumulatorInRegister(exception);
4085 102122 : VisitFunctionClosureForContext();
4086 : builder()->CreateCatchContext(exception, scope->catch_variable()->raw_name(),
4087 204244 : scope);
4088 102122 : }
4089 :
4090 8000 : void BytecodeGenerator::VisitObjectLiteralAccessor(
4091 3420 : Register home_object, ObjectLiteralProperty* property, Register value_out) {
4092 8000 : if (property == nullptr) {
4093 3420 : builder()->LoadNull().StoreAccumulatorInRegister(value_out);
4094 : } else {
4095 4580 : VisitForRegisterValue(property->value(), value_out);
4096 4580 : VisitSetHomeObject(value_out, home_object, property);
4097 : }
4098 8000 : }
4099 :
4100 406223 : void BytecodeGenerator::VisitSetHomeObject(Register value, Register home_object,
4101 525364 : LiteralProperty* property) {
4102 : Expression* expr = property->value();
4103 406223 : if (FunctionLiteral::NeedsHomeObject(expr)) {
4104 119141 : FeedbackSlot slot = feedback_spec()->AddStoreICSlot(language_mode());
4105 : builder()
4106 119141 : ->LoadAccumulatorWithRegister(home_object)
4107 119141 : .StoreHomeObjectProperty(value, feedback_index(slot), language_mode());
4108 : }
4109 406223 : }
4110 :
4111 2284219 : void BytecodeGenerator::VisitArgumentsObject(Variable* variable) {
4112 4262642 : if (variable == nullptr) return;
4113 :
4114 : DCHECK(variable->IsContextSlot() || variable->IsStackAllocated());
4115 :
4116 : // Allocate and initialize a new arguments object and assign to the
4117 : // {arguments} variable.
4118 : CreateArgumentsType type =
4119 57204 : is_strict(language_mode()) || !info()->has_simple_parameters()
4120 : ? CreateArgumentsType::kUnmappedArguments
4121 95694 : : CreateArgumentsType::kMappedArguments;
4122 95694 : builder()->CreateArguments(type);
4123 95694 : BuildVariableAssignment(variable, Token::ASSIGN, HoleCheckMode::kElided);
4124 : }
4125 :
4126 2135316 : void BytecodeGenerator::VisitRestArgumentsArray(Variable* rest) {
4127 4262646 : if (rest == nullptr) return;
4128 :
4129 : // Allocate and initialize a new rest parameter and assign to the {rest}
4130 : // variable.
4131 3993 : builder()->CreateArguments(CreateArgumentsType::kRestParameter);
4132 : DCHECK(rest->IsContextSlot() || rest->IsStackAllocated());
4133 3993 : BuildVariableAssignment(rest, Token::ASSIGN, HoleCheckMode::kElided);
4134 : }
4135 :
4136 2139411 : void BytecodeGenerator::VisitThisFunctionVariable(Variable* variable) {
4137 4262646 : if (variable == nullptr) return;
4138 :
4139 : // Store the closure we were called with in the given variable.
4140 16176 : builder()->LoadAccumulatorWithRegister(Register::function_closure());
4141 8088 : BuildVariableAssignment(variable, Token::INIT, HoleCheckMode::kElided);
4142 : }
4143 :
4144 2426005 : void BytecodeGenerator::VisitNewTargetVariable(Variable* variable) {
4145 2131321 : if (variable == nullptr) return;
4146 :
4147 : // The generator resume trampoline abuses the new.target register
4148 : // to pass in the generator object. In ordinary calls, new.target is always
4149 : // undefined because generator functions are non-constructible, so don't
4150 : // assign anything to the new.target variable.
4151 206350 : if (info()->literal()->CanSuspend()) return;
4152 :
4153 102885 : if (variable->location() == VariableLocation::LOCAL) {
4154 : // The new.target register was already assigned by entry trampoline.
4155 : DCHECK_EQ(incoming_new_target_or_generator_.index(),
4156 : GetRegisterForLocalVariable(variable).index());
4157 : return;
4158 : }
4159 :
4160 : // Store the new target we were called with in the given variable.
4161 88624 : builder()->LoadAccumulatorWithRegister(incoming_new_target_or_generator_);
4162 88624 : BuildVariableAssignment(variable, Token::INIT, HoleCheckMode::kElided);
4163 : }
4164 :
4165 24858 : void BytecodeGenerator::BuildGeneratorObjectVariableInitialization() {
4166 : DCHECK(IsResumableFunction(info()->literal()->kind()));
4167 :
4168 8286 : Variable* generator_object_var = closure_scope()->generator_object_var();
4169 : RegisterAllocationScope register_scope(this);
4170 8286 : RegisterList args = register_allocator()->NewRegisterList(2);
4171 : builder()
4172 16572 : ->MoveRegister(Register::function_closure(), args[0])
4173 16572 : .MoveRegister(builder()->Receiver(), args[1])
4174 8286 : .CallRuntime(Runtime::kInlineCreateJSGeneratorObject, args)
4175 8286 : .StoreAccumulatorInRegister(generator_object());
4176 :
4177 8286 : if (generator_object_var->location() == VariableLocation::LOCAL) {
4178 : // The generator object register is already set to the variable's local
4179 : // register.
4180 : DCHECK_EQ(generator_object().index(),
4181 : GetRegisterForLocalVariable(generator_object_var).index());
4182 : } else {
4183 : BuildVariableAssignment(generator_object_var, Token::INIT,
4184 1067 : HoleCheckMode::kElided);
4185 8286 : }
4186 8286 : }
4187 :
4188 485031 : void BytecodeGenerator::VisitFunctionClosureForContext() {
4189 : ValueResultScope value_execution_result(this);
4190 161677 : if (closure_scope()->is_script_scope()) {
4191 : // Contexts nested in the native context have a canonical empty function as
4192 : // their closure, not the anonymous closure containing the global code.
4193 23293 : Register native_context = register_allocator()->NewRegister();
4194 : builder()
4195 : ->LoadContextSlot(execution_context()->reg(),
4196 : Context::NATIVE_CONTEXT_INDEX, 0,
4197 23293 : BytecodeArrayBuilder::kImmutableSlot)
4198 23293 : .StoreAccumulatorInRegister(native_context)
4199 : .LoadContextSlot(native_context, Context::CLOSURE_INDEX, 0,
4200 23293 : BytecodeArrayBuilder::kImmutableSlot);
4201 138384 : } else if (closure_scope()->is_eval_scope()) {
4202 : // Contexts created by a call to eval have the same closure as the
4203 : // context calling eval, not the anonymous closure containing the eval
4204 : // code. Fetch it from the context.
4205 : builder()->LoadContextSlot(execution_context()->reg(),
4206 : Context::CLOSURE_INDEX, 0,
4207 25494 : BytecodeArrayBuilder::kImmutableSlot);
4208 : } else {
4209 : DCHECK(closure_scope()->is_function_scope() ||
4210 : closure_scope()->is_module_scope());
4211 225780 : builder()->LoadAccumulatorWithRegister(Register::function_closure());
4212 : }
4213 161677 : }
4214 :
4215 596 : void BytecodeGenerator::BuildPushUndefinedIntoRegisterList(
4216 596 : RegisterList* reg_list) {
4217 596 : Register reg = register_allocator()->GrowRegisterList(reg_list);
4218 596 : builder()->LoadUndefined().StoreAccumulatorInRegister(reg);
4219 596 : }
4220 :
4221 801266 : void BytecodeGenerator::BuildLoadPropertyKey(LiteralProperty* property,
4222 7237 : Register out_reg) {
4223 400633 : if (property->key()->IsStringLiteral()) {
4224 : VisitForRegisterValue(property->key(), out_reg);
4225 : } else {
4226 7237 : VisitForAccumulatorValue(property->key());
4227 7237 : builder()->ToName(out_reg);
4228 : }
4229 400633 : }
4230 :
4231 0 : int BytecodeGenerator::AllocateBlockCoverageSlotIfEnabled(
4232 : AstNode* node, SourceRangeKind kind) {
4233 2319529 : return (block_coverage_builder_ == nullptr)
4234 : ? BlockCoverageBuilder::kNoCoverageArraySlot
4235 2319529 : : block_coverage_builder_->AllocateBlockCoverageSlot(node, kind);
4236 : }
4237 :
4238 0 : void BytecodeGenerator::BuildIncrementBlockCoverageCounterIfEnabled(
4239 : AstNode* node, SourceRangeKind kind) {
4240 296892 : if (block_coverage_builder_ == nullptr) return;
4241 786 : block_coverage_builder_->IncrementBlockCounter(node, kind);
4242 : }
4243 :
4244 0 : void BytecodeGenerator::BuildIncrementBlockCoverageCounterIfEnabled(
4245 : int coverage_array_slot) {
4246 0 : if (block_coverage_builder_ != nullptr) {
4247 : block_coverage_builder_->IncrementBlockCounter(coverage_array_slot);
4248 : }
4249 0 : }
4250 :
4251 : // Visits the expression |expr| and places the result in the accumulator.
4252 18947646 : BytecodeGenerator::TypeHint BytecodeGenerator::VisitForAccumulatorValue(
4253 : Expression* expr) {
4254 : ValueResultScope accumulator_scope(this);
4255 18947646 : Visit(expr);
4256 37895316 : return accumulator_scope.type_hint();
4257 : }
4258 :
4259 112939 : void BytecodeGenerator::VisitForAccumulatorValueOrTheHole(Expression* expr) {
4260 59344 : if (expr == nullptr) {
4261 53595 : builder()->LoadTheHole();
4262 : } else {
4263 5749 : VisitForAccumulatorValue(expr);
4264 : }
4265 59344 : }
4266 :
4267 : // Visits the expression |expr| and discards the result.
4268 9541607 : void BytecodeGenerator::VisitForEffect(Expression* expr) {
4269 : EffectResultScope effect_scope(this);
4270 9541607 : Visit(expr);
4271 9541610 : }
4272 :
4273 : // Visits the expression |expr| and returns the register containing
4274 : // the expression result.
4275 12517496 : Register BytecodeGenerator::VisitForRegisterValue(Expression* expr) {
4276 6258747 : VisitForAccumulatorValue(expr);
4277 6258749 : Register result = register_allocator()->NewRegister();
4278 6258749 : builder()->StoreAccumulatorInRegister(result);
4279 6258748 : return result;
4280 : }
4281 :
4282 : // Visits the expression |expr| and stores the expression result in
4283 : // |destination|.
4284 : void BytecodeGenerator::VisitForRegisterValue(Expression* expr,
4285 1543408 : Register destination) {
4286 1543406 : ValueResultScope register_scope(this);
4287 1543406 : Visit(expr);
4288 1543408 : builder()->StoreAccumulatorInRegister(destination);
4289 : }
4290 :
4291 : // Visits the expression |expr| and pushes the result into a new register
4292 : // added to the end of |reg_list|.
4293 8176847 : void BytecodeGenerator::VisitAndPushIntoRegisterList(Expression* expr,
4294 8176848 : RegisterList* reg_list) {
4295 : {
4296 : ValueResultScope register_scope(this);
4297 8176847 : Visit(expr);
4298 : }
4299 : // Grow the register list after visiting the expression to avoid reserving
4300 : // the register across the expression evaluation, which could cause memory
4301 : // leaks for deep expressions due to dead objects being kept alive by pointers
4302 : // in registers.
4303 8176848 : Register destination = register_allocator()->GrowRegisterList(reg_list);
4304 8176848 : builder()->StoreAccumulatorInRegister(destination);
4305 8176846 : }
4306 :
4307 1229536 : void BytecodeGenerator::BuildTest(ToBooleanMode mode,
4308 : BytecodeLabels* then_labels,
4309 : BytecodeLabels* else_labels,
4310 1229536 : TestFallthrough fallthrough) {
4311 1229536 : switch (fallthrough) {
4312 : case TestFallthrough::kThen:
4313 1803368 : builder()->JumpIfFalse(mode, else_labels->New());
4314 901684 : break;
4315 : case TestFallthrough::kElse:
4316 655704 : builder()->JumpIfTrue(mode, then_labels->New());
4317 327852 : break;
4318 : case TestFallthrough::kNone:
4319 0 : builder()->JumpIfTrue(mode, then_labels->New());
4320 0 : builder()->Jump(else_labels->New());
4321 0 : break;
4322 : }
4323 1229536 : }
4324 :
4325 : // Visits the expression |expr| for testing its boolean value and jumping to the
4326 : // |then| or |other| label depending on value and short-circuit semantics
4327 1356473 : void BytecodeGenerator::VisitForTest(Expression* expr,
4328 : BytecodeLabels* then_labels,
4329 : BytecodeLabels* else_labels,
4330 : TestFallthrough fallthrough) {
4331 : bool result_consumed;
4332 : TypeHint type_hint;
4333 : {
4334 : // To make sure that all temporary registers are returned before generating
4335 : // jumps below, we ensure that the result scope is deleted before doing so.
4336 : // Dead registers might be materialized otherwise.
4337 : TestResultScope test_result(this, then_labels, else_labels, fallthrough);
4338 1356473 : Visit(expr);
4339 1356472 : result_consumed = test_result.result_consumed_by_test();
4340 1356472 : type_hint = test_result.type_hint();
4341 : // Labels and fallthrough might have been mutated, so update based on
4342 : // TestResultScope.
4343 1356472 : then_labels = test_result.then_labels();
4344 1356472 : else_labels = test_result.else_labels();
4345 1356472 : fallthrough = test_result.fallthrough();
4346 : }
4347 1356472 : if (!result_consumed) {
4348 : BuildTest(ToBooleanModeFromTypeHint(type_hint), then_labels, else_labels,
4349 894424 : fallthrough);
4350 : }
4351 1356472 : }
4352 :
4353 923478 : void BytecodeGenerator::VisitInSameTestExecutionScope(Expression* expr) {
4354 : DCHECK(execution_result()->IsTest());
4355 : {
4356 : RegisterAllocationScope reg_scope(this);
4357 461739 : Visit(expr);
4358 : }
4359 461739 : if (!execution_result()->AsTest()->result_consumed_by_test()) {
4360 335112 : TestResultScope* result_scope = execution_result()->AsTest();
4361 : BuildTest(ToBooleanModeFromTypeHint(result_scope->type_hint()),
4362 : result_scope->then_labels(), result_scope->else_labels(),
4363 670224 : result_scope->fallthrough());
4364 : result_scope->SetResultConsumedByTest();
4365 : }
4366 461739 : }
4367 :
4368 105146 : void BytecodeGenerator::VisitInScope(Statement* stmt, Scope* scope) {
4369 : DCHECK(scope->declarations()->is_empty());
4370 : CurrentScope current_scope(this, scope);
4371 210292 : ContextScope context_scope(this, scope);
4372 105146 : Visit(stmt);
4373 105146 : }
4374 :
4375 21480 : Register BytecodeGenerator::GetRegisterForLocalVariable(Variable* variable) {
4376 : DCHECK_EQ(VariableLocation::LOCAL, variable->location());
4377 21480 : return builder()->Local(variable->index());
4378 : }
4379 :
4380 23775 : FunctionKind BytecodeGenerator::function_kind() const {
4381 23775 : return info()->literal()->kind();
4382 : }
4383 :
4384 6085811 : LanguageMode BytecodeGenerator::language_mode() const {
4385 : return current_scope()->language_mode();
4386 : }
4387 :
4388 : Register BytecodeGenerator::generator_object() const {
4389 : DCHECK(info()->literal()->CanSuspend());
4390 : return incoming_new_target_or_generator_;
4391 : }
4392 :
4393 19398787 : FeedbackVectorSpec* BytecodeGenerator::feedback_spec() {
4394 : return info()->feedback_vector_spec();
4395 : }
4396 :
4397 : int BytecodeGenerator::feedback_index(FeedbackSlot slot) const {
4398 : DCHECK(!slot.IsInvalid());
4399 : return FeedbackVector::GetIndex(slot);
4400 : }
4401 :
4402 3897155 : FeedbackSlot BytecodeGenerator::GetCachedLoadGlobalICSlot(
4403 6313418 : TypeofMode typeof_mode, Variable* variable) {
4404 3897155 : FeedbackSlot slot = feedback_slot_cache()->Get(typeof_mode, variable);
4405 3897155 : if (!slot.IsInvalid()) {
4406 1480892 : return slot;
4407 : }
4408 2416263 : slot = feedback_spec()->AddLoadGlobalICSlot(typeof_mode);
4409 : feedback_slot_cache()->Put(typeof_mode, variable, slot);
4410 2416263 : return slot;
4411 : }
4412 :
4413 4157075 : FeedbackSlot BytecodeGenerator::GetCachedCreateClosureSlot(
4414 8314148 : FunctionLiteral* literal) {
4415 4157075 : FeedbackSlot slot = feedback_slot_cache()->Get(literal);
4416 4157074 : if (!slot.IsInvalid()) {
4417 0 : return slot;
4418 : }
4419 4157074 : slot = feedback_spec()->AddCreateClosureSlot();
4420 : feedback_slot_cache()->Put(literal, slot);
4421 4157072 : return slot;
4422 : }
4423 :
4424 : Runtime::FunctionId BytecodeGenerator::StoreToSuperRuntimeId() {
4425 : return is_strict(language_mode()) ? Runtime::kStoreToSuper_Strict
4426 268 : : Runtime::kStoreToSuper_Sloppy;
4427 : }
4428 :
4429 : Runtime::FunctionId BytecodeGenerator::StoreKeyedToSuperRuntimeId() {
4430 : return is_strict(language_mode()) ? Runtime::kStoreKeyedToSuper_Strict
4431 433 : : Runtime::kStoreKeyedToSuper_Sloppy;
4432 : }
4433 :
4434 : } // namespace interpreter
4435 : } // namespace internal
4436 : } // namespace v8
|