1 // Copyright 2014 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/compiler/ast-graph-builder.h"
6
7 #include "src/ast/compile-time-value.h"
8 #include "src/ast/scopes.h"
9 #include "src/compilation-info.h"
10 #include "src/compiler.h"
11 #include "src/compiler/ast-loop-assignment-analyzer.h"
12 #include "src/compiler/control-builders.h"
13 #include "src/compiler/linkage.h"
14 #include "src/compiler/liveness-analyzer.h"
15 #include "src/compiler/machine-operator.h"
16 #include "src/compiler/node-matchers.h"
17 #include "src/compiler/node-properties.h"
18 #include "src/compiler/operator-properties.h"
19 #include "src/compiler/state-values-utils.h"
20 #include "src/compiler/type-hint-analyzer.h"
21
22 namespace v8 {
23 namespace internal {
24 namespace compiler {
25
26
27 // Each expression in the AST is evaluated in a specific context. This context
28 // decides how the evaluation result is passed up the visitor.
29 class AstGraphBuilder::AstContext BASE_EMBEDDED {
30 public:
IsEffect() const31 bool IsEffect() const { return kind_ == Expression::kEffect; }
IsValue() const32 bool IsValue() const { return kind_ == Expression::kValue; }
IsTest() const33 bool IsTest() const { return kind_ == Expression::kTest; }
34
35 // Determines how to combine the frame state with the value
36 // that is about to be plugged into this AstContext.
GetStateCombine()37 OutputFrameStateCombine GetStateCombine() {
38 return IsEffect() ? OutputFrameStateCombine::Ignore()
39 : OutputFrameStateCombine::Push();
40 }
41
42 // Plug a node into this expression context. Call this function in tail
43 // position in the Visit functions for expressions.
44 virtual void ProduceValue(Expression* expr, Node* value) = 0;
45
46 // Unplugs a node from this expression context. Call this to retrieve the
47 // result of another Visit function that already plugged the context.
48 virtual Node* ConsumeValue() = 0;
49
50 // Shortcut for "context->ProduceValue(context->ConsumeValue())".
ReplaceValue(Expression * expr)51 void ReplaceValue(Expression* expr) { ProduceValue(expr, ConsumeValue()); }
52
53 protected:
54 AstContext(AstGraphBuilder* owner, Expression::Context kind);
55 virtual ~AstContext();
56
owner() const57 AstGraphBuilder* owner() const { return owner_; }
environment() const58 Environment* environment() const { return owner_->environment(); }
59
60 // We want to be able to assert, in a context-specific way, that the stack
61 // height makes sense when the context is filled.
62 #ifdef DEBUG
63 int original_height_;
64 #endif
65
66 private:
67 Expression::Context kind_;
68 AstGraphBuilder* owner_;
69 AstContext* outer_;
70 };
71
72
73 // Context to evaluate expression for its side effects only.
74 class AstGraphBuilder::AstEffectContext final : public AstContext {
75 public:
AstEffectContext(AstGraphBuilder * owner)76 explicit AstEffectContext(AstGraphBuilder* owner)
77 : AstContext(owner, Expression::kEffect) {}
78 ~AstEffectContext() final;
79 void ProduceValue(Expression* expr, Node* value) final;
80 Node* ConsumeValue() final;
81 };
82
83
84 // Context to evaluate expression for its value (and side effects).
85 class AstGraphBuilder::AstValueContext final : public AstContext {
86 public:
AstValueContext(AstGraphBuilder * owner)87 explicit AstValueContext(AstGraphBuilder* owner)
88 : AstContext(owner, Expression::kValue) {}
89 ~AstValueContext() final;
90 void ProduceValue(Expression* expr, Node* value) final;
91 Node* ConsumeValue() final;
92 };
93
94
95 // Context to evaluate expression for a condition value (and side effects).
96 class AstGraphBuilder::AstTestContext final : public AstContext {
97 public:
AstTestContext(AstGraphBuilder * owner,TypeFeedbackId feedback_id)98 AstTestContext(AstGraphBuilder* owner, TypeFeedbackId feedback_id)
99 : AstContext(owner, Expression::kTest), feedback_id_(feedback_id) {}
100 ~AstTestContext() final;
101 void ProduceValue(Expression* expr, Node* value) final;
102 Node* ConsumeValue() final;
103
104 private:
105 TypeFeedbackId const feedback_id_;
106 };
107
108
109 // Scoped class tracking context objects created by the visitor. Represents
110 // mutations of the context chain within the function body and allows to
111 // change the current {scope} and {context} during visitation.
112 class AstGraphBuilder::ContextScope BASE_EMBEDDED {
113 public:
ContextScope(AstGraphBuilder * builder,Scope * scope,Node * context)114 ContextScope(AstGraphBuilder* builder, Scope* scope, Node* context)
115 : builder_(builder),
116 outer_(builder->execution_context()),
117 scope_(scope),
118 depth_(builder_->environment()->context_chain_length()) {
119 builder_->environment()->PushContext(context); // Push.
120 builder_->set_execution_context(this);
121 }
122
~ContextScope()123 ~ContextScope() {
124 builder_->set_execution_context(outer_); // Pop.
125 builder_->environment()->PopContext();
126 CHECK_EQ(depth_, builder_->environment()->context_chain_length());
127 }
128
129 // Current scope during visitation.
scope() const130 Scope* scope() const { return scope_; }
131
132 private:
133 AstGraphBuilder* builder_;
134 ContextScope* outer_;
135 Scope* scope_;
136 int depth_;
137 };
138
139
140 // Scoped class tracking control statements entered by the visitor. There are
141 // different types of statements participating in this stack to properly track
142 // local as well as non-local control flow:
143 // - IterationStatement : Allows proper 'break' and 'continue' behavior.
144 // - BreakableStatement : Allows 'break' from block and switch statements.
145 // - TryCatchStatement : Intercepts 'throw' and implicit exceptional edges.
146 // - TryFinallyStatement: Intercepts 'break', 'continue', 'throw' and 'return'.
147 class AstGraphBuilder::ControlScope BASE_EMBEDDED {
148 public:
ControlScope(AstGraphBuilder * builder)149 explicit ControlScope(AstGraphBuilder* builder)
150 : builder_(builder),
151 outer_(builder->execution_control()),
152 context_length_(builder->environment()->context_chain_length()),
153 stack_height_(builder->environment()->stack_height()) {
154 builder_->set_execution_control(this); // Push.
155 }
156
~ControlScope()157 virtual ~ControlScope() {
158 builder_->set_execution_control(outer_); // Pop.
159 }
160
161 // Either 'break' or 'continue' to the target statement.
162 void BreakTo(BreakableStatement* target);
163 void ContinueTo(BreakableStatement* target);
164
165 // Either 'return' or 'throw' the given value.
166 void ReturnValue(Node* return_value);
167 void ThrowValue(Node* exception_value);
168
169 class DeferredCommands;
170
171 protected:
172 enum Command { CMD_BREAK, CMD_CONTINUE, CMD_RETURN, CMD_THROW };
173
174 // Performs one of the above commands on this stack of control scopes. This
175 // walks through the stack giving each scope a chance to execute or defer the
176 // given command by overriding the {Execute} method appropriately. Note that
177 // this also drops extra operands from the environment for each skipped scope.
178 void PerformCommand(Command cmd, Statement* target, Node* value);
179
180 // Interface to execute a given command in this scope. Returning {true} here
181 // indicates successful execution whereas {false} requests to skip scope.
Execute(Command cmd,Statement * target,Node ** value)182 virtual bool Execute(Command cmd, Statement* target, Node** value) {
183 // For function-level control.
184 switch (cmd) {
185 case CMD_THROW:
186 builder()->BuildThrow(*value);
187 return true;
188 case CMD_RETURN:
189 builder()->BuildReturn(*value);
190 return true;
191 case CMD_BREAK:
192 case CMD_CONTINUE:
193 break;
194 }
195 return false;
196 }
197
environment()198 Environment* environment() { return builder_->environment(); }
builder() const199 AstGraphBuilder* builder() const { return builder_; }
context_length() const200 int context_length() const { return context_length_; }
stack_height() const201 int stack_height() const { return stack_height_; }
202
203 private:
204 AstGraphBuilder* builder_;
205 ControlScope* outer_;
206 int context_length_;
207 int stack_height_;
208 };
209
210 // Helper class for a try-finally control scope. It can record intercepted
211 // control-flow commands that cause entry into a finally-block, and re-apply
212 // them after again leaving that block. Special tokens are used to identify
213 // paths going through the finally-block to dispatch after leaving the block.
214 class AstGraphBuilder::ControlScope::DeferredCommands : public ZoneObject {
215 public:
DeferredCommands(AstGraphBuilder * owner)216 explicit DeferredCommands(AstGraphBuilder* owner)
217 : owner_(owner),
218 deferred_(owner->local_zone()),
219 return_token_(nullptr),
220 throw_token_(nullptr) {}
221
222 // One recorded control-flow command.
223 struct Entry {
224 Command command; // The command type being applied on this path.
225 Statement* statement; // The target statement for the command or {nullptr}.
226 Node* token; // A token identifying this particular path.
227 };
228
229 // Records a control-flow command while entering the finally-block. This also
230 // generates a new dispatch token that identifies one particular path.
RecordCommand(Command cmd,Statement * stmt,Node * value)231 Node* RecordCommand(Command cmd, Statement* stmt, Node* value) {
232 Node* token = nullptr;
233 switch (cmd) {
234 case CMD_BREAK:
235 case CMD_CONTINUE:
236 token = NewPathToken(dispenser_.GetBreakContinueToken());
237 break;
238 case CMD_THROW:
239 if (throw_token_) return throw_token_;
240 token = NewPathToken(TokenDispenserForFinally::kThrowToken);
241 throw_token_ = token;
242 break;
243 case CMD_RETURN:
244 if (return_token_) return return_token_;
245 token = NewPathToken(TokenDispenserForFinally::kReturnToken);
246 return_token_ = token;
247 break;
248 }
249 DCHECK_NOT_NULL(token);
250 deferred_.push_back({cmd, stmt, token});
251 return token;
252 }
253
254 // Returns the dispatch token to be used to identify the implicit fall-through
255 // path at the end of a try-block into the corresponding finally-block.
GetFallThroughToken()256 Node* GetFallThroughToken() { return NewPathTokenForImplicitFallThrough(); }
257
258 // Applies all recorded control-flow commands after the finally-block again.
259 // This generates a dynamic dispatch on the token from the entry point.
ApplyDeferredCommands(Node * token,Node * value)260 void ApplyDeferredCommands(Node* token, Node* value) {
261 SwitchBuilder dispatch(owner_, static_cast<int>(deferred_.size()));
262 dispatch.BeginSwitch();
263 for (size_t i = 0; i < deferred_.size(); ++i) {
264 Node* condition = NewPathDispatchCondition(token, deferred_[i].token);
265 dispatch.BeginLabel(static_cast<int>(i), condition);
266 dispatch.EndLabel();
267 }
268 for (size_t i = 0; i < deferred_.size(); ++i) {
269 dispatch.BeginCase(static_cast<int>(i));
270 owner_->execution_control()->PerformCommand(
271 deferred_[i].command, deferred_[i].statement, value);
272 dispatch.EndCase();
273 }
274 dispatch.EndSwitch();
275 }
276
277 protected:
NewPathToken(int token_id)278 Node* NewPathToken(int token_id) {
279 return owner_->jsgraph()->Constant(token_id);
280 }
NewPathTokenForImplicitFallThrough()281 Node* NewPathTokenForImplicitFallThrough() {
282 return NewPathToken(TokenDispenserForFinally::kFallThroughToken);
283 }
NewPathDispatchCondition(Node * t1,Node * t2)284 Node* NewPathDispatchCondition(Node* t1, Node* t2) {
285 return owner_->NewNode(
286 owner_->javascript()->StrictEqual(CompareOperationHint::kAny), t1, t2);
287 }
288
289 private:
290 TokenDispenserForFinally dispenser_;
291 AstGraphBuilder* owner_;
292 ZoneVector<Entry> deferred_;
293 Node* return_token_;
294 Node* throw_token_;
295 };
296
297
298 // Control scope implementation for a BreakableStatement.
299 class AstGraphBuilder::ControlScopeForBreakable : public ControlScope {
300 public:
ControlScopeForBreakable(AstGraphBuilder * owner,BreakableStatement * target,ControlBuilder * control)301 ControlScopeForBreakable(AstGraphBuilder* owner, BreakableStatement* target,
302 ControlBuilder* control)
303 : ControlScope(owner), target_(target), control_(control) {}
304
305 protected:
Execute(Command cmd,Statement * target,Node ** value)306 bool Execute(Command cmd, Statement* target, Node** value) override {
307 if (target != target_) return false; // We are not the command target.
308 switch (cmd) {
309 case CMD_BREAK:
310 control_->Break();
311 return true;
312 case CMD_CONTINUE:
313 case CMD_THROW:
314 case CMD_RETURN:
315 break;
316 }
317 return false;
318 }
319
320 private:
321 BreakableStatement* target_;
322 ControlBuilder* control_;
323 };
324
325
326 // Control scope implementation for an IterationStatement.
327 class AstGraphBuilder::ControlScopeForIteration : public ControlScope {
328 public:
ControlScopeForIteration(AstGraphBuilder * owner,IterationStatement * target,LoopBuilder * control)329 ControlScopeForIteration(AstGraphBuilder* owner, IterationStatement* target,
330 LoopBuilder* control)
331 : ControlScope(owner), target_(target), control_(control) {}
332
333 protected:
Execute(Command cmd,Statement * target,Node ** value)334 bool Execute(Command cmd, Statement* target, Node** value) override {
335 if (target != target_) {
336 control_->ExitLoop(value);
337 return false;
338 }
339 switch (cmd) {
340 case CMD_BREAK:
341 control_->Break();
342 return true;
343 case CMD_CONTINUE:
344 control_->Continue();
345 return true;
346 case CMD_THROW:
347 case CMD_RETURN:
348 break;
349 }
350 return false;
351 }
352
353 private:
354 BreakableStatement* target_;
355 LoopBuilder* control_;
356 };
357
358
359 // Control scope implementation for a TryCatchStatement.
360 class AstGraphBuilder::ControlScopeForCatch : public ControlScope {
361 public:
ControlScopeForCatch(AstGraphBuilder * owner,TryCatchStatement * stmt,TryCatchBuilder * control)362 ControlScopeForCatch(AstGraphBuilder* owner, TryCatchStatement* stmt,
363 TryCatchBuilder* control)
364 : ControlScope(owner), control_(control) {
365 builder()->try_nesting_level_++; // Increment nesting.
366 }
~ControlScopeForCatch()367 ~ControlScopeForCatch() {
368 builder()->try_nesting_level_--; // Decrement nesting.
369 }
370
371 protected:
Execute(Command cmd,Statement * target,Node ** value)372 bool Execute(Command cmd, Statement* target, Node** value) override {
373 switch (cmd) {
374 case CMD_THROW:
375 control_->Throw(*value);
376 return true;
377 case CMD_BREAK:
378 case CMD_CONTINUE:
379 case CMD_RETURN:
380 break;
381 }
382 return false;
383 }
384
385 private:
386 TryCatchBuilder* control_;
387 };
388
389
390 // Control scope implementation for a TryFinallyStatement.
391 class AstGraphBuilder::ControlScopeForFinally : public ControlScope {
392 public:
ControlScopeForFinally(AstGraphBuilder * owner,TryFinallyStatement * stmt,DeferredCommands * commands,TryFinallyBuilder * control)393 ControlScopeForFinally(AstGraphBuilder* owner, TryFinallyStatement* stmt,
394 DeferredCommands* commands, TryFinallyBuilder* control)
395 : ControlScope(owner), commands_(commands), control_(control) {
396 builder()->try_nesting_level_++; // Increment nesting.
397 }
~ControlScopeForFinally()398 ~ControlScopeForFinally() {
399 builder()->try_nesting_level_--; // Decrement nesting.
400 }
401
402 protected:
Execute(Command cmd,Statement * target,Node ** value)403 bool Execute(Command cmd, Statement* target, Node** value) override {
404 Node* token = commands_->RecordCommand(cmd, target, *value);
405 control_->LeaveTry(token, *value);
406 return true;
407 }
408
409 private:
410 DeferredCommands* commands_;
411 TryFinallyBuilder* control_;
412 };
413
AstGraphBuilder(Zone * local_zone,CompilationInfo * info,JSGraph * jsgraph,float invocation_frequency,LoopAssignmentAnalysis * loop,TypeHintAnalysis * type_hint_analysis)414 AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info,
415 JSGraph* jsgraph, float invocation_frequency,
416 LoopAssignmentAnalysis* loop,
417 TypeHintAnalysis* type_hint_analysis)
418 : isolate_(info->isolate()),
419 local_zone_(local_zone),
420 info_(info),
421 jsgraph_(jsgraph),
422 invocation_frequency_(invocation_frequency),
423 environment_(nullptr),
424 ast_context_(nullptr),
425 globals_(0, local_zone),
426 execution_control_(nullptr),
427 execution_context_(nullptr),
428 try_nesting_level_(0),
429 input_buffer_size_(0),
430 input_buffer_(nullptr),
431 exit_controls_(local_zone),
432 loop_assignment_analysis_(loop),
433 type_hint_analysis_(type_hint_analysis),
434 state_values_cache_(jsgraph),
435 liveness_analyzer_(static_cast<size_t>(info->scope()->num_stack_slots()),
436 false, local_zone),
437 frame_state_function_info_(common()->CreateFrameStateFunctionInfo(
438 FrameStateType::kJavaScriptFunction, info->num_parameters() + 1,
439 info->scope()->num_stack_slots(), info->shared_info())) {
440 InitializeAstVisitor(info->isolate());
441 }
442
443
GetFunctionClosureForContext()444 Node* AstGraphBuilder::GetFunctionClosureForContext() {
445 DeclarationScope* closure_scope = current_scope()->GetClosureScope();
446 if (closure_scope->is_script_scope() ||
447 closure_scope->is_module_scope()) {
448 // Contexts nested in the native context have a canonical empty function as
449 // their closure, not the anonymous closure containing the global code.
450 return BuildLoadNativeContextField(Context::CLOSURE_INDEX);
451 } else if (closure_scope->is_eval_scope()) {
452 // Contexts nested inside eval code have the same closure as the context
453 // calling eval, not the anonymous closure containing the eval code.
454 const Operator* op =
455 javascript()->LoadContext(0, Context::CLOSURE_INDEX, false);
456 return NewNode(op, current_context());
457 } else {
458 DCHECK(closure_scope->is_function_scope());
459 return GetFunctionClosure();
460 }
461 }
462
463
GetFunctionClosure()464 Node* AstGraphBuilder::GetFunctionClosure() {
465 if (!function_closure_.is_set()) {
466 int index = Linkage::kJSCallClosureParamIndex;
467 const Operator* op = common()->Parameter(index, "%closure");
468 Node* node = NewNode(op, graph()->start());
469 function_closure_.set(node);
470 }
471 return function_closure_.get();
472 }
473
474
GetFunctionContext()475 Node* AstGraphBuilder::GetFunctionContext() {
476 if (!function_context_.is_set()) {
477 int params = info()->num_parameters_including_this();
478 int index = Linkage::GetJSCallContextParamIndex(params);
479 const Operator* op = common()->Parameter(index, "%context");
480 Node* node = NewNode(op, graph()->start());
481 function_context_.set(node);
482 }
483 return function_context_.get();
484 }
485
486
GetNewTarget()487 Node* AstGraphBuilder::GetNewTarget() {
488 if (!new_target_.is_set()) {
489 int params = info()->num_parameters_including_this();
490 int index = Linkage::GetJSCallNewTargetParamIndex(params);
491 const Operator* op = common()->Parameter(index, "%new.target");
492 Node* node = NewNode(op, graph()->start());
493 new_target_.set(node);
494 }
495 return new_target_.get();
496 }
497
GetEmptyFrameState()498 Node* AstGraphBuilder::GetEmptyFrameState() {
499 if (!empty_frame_state_.is_set()) {
500 const Operator* op = common()->FrameState(
501 BailoutId::None(), OutputFrameStateCombine::Ignore(), nullptr);
502 Node* node = graph()->NewNode(
503 op, jsgraph()->EmptyStateValues(), jsgraph()->EmptyStateValues(),
504 jsgraph()->EmptyStateValues(), jsgraph()->NoContextConstant(),
505 jsgraph()->UndefinedConstant(), graph()->start());
506 empty_frame_state_.set(node);
507 }
508 return empty_frame_state_.get();
509 }
510
CreateGraph(bool stack_check)511 bool AstGraphBuilder::CreateGraph(bool stack_check) {
512 DeclarationScope* scope = info()->scope();
513 DCHECK_NOT_NULL(graph());
514
515 // Set up the basic structure of the graph. Outputs for {Start} are the formal
516 // parameters (including the receiver) plus new target, number of arguments,
517 // context and closure.
518 int actual_parameter_count = info()->num_parameters_including_this() + 4;
519 graph()->SetStart(graph()->NewNode(common()->Start(actual_parameter_count)));
520
521 // Initialize the top-level environment.
522 Environment env(this, scope, graph()->start());
523 set_environment(&env);
524
525 if (info()->is_osr()) {
526 // Use OSR normal entry as the start of the top-level environment.
527 // It will be replaced with {Dead} after typing and optimizations.
528 NewNode(common()->OsrNormalEntry());
529 }
530
531 // Initialize the incoming context.
532 ContextScope incoming(this, scope, GetFunctionContext());
533
534 // Initialize control scope.
535 ControlScope control(this);
536
537 // TODO(mstarzinger): For now we cannot assume that the {this} parameter is
538 // not {the_hole}, because for derived classes {this} has a TDZ and the
539 // JSConstructStubForDerived magically passes {the_hole} as a receiver.
540 if (scope->has_this_declaration() && scope->receiver()->mode() == CONST) {
541 env.RawParameterBind(0, jsgraph()->TheHoleConstant());
542 }
543
544 if (scope->NeedsContext()) {
545 // Push a new inner context scope for the current activation.
546 Node* inner_context = BuildLocalActivationContext(GetFunctionContext());
547 ContextScope top_context(this, scope, inner_context);
548 CreateGraphBody(stack_check);
549 } else {
550 // Simply use the outer function context in building the graph.
551 CreateGraphBody(stack_check);
552 }
553
554 // Finish the basic structure of the graph.
555 DCHECK_NE(0u, exit_controls_.size());
556 int const input_count = static_cast<int>(exit_controls_.size());
557 Node** const inputs = &exit_controls_.front();
558 Node* end = graph()->NewNode(common()->End(input_count), input_count, inputs);
559 graph()->SetEnd(end);
560
561 // Compute local variable liveness information and use it to relax
562 // frame states.
563 ClearNonLiveSlotsInFrameStates();
564
565 // Failures indicated by stack overflow.
566 return !HasStackOverflow();
567 }
568
569
CreateGraphBody(bool stack_check)570 void AstGraphBuilder::CreateGraphBody(bool stack_check) {
571 DeclarationScope* scope = info()->scope();
572
573 // Build the arguments object if it is used.
574 BuildArgumentsObject(scope->arguments());
575
576 // Build rest arguments array if it is used.
577 Variable* rest_parameter = scope->rest_parameter();
578 BuildRestArgumentsArray(rest_parameter);
579
580 // Build assignment to {.this_function} variable if it is used.
581 BuildThisFunctionVariable(scope->this_function_var());
582
583 // Build assignment to {new.target} variable if it is used.
584 BuildNewTargetVariable(scope->new_target_var());
585
586 // Emit tracing call if requested to do so.
587 if (FLAG_trace) {
588 NewNode(javascript()->CallRuntime(Runtime::kTraceEnter));
589 }
590
591 // Visit declarations within the function scope.
592 VisitDeclarations(scope->declarations());
593
594 // Build a stack-check before the body.
595 if (stack_check) {
596 Node* node = NewNode(javascript()->StackCheck());
597 PrepareFrameState(node, BailoutId::FunctionEntry());
598 }
599
600 // Visit statements in the function body.
601 VisitStatements(info()->literal()->body());
602
603 // Return 'undefined' in case we can fall off the end.
604 BuildReturn(jsgraph()->UndefinedConstant());
605 }
606
607
ClearNonLiveSlotsInFrameStates()608 void AstGraphBuilder::ClearNonLiveSlotsInFrameStates() {
609 if (!FLAG_analyze_environment_liveness ||
610 !info()->is_deoptimization_enabled()) {
611 return;
612 }
613
614 NonLiveFrameStateSlotReplacer replacer(
615 &state_values_cache_, jsgraph()->OptimizedOutConstant(),
616 liveness_analyzer()->local_count(), false, local_zone());
617 Variable* arguments = info()->scope()->arguments();
618 if (arguments != nullptr && arguments->IsStackAllocated()) {
619 replacer.MarkPermanentlyLive(arguments->index());
620 }
621 liveness_analyzer()->Run(&replacer);
622 if (FLAG_trace_environment_liveness) {
623 OFStream os(stdout);
624 liveness_analyzer()->Print(os);
625 }
626 }
627
628
629 // Gets the bailout id just before reading a variable proxy, but only for
630 // unallocated variables.
BeforeId(VariableProxy * proxy)631 static BailoutId BeforeId(VariableProxy* proxy) {
632 return proxy->var()->IsUnallocated() ? proxy->BeforeId() : BailoutId::None();
633 }
634
GetDebugParameterName(Zone * zone,DeclarationScope * scope,int index)635 static const char* GetDebugParameterName(Zone* zone, DeclarationScope* scope,
636 int index) {
637 #if DEBUG
638 const AstRawString* name = scope->parameter(index)->raw_name();
639 if (name && name->length() > 0) {
640 char* data = zone->NewArray<char>(name->length() + 1);
641 data[name->length()] = 0;
642 memcpy(data, name->raw_data(), name->length());
643 return data;
644 }
645 #endif
646 return nullptr;
647 }
648
Environment(AstGraphBuilder * builder,DeclarationScope * scope,Node * control_dependency)649 AstGraphBuilder::Environment::Environment(AstGraphBuilder* builder,
650 DeclarationScope* scope,
651 Node* control_dependency)
652 : builder_(builder),
653 parameters_count_(scope->num_parameters() + 1),
654 locals_count_(scope->num_stack_slots()),
655 liveness_block_(IsLivenessAnalysisEnabled()
656 ? builder_->liveness_analyzer()->NewBlock()
657 : nullptr),
658 values_(builder_->local_zone()),
659 contexts_(builder_->local_zone()),
660 control_dependency_(control_dependency),
661 effect_dependency_(control_dependency),
662 parameters_node_(nullptr),
663 locals_node_(nullptr),
664 stack_node_(nullptr) {
665 DCHECK_EQ(scope->num_parameters() + 1, parameters_count());
666
667 // Bind the receiver variable.
668 int param_num = 0;
669 if (builder->info()->is_this_defined()) {
670 const Operator* op = common()->Parameter(param_num++, "%this");
671 Node* receiver = builder->graph()->NewNode(op, builder->graph()->start());
672 values()->push_back(receiver);
673 } else {
674 values()->push_back(builder->jsgraph()->UndefinedConstant());
675 }
676
677 // Bind all parameter variables. The parameter indices are shifted by 1
678 // (receiver is variable index -1 but {Parameter} node index 0 and located at
679 // index 0 in the environment).
680 for (int i = 0; i < scope->num_parameters(); ++i) {
681 const char* debug_name = GetDebugParameterName(graph()->zone(), scope, i);
682 const Operator* op = common()->Parameter(param_num++, debug_name);
683 Node* parameter = builder->graph()->NewNode(op, builder->graph()->start());
684 values()->push_back(parameter);
685 }
686
687 // Bind all local variables to undefined.
688 Node* undefined_constant = builder->jsgraph()->UndefinedConstant();
689 values()->insert(values()->end(), locals_count(), undefined_constant);
690 }
691
692
Environment(AstGraphBuilder::Environment * copy,LivenessAnalyzerBlock * liveness_block)693 AstGraphBuilder::Environment::Environment(AstGraphBuilder::Environment* copy,
694 LivenessAnalyzerBlock* liveness_block)
695 : builder_(copy->builder_),
696 parameters_count_(copy->parameters_count_),
697 locals_count_(copy->locals_count_),
698 liveness_block_(liveness_block),
699 values_(copy->zone()),
700 contexts_(copy->zone()),
701 control_dependency_(copy->control_dependency_),
702 effect_dependency_(copy->effect_dependency_),
703 parameters_node_(copy->parameters_node_),
704 locals_node_(copy->locals_node_),
705 stack_node_(copy->stack_node_) {
706 const size_t kStackEstimate = 7; // optimum from experimentation!
707 values_.reserve(copy->values_.size() + kStackEstimate);
708 values_.insert(values_.begin(), copy->values_.begin(), copy->values_.end());
709 contexts_.reserve(copy->contexts_.size());
710 contexts_.insert(contexts_.begin(), copy->contexts_.begin(),
711 copy->contexts_.end());
712 }
713
714
Bind(Variable * variable,Node * node)715 void AstGraphBuilder::Environment::Bind(Variable* variable, Node* node) {
716 DCHECK(variable->IsStackAllocated());
717 if (variable->IsParameter()) {
718 // The parameter indices are shifted by 1 (receiver is variable
719 // index -1 but located at index 0 in the environment).
720 values()->at(variable->index() + 1) = node;
721 } else {
722 DCHECK(variable->IsStackLocal());
723 values()->at(variable->index() + parameters_count_) = node;
724 DCHECK(IsLivenessBlockConsistent());
725 if (liveness_block() != nullptr) {
726 liveness_block()->Bind(variable->index());
727 }
728 }
729 }
730
731
Lookup(Variable * variable)732 Node* AstGraphBuilder::Environment::Lookup(Variable* variable) {
733 DCHECK(variable->IsStackAllocated());
734 if (variable->IsParameter()) {
735 // The parameter indices are shifted by 1 (receiver is variable
736 // index -1 but located at index 0 in the environment).
737 return values()->at(variable->index() + 1);
738 } else {
739 DCHECK(variable->IsStackLocal());
740 DCHECK(IsLivenessBlockConsistent());
741 if (liveness_block() != nullptr) {
742 liveness_block()->Lookup(variable->index());
743 }
744 return values()->at(variable->index() + parameters_count_);
745 }
746 }
747
748
MarkAllLocalsLive()749 void AstGraphBuilder::Environment::MarkAllLocalsLive() {
750 DCHECK(IsLivenessBlockConsistent());
751 if (liveness_block() != nullptr) {
752 for (int i = 0; i < locals_count_; i++) {
753 liveness_block()->Lookup(i);
754 }
755 }
756 }
757
758
RawParameterBind(int index,Node * node)759 void AstGraphBuilder::Environment::RawParameterBind(int index, Node* node) {
760 DCHECK_LT(index, parameters_count());
761 values()->at(index) = node;
762 }
763
764
RawParameterLookup(int index)765 Node* AstGraphBuilder::Environment::RawParameterLookup(int index) {
766 DCHECK_LT(index, parameters_count());
767 return values()->at(index);
768 }
769
770
771 AstGraphBuilder::Environment*
CopyForConditional()772 AstGraphBuilder::Environment::CopyForConditional() {
773 LivenessAnalyzerBlock* copy_liveness_block = nullptr;
774 if (liveness_block() != nullptr) {
775 copy_liveness_block =
776 builder_->liveness_analyzer()->NewBlock(liveness_block());
777 liveness_block_ = builder_->liveness_analyzer()->NewBlock(liveness_block());
778 }
779 return new (zone()) Environment(this, copy_liveness_block);
780 }
781
782
783 AstGraphBuilder::Environment*
CopyAsUnreachable()784 AstGraphBuilder::Environment::CopyAsUnreachable() {
785 Environment* env = new (zone()) Environment(this, nullptr);
786 env->MarkAsUnreachable();
787 return env;
788 }
789
CopyForOsrEntry()790 AstGraphBuilder::Environment* AstGraphBuilder::Environment::CopyForOsrEntry() {
791 LivenessAnalyzerBlock* copy_block =
792 liveness_block() == nullptr ? nullptr
793 : builder_->liveness_analyzer()->NewBlock();
794 return new (zone()) Environment(this, copy_block);
795 }
796
797 AstGraphBuilder::Environment*
CopyAndShareLiveness()798 AstGraphBuilder::Environment::CopyAndShareLiveness() {
799 if (liveness_block() != nullptr) {
800 // Finish the current liveness block before copying.
801 liveness_block_ = builder_->liveness_analyzer()->NewBlock(liveness_block());
802 }
803 Environment* env = new (zone()) Environment(this, liveness_block());
804 return env;
805 }
806
807
CopyForLoop(BitVector * assigned,bool is_osr)808 AstGraphBuilder::Environment* AstGraphBuilder::Environment::CopyForLoop(
809 BitVector* assigned, bool is_osr) {
810 PrepareForLoop(assigned);
811 Environment* loop = CopyAndShareLiveness();
812 if (is_osr) {
813 // Create and merge the OSR entry if necessary.
814 Environment* osr_env = CopyForOsrEntry();
815 osr_env->PrepareForOsrEntry();
816 loop->Merge(osr_env);
817 }
818 return loop;
819 }
820
821
UpdateStateValues(Node ** state_values,int offset,int count)822 void AstGraphBuilder::Environment::UpdateStateValues(Node** state_values,
823 int offset, int count) {
824 bool should_update = false;
825 Node** env_values = (count == 0) ? nullptr : &values()->at(offset);
826 if (*state_values == nullptr || (*state_values)->InputCount() != count) {
827 should_update = true;
828 } else {
829 DCHECK(static_cast<size_t>(offset + count) <= values()->size());
830 for (int i = 0; i < count; i++) {
831 if ((*state_values)->InputAt(i) != env_values[i]) {
832 should_update = true;
833 break;
834 }
835 }
836 }
837 if (should_update) {
838 const Operator* op = common()->StateValues(count);
839 (*state_values) = graph()->NewNode(op, count, env_values);
840 }
841 }
842
843
Checkpoint(BailoutId ast_id,OutputFrameStateCombine combine,bool owner_has_exception)844 Node* AstGraphBuilder::Environment::Checkpoint(BailoutId ast_id,
845 OutputFrameStateCombine combine,
846 bool owner_has_exception) {
847 if (!builder()->info()->is_deoptimization_enabled()) {
848 return builder()->GetEmptyFrameState();
849 }
850
851 UpdateStateValues(¶meters_node_, 0, parameters_count());
852 UpdateStateValues(&locals_node_, parameters_count(), locals_count());
853 UpdateStateValues(&stack_node_, parameters_count() + locals_count(),
854 stack_height());
855
856 const Operator* op = common()->FrameState(
857 ast_id, combine, builder()->frame_state_function_info());
858
859 Node* result = graph()->NewNode(op, parameters_node_, locals_node_,
860 stack_node_, builder()->current_context(),
861 builder()->GetFunctionClosure(),
862 builder()->graph()->start());
863
864 DCHECK(IsLivenessBlockConsistent());
865 if (liveness_block() != nullptr) {
866 // If the owning node has an exception, register the checkpoint to the
867 // predecessor so that the checkpoint is used for both the normal and the
868 // exceptional paths. Yes, this is a terrible hack and we might want
869 // to use an explicit frame state for the exceptional path.
870 if (owner_has_exception) {
871 liveness_block()->GetPredecessor()->Checkpoint(result);
872 } else {
873 liveness_block()->Checkpoint(result);
874 }
875 }
876 return result;
877 }
878
PrepareForLoopExit(Node * loop,BitVector * assigned_variables)879 void AstGraphBuilder::Environment::PrepareForLoopExit(
880 Node* loop, BitVector* assigned_variables) {
881 if (IsMarkedAsUnreachable()) return;
882
883 DCHECK_EQ(loop->opcode(), IrOpcode::kLoop);
884
885 Node* control = GetControlDependency();
886
887 // Create the loop exit node.
888 Node* loop_exit = graph()->NewNode(common()->LoopExit(), control, loop);
889 UpdateControlDependency(loop_exit);
890
891 // Rename the environmnent values.
892 for (size_t i = 0; i < values()->size(); i++) {
893 if (assigned_variables == nullptr ||
894 static_cast<int>(i) >= assigned_variables->length() ||
895 assigned_variables->Contains(static_cast<int>(i))) {
896 Node* rename = graph()->NewNode(common()->LoopExitValue(), (*values())[i],
897 loop_exit);
898 (*values())[i] = rename;
899 }
900 }
901
902 // Rename the effect.
903 Node* effect_rename = graph()->NewNode(common()->LoopExitEffect(),
904 GetEffectDependency(), loop_exit);
905 UpdateEffectDependency(effect_rename);
906 }
907
IsLivenessAnalysisEnabled()908 bool AstGraphBuilder::Environment::IsLivenessAnalysisEnabled() {
909 return FLAG_analyze_environment_liveness &&
910 builder()->info()->is_deoptimization_enabled();
911 }
912
913
IsLivenessBlockConsistent()914 bool AstGraphBuilder::Environment::IsLivenessBlockConsistent() {
915 return (!IsLivenessAnalysisEnabled() || IsMarkedAsUnreachable()) ==
916 (liveness_block() == nullptr);
917 }
918
919
AstContext(AstGraphBuilder * own,Expression::Context kind)920 AstGraphBuilder::AstContext::AstContext(AstGraphBuilder* own,
921 Expression::Context kind)
922 : kind_(kind), owner_(own), outer_(own->ast_context()) {
923 owner()->set_ast_context(this); // Push.
924 #ifdef DEBUG
925 original_height_ = environment()->stack_height();
926 #endif
927 }
928
929
~AstContext()930 AstGraphBuilder::AstContext::~AstContext() {
931 owner()->set_ast_context(outer_); // Pop.
932 }
933
934
~AstEffectContext()935 AstGraphBuilder::AstEffectContext::~AstEffectContext() {
936 DCHECK(environment()->stack_height() == original_height_);
937 }
938
939
~AstValueContext()940 AstGraphBuilder::AstValueContext::~AstValueContext() {
941 DCHECK(environment()->stack_height() == original_height_ + 1);
942 }
943
944
~AstTestContext()945 AstGraphBuilder::AstTestContext::~AstTestContext() {
946 DCHECK(environment()->stack_height() == original_height_ + 1);
947 }
948
ProduceValue(Expression * expr,Node * value)949 void AstGraphBuilder::AstEffectContext::ProduceValue(Expression* expr,
950 Node* value) {
951 // The value is ignored.
952 owner()->PrepareEagerCheckpoint(expr->id());
953 }
954
ProduceValue(Expression * expr,Node * value)955 void AstGraphBuilder::AstValueContext::ProduceValue(Expression* expr,
956 Node* value) {
957 environment()->Push(value);
958 owner()->PrepareEagerCheckpoint(expr->id());
959 }
960
ProduceValue(Expression * expr,Node * value)961 void AstGraphBuilder::AstTestContext::ProduceValue(Expression* expr,
962 Node* value) {
963 environment()->Push(owner()->BuildToBoolean(value, feedback_id_));
964 owner()->PrepareEagerCheckpoint(expr->id());
965 }
966
967
ConsumeValue()968 Node* AstGraphBuilder::AstEffectContext::ConsumeValue() { return nullptr; }
969
970
ConsumeValue()971 Node* AstGraphBuilder::AstValueContext::ConsumeValue() {
972 return environment()->Pop();
973 }
974
975
ConsumeValue()976 Node* AstGraphBuilder::AstTestContext::ConsumeValue() {
977 return environment()->Pop();
978 }
979
980
current_scope() const981 Scope* AstGraphBuilder::current_scope() const {
982 return execution_context_->scope();
983 }
984
985
current_context() const986 Node* AstGraphBuilder::current_context() const {
987 return environment()->Context();
988 }
989
990
PerformCommand(Command command,Statement * target,Node * value)991 void AstGraphBuilder::ControlScope::PerformCommand(Command command,
992 Statement* target,
993 Node* value) {
994 Environment* env = environment()->CopyAsUnreachable();
995 ControlScope* current = this;
996 while (current != nullptr) {
997 environment()->TrimStack(current->stack_height());
998 environment()->TrimContextChain(current->context_length());
999 if (current->Execute(command, target, &value)) break;
1000 current = current->outer_;
1001 }
1002 builder()->set_environment(env);
1003 DCHECK_NOT_NULL(current); // Always handled (unless stack is malformed).
1004 }
1005
1006
BreakTo(BreakableStatement * stmt)1007 void AstGraphBuilder::ControlScope::BreakTo(BreakableStatement* stmt) {
1008 PerformCommand(CMD_BREAK, stmt, builder()->jsgraph()->TheHoleConstant());
1009 }
1010
1011
ContinueTo(BreakableStatement * stmt)1012 void AstGraphBuilder::ControlScope::ContinueTo(BreakableStatement* stmt) {
1013 PerformCommand(CMD_CONTINUE, stmt, builder()->jsgraph()->TheHoleConstant());
1014 }
1015
1016
ReturnValue(Node * return_value)1017 void AstGraphBuilder::ControlScope::ReturnValue(Node* return_value) {
1018 PerformCommand(CMD_RETURN, nullptr, return_value);
1019 }
1020
1021
ThrowValue(Node * exception_value)1022 void AstGraphBuilder::ControlScope::ThrowValue(Node* exception_value) {
1023 PerformCommand(CMD_THROW, nullptr, exception_value);
1024 }
1025
1026
VisitForValueOrNull(Expression * expr)1027 void AstGraphBuilder::VisitForValueOrNull(Expression* expr) {
1028 if (expr == nullptr) {
1029 return environment()->Push(jsgraph()->NullConstant());
1030 }
1031 VisitForValue(expr);
1032 }
1033
1034
VisitForValueOrTheHole(Expression * expr)1035 void AstGraphBuilder::VisitForValueOrTheHole(Expression* expr) {
1036 if (expr == nullptr) {
1037 return environment()->Push(jsgraph()->TheHoleConstant());
1038 }
1039 VisitForValue(expr);
1040 }
1041
1042
VisitForValues(ZoneList<Expression * > * exprs)1043 void AstGraphBuilder::VisitForValues(ZoneList<Expression*>* exprs) {
1044 for (int i = 0; i < exprs->length(); ++i) {
1045 VisitForValue(exprs->at(i));
1046 }
1047 }
1048
1049
VisitForValue(Expression * expr)1050 void AstGraphBuilder::VisitForValue(Expression* expr) {
1051 AstValueContext for_value(this);
1052 if (!CheckStackOverflow()) {
1053 VisitNoStackOverflowCheck(expr);
1054 } else {
1055 ast_context()->ProduceValue(expr, jsgraph()->UndefinedConstant());
1056 }
1057 }
1058
1059
VisitForEffect(Expression * expr)1060 void AstGraphBuilder::VisitForEffect(Expression* expr) {
1061 AstEffectContext for_effect(this);
1062 if (!CheckStackOverflow()) {
1063 VisitNoStackOverflowCheck(expr);
1064 } else {
1065 ast_context()->ProduceValue(expr, jsgraph()->UndefinedConstant());
1066 }
1067 }
1068
1069
VisitForTest(Expression * expr)1070 void AstGraphBuilder::VisitForTest(Expression* expr) {
1071 AstTestContext for_condition(this, expr->test_id());
1072 if (!CheckStackOverflow()) {
1073 VisitNoStackOverflowCheck(expr);
1074 } else {
1075 ast_context()->ProduceValue(expr, jsgraph()->UndefinedConstant());
1076 }
1077 }
1078
1079
Visit(Expression * expr)1080 void AstGraphBuilder::Visit(Expression* expr) {
1081 // Reuses enclosing AstContext.
1082 if (!CheckStackOverflow()) {
1083 VisitNoStackOverflowCheck(expr);
1084 } else {
1085 ast_context()->ProduceValue(expr, jsgraph()->UndefinedConstant());
1086 }
1087 }
1088
1089
VisitVariableDeclaration(VariableDeclaration * decl)1090 void AstGraphBuilder::VisitVariableDeclaration(VariableDeclaration* decl) {
1091 Variable* variable = decl->proxy()->var();
1092 switch (variable->location()) {
1093 case VariableLocation::UNALLOCATED: {
1094 DCHECK(!variable->binding_needs_init());
1095 FeedbackVectorSlot slot = decl->proxy()->VariableFeedbackSlot();
1096 DCHECK(!slot.IsInvalid());
1097 globals()->push_back(handle(Smi::FromInt(slot.ToInt()), isolate()));
1098 globals()->push_back(isolate()->factory()->undefined_value());
1099 break;
1100 }
1101 case VariableLocation::PARAMETER:
1102 case VariableLocation::LOCAL:
1103 if (variable->binding_needs_init()) {
1104 Node* value = jsgraph()->TheHoleConstant();
1105 environment()->Bind(variable, value);
1106 }
1107 break;
1108 case VariableLocation::CONTEXT:
1109 if (variable->binding_needs_init()) {
1110 Node* value = jsgraph()->TheHoleConstant();
1111 const Operator* op = javascript()->StoreContext(0, variable->index());
1112 NewNode(op, current_context(), value);
1113 }
1114 break;
1115 case VariableLocation::LOOKUP: {
1116 DCHECK(!variable->binding_needs_init());
1117 Node* name = jsgraph()->Constant(variable->name());
1118 const Operator* op = javascript()->CallRuntime(Runtime::kDeclareEvalVar);
1119 Node* store = NewNode(op, name);
1120 PrepareFrameState(store, decl->proxy()->id());
1121 break;
1122 }
1123 case VariableLocation::MODULE:
1124 UNREACHABLE();
1125 }
1126 }
1127
1128
VisitFunctionDeclaration(FunctionDeclaration * decl)1129 void AstGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* decl) {
1130 Variable* variable = decl->proxy()->var();
1131 switch (variable->location()) {
1132 case VariableLocation::UNALLOCATED: {
1133 Handle<SharedFunctionInfo> function = Compiler::GetSharedFunctionInfo(
1134 decl->fun(), info()->script(), info());
1135 // Check for stack-overflow exception.
1136 if (function.is_null()) return SetStackOverflow();
1137 FeedbackVectorSlot slot = decl->proxy()->VariableFeedbackSlot();
1138 DCHECK(!slot.IsInvalid());
1139 globals()->push_back(handle(Smi::FromInt(slot.ToInt()), isolate()));
1140 globals()->push_back(function);
1141 break;
1142 }
1143 case VariableLocation::PARAMETER:
1144 case VariableLocation::LOCAL: {
1145 VisitForValue(decl->fun());
1146 Node* value = environment()->Pop();
1147 environment()->Bind(variable, value);
1148 break;
1149 }
1150 case VariableLocation::CONTEXT: {
1151 VisitForValue(decl->fun());
1152 Node* value = environment()->Pop();
1153 const Operator* op = javascript()->StoreContext(0, variable->index());
1154 NewNode(op, current_context(), value);
1155 break;
1156 }
1157 case VariableLocation::LOOKUP: {
1158 VisitForValue(decl->fun());
1159 Node* value = environment()->Pop();
1160 Node* name = jsgraph()->Constant(variable->name());
1161 const Operator* op =
1162 javascript()->CallRuntime(Runtime::kDeclareEvalFunction);
1163 Node* store = NewNode(op, name, value);
1164 PrepareFrameState(store, decl->proxy()->id());
1165 break;
1166 }
1167 case VariableLocation::MODULE:
1168 UNREACHABLE();
1169 }
1170 }
1171
1172
VisitBlock(Block * stmt)1173 void AstGraphBuilder::VisitBlock(Block* stmt) {
1174 BlockBuilder block(this);
1175 ControlScopeForBreakable scope(this, stmt, &block);
1176 if (stmt->labels() != nullptr) block.BeginBlock();
1177 if (stmt->scope() == nullptr) {
1178 // Visit statements in the same scope, no declarations.
1179 VisitStatements(stmt->statements());
1180 } else {
1181 // Visit declarations and statements in a block scope.
1182 if (stmt->scope()->NeedsContext()) {
1183 Node* context = BuildLocalBlockContext(stmt->scope());
1184 ContextScope scope(this, stmt->scope(), context);
1185 VisitDeclarations(stmt->scope()->declarations());
1186 VisitStatements(stmt->statements());
1187 } else {
1188 VisitDeclarations(stmt->scope()->declarations());
1189 VisitStatements(stmt->statements());
1190 }
1191 }
1192 if (stmt->labels() != nullptr) block.EndBlock();
1193 }
1194
1195
VisitExpressionStatement(ExpressionStatement * stmt)1196 void AstGraphBuilder::VisitExpressionStatement(ExpressionStatement* stmt) {
1197 VisitForEffect(stmt->expression());
1198 }
1199
1200
VisitEmptyStatement(EmptyStatement * stmt)1201 void AstGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) {
1202 // Do nothing.
1203 }
1204
1205
VisitSloppyBlockFunctionStatement(SloppyBlockFunctionStatement * stmt)1206 void AstGraphBuilder::VisitSloppyBlockFunctionStatement(
1207 SloppyBlockFunctionStatement* stmt) {
1208 Visit(stmt->statement());
1209 }
1210
1211
VisitIfStatement(IfStatement * stmt)1212 void AstGraphBuilder::VisitIfStatement(IfStatement* stmt) {
1213 IfBuilder compare_if(this);
1214 VisitForTest(stmt->condition());
1215 Node* condition = environment()->Pop();
1216 compare_if.If(condition);
1217 compare_if.Then();
1218 Visit(stmt->then_statement());
1219 compare_if.Else();
1220 Visit(stmt->else_statement());
1221 compare_if.End();
1222 }
1223
1224
VisitContinueStatement(ContinueStatement * stmt)1225 void AstGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) {
1226 execution_control()->ContinueTo(stmt->target());
1227 }
1228
1229
VisitBreakStatement(BreakStatement * stmt)1230 void AstGraphBuilder::VisitBreakStatement(BreakStatement* stmt) {
1231 execution_control()->BreakTo(stmt->target());
1232 }
1233
1234
VisitReturnStatement(ReturnStatement * stmt)1235 void AstGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
1236 VisitForValue(stmt->expression());
1237 Node* result = environment()->Pop();
1238 execution_control()->ReturnValue(result);
1239 }
1240
1241
VisitWithStatement(WithStatement * stmt)1242 void AstGraphBuilder::VisitWithStatement(WithStatement* stmt) {
1243 VisitForValue(stmt->expression());
1244 Node* value = environment()->Pop();
1245 Node* object = BuildToObject(value, stmt->ToObjectId());
1246 Handle<ScopeInfo> scope_info = stmt->scope()->scope_info();
1247 const Operator* op = javascript()->CreateWithContext(scope_info);
1248 Node* context = NewNode(op, object, GetFunctionClosureForContext());
1249 PrepareFrameState(context, stmt->EntryId());
1250 VisitInScope(stmt->statement(), stmt->scope(), context);
1251 }
1252
1253
VisitSwitchStatement(SwitchStatement * stmt)1254 void AstGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
1255 ZoneList<CaseClause*>* clauses = stmt->cases();
1256 SwitchBuilder compare_switch(this, clauses->length());
1257 ControlScopeForBreakable scope(this, stmt, &compare_switch);
1258 compare_switch.BeginSwitch();
1259 int default_index = -1;
1260
1261 // Keep the switch value on the stack until a case matches.
1262 VisitForValue(stmt->tag());
1263
1264 // Iterate over all cases and create nodes for label comparison.
1265 for (int i = 0; i < clauses->length(); i++) {
1266 CaseClause* clause = clauses->at(i);
1267
1268 // The default is not a test, remember index.
1269 if (clause->is_default()) {
1270 default_index = i;
1271 continue;
1272 }
1273
1274 // Create nodes to perform label comparison as if via '==='. The switch
1275 // value is still on the operand stack while the label is evaluated.
1276 VisitForValue(clause->label());
1277 Node* label = environment()->Pop();
1278 Node* tag = environment()->Top();
1279
1280 CompareOperationHint hint;
1281 if (!type_hint_analysis_ ||
1282 !type_hint_analysis_->GetCompareOperationHint(clause->CompareId(),
1283 &hint)) {
1284 hint = CompareOperationHint::kAny;
1285 }
1286
1287 const Operator* op = javascript()->StrictEqual(hint);
1288 Node* condition = NewNode(op, tag, label);
1289 compare_switch.BeginLabel(i, condition);
1290
1291 // Discard the switch value at label match.
1292 environment()->Pop();
1293 compare_switch.EndLabel();
1294 }
1295
1296 // Discard the switch value and mark the default case.
1297 environment()->Pop();
1298 if (default_index >= 0) {
1299 compare_switch.DefaultAt(default_index);
1300 }
1301
1302 // Iterate over all cases and create nodes for case bodies.
1303 for (int i = 0; i < clauses->length(); i++) {
1304 CaseClause* clause = clauses->at(i);
1305 compare_switch.BeginCase(i);
1306 VisitStatements(clause->statements());
1307 compare_switch.EndCase();
1308 }
1309
1310 compare_switch.EndSwitch();
1311 }
1312
1313
VisitDoWhileStatement(DoWhileStatement * stmt)1314 void AstGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
1315 LoopBuilder while_loop(this);
1316 while_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt));
1317 VisitIterationBody(stmt, &while_loop, stmt->StackCheckId());
1318 while_loop.EndBody();
1319 VisitForTest(stmt->cond());
1320 Node* condition = environment()->Pop();
1321 while_loop.BreakUnless(condition);
1322 while_loop.EndLoop();
1323 }
1324
1325
VisitWhileStatement(WhileStatement * stmt)1326 void AstGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
1327 LoopBuilder while_loop(this);
1328 while_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt));
1329 VisitForTest(stmt->cond());
1330 Node* condition = environment()->Pop();
1331 while_loop.BreakUnless(condition);
1332 VisitIterationBody(stmt, &while_loop, stmt->StackCheckId());
1333 while_loop.EndBody();
1334 while_loop.EndLoop();
1335 }
1336
1337
VisitForStatement(ForStatement * stmt)1338 void AstGraphBuilder::VisitForStatement(ForStatement* stmt) {
1339 LoopBuilder for_loop(this);
1340 VisitIfNotNull(stmt->init());
1341 for_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt));
1342 if (stmt->cond() != nullptr) {
1343 VisitForTest(stmt->cond());
1344 Node* condition = environment()->Pop();
1345 for_loop.BreakUnless(condition);
1346 } else {
1347 for_loop.BreakUnless(jsgraph()->TrueConstant());
1348 }
1349 VisitIterationBody(stmt, &for_loop, stmt->StackCheckId());
1350 for_loop.EndBody();
1351 VisitIfNotNull(stmt->next());
1352 for_loop.EndLoop();
1353 }
1354
1355
VisitForInStatement(ForInStatement * stmt)1356 void AstGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
1357 VisitForValue(stmt->subject());
1358 Node* object = environment()->Pop();
1359 BlockBuilder for_block(this);
1360 for_block.BeginBlock();
1361 // Check for null or undefined before entering loop.
1362 Node* is_null_cond =
1363 NewNode(javascript()->StrictEqual(CompareOperationHint::kAny), object,
1364 jsgraph()->NullConstant());
1365 for_block.BreakWhen(is_null_cond, BranchHint::kFalse);
1366 Node* is_undefined_cond =
1367 NewNode(javascript()->StrictEqual(CompareOperationHint::kAny), object,
1368 jsgraph()->UndefinedConstant());
1369 for_block.BreakWhen(is_undefined_cond, BranchHint::kFalse);
1370 {
1371 // Convert object to jsobject.
1372 object = BuildToObject(object, stmt->ToObjectId());
1373 environment()->Push(object);
1374
1375 // Prepare for-in cache.
1376 Node* prepare = NewNode(javascript()->ForInPrepare(), object);
1377 PrepareFrameState(prepare, stmt->PrepareId(),
1378 OutputFrameStateCombine::Push(3));
1379 Node* cache_type = NewNode(common()->Projection(0), prepare);
1380 Node* cache_array = NewNode(common()->Projection(1), prepare);
1381 Node* cache_length = NewNode(common()->Projection(2), prepare);
1382
1383 // Construct the rest of the environment.
1384 environment()->Push(cache_type);
1385 environment()->Push(cache_array);
1386 environment()->Push(cache_length);
1387 environment()->Push(jsgraph()->ZeroConstant());
1388
1389 // Build the actual loop body.
1390 LoopBuilder for_loop(this);
1391 for_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt));
1392 {
1393 // These stack values are renamed in the case of OSR, so reload them
1394 // from the environment.
1395 Node* index = environment()->Peek(0);
1396 Node* cache_length = environment()->Peek(1);
1397 Node* cache_array = environment()->Peek(2);
1398 Node* cache_type = environment()->Peek(3);
1399 Node* object = environment()->Peek(4);
1400
1401 // Check loop termination condition (we know that the {index} is always
1402 // in Smi range, so we can just set the hint on the comparison below).
1403 PrepareEagerCheckpoint(stmt->EntryId());
1404 Node* exit_cond =
1405 NewNode(javascript()->LessThan(CompareOperationHint::kSignedSmall),
1406 index, cache_length);
1407 PrepareFrameState(exit_cond, BailoutId::None());
1408 for_loop.BreakUnless(exit_cond);
1409
1410 // Compute the next enumerated value.
1411 Node* value = NewNode(javascript()->ForInNext(), object, cache_array,
1412 cache_type, index);
1413 PrepareFrameState(value, stmt->FilterId(),
1414 OutputFrameStateCombine::Push());
1415 IfBuilder test_value(this);
1416 Node* test_value_cond =
1417 NewNode(javascript()->StrictEqual(CompareOperationHint::kAny), value,
1418 jsgraph()->UndefinedConstant());
1419 test_value.If(test_value_cond, BranchHint::kFalse);
1420 test_value.Then();
1421 test_value.Else();
1422 {
1423 environment()->Push(value);
1424 PrepareEagerCheckpoint(stmt->FilterId());
1425 value = environment()->Pop();
1426 // Bind value and do loop body.
1427 VectorSlotPair feedback =
1428 CreateVectorSlotPair(stmt->EachFeedbackSlot());
1429 VisitForInAssignment(stmt->each(), value, feedback,
1430 stmt->AssignmentId());
1431 VisitIterationBody(stmt, &for_loop, stmt->StackCheckId());
1432 }
1433 test_value.End();
1434 for_loop.EndBody();
1435
1436 // Increment counter and continue (we know that the {index} is always
1437 // in Smi range, so we can just set the hint on the increment below).
1438 index = environment()->Peek(0);
1439 PrepareEagerCheckpoint(stmt->IncrementId());
1440 index = NewNode(javascript()->Add(BinaryOperationHint::kSignedSmall),
1441 index, jsgraph()->OneConstant());
1442 PrepareFrameState(index, BailoutId::None());
1443 environment()->Poke(0, index);
1444 }
1445 for_loop.EndLoop();
1446 environment()->Drop(5);
1447 }
1448 for_block.EndBlock();
1449 }
1450
1451
VisitForOfStatement(ForOfStatement * stmt)1452 void AstGraphBuilder::VisitForOfStatement(ForOfStatement* stmt) {
1453 LoopBuilder for_loop(this);
1454 VisitForEffect(stmt->assign_iterator());
1455 for_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt));
1456 VisitForEffect(stmt->next_result());
1457 VisitForTest(stmt->result_done());
1458 Node* condition = environment()->Pop();
1459 for_loop.BreakWhen(condition);
1460 VisitForEffect(stmt->assign_each());
1461 VisitIterationBody(stmt, &for_loop, stmt->StackCheckId());
1462 for_loop.EndBody();
1463 for_loop.EndLoop();
1464 }
1465
1466
VisitTryCatchStatement(TryCatchStatement * stmt)1467 void AstGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) {
1468 TryCatchBuilder try_control(this);
1469
1470 // Evaluate the try-block inside a control scope. This simulates a handler
1471 // that is intercepting 'throw' control commands.
1472 try_control.BeginTry();
1473 {
1474 ControlScopeForCatch scope(this, stmt, &try_control);
1475 STATIC_ASSERT(TryBlockConstant::kElementCount == 1);
1476 environment()->Push(current_context());
1477 Visit(stmt->try_block());
1478 environment()->Pop();
1479 }
1480 try_control.EndTry();
1481
1482 // If requested, clear message object as we enter the catch block.
1483 if (stmt->clear_pending_message()) {
1484 Node* the_hole = jsgraph()->TheHoleConstant();
1485 NewNode(javascript()->StoreMessage(), the_hole);
1486 }
1487
1488 // Create a catch scope that binds the exception.
1489 Node* exception = try_control.GetExceptionNode();
1490 Handle<String> name = stmt->variable()->name();
1491 Handle<ScopeInfo> scope_info = stmt->scope()->scope_info();
1492 const Operator* op = javascript()->CreateCatchContext(name, scope_info);
1493 Node* context = NewNode(op, exception, GetFunctionClosureForContext());
1494
1495 // Evaluate the catch-block.
1496 VisitInScope(stmt->catch_block(), stmt->scope(), context);
1497 try_control.EndCatch();
1498 }
1499
1500
VisitTryFinallyStatement(TryFinallyStatement * stmt)1501 void AstGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
1502 TryFinallyBuilder try_control(this);
1503
1504 // We keep a record of all paths that enter the finally-block to be able to
1505 // dispatch to the correct continuation point after the statements in the
1506 // finally-block have been evaluated.
1507 //
1508 // The try-finally construct can enter the finally-block in three ways:
1509 // 1. By exiting the try-block normally, falling through at the end.
1510 // 2. By exiting the try-block with a function-local control flow transfer
1511 // (i.e. through break/continue/return statements).
1512 // 3. By exiting the try-block with a thrown exception.
1513 Node* fallthrough_result = jsgraph()->TheHoleConstant();
1514 ControlScope::DeferredCommands* commands =
1515 new (local_zone()) ControlScope::DeferredCommands(this);
1516
1517 // Evaluate the try-block inside a control scope. This simulates a handler
1518 // that is intercepting all control commands.
1519 try_control.BeginTry();
1520 {
1521 ControlScopeForFinally scope(this, stmt, commands, &try_control);
1522 STATIC_ASSERT(TryBlockConstant::kElementCount == 1);
1523 environment()->Push(current_context());
1524 Visit(stmt->try_block());
1525 environment()->Pop();
1526 }
1527 try_control.EndTry(commands->GetFallThroughToken(), fallthrough_result);
1528
1529 // The result value semantics depend on how the block was entered:
1530 // - ReturnStatement: It represents the return value being returned.
1531 // - ThrowStatement: It represents the exception being thrown.
1532 // - BreakStatement/ContinueStatement: Filled with the hole.
1533 // - Falling through into finally-block: Filled with the hole.
1534 Node* result = try_control.GetResultValueNode();
1535 Node* token = try_control.GetDispatchTokenNode();
1536
1537 // The result value, dispatch token and message is expected on the operand
1538 // stack (this is in sync with FullCodeGenerator::EnterFinallyBlock).
1539 Node* message = NewNode(javascript()->LoadMessage());
1540 environment()->Push(token);
1541 environment()->Push(result);
1542 environment()->Push(message);
1543
1544 // Clear message object as we enter the finally block.
1545 Node* the_hole = jsgraph()->TheHoleConstant();
1546 NewNode(javascript()->StoreMessage(), the_hole);
1547
1548 // Evaluate the finally-block.
1549 Visit(stmt->finally_block());
1550 try_control.EndFinally();
1551
1552 // The result value, dispatch token and message is restored from the operand
1553 // stack (this is in sync with FullCodeGenerator::ExitFinallyBlock).
1554 message = environment()->Pop();
1555 result = environment()->Pop();
1556 token = environment()->Pop();
1557 NewNode(javascript()->StoreMessage(), message);
1558
1559 // Dynamic dispatch after the finally-block.
1560 commands->ApplyDeferredCommands(token, result);
1561 }
1562
1563
VisitDebuggerStatement(DebuggerStatement * stmt)1564 void AstGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
1565 Node* node =
1566 NewNode(javascript()->CallRuntime(Runtime::kHandleDebuggerStatement));
1567 PrepareFrameState(node, stmt->DebugBreakId());
1568 environment()->MarkAllLocalsLive();
1569 }
1570
1571
VisitFunctionLiteral(FunctionLiteral * expr)1572 void AstGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
1573 // Find or build a shared function info.
1574 Handle<SharedFunctionInfo> shared_info =
1575 Compiler::GetSharedFunctionInfo(expr, info()->script(), info());
1576 CHECK(!shared_info.is_null()); // TODO(mstarzinger): Set stack overflow?
1577
1578 // Create node to instantiate a new closure.
1579 PretenureFlag pretenure = expr->pretenure() ? TENURED : NOT_TENURED;
1580 const Operator* op = javascript()->CreateClosure(shared_info, pretenure);
1581 Node* value = NewNode(op);
1582 ast_context()->ProduceValue(expr, value);
1583 }
1584
1585
VisitClassLiteral(ClassLiteral * expr)1586 void AstGraphBuilder::VisitClassLiteral(ClassLiteral* expr) {
1587 VisitForValueOrTheHole(expr->extends());
1588 VisitForValue(expr->constructor());
1589
1590 // Create node to instantiate a new class.
1591 Node* constructor = environment()->Pop();
1592 Node* extends = environment()->Pop();
1593 Node* start = jsgraph()->Constant(expr->start_position());
1594 Node* end = jsgraph()->Constant(expr->end_position());
1595 const Operator* opc = javascript()->CallRuntime(Runtime::kDefineClass);
1596 Node* literal = NewNode(opc, extends, constructor, start, end);
1597 PrepareFrameState(literal, expr->CreateLiteralId(),
1598 OutputFrameStateCombine::Push());
1599 environment()->Push(literal);
1600
1601 // Load the "prototype" from the constructor.
1602 PrepareEagerCheckpoint(expr->CreateLiteralId());
1603 Handle<Name> name = isolate()->factory()->prototype_string();
1604 VectorSlotPair pair = CreateVectorSlotPair(expr->PrototypeSlot());
1605 Node* prototype = BuildNamedLoad(literal, name, pair);
1606 PrepareFrameState(prototype, expr->PrototypeId(),
1607 OutputFrameStateCombine::Push());
1608 environment()->Push(prototype);
1609
1610 // Create nodes to store method values into the literal.
1611 for (int i = 0; i < expr->properties()->length(); i++) {
1612 ClassLiteral::Property* property = expr->properties()->at(i);
1613 environment()->Push(environment()->Peek(property->is_static() ? 1 : 0));
1614
1615 VisitForValue(property->key());
1616 Node* name = BuildToName(environment()->Pop(), expr->GetIdForProperty(i));
1617 environment()->Push(name);
1618
1619 // The static prototype property is read only. We handle the non computed
1620 // property name case in the parser. Since this is the only case where we
1621 // need to check for an own read only property we special case this so we do
1622 // not need to do this for every property.
1623 if (property->is_static() && property->is_computed_name()) {
1624 Node* check = BuildThrowIfStaticPrototype(environment()->Pop(),
1625 expr->GetIdForProperty(i));
1626 environment()->Push(check);
1627 }
1628
1629 VisitForValue(property->value());
1630 Node* value = environment()->Pop();
1631 Node* key = environment()->Pop();
1632 Node* receiver = environment()->Pop();
1633
1634 BuildSetHomeObject(value, receiver, property);
1635
1636 switch (property->kind()) {
1637 case ClassLiteral::Property::METHOD: {
1638 Node* attr = jsgraph()->Constant(DONT_ENUM);
1639 Node* set_function_name =
1640 jsgraph()->Constant(property->NeedsSetFunctionName());
1641 const Operator* op =
1642 javascript()->CallRuntime(Runtime::kDefineDataPropertyInLiteral);
1643 Node* call = NewNode(op, receiver, key, value, attr, set_function_name);
1644 PrepareFrameState(call, BailoutId::None());
1645 break;
1646 }
1647 case ClassLiteral::Property::GETTER: {
1648 Node* attr = jsgraph()->Constant(DONT_ENUM);
1649 const Operator* op = javascript()->CallRuntime(
1650 Runtime::kDefineGetterPropertyUnchecked, 4);
1651 NewNode(op, receiver, key, value, attr);
1652 break;
1653 }
1654 case ClassLiteral::Property::SETTER: {
1655 Node* attr = jsgraph()->Constant(DONT_ENUM);
1656 const Operator* op = javascript()->CallRuntime(
1657 Runtime::kDefineSetterPropertyUnchecked, 4);
1658 NewNode(op, receiver, key, value, attr);
1659 break;
1660 }
1661 case ClassLiteral::Property::FIELD: {
1662 UNREACHABLE();
1663 break;
1664 }
1665 }
1666 }
1667
1668 // Set the constructor to have fast properties.
1669 prototype = environment()->Pop();
1670 literal = environment()->Pop();
1671 const Operator* op = javascript()->CallRuntime(Runtime::kToFastProperties);
1672 literal = NewNode(op, literal);
1673
1674 // Assign to class variable.
1675 if (expr->class_variable_proxy() != nullptr) {
1676 Variable* var = expr->class_variable_proxy()->var();
1677 VectorSlotPair feedback = CreateVectorSlotPair(
1678 expr->NeedsProxySlot() ? expr->ProxySlot()
1679 : FeedbackVectorSlot::Invalid());
1680 BuildVariableAssignment(var, literal, Token::INIT, feedback,
1681 BailoutId::None());
1682 }
1683 ast_context()->ProduceValue(expr, literal);
1684 }
1685
1686
VisitNativeFunctionLiteral(NativeFunctionLiteral * expr)1687 void AstGraphBuilder::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
1688 UNREACHABLE();
1689 }
1690
1691
VisitDoExpression(DoExpression * expr)1692 void AstGraphBuilder::VisitDoExpression(DoExpression* expr) {
1693 VisitBlock(expr->block());
1694 VisitVariableProxy(expr->result());
1695 ast_context()->ReplaceValue(expr);
1696 }
1697
1698
VisitConditional(Conditional * expr)1699 void AstGraphBuilder::VisitConditional(Conditional* expr) {
1700 IfBuilder compare_if(this);
1701 VisitForTest(expr->condition());
1702 Node* condition = environment()->Pop();
1703 compare_if.If(condition);
1704 compare_if.Then();
1705 Visit(expr->then_expression());
1706 compare_if.Else();
1707 Visit(expr->else_expression());
1708 compare_if.End();
1709 // Skip plugging AST evaluation contexts of the test kind. This is to stay in
1710 // sync with full codegen which doesn't prepare the proper bailout point (see
1711 // the implementation of FullCodeGenerator::VisitForControl).
1712 if (ast_context()->IsTest()) return;
1713 ast_context()->ReplaceValue(expr);
1714 }
1715
1716
VisitVariableProxy(VariableProxy * expr)1717 void AstGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
1718 VectorSlotPair pair = CreateVectorSlotPair(expr->VariableFeedbackSlot());
1719 PrepareEagerCheckpoint(BeforeId(expr));
1720 Node* value = BuildVariableLoad(expr->var(), expr->id(), pair,
1721 ast_context()->GetStateCombine());
1722 ast_context()->ProduceValue(expr, value);
1723 }
1724
1725
VisitLiteral(Literal * expr)1726 void AstGraphBuilder::VisitLiteral(Literal* expr) {
1727 Node* value = jsgraph()->Constant(expr->value());
1728 ast_context()->ProduceValue(expr, value);
1729 }
1730
1731
VisitRegExpLiteral(RegExpLiteral * expr)1732 void AstGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
1733 Node* closure = GetFunctionClosure();
1734
1735 // Create node to materialize a regular expression literal.
1736 const Operator* op = javascript()->CreateLiteralRegExp(
1737 expr->pattern(), expr->flags(), expr->literal_index());
1738 Node* literal = NewNode(op, closure);
1739 PrepareFrameState(literal, expr->id(), ast_context()->GetStateCombine());
1740 ast_context()->ProduceValue(expr, literal);
1741 }
1742
1743
VisitObjectLiteral(ObjectLiteral * expr)1744 void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
1745 Node* closure = GetFunctionClosure();
1746
1747 // Create node to deep-copy the literal boilerplate.
1748 const Operator* op = javascript()->CreateLiteralObject(
1749 expr->constant_properties(), expr->ComputeFlags(true),
1750 expr->literal_index(), expr->properties_count());
1751 Node* literal = NewNode(op, closure);
1752 PrepareFrameState(literal, expr->CreateLiteralId(),
1753 OutputFrameStateCombine::Push());
1754
1755 // The object is expected on the operand stack during computation of the
1756 // property values and is the value of the entire expression.
1757 environment()->Push(literal);
1758
1759 // Create nodes to store computed values into the literal.
1760 int property_index = 0;
1761 AccessorTable accessor_table(local_zone());
1762 for (; property_index < expr->properties()->length(); property_index++) {
1763 ObjectLiteral::Property* property = expr->properties()->at(property_index);
1764 if (property->is_computed_name()) break;
1765 if (property->IsCompileTimeValue()) continue;
1766
1767 Literal* key = property->key()->AsLiteral();
1768 switch (property->kind()) {
1769 case ObjectLiteral::Property::CONSTANT:
1770 UNREACHABLE();
1771 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1772 DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value()));
1773 // Fall through.
1774 case ObjectLiteral::Property::COMPUTED: {
1775 // It is safe to use [[Put]] here because the boilerplate already
1776 // contains computed properties with an uninitialized value.
1777 if (key->IsStringLiteral()) {
1778 DCHECK(key->IsPropertyName());
1779 if (property->emit_store()) {
1780 VisitForValue(property->value());
1781 Node* value = environment()->Pop();
1782 Node* literal = environment()->Top();
1783 Handle<Name> name = key->AsPropertyName();
1784 VectorSlotPair feedback =
1785 CreateVectorSlotPair(property->GetSlot(0));
1786 Node* store = BuildNamedStore(literal, name, value, feedback);
1787 PrepareFrameState(store, key->id(),
1788 OutputFrameStateCombine::Ignore());
1789 BuildSetHomeObject(value, literal, property, 1);
1790 } else {
1791 VisitForEffect(property->value());
1792 }
1793 break;
1794 }
1795 environment()->Push(environment()->Top()); // Duplicate receiver.
1796 VisitForValue(property->key());
1797 VisitForValue(property->value());
1798 Node* value = environment()->Pop();
1799 Node* key = environment()->Pop();
1800 Node* receiver = environment()->Pop();
1801 if (property->emit_store()) {
1802 Node* language = jsgraph()->Constant(SLOPPY);
1803 const Operator* op = javascript()->CallRuntime(Runtime::kSetProperty);
1804 Node* set_property = NewNode(op, receiver, key, value, language);
1805 // SetProperty should not lazy deopt on an object literal.
1806 PrepareFrameState(set_property, BailoutId::None());
1807 BuildSetHomeObject(value, receiver, property);
1808 }
1809 break;
1810 }
1811 case ObjectLiteral::Property::PROTOTYPE: {
1812 environment()->Push(environment()->Top()); // Duplicate receiver.
1813 VisitForValue(property->value());
1814 Node* value = environment()->Pop();
1815 Node* receiver = environment()->Pop();
1816 DCHECK(property->emit_store());
1817 const Operator* op =
1818 javascript()->CallRuntime(Runtime::kInternalSetPrototype);
1819 Node* set_prototype = NewNode(op, receiver, value);
1820 // SetPrototype should not lazy deopt on an object literal.
1821 PrepareFrameState(set_prototype,
1822 expr->GetIdForPropertySet(property_index));
1823 break;
1824 }
1825 case ObjectLiteral::Property::GETTER:
1826 if (property->emit_store()) {
1827 AccessorTable::Iterator it = accessor_table.lookup(key);
1828 it->second->bailout_id = expr->GetIdForPropertySet(property_index);
1829 it->second->getter = property;
1830 }
1831 break;
1832 case ObjectLiteral::Property::SETTER:
1833 if (property->emit_store()) {
1834 AccessorTable::Iterator it = accessor_table.lookup(key);
1835 it->second->bailout_id = expr->GetIdForPropertySet(property_index);
1836 it->second->setter = property;
1837 }
1838 break;
1839 }
1840 }
1841
1842 // Create nodes to define accessors, using only a single call to the runtime
1843 // for each pair of corresponding getters and setters.
1844 literal = environment()->Top(); // Reload from operand stack.
1845 for (AccessorTable::Iterator it = accessor_table.begin();
1846 it != accessor_table.end(); ++it) {
1847 VisitForValue(it->first);
1848 VisitObjectLiteralAccessor(literal, it->second->getter);
1849 VisitObjectLiteralAccessor(literal, it->second->setter);
1850 Node* setter = environment()->Pop();
1851 Node* getter = environment()->Pop();
1852 Node* name = environment()->Pop();
1853 Node* attr = jsgraph()->Constant(NONE);
1854 const Operator* op =
1855 javascript()->CallRuntime(Runtime::kDefineAccessorPropertyUnchecked);
1856 Node* call = NewNode(op, literal, name, getter, setter, attr);
1857 PrepareFrameState(call, it->second->bailout_id);
1858 }
1859
1860 // Object literals have two parts. The "static" part on the left contains no
1861 // computed property names, and so we can compute its map ahead of time; see
1862 // Runtime_CreateObjectLiteralBoilerplate. The second "dynamic" part starts
1863 // with the first computed property name and continues with all properties to
1864 // its right. All the code from above initializes the static component of the
1865 // object literal, and arranges for the map of the result to reflect the
1866 // static order in which the keys appear. For the dynamic properties, we
1867 // compile them into a series of "SetOwnProperty" runtime calls. This will
1868 // preserve insertion order.
1869 for (; property_index < expr->properties()->length(); property_index++) {
1870 ObjectLiteral::Property* property = expr->properties()->at(property_index);
1871
1872 if (property->kind() == ObjectLiteral::Property::PROTOTYPE) {
1873 environment()->Push(environment()->Top()); // Duplicate receiver.
1874 VisitForValue(property->value());
1875 Node* value = environment()->Pop();
1876 Node* receiver = environment()->Pop();
1877 const Operator* op =
1878 javascript()->CallRuntime(Runtime::kInternalSetPrototype);
1879 Node* call = NewNode(op, receiver, value);
1880 PrepareFrameState(call, expr->GetIdForPropertySet(property_index));
1881 continue;
1882 }
1883
1884 environment()->Push(environment()->Top()); // Duplicate receiver.
1885 VisitForValue(property->key());
1886 Node* name = BuildToName(environment()->Pop(),
1887 expr->GetIdForPropertyName(property_index));
1888 environment()->Push(name);
1889 VisitForValue(property->value());
1890 Node* value = environment()->Pop();
1891 Node* key = environment()->Pop();
1892 Node* receiver = environment()->Pop();
1893 BuildSetHomeObject(value, receiver, property);
1894 switch (property->kind()) {
1895 case ObjectLiteral::Property::CONSTANT:
1896 case ObjectLiteral::Property::COMPUTED:
1897 case ObjectLiteral::Property::MATERIALIZED_LITERAL: {
1898 if (!property->emit_store()) continue;
1899 Node* attr = jsgraph()->Constant(NONE);
1900 Node* set_function_name =
1901 jsgraph()->Constant(property->NeedsSetFunctionName());
1902 const Operator* op =
1903 javascript()->CallRuntime(Runtime::kDefineDataPropertyInLiteral);
1904 Node* call = NewNode(op, receiver, key, value, attr, set_function_name);
1905 PrepareFrameState(call, expr->GetIdForPropertySet(property_index));
1906 break;
1907 }
1908 case ObjectLiteral::Property::PROTOTYPE:
1909 UNREACHABLE(); // Handled specially above.
1910 break;
1911 case ObjectLiteral::Property::GETTER: {
1912 Node* attr = jsgraph()->Constant(NONE);
1913 const Operator* op = javascript()->CallRuntime(
1914 Runtime::kDefineGetterPropertyUnchecked, 4);
1915 Node* call = NewNode(op, receiver, key, value, attr);
1916 PrepareFrameState(call, BailoutId::None());
1917 break;
1918 }
1919 case ObjectLiteral::Property::SETTER: {
1920 Node* attr = jsgraph()->Constant(NONE);
1921 const Operator* op = javascript()->CallRuntime(
1922 Runtime::kDefineSetterPropertyUnchecked, 4);
1923 Node* call = NewNode(op, receiver, key, value, attr);
1924 PrepareFrameState(call, BailoutId::None());
1925 break;
1926 }
1927 }
1928 }
1929
1930 ast_context()->ProduceValue(expr, environment()->Pop());
1931 }
1932
1933
VisitObjectLiteralAccessor(Node * home_object,ObjectLiteralProperty * property)1934 void AstGraphBuilder::VisitObjectLiteralAccessor(
1935 Node* home_object, ObjectLiteralProperty* property) {
1936 if (property == nullptr) {
1937 VisitForValueOrNull(nullptr);
1938 } else {
1939 VisitForValue(property->value());
1940 BuildSetHomeObject(environment()->Top(), home_object, property);
1941 }
1942 }
1943
1944
VisitArrayLiteral(ArrayLiteral * expr)1945 void AstGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
1946 Node* closure = GetFunctionClosure();
1947
1948 // Create node to deep-copy the literal boilerplate.
1949 const Operator* op = javascript()->CreateLiteralArray(
1950 expr->constant_elements(), expr->ComputeFlags(true),
1951 expr->literal_index(), expr->values()->length());
1952 Node* literal = NewNode(op, closure);
1953 PrepareFrameState(literal, expr->CreateLiteralId(),
1954 OutputFrameStateCombine::Push());
1955
1956 // The array is expected on the operand stack during computation of the
1957 // element values.
1958 environment()->Push(literal);
1959
1960 // Create nodes to evaluate all the non-constant subexpressions and to store
1961 // them into the newly cloned array.
1962 for (int array_index = 0; array_index < expr->values()->length();
1963 array_index++) {
1964 Expression* subexpr = expr->values()->at(array_index);
1965 DCHECK(!subexpr->IsSpread());
1966 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
1967
1968 VisitForValue(subexpr);
1969 VectorSlotPair pair = CreateVectorSlotPair(expr->LiteralFeedbackSlot());
1970 Node* value = environment()->Pop();
1971 Node* index = jsgraph()->Constant(array_index);
1972 Node* literal = environment()->Top();
1973 Node* store = BuildKeyedStore(literal, index, value, pair);
1974 PrepareFrameState(store, expr->GetIdForElement(array_index),
1975 OutputFrameStateCombine::Ignore());
1976 }
1977
1978 ast_context()->ProduceValue(expr, environment()->Pop());
1979 }
1980
VisitForInAssignment(Expression * expr,Node * value,const VectorSlotPair & feedback,BailoutId bailout_id)1981 void AstGraphBuilder::VisitForInAssignment(Expression* expr, Node* value,
1982 const VectorSlotPair& feedback,
1983 BailoutId bailout_id) {
1984 DCHECK(expr->IsValidReferenceExpressionOrThis());
1985
1986 // Left-hand side can only be a property, a global or a variable slot.
1987 Property* property = expr->AsProperty();
1988 LhsKind assign_type = Property::GetAssignType(property);
1989
1990 // Evaluate LHS expression and store the value.
1991 switch (assign_type) {
1992 case VARIABLE: {
1993 Variable* var = expr->AsVariableProxy()->var();
1994 BuildVariableAssignment(var, value, Token::ASSIGN, feedback, bailout_id);
1995 break;
1996 }
1997 case NAMED_PROPERTY: {
1998 environment()->Push(value);
1999 VisitForValue(property->obj());
2000 Node* object = environment()->Pop();
2001 value = environment()->Pop();
2002 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
2003 Node* store = BuildNamedStore(object, name, value, feedback);
2004 PrepareFrameState(store, bailout_id, OutputFrameStateCombine::Ignore());
2005 break;
2006 }
2007 case KEYED_PROPERTY: {
2008 environment()->Push(value);
2009 VisitForValue(property->obj());
2010 VisitForValue(property->key());
2011 Node* key = environment()->Pop();
2012 Node* object = environment()->Pop();
2013 value = environment()->Pop();
2014 Node* store = BuildKeyedStore(object, key, value, feedback);
2015 PrepareFrameState(store, bailout_id, OutputFrameStateCombine::Ignore());
2016 break;
2017 }
2018 case NAMED_SUPER_PROPERTY: {
2019 environment()->Push(value);
2020 VisitForValue(property->obj()->AsSuperPropertyReference()->this_var());
2021 VisitForValue(property->obj()->AsSuperPropertyReference()->home_object());
2022 Node* home_object = environment()->Pop();
2023 Node* receiver = environment()->Pop();
2024 value = environment()->Pop();
2025 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
2026 Node* store = BuildNamedSuperStore(receiver, home_object, name, value);
2027 PrepareFrameState(store, bailout_id, OutputFrameStateCombine::Ignore());
2028 break;
2029 }
2030 case KEYED_SUPER_PROPERTY: {
2031 environment()->Push(value);
2032 VisitForValue(property->obj()->AsSuperPropertyReference()->this_var());
2033 VisitForValue(property->obj()->AsSuperPropertyReference()->home_object());
2034 VisitForValue(property->key());
2035 Node* key = environment()->Pop();
2036 Node* home_object = environment()->Pop();
2037 Node* receiver = environment()->Pop();
2038 value = environment()->Pop();
2039 Node* store = BuildKeyedSuperStore(receiver, home_object, key, value);
2040 PrepareFrameState(store, bailout_id, OutputFrameStateCombine::Ignore());
2041 break;
2042 }
2043 }
2044 }
2045
2046
VisitAssignment(Assignment * expr)2047 void AstGraphBuilder::VisitAssignment(Assignment* expr) {
2048 DCHECK(expr->target()->IsValidReferenceExpressionOrThis());
2049
2050 // Left-hand side can only be a property, a global or a variable slot.
2051 Property* property = expr->target()->AsProperty();
2052 LhsKind assign_type = Property::GetAssignType(property);
2053 bool needs_frame_state_before = true;
2054
2055 // Evaluate LHS expression.
2056 switch (assign_type) {
2057 case VARIABLE: {
2058 Variable* variable = expr->target()->AsVariableProxy()->var();
2059 if (variable->location() == VariableLocation::PARAMETER ||
2060 variable->location() == VariableLocation::LOCAL ||
2061 variable->location() == VariableLocation::CONTEXT) {
2062 needs_frame_state_before = false;
2063 }
2064 break;
2065 }
2066 case NAMED_PROPERTY:
2067 VisitForValue(property->obj());
2068 break;
2069 case KEYED_PROPERTY:
2070 VisitForValue(property->obj());
2071 VisitForValue(property->key());
2072 break;
2073 case NAMED_SUPER_PROPERTY:
2074 VisitForValue(property->obj()->AsSuperPropertyReference()->this_var());
2075 VisitForValue(property->obj()->AsSuperPropertyReference()->home_object());
2076 break;
2077 case KEYED_SUPER_PROPERTY:
2078 VisitForValue(property->obj()->AsSuperPropertyReference()->this_var());
2079 VisitForValue(property->obj()->AsSuperPropertyReference()->home_object());
2080 VisitForValue(property->key());
2081 break;
2082 }
2083
2084 // Evaluate the value and potentially handle compound assignments by loading
2085 // the left-hand side value and performing a binary operation.
2086 if (expr->is_compound()) {
2087 Node* old_value = nullptr;
2088 switch (assign_type) {
2089 case VARIABLE: {
2090 VariableProxy* proxy = expr->target()->AsVariableProxy();
2091 VectorSlotPair pair =
2092 CreateVectorSlotPair(proxy->VariableFeedbackSlot());
2093 PrepareEagerCheckpoint(BeforeId(proxy));
2094 old_value = BuildVariableLoad(proxy->var(), expr->target()->id(), pair,
2095 OutputFrameStateCombine::Push());
2096 break;
2097 }
2098 case NAMED_PROPERTY: {
2099 Node* object = environment()->Top();
2100 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
2101 VectorSlotPair pair =
2102 CreateVectorSlotPair(property->PropertyFeedbackSlot());
2103 old_value = BuildNamedLoad(object, name, pair);
2104 PrepareFrameState(old_value, property->LoadId(),
2105 OutputFrameStateCombine::Push());
2106 break;
2107 }
2108 case KEYED_PROPERTY: {
2109 Node* key = environment()->Top();
2110 Node* object = environment()->Peek(1);
2111 VectorSlotPair pair =
2112 CreateVectorSlotPair(property->PropertyFeedbackSlot());
2113 old_value = BuildKeyedLoad(object, key, pair);
2114 PrepareFrameState(old_value, property->LoadId(),
2115 OutputFrameStateCombine::Push());
2116 break;
2117 }
2118 case NAMED_SUPER_PROPERTY: {
2119 Node* home_object = environment()->Top();
2120 Node* receiver = environment()->Peek(1);
2121 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
2122 VectorSlotPair pair =
2123 CreateVectorSlotPair(property->PropertyFeedbackSlot());
2124 old_value = BuildNamedSuperLoad(receiver, home_object, name, pair);
2125 PrepareFrameState(old_value, property->LoadId(),
2126 OutputFrameStateCombine::Push());
2127 break;
2128 }
2129 case KEYED_SUPER_PROPERTY: {
2130 Node* key = environment()->Top();
2131 Node* home_object = environment()->Peek(1);
2132 Node* receiver = environment()->Peek(2);
2133 VectorSlotPair pair =
2134 CreateVectorSlotPair(property->PropertyFeedbackSlot());
2135 old_value = BuildKeyedSuperLoad(receiver, home_object, key, pair);
2136 PrepareFrameState(old_value, property->LoadId(),
2137 OutputFrameStateCombine::Push());
2138 break;
2139 }
2140 }
2141 environment()->Push(old_value);
2142 VisitForValue(expr->value());
2143 Node* right = environment()->Pop();
2144 Node* left = environment()->Pop();
2145 Node* value =
2146 BuildBinaryOp(left, right, expr->binary_op(),
2147 expr->binary_operation()->BinaryOperationFeedbackId());
2148 PrepareFrameState(value, expr->binary_operation()->id(),
2149 OutputFrameStateCombine::Push());
2150 environment()->Push(value);
2151 if (needs_frame_state_before) {
2152 PrepareEagerCheckpoint(expr->binary_operation()->id());
2153 }
2154 } else {
2155 VisitForValue(expr->value());
2156 }
2157
2158 // Store the value.
2159 Node* value = environment()->Pop();
2160 VectorSlotPair feedback = CreateVectorSlotPair(expr->AssignmentSlot());
2161 switch (assign_type) {
2162 case VARIABLE: {
2163 Variable* variable = expr->target()->AsVariableProxy()->var();
2164 BuildVariableAssignment(variable, value, expr->op(), feedback, expr->id(),
2165 ast_context()->GetStateCombine());
2166 break;
2167 }
2168 case NAMED_PROPERTY: {
2169 Node* object = environment()->Pop();
2170 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
2171 Node* store = BuildNamedStore(object, name, value, feedback);
2172 PrepareFrameState(store, expr->AssignmentId(),
2173 OutputFrameStateCombine::Push());
2174 break;
2175 }
2176 case KEYED_PROPERTY: {
2177 Node* key = environment()->Pop();
2178 Node* object = environment()->Pop();
2179 Node* store = BuildKeyedStore(object, key, value, feedback);
2180 PrepareFrameState(store, expr->AssignmentId(),
2181 OutputFrameStateCombine::Push());
2182 break;
2183 }
2184 case NAMED_SUPER_PROPERTY: {
2185 Node* home_object = environment()->Pop();
2186 Node* receiver = environment()->Pop();
2187 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
2188 Node* store = BuildNamedSuperStore(receiver, home_object, name, value);
2189 PrepareFrameState(store, expr->id(), ast_context()->GetStateCombine());
2190 break;
2191 }
2192 case KEYED_SUPER_PROPERTY: {
2193 Node* key = environment()->Pop();
2194 Node* home_object = environment()->Pop();
2195 Node* receiver = environment()->Pop();
2196 Node* store = BuildKeyedSuperStore(receiver, home_object, key, value);
2197 PrepareFrameState(store, expr->id(), ast_context()->GetStateCombine());
2198 break;
2199 }
2200 }
2201
2202 ast_context()->ProduceValue(expr, value);
2203 }
2204
2205
VisitYield(Yield * expr)2206 void AstGraphBuilder::VisitYield(Yield* expr) {
2207 // Generator functions are supported only by going through Ignition first.
2208 SetStackOverflow();
2209 ast_context()->ProduceValue(expr, jsgraph()->UndefinedConstant());
2210 }
2211
2212
VisitThrow(Throw * expr)2213 void AstGraphBuilder::VisitThrow(Throw* expr) {
2214 VisitForValue(expr->exception());
2215 Node* exception = environment()->Pop();
2216 Node* value = BuildThrowError(exception, expr->id());
2217 ast_context()->ProduceValue(expr, value);
2218 }
2219
2220
VisitProperty(Property * expr)2221 void AstGraphBuilder::VisitProperty(Property* expr) {
2222 Node* value = nullptr;
2223 LhsKind property_kind = Property::GetAssignType(expr);
2224 VectorSlotPair pair = CreateVectorSlotPair(expr->PropertyFeedbackSlot());
2225 switch (property_kind) {
2226 case VARIABLE:
2227 UNREACHABLE();
2228 break;
2229 case NAMED_PROPERTY: {
2230 VisitForValue(expr->obj());
2231 Node* object = environment()->Pop();
2232 Handle<Name> name = expr->key()->AsLiteral()->AsPropertyName();
2233 value = BuildNamedLoad(object, name, pair);
2234 PrepareFrameState(value, expr->LoadId(), OutputFrameStateCombine::Push());
2235 break;
2236 }
2237 case KEYED_PROPERTY: {
2238 VisitForValue(expr->obj());
2239 VisitForValue(expr->key());
2240 Node* key = environment()->Pop();
2241 Node* object = environment()->Pop();
2242 value = BuildKeyedLoad(object, key, pair);
2243 PrepareFrameState(value, expr->LoadId(), OutputFrameStateCombine::Push());
2244 break;
2245 }
2246 case NAMED_SUPER_PROPERTY: {
2247 VisitForValue(expr->obj()->AsSuperPropertyReference()->this_var());
2248 VisitForValue(expr->obj()->AsSuperPropertyReference()->home_object());
2249 Node* home_object = environment()->Pop();
2250 Node* receiver = environment()->Pop();
2251 Handle<Name> name = expr->key()->AsLiteral()->AsPropertyName();
2252 value = BuildNamedSuperLoad(receiver, home_object, name, pair);
2253 PrepareFrameState(value, expr->LoadId(), OutputFrameStateCombine::Push());
2254 break;
2255 }
2256 case KEYED_SUPER_PROPERTY: {
2257 VisitForValue(expr->obj()->AsSuperPropertyReference()->this_var());
2258 VisitForValue(expr->obj()->AsSuperPropertyReference()->home_object());
2259 VisitForValue(expr->key());
2260 Node* key = environment()->Pop();
2261 Node* home_object = environment()->Pop();
2262 Node* receiver = environment()->Pop();
2263 value = BuildKeyedSuperLoad(receiver, home_object, key, pair);
2264 PrepareFrameState(value, expr->LoadId(), OutputFrameStateCombine::Push());
2265 break;
2266 }
2267 }
2268 ast_context()->ProduceValue(expr, value);
2269 }
2270
2271
VisitCall(Call * expr)2272 void AstGraphBuilder::VisitCall(Call* expr) {
2273 Expression* callee = expr->expression();
2274 Call::CallType call_type = expr->GetCallType();
2275
2276 // Prepare the callee and the receiver to the function call. This depends on
2277 // the semantics of the underlying call type.
2278 ConvertReceiverMode receiver_hint = ConvertReceiverMode::kAny;
2279 Node* receiver_value = nullptr;
2280 Node* callee_value = nullptr;
2281 if (expr->is_possibly_eval()) {
2282 if (callee->AsVariableProxy()->var()->IsLookupSlot()) {
2283 Variable* variable = callee->AsVariableProxy()->var();
2284 Node* name = jsgraph()->Constant(variable->name());
2285 const Operator* op =
2286 javascript()->CallRuntime(Runtime::kLoadLookupSlotForCall);
2287 Node* pair = NewNode(op, name);
2288 callee_value = NewNode(common()->Projection(0), pair);
2289 receiver_value = NewNode(common()->Projection(1), pair);
2290 PrepareFrameState(pair, expr->LookupId(),
2291 OutputFrameStateCombine::Push(2));
2292 } else {
2293 VisitForValue(callee);
2294 callee_value = environment()->Pop();
2295 receiver_hint = ConvertReceiverMode::kNullOrUndefined;
2296 receiver_value = jsgraph()->UndefinedConstant();
2297 }
2298 } else {
2299 switch (call_type) {
2300 case Call::GLOBAL_CALL: {
2301 VariableProxy* proxy = callee->AsVariableProxy();
2302 VectorSlotPair pair =
2303 CreateVectorSlotPair(proxy->VariableFeedbackSlot());
2304 PrepareEagerCheckpoint(BeforeId(proxy));
2305 callee_value = BuildVariableLoad(proxy->var(), expr->expression()->id(),
2306 pair, OutputFrameStateCombine::Push());
2307 receiver_hint = ConvertReceiverMode::kNullOrUndefined;
2308 receiver_value = jsgraph()->UndefinedConstant();
2309 break;
2310 }
2311 case Call::WITH_CALL: {
2312 Variable* variable = callee->AsVariableProxy()->var();
2313 Node* name = jsgraph()->Constant(variable->name());
2314 const Operator* op =
2315 javascript()->CallRuntime(Runtime::kLoadLookupSlotForCall);
2316 Node* pair = NewNode(op, name);
2317 callee_value = NewNode(common()->Projection(0), pair);
2318 receiver_value = NewNode(common()->Projection(1), pair);
2319 PrepareFrameState(pair, expr->LookupId(),
2320 OutputFrameStateCombine::Push(2));
2321 break;
2322 }
2323 case Call::NAMED_PROPERTY_CALL: {
2324 Property* property = callee->AsProperty();
2325 VectorSlotPair feedback =
2326 CreateVectorSlotPair(property->PropertyFeedbackSlot());
2327 VisitForValue(property->obj());
2328 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
2329 Node* object = environment()->Top();
2330 callee_value = BuildNamedLoad(object, name, feedback);
2331 PrepareFrameState(callee_value, property->LoadId(),
2332 OutputFrameStateCombine::Push());
2333 // Note that a property call requires the receiver to be wrapped into
2334 // an object for sloppy callees. However the receiver is guaranteed
2335 // not to be null or undefined at this point.
2336 receiver_hint = ConvertReceiverMode::kNotNullOrUndefined;
2337 receiver_value = environment()->Pop();
2338 break;
2339 }
2340 case Call::KEYED_PROPERTY_CALL: {
2341 Property* property = callee->AsProperty();
2342 VectorSlotPair feedback =
2343 CreateVectorSlotPair(property->PropertyFeedbackSlot());
2344 VisitForValue(property->obj());
2345 VisitForValue(property->key());
2346 Node* key = environment()->Pop();
2347 Node* object = environment()->Top();
2348 callee_value = BuildKeyedLoad(object, key, feedback);
2349 PrepareFrameState(callee_value, property->LoadId(),
2350 OutputFrameStateCombine::Push());
2351 // Note that a property call requires the receiver to be wrapped into
2352 // an object for sloppy callees. However the receiver is guaranteed
2353 // not to be null or undefined at this point.
2354 receiver_hint = ConvertReceiverMode::kNotNullOrUndefined;
2355 receiver_value = environment()->Pop();
2356 break;
2357 }
2358 case Call::NAMED_SUPER_PROPERTY_CALL: {
2359 Property* property = callee->AsProperty();
2360 SuperPropertyReference* super_ref =
2361 property->obj()->AsSuperPropertyReference();
2362 VisitForValue(super_ref->home_object());
2363 VisitForValue(super_ref->this_var());
2364 Node* home = environment()->Peek(1);
2365 Node* object = environment()->Top();
2366 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
2367 callee_value =
2368 BuildNamedSuperLoad(object, home, name, VectorSlotPair());
2369 PrepareFrameState(callee_value, property->LoadId(),
2370 OutputFrameStateCombine::Push());
2371 // Note that a property call requires the receiver to be wrapped into
2372 // an object for sloppy callees. Since the receiver is not the target of
2373 // the load, it could very well be null or undefined at this point.
2374 receiver_value = environment()->Pop();
2375 environment()->Drop(1);
2376 break;
2377 }
2378 case Call::KEYED_SUPER_PROPERTY_CALL: {
2379 Property* property = callee->AsProperty();
2380 SuperPropertyReference* super_ref =
2381 property->obj()->AsSuperPropertyReference();
2382 VisitForValue(super_ref->home_object());
2383 VisitForValue(super_ref->this_var());
2384 environment()->Push(environment()->Top()); // Duplicate this_var.
2385 environment()->Push(environment()->Peek(2)); // Duplicate home_obj.
2386 VisitForValue(property->key());
2387 Node* key = environment()->Pop();
2388 Node* home = environment()->Pop();
2389 Node* object = environment()->Pop();
2390 callee_value = BuildKeyedSuperLoad(object, home, key, VectorSlotPair());
2391 PrepareFrameState(callee_value, property->LoadId(),
2392 OutputFrameStateCombine::Push());
2393 // Note that a property call requires the receiver to be wrapped into
2394 // an object for sloppy callees. Since the receiver is not the target of
2395 // the load, it could very well be null or undefined at this point.
2396 receiver_value = environment()->Pop();
2397 environment()->Drop(1);
2398 break;
2399 }
2400 case Call::SUPER_CALL:
2401 return VisitCallSuper(expr);
2402 case Call::OTHER_CALL:
2403 VisitForValue(callee);
2404 callee_value = environment()->Pop();
2405 receiver_hint = ConvertReceiverMode::kNullOrUndefined;
2406 receiver_value = jsgraph()->UndefinedConstant();
2407 break;
2408 }
2409 }
2410
2411 // The callee and the receiver both have to be pushed onto the operand stack
2412 // before arguments are being evaluated.
2413 environment()->Push(callee_value);
2414 environment()->Push(receiver_value);
2415
2416 // Evaluate all arguments to the function call,
2417 ZoneList<Expression*>* args = expr->arguments();
2418 VisitForValues(args);
2419
2420 // Resolve callee for a potential direct eval call. This block will mutate the
2421 // callee value pushed onto the environment.
2422 if (expr->is_possibly_eval() && args->length() > 0) {
2423 int arg_count = args->length();
2424
2425 // Extract callee and source string from the environment.
2426 Node* callee = environment()->Peek(arg_count + 1);
2427 Node* source = environment()->Peek(arg_count - 1);
2428
2429 // Create node to ask for help resolving potential eval call. This will
2430 // provide a fully resolved callee to patch into the environment.
2431 Node* function = GetFunctionClosure();
2432 Node* language = jsgraph()->Constant(language_mode());
2433 Node* eval_scope_position =
2434 jsgraph()->Constant(current_scope()->start_position());
2435 Node* eval_position = jsgraph()->Constant(expr->position());
2436 const Operator* op =
2437 javascript()->CallRuntime(Runtime::kResolvePossiblyDirectEval);
2438 Node* new_callee = NewNode(op, callee, source, function, language,
2439 eval_scope_position, eval_position);
2440 PrepareFrameState(new_callee, expr->EvalId(),
2441 OutputFrameStateCombine::PokeAt(arg_count + 1));
2442
2443 // Patch callee on the environment.
2444 environment()->Poke(arg_count + 1, new_callee);
2445 }
2446
2447 // Create node to perform the function call.
2448 float const frequency = ComputeCallFrequency(expr->CallFeedbackICSlot());
2449 VectorSlotPair feedback = CreateVectorSlotPair(expr->CallFeedbackICSlot());
2450 const Operator* call =
2451 javascript()->CallFunction(args->length() + 2, frequency, feedback,
2452 receiver_hint, expr->tail_call_mode());
2453 PrepareEagerCheckpoint(expr->is_possibly_eval() ? expr->EvalId()
2454 : expr->CallId());
2455 Node* value = ProcessArguments(call, args->length() + 2);
2456 // The callee passed to the call, we just need to push something here to
2457 // satisfy the bailout location contract. The fullcodegen code will not
2458 // ever look at this value, so we just push optimized_out here.
2459 environment()->Push(jsgraph()->OptimizedOutConstant());
2460 PrepareFrameState(value, expr->ReturnId(), OutputFrameStateCombine::Push());
2461 environment()->Drop(1);
2462 ast_context()->ProduceValue(expr, value);
2463 }
2464
2465
VisitCallSuper(Call * expr)2466 void AstGraphBuilder::VisitCallSuper(Call* expr) {
2467 SuperCallReference* super = expr->expression()->AsSuperCallReference();
2468 DCHECK_NOT_NULL(super);
2469
2470 // Prepare the callee to the super call.
2471 VisitForValue(super->this_function_var());
2472 Node* this_function = environment()->Pop();
2473 const Operator* op =
2474 javascript()->CallRuntime(Runtime::kInlineGetSuperConstructor, 1);
2475 Node* super_function = NewNode(op, this_function);
2476 environment()->Push(super_function);
2477
2478 // Evaluate all arguments to the super call.
2479 ZoneList<Expression*>* args = expr->arguments();
2480 VisitForValues(args);
2481
2482 // The new target is loaded from the {new.target} variable.
2483 VisitForValue(super->new_target_var());
2484
2485 // Create node to perform the super call.
2486 const Operator* call =
2487 javascript()->CallConstruct(args->length() + 2, 0.0f, VectorSlotPair());
2488 Node* value = ProcessArguments(call, args->length() + 2);
2489 PrepareFrameState(value, expr->ReturnId(), OutputFrameStateCombine::Push());
2490 ast_context()->ProduceValue(expr, value);
2491 }
2492
2493
VisitCallNew(CallNew * expr)2494 void AstGraphBuilder::VisitCallNew(CallNew* expr) {
2495 VisitForValue(expr->expression());
2496
2497 // Evaluate all arguments to the construct call.
2498 ZoneList<Expression*>* args = expr->arguments();
2499 VisitForValues(args);
2500
2501 // The new target is the same as the callee.
2502 environment()->Push(environment()->Peek(args->length()));
2503
2504 // Create node to perform the construct call.
2505 float const frequency = ComputeCallFrequency(expr->CallNewFeedbackSlot());
2506 VectorSlotPair feedback = CreateVectorSlotPair(expr->CallNewFeedbackSlot());
2507 const Operator* call =
2508 javascript()->CallConstruct(args->length() + 2, frequency, feedback);
2509 Node* value = ProcessArguments(call, args->length() + 2);
2510 PrepareFrameState(value, expr->ReturnId(), OutputFrameStateCombine::Push());
2511 ast_context()->ProduceValue(expr, value);
2512 }
2513
2514
VisitCallJSRuntime(CallRuntime * expr)2515 void AstGraphBuilder::VisitCallJSRuntime(CallRuntime* expr) {
2516 // The callee and the receiver both have to be pushed onto the operand stack
2517 // before arguments are being evaluated.
2518 Node* callee_value = BuildLoadNativeContextField(expr->context_index());
2519 Node* receiver_value = jsgraph()->UndefinedConstant();
2520
2521 environment()->Push(callee_value);
2522 environment()->Push(receiver_value);
2523
2524 // Evaluate all arguments to the JS runtime call.
2525 ZoneList<Expression*>* args = expr->arguments();
2526 VisitForValues(args);
2527
2528 // Create node to perform the JS runtime call.
2529 const Operator* call = javascript()->CallFunction(args->length() + 2);
2530 PrepareEagerCheckpoint(expr->CallId());
2531 Node* value = ProcessArguments(call, args->length() + 2);
2532 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
2533 ast_context()->ProduceValue(expr, value);
2534 }
2535
2536
VisitCallRuntime(CallRuntime * expr)2537 void AstGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
2538 // Handle calls to runtime functions implemented in JavaScript separately as
2539 // the call follows JavaScript ABI and the callee is statically unknown.
2540 if (expr->is_jsruntime()) {
2541 return VisitCallJSRuntime(expr);
2542 }
2543
2544 // Evaluate all arguments to the runtime call.
2545 ZoneList<Expression*>* args = expr->arguments();
2546 VisitForValues(args);
2547
2548 // Create node to perform the runtime call.
2549 Runtime::FunctionId functionId = expr->function()->function_id;
2550 const Operator* call = javascript()->CallRuntime(functionId, args->length());
2551 if (expr->function()->intrinsic_type == Runtime::IntrinsicType::RUNTIME ||
2552 expr->function()->function_id == Runtime::kInlineCall) {
2553 PrepareEagerCheckpoint(expr->CallId());
2554 }
2555 Node* value = ProcessArguments(call, args->length());
2556 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
2557 ast_context()->ProduceValue(expr, value);
2558 }
2559
2560
VisitUnaryOperation(UnaryOperation * expr)2561 void AstGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
2562 switch (expr->op()) {
2563 case Token::DELETE:
2564 return VisitDelete(expr);
2565 case Token::VOID:
2566 return VisitVoid(expr);
2567 case Token::TYPEOF:
2568 return VisitTypeof(expr);
2569 case Token::NOT:
2570 return VisitNot(expr);
2571 default:
2572 UNREACHABLE();
2573 }
2574 }
2575
2576
VisitCountOperation(CountOperation * expr)2577 void AstGraphBuilder::VisitCountOperation(CountOperation* expr) {
2578 DCHECK(expr->expression()->IsValidReferenceExpressionOrThis());
2579
2580 // Left-hand side can only be a property, a global or a variable slot.
2581 Property* property = expr->expression()->AsProperty();
2582 LhsKind assign_type = Property::GetAssignType(property);
2583
2584 // Reserve space for result of postfix operation.
2585 bool is_postfix = expr->is_postfix() && !ast_context()->IsEffect();
2586 if (is_postfix && assign_type != VARIABLE) {
2587 environment()->Push(jsgraph()->ZeroConstant());
2588 }
2589
2590 // Evaluate LHS expression and get old value.
2591 Node* old_value = nullptr;
2592 int stack_depth = -1;
2593 switch (assign_type) {
2594 case VARIABLE: {
2595 VariableProxy* proxy = expr->expression()->AsVariableProxy();
2596 VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot());
2597 PrepareEagerCheckpoint(BeforeId(proxy));
2598 old_value = BuildVariableLoad(proxy->var(), expr->expression()->id(),
2599 pair, OutputFrameStateCombine::Push());
2600 stack_depth = 0;
2601 break;
2602 }
2603 case NAMED_PROPERTY: {
2604 VisitForValue(property->obj());
2605 Node* object = environment()->Top();
2606 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
2607 VectorSlotPair pair =
2608 CreateVectorSlotPair(property->PropertyFeedbackSlot());
2609 old_value = BuildNamedLoad(object, name, pair);
2610 PrepareFrameState(old_value, property->LoadId(),
2611 OutputFrameStateCombine::Push());
2612 stack_depth = 1;
2613 break;
2614 }
2615 case KEYED_PROPERTY: {
2616 VisitForValue(property->obj());
2617 VisitForValue(property->key());
2618 Node* key = environment()->Top();
2619 Node* object = environment()->Peek(1);
2620 VectorSlotPair pair =
2621 CreateVectorSlotPair(property->PropertyFeedbackSlot());
2622 old_value = BuildKeyedLoad(object, key, pair);
2623 PrepareFrameState(old_value, property->LoadId(),
2624 OutputFrameStateCombine::Push());
2625 stack_depth = 2;
2626 break;
2627 }
2628 case NAMED_SUPER_PROPERTY: {
2629 VisitForValue(property->obj()->AsSuperPropertyReference()->this_var());
2630 VisitForValue(property->obj()->AsSuperPropertyReference()->home_object());
2631 Node* home_object = environment()->Top();
2632 Node* receiver = environment()->Peek(1);
2633 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
2634 VectorSlotPair pair =
2635 CreateVectorSlotPair(property->PropertyFeedbackSlot());
2636 old_value = BuildNamedSuperLoad(receiver, home_object, name, pair);
2637 PrepareFrameState(old_value, property->LoadId(),
2638 OutputFrameStateCombine::Push());
2639 stack_depth = 2;
2640 break;
2641 }
2642 case KEYED_SUPER_PROPERTY: {
2643 VisitForValue(property->obj()->AsSuperPropertyReference()->this_var());
2644 VisitForValue(property->obj()->AsSuperPropertyReference()->home_object());
2645 VisitForValue(property->key());
2646 Node* key = environment()->Top();
2647 Node* home_object = environment()->Peek(1);
2648 Node* receiver = environment()->Peek(2);
2649 VectorSlotPair pair =
2650 CreateVectorSlotPair(property->PropertyFeedbackSlot());
2651 old_value = BuildKeyedSuperLoad(receiver, home_object, key, pair);
2652 PrepareFrameState(old_value, property->LoadId(),
2653 OutputFrameStateCombine::Push());
2654 stack_depth = 3;
2655 break;
2656 }
2657 }
2658
2659 // Convert old value into a number.
2660 old_value = NewNode(javascript()->ToNumber(), old_value);
2661 PrepareFrameState(old_value, expr->ToNumberId(),
2662 OutputFrameStateCombine::Push());
2663
2664 // Create a proper eager frame state for the stores.
2665 environment()->Push(old_value);
2666 PrepareEagerCheckpoint(expr->ToNumberId());
2667 old_value = environment()->Pop();
2668
2669 // Save result for postfix expressions at correct stack depth.
2670 if (is_postfix) {
2671 if (assign_type != VARIABLE) {
2672 environment()->Poke(stack_depth, old_value);
2673 } else {
2674 environment()->Push(old_value);
2675 }
2676 }
2677
2678 // Create node to perform +1/-1 operation.
2679 Node* value = BuildBinaryOp(old_value, jsgraph()->OneConstant(),
2680 expr->binary_op(), expr->CountBinOpFeedbackId());
2681 // This should never lazy deopt because we have converted to number before.
2682 PrepareFrameState(value, BailoutId::None());
2683
2684 // Store the value.
2685 VectorSlotPair feedback = CreateVectorSlotPair(expr->CountSlot());
2686 switch (assign_type) {
2687 case VARIABLE: {
2688 Variable* variable = expr->expression()->AsVariableProxy()->var();
2689 environment()->Push(value);
2690 BuildVariableAssignment(variable, value, expr->op(), feedback,
2691 expr->AssignmentId());
2692 environment()->Pop();
2693 break;
2694 }
2695 case NAMED_PROPERTY: {
2696 Node* object = environment()->Pop();
2697 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
2698 Node* store = BuildNamedStore(object, name, value, feedback);
2699 PrepareFrameState(store, expr->AssignmentId(),
2700 OutputFrameStateCombine::Push());
2701 break;
2702 }
2703 case KEYED_PROPERTY: {
2704 Node* key = environment()->Pop();
2705 Node* object = environment()->Pop();
2706 Node* store = BuildKeyedStore(object, key, value, feedback);
2707 PrepareFrameState(store, expr->AssignmentId(),
2708 OutputFrameStateCombine::Push());
2709 break;
2710 }
2711 case NAMED_SUPER_PROPERTY: {
2712 Node* home_object = environment()->Pop();
2713 Node* receiver = environment()->Pop();
2714 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
2715 Node* store = BuildNamedSuperStore(receiver, home_object, name, value);
2716 PrepareFrameState(store, expr->AssignmentId(),
2717 OutputFrameStateCombine::Push());
2718 break;
2719 }
2720 case KEYED_SUPER_PROPERTY: {
2721 Node* key = environment()->Pop();
2722 Node* home_object = environment()->Pop();
2723 Node* receiver = environment()->Pop();
2724 Node* store = BuildKeyedSuperStore(receiver, home_object, key, value);
2725 PrepareFrameState(store, expr->AssignmentId(),
2726 OutputFrameStateCombine::Push());
2727 break;
2728 }
2729 }
2730
2731 // Restore old value for postfix expressions.
2732 if (is_postfix) value = environment()->Pop();
2733
2734 ast_context()->ProduceValue(expr, value);
2735 }
2736
2737
VisitBinaryOperation(BinaryOperation * expr)2738 void AstGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
2739 switch (expr->op()) {
2740 case Token::COMMA:
2741 return VisitComma(expr);
2742 case Token::OR:
2743 case Token::AND:
2744 return VisitLogicalExpression(expr);
2745 default: {
2746 VisitForValue(expr->left());
2747 VisitForValue(expr->right());
2748 Node* right = environment()->Pop();
2749 Node* left = environment()->Pop();
2750 Node* value = BuildBinaryOp(left, right, expr->op(),
2751 expr->BinaryOperationFeedbackId());
2752 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
2753 ast_context()->ProduceValue(expr, value);
2754 }
2755 }
2756 }
2757
VisitLiteralCompareNil(CompareOperation * expr,Expression * sub_expr,Node * nil_value)2758 void AstGraphBuilder::VisitLiteralCompareNil(CompareOperation* expr,
2759 Expression* sub_expr,
2760 Node* nil_value) {
2761 const Operator* op = nullptr;
2762 switch (expr->op()) {
2763 case Token::EQ:
2764 op = javascript()->Equal(CompareOperationHint::kAny);
2765 break;
2766 case Token::EQ_STRICT:
2767 op = javascript()->StrictEqual(CompareOperationHint::kAny);
2768 break;
2769 default:
2770 UNREACHABLE();
2771 }
2772 VisitForValue(sub_expr);
2773 Node* value_to_compare = environment()->Pop();
2774 Node* value = NewNode(op, value_to_compare, nil_value);
2775 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
2776 return ast_context()->ProduceValue(expr, value);
2777 }
2778
VisitLiteralCompareTypeof(CompareOperation * expr,Expression * sub_expr,Handle<String> check)2779 void AstGraphBuilder::VisitLiteralCompareTypeof(CompareOperation* expr,
2780 Expression* sub_expr,
2781 Handle<String> check) {
2782 VisitTypeofExpression(sub_expr);
2783 Node* typeof_arg = NewNode(javascript()->TypeOf(), environment()->Pop());
2784 Node* value = NewNode(javascript()->StrictEqual(CompareOperationHint::kAny),
2785 typeof_arg, jsgraph()->Constant(check));
2786 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
2787 return ast_context()->ProduceValue(expr, value);
2788 }
2789
VisitCompareOperation(CompareOperation * expr)2790 void AstGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
2791 // Check for a few fast cases. The AST visiting behavior must be in sync
2792 // with the full codegen: We don't push both left and right values onto
2793 // the expression stack when one side is a special-case literal.
2794 Expression* sub_expr = nullptr;
2795 Handle<String> check;
2796 if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) {
2797 return VisitLiteralCompareTypeof(expr, sub_expr, check);
2798 }
2799 if (expr->IsLiteralCompareUndefined(&sub_expr)) {
2800 return VisitLiteralCompareNil(expr, sub_expr,
2801 jsgraph()->UndefinedConstant());
2802 }
2803 if (expr->IsLiteralCompareNull(&sub_expr)) {
2804 return VisitLiteralCompareNil(expr, sub_expr, jsgraph()->NullConstant());
2805 }
2806
2807 CompareOperationHint hint;
2808 if (!type_hint_analysis_ ||
2809 !type_hint_analysis_->GetCompareOperationHint(
2810 expr->CompareOperationFeedbackId(), &hint)) {
2811 hint = CompareOperationHint::kAny;
2812 }
2813
2814 const Operator* op;
2815 switch (expr->op()) {
2816 case Token::EQ:
2817 op = javascript()->Equal(hint);
2818 break;
2819 case Token::NE:
2820 op = javascript()->NotEqual(hint);
2821 break;
2822 case Token::EQ_STRICT:
2823 op = javascript()->StrictEqual(hint);
2824 break;
2825 case Token::NE_STRICT:
2826 op = javascript()->StrictNotEqual(hint);
2827 break;
2828 case Token::LT:
2829 op = javascript()->LessThan(hint);
2830 break;
2831 case Token::GT:
2832 op = javascript()->GreaterThan(hint);
2833 break;
2834 case Token::LTE:
2835 op = javascript()->LessThanOrEqual(hint);
2836 break;
2837 case Token::GTE:
2838 op = javascript()->GreaterThanOrEqual(hint);
2839 break;
2840 case Token::INSTANCEOF:
2841 op = javascript()->InstanceOf();
2842 break;
2843 case Token::IN:
2844 op = javascript()->HasProperty();
2845 break;
2846 default:
2847 op = nullptr;
2848 UNREACHABLE();
2849 }
2850 VisitForValue(expr->left());
2851 VisitForValue(expr->right());
2852 Node* right = environment()->Pop();
2853 Node* left = environment()->Pop();
2854 Node* value = NewNode(op, left, right);
2855 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
2856 ast_context()->ProduceValue(expr, value);
2857 }
2858
2859
VisitSpread(Spread * expr)2860 void AstGraphBuilder::VisitSpread(Spread* expr) {
2861 // Handled entirely by the parser itself.
2862 UNREACHABLE();
2863 }
2864
2865
VisitEmptyParentheses(EmptyParentheses * expr)2866 void AstGraphBuilder::VisitEmptyParentheses(EmptyParentheses* expr) {
2867 // Handled entirely by the parser itself.
2868 UNREACHABLE();
2869 }
2870
2871
VisitThisFunction(ThisFunction * expr)2872 void AstGraphBuilder::VisitThisFunction(ThisFunction* expr) {
2873 Node* value = GetFunctionClosure();
2874 ast_context()->ProduceValue(expr, value);
2875 }
2876
2877
VisitSuperPropertyReference(SuperPropertyReference * expr)2878 void AstGraphBuilder::VisitSuperPropertyReference(
2879 SuperPropertyReference* expr) {
2880 Node* value = BuildThrowUnsupportedSuperError(expr->id());
2881 ast_context()->ProduceValue(expr, value);
2882 }
2883
2884
VisitSuperCallReference(SuperCallReference * expr)2885 void AstGraphBuilder::VisitSuperCallReference(SuperCallReference* expr) {
2886 // Handled by VisitCall
2887 UNREACHABLE();
2888 }
2889
2890
VisitCaseClause(CaseClause * expr)2891 void AstGraphBuilder::VisitCaseClause(CaseClause* expr) {
2892 // Handled entirely in VisitSwitch.
2893 UNREACHABLE();
2894 }
2895
VisitDeclarations(Declaration::List * declarations)2896 void AstGraphBuilder::VisitDeclarations(Declaration::List* declarations) {
2897 DCHECK(globals()->empty());
2898 AstVisitor<AstGraphBuilder>::VisitDeclarations(declarations);
2899 if (globals()->empty()) return;
2900 int array_index = 0;
2901 Handle<TypeFeedbackVector> feedback_vector(
2902 info()->closure()->feedback_vector());
2903 Handle<FixedArray> data = isolate()->factory()->NewFixedArray(
2904 static_cast<int>(globals()->size()), TENURED);
2905 for (Handle<Object> obj : *globals()) data->set(array_index++, *obj);
2906 int encoded_flags = info()->GetDeclareGlobalsFlags();
2907 Node* flags = jsgraph()->Constant(encoded_flags);
2908 Node* pairs = jsgraph()->Constant(data);
2909 Node* vector = jsgraph()->Constant(feedback_vector);
2910 const Operator* op = javascript()->CallRuntime(Runtime::kDeclareGlobals);
2911 Node* call = NewNode(op, pairs, flags, vector);
2912 PrepareFrameState(call, BailoutId::Declarations());
2913 globals()->clear();
2914 }
2915
2916
VisitIfNotNull(Statement * stmt)2917 void AstGraphBuilder::VisitIfNotNull(Statement* stmt) {
2918 if (stmt == nullptr) return;
2919 Visit(stmt);
2920 }
2921
2922
VisitInScope(Statement * stmt,Scope * s,Node * context)2923 void AstGraphBuilder::VisitInScope(Statement* stmt, Scope* s, Node* context) {
2924 ContextScope scope(this, s, context);
2925 DCHECK(s->declarations()->is_empty());
2926 Visit(stmt);
2927 }
2928
VisitIterationBody(IterationStatement * stmt,LoopBuilder * loop,BailoutId stack_check_id)2929 void AstGraphBuilder::VisitIterationBody(IterationStatement* stmt,
2930 LoopBuilder* loop,
2931 BailoutId stack_check_id) {
2932 ControlScopeForIteration scope(this, stmt, loop);
2933 if (FLAG_turbo_loop_stackcheck || !info()->shared_info()->asm_function()) {
2934 Node* node = NewNode(javascript()->StackCheck());
2935 PrepareFrameState(node, stack_check_id);
2936 }
2937 Visit(stmt->body());
2938 }
2939
2940
VisitDelete(UnaryOperation * expr)2941 void AstGraphBuilder::VisitDelete(UnaryOperation* expr) {
2942 Node* value;
2943 if (expr->expression()->IsVariableProxy()) {
2944 // Delete of an unqualified identifier is disallowed in strict mode but
2945 // "delete this" is allowed.
2946 Variable* variable = expr->expression()->AsVariableProxy()->var();
2947 DCHECK(is_sloppy(language_mode()) || variable->is_this());
2948 value = BuildVariableDelete(variable, expr->id(),
2949 ast_context()->GetStateCombine());
2950 } else if (expr->expression()->IsProperty()) {
2951 Property* property = expr->expression()->AsProperty();
2952 VisitForValue(property->obj());
2953 VisitForValue(property->key());
2954 Node* key = environment()->Pop();
2955 Node* object = environment()->Pop();
2956 value = NewNode(javascript()->DeleteProperty(language_mode()), object, key);
2957 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
2958 } else {
2959 VisitForEffect(expr->expression());
2960 value = jsgraph()->TrueConstant();
2961 }
2962 ast_context()->ProduceValue(expr, value);
2963 }
2964
2965
VisitVoid(UnaryOperation * expr)2966 void AstGraphBuilder::VisitVoid(UnaryOperation* expr) {
2967 VisitForEffect(expr->expression());
2968 Node* value = jsgraph()->UndefinedConstant();
2969 ast_context()->ProduceValue(expr, value);
2970 }
2971
VisitTypeofExpression(Expression * expr)2972 void AstGraphBuilder::VisitTypeofExpression(Expression* expr) {
2973 if (expr->IsVariableProxy()) {
2974 // Typeof does not throw a reference error on global variables, hence we
2975 // perform a non-contextual load in case the operand is a variable proxy.
2976 VariableProxy* proxy = expr->AsVariableProxy();
2977 VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot());
2978 PrepareEagerCheckpoint(BeforeId(proxy));
2979 Node* load =
2980 BuildVariableLoad(proxy->var(), expr->id(), pair,
2981 OutputFrameStateCombine::Push(), INSIDE_TYPEOF);
2982 environment()->Push(load);
2983 } else {
2984 VisitForValue(expr);
2985 }
2986 }
2987
VisitTypeof(UnaryOperation * expr)2988 void AstGraphBuilder::VisitTypeof(UnaryOperation* expr) {
2989 VisitTypeofExpression(expr->expression());
2990 Node* value = NewNode(javascript()->TypeOf(), environment()->Pop());
2991 ast_context()->ProduceValue(expr, value);
2992 }
2993
2994
VisitNot(UnaryOperation * expr)2995 void AstGraphBuilder::VisitNot(UnaryOperation* expr) {
2996 VisitForTest(expr->expression());
2997 Node* input = environment()->Pop();
2998 Node* value = NewNode(common()->Select(MachineRepresentation::kTagged), input,
2999 jsgraph()->FalseConstant(), jsgraph()->TrueConstant());
3000 // Skip plugging AST evaluation contexts of the test kind. This is to stay in
3001 // sync with full codegen which doesn't prepare the proper bailout point (see
3002 // the implementation of FullCodeGenerator::VisitForControl).
3003 if (ast_context()->IsTest()) return environment()->Push(value);
3004 ast_context()->ProduceValue(expr, value);
3005 }
3006
3007
VisitComma(BinaryOperation * expr)3008 void AstGraphBuilder::VisitComma(BinaryOperation* expr) {
3009 VisitForEffect(expr->left());
3010 Visit(expr->right());
3011 // Skip plugging AST evaluation contexts of the test kind. This is to stay in
3012 // sync with full codegen which doesn't prepare the proper bailout point (see
3013 // the implementation of FullCodeGenerator::VisitForControl).
3014 if (ast_context()->IsTest()) return;
3015 ast_context()->ReplaceValue(expr);
3016 }
3017
3018
VisitLogicalExpression(BinaryOperation * expr)3019 void AstGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) {
3020 bool is_logical_and = expr->op() == Token::AND;
3021 IfBuilder compare_if(this);
3022 // Only use an AST evaluation context of the value kind when this expression
3023 // is evaluated as value as well. Otherwise stick to a test context which is
3024 // in sync with full codegen (see FullCodeGenerator::VisitLogicalExpression).
3025 Node* condition = nullptr;
3026 if (ast_context()->IsValue()) {
3027 VisitForValue(expr->left());
3028 Node* left = environment()->Top();
3029 condition = BuildToBoolean(left, expr->left()->test_id());
3030 } else {
3031 VisitForTest(expr->left());
3032 condition = environment()->Top();
3033 }
3034 compare_if.If(condition);
3035 compare_if.Then();
3036 if (is_logical_and) {
3037 environment()->Pop();
3038 Visit(expr->right());
3039 } else if (ast_context()->IsEffect()) {
3040 environment()->Pop();
3041 } else if (ast_context()->IsTest()) {
3042 environment()->Poke(0, jsgraph()->TrueConstant());
3043 }
3044 compare_if.Else();
3045 if (!is_logical_and) {
3046 environment()->Pop();
3047 Visit(expr->right());
3048 } else if (ast_context()->IsEffect()) {
3049 environment()->Pop();
3050 } else if (ast_context()->IsTest()) {
3051 environment()->Poke(0, jsgraph()->FalseConstant());
3052 }
3053 compare_if.End();
3054 // Skip plugging AST evaluation contexts of the test kind. This is to stay in
3055 // sync with full codegen which doesn't prepare the proper bailout point (see
3056 // the implementation of FullCodeGenerator::VisitForControl).
3057 if (ast_context()->IsTest()) return;
3058 ast_context()->ReplaceValue(expr);
3059 }
3060
3061
language_mode() const3062 LanguageMode AstGraphBuilder::language_mode() const {
3063 return current_scope()->language_mode();
3064 }
3065
3066
CreateVectorSlotPair(FeedbackVectorSlot slot) const3067 VectorSlotPair AstGraphBuilder::CreateVectorSlotPair(
3068 FeedbackVectorSlot slot) const {
3069 return VectorSlotPair(handle(info()->closure()->feedback_vector()), slot);
3070 }
3071
3072
VisitRewritableExpression(RewritableExpression * node)3073 void AstGraphBuilder::VisitRewritableExpression(RewritableExpression* node) {
3074 Visit(node->expression());
3075 }
3076
3077
3078 namespace {
3079
3080 // Limit of context chain length to which inline check is possible.
3081 const int kMaxCheckDepth = 30;
3082
3083 // Sentinel for {TryLoadDynamicVariable} disabling inline checks.
3084 const uint32_t kFullCheckRequired = -1;
3085
3086 } // namespace
3087
3088
ComputeBitsetForDynamicGlobal(Variable * variable)3089 uint32_t AstGraphBuilder::ComputeBitsetForDynamicGlobal(Variable* variable) {
3090 DCHECK_EQ(DYNAMIC_GLOBAL, variable->mode());
3091 uint32_t check_depths = 0;
3092 for (Scope* s = current_scope(); s != nullptr; s = s->outer_scope()) {
3093 if (!s->NeedsContext()) continue;
3094 if (!s->calls_sloppy_eval()) continue;
3095 int depth = current_scope()->ContextChainLength(s);
3096 if (depth > kMaxCheckDepth) return kFullCheckRequired;
3097 check_depths |= 1 << depth;
3098 }
3099 return check_depths;
3100 }
3101
3102
ComputeBitsetForDynamicContext(Variable * variable)3103 uint32_t AstGraphBuilder::ComputeBitsetForDynamicContext(Variable* variable) {
3104 DCHECK_EQ(DYNAMIC_LOCAL, variable->mode());
3105 uint32_t check_depths = 0;
3106 for (Scope* s = current_scope(); s != nullptr; s = s->outer_scope()) {
3107 if (!s->NeedsContext()) continue;
3108 if (!s->calls_sloppy_eval() && s != variable->scope()) continue;
3109 int depth = current_scope()->ContextChainLength(s);
3110 if (depth > kMaxCheckDepth) return kFullCheckRequired;
3111 check_depths |= 1 << depth;
3112 if (s == variable->scope()) break;
3113 }
3114 return check_depths;
3115 }
3116
ComputeCallFrequency(FeedbackVectorSlot slot) const3117 float AstGraphBuilder::ComputeCallFrequency(FeedbackVectorSlot slot) const {
3118 if (slot.IsInvalid()) return 0.0f;
3119 Handle<TypeFeedbackVector> feedback_vector(
3120 info()->closure()->feedback_vector(), isolate());
3121 CallICNexus nexus(feedback_vector, slot);
3122 return nexus.ComputeCallFrequency() * invocation_frequency_;
3123 }
3124
ProcessArguments(const Operator * op,int arity)3125 Node* AstGraphBuilder::ProcessArguments(const Operator* op, int arity) {
3126 DCHECK(environment()->stack_height() >= arity);
3127 Node** all = info()->zone()->NewArray<Node*>(arity);
3128 for (int i = arity - 1; i >= 0; --i) {
3129 all[i] = environment()->Pop();
3130 }
3131 Node* value = NewNode(op, arity, all);
3132 return value;
3133 }
3134
3135
BuildLocalActivationContext(Node * context)3136 Node* AstGraphBuilder::BuildLocalActivationContext(Node* context) {
3137 DeclarationScope* scope = info()->scope();
3138
3139 // Allocate a new local context.
3140 Node* local_context = scope->is_script_scope()
3141 ? BuildLocalScriptContext(scope)
3142 : BuildLocalFunctionContext(scope);
3143
3144 if (scope->has_this_declaration() && scope->receiver()->IsContextSlot()) {
3145 Node* receiver = environment()->RawParameterLookup(0);
3146 // Context variable (at bottom of the context chain).
3147 Variable* variable = scope->receiver();
3148 DCHECK_EQ(0, scope->ContextChainLength(variable->scope()));
3149 const Operator* op = javascript()->StoreContext(0, variable->index());
3150 NewNode(op, local_context, receiver);
3151 }
3152
3153 // Copy parameters into context if necessary.
3154 int num_parameters = scope->num_parameters();
3155 for (int i = 0; i < num_parameters; i++) {
3156 Variable* variable = scope->parameter(i);
3157 if (!variable->IsContextSlot()) continue;
3158 Node* parameter = environment()->RawParameterLookup(i + 1);
3159 // Context variable (at bottom of the context chain).
3160 DCHECK_EQ(0, scope->ContextChainLength(variable->scope()));
3161 const Operator* op = javascript()->StoreContext(0, variable->index());
3162 NewNode(op, local_context, parameter);
3163 }
3164
3165 return local_context;
3166 }
3167
3168
BuildLocalFunctionContext(Scope * scope)3169 Node* AstGraphBuilder::BuildLocalFunctionContext(Scope* scope) {
3170 DCHECK(scope->is_function_scope() || scope->is_eval_scope());
3171
3172 // Allocate a new local context.
3173 int slot_count = scope->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
3174 const Operator* op = javascript()->CreateFunctionContext(slot_count);
3175 Node* local_context = NewNode(op, GetFunctionClosure());
3176
3177 return local_context;
3178 }
3179
3180
BuildLocalScriptContext(Scope * scope)3181 Node* AstGraphBuilder::BuildLocalScriptContext(Scope* scope) {
3182 DCHECK(scope->is_script_scope());
3183
3184 // Allocate a new local context.
3185 Handle<ScopeInfo> scope_info = scope->scope_info();
3186 const Operator* op = javascript()->CreateScriptContext(scope_info);
3187 Node* local_context = NewNode(op, GetFunctionClosure());
3188 PrepareFrameState(local_context, BailoutId::ScriptContext(),
3189 OutputFrameStateCombine::Push());
3190
3191 return local_context;
3192 }
3193
3194
BuildLocalBlockContext(Scope * scope)3195 Node* AstGraphBuilder::BuildLocalBlockContext(Scope* scope) {
3196 DCHECK(scope->is_block_scope());
3197
3198 // Allocate a new local context.
3199 Handle<ScopeInfo> scope_info = scope->scope_info();
3200 const Operator* op = javascript()->CreateBlockContext(scope_info);
3201 Node* local_context = NewNode(op, GetFunctionClosureForContext());
3202
3203 return local_context;
3204 }
3205
3206
BuildArgumentsObject(Variable * arguments)3207 Node* AstGraphBuilder::BuildArgumentsObject(Variable* arguments) {
3208 if (arguments == nullptr) return nullptr;
3209
3210 // Allocate and initialize a new arguments object.
3211 CreateArgumentsType type =
3212 is_strict(language_mode()) || !info()->has_simple_parameters()
3213 ? CreateArgumentsType::kUnmappedArguments
3214 : CreateArgumentsType::kMappedArguments;
3215 const Operator* op = javascript()->CreateArguments(type);
3216 Node* object = NewNode(op, GetFunctionClosure());
3217 PrepareFrameState(object, BailoutId::None());
3218
3219 // Assign the object to the {arguments} variable. This should never lazy
3220 // deopt, so it is fine to send invalid bailout id.
3221 DCHECK(arguments->IsContextSlot() || arguments->IsStackAllocated());
3222 BuildVariableAssignment(arguments, object, Token::ASSIGN, VectorSlotPair(),
3223 BailoutId::None());
3224 return object;
3225 }
3226
BuildRestArgumentsArray(Variable * rest)3227 Node* AstGraphBuilder::BuildRestArgumentsArray(Variable* rest) {
3228 if (rest == nullptr) return nullptr;
3229
3230 // Allocate and initialize a new arguments object.
3231 CreateArgumentsType type = CreateArgumentsType::kRestParameter;
3232 const Operator* op = javascript()->CreateArguments(type);
3233 Node* object = NewNode(op, GetFunctionClosure());
3234 PrepareFrameState(object, BailoutId::None());
3235
3236 // Assign the object to the {rest} variable. This should never lazy
3237 // deopt, so it is fine to send invalid bailout id.
3238 DCHECK(rest->IsContextSlot() || rest->IsStackAllocated());
3239 BuildVariableAssignment(rest, object, Token::ASSIGN, VectorSlotPair(),
3240 BailoutId::None());
3241 return object;
3242 }
3243
3244
BuildThisFunctionVariable(Variable * this_function_var)3245 Node* AstGraphBuilder::BuildThisFunctionVariable(Variable* this_function_var) {
3246 if (this_function_var == nullptr) return nullptr;
3247
3248 // Retrieve the closure we were called with.
3249 Node* this_function = GetFunctionClosure();
3250
3251 // Assign the object to the {.this_function} variable. This should never lazy
3252 // deopt, so it is fine to send invalid bailout id.
3253 BuildVariableAssignment(this_function_var, this_function, Token::INIT,
3254 VectorSlotPair(), BailoutId::None());
3255 return this_function;
3256 }
3257
3258
BuildNewTargetVariable(Variable * new_target_var)3259 Node* AstGraphBuilder::BuildNewTargetVariable(Variable* new_target_var) {
3260 if (new_target_var == nullptr) return nullptr;
3261
3262 // Retrieve the new target we were called with.
3263 Node* object = GetNewTarget();
3264
3265 // Assign the object to the {new.target} variable. This should never lazy
3266 // deopt, so it is fine to send invalid bailout id.
3267 BuildVariableAssignment(new_target_var, object, Token::INIT, VectorSlotPair(),
3268 BailoutId::None());
3269 return object;
3270 }
3271
3272
BuildHoleCheckThenThrow(Node * value,Variable * variable,Node * not_hole,BailoutId bailout_id)3273 Node* AstGraphBuilder::BuildHoleCheckThenThrow(Node* value, Variable* variable,
3274 Node* not_hole,
3275 BailoutId bailout_id) {
3276 IfBuilder hole_check(this);
3277 Node* the_hole = jsgraph()->TheHoleConstant();
3278 Node* check = NewNode(javascript()->StrictEqual(CompareOperationHint::kAny),
3279 value, the_hole);
3280 hole_check.If(check);
3281 hole_check.Then();
3282 Node* error = BuildThrowReferenceError(variable, bailout_id);
3283 environment()->Push(error);
3284 hole_check.Else();
3285 environment()->Push(not_hole);
3286 hole_check.End();
3287 return environment()->Pop();
3288 }
3289
3290
BuildHoleCheckElseThrow(Node * value,Variable * variable,Node * for_hole,BailoutId bailout_id)3291 Node* AstGraphBuilder::BuildHoleCheckElseThrow(Node* value, Variable* variable,
3292 Node* for_hole,
3293 BailoutId bailout_id) {
3294 IfBuilder hole_check(this);
3295 Node* the_hole = jsgraph()->TheHoleConstant();
3296 Node* check = NewNode(javascript()->StrictEqual(CompareOperationHint::kAny),
3297 value, the_hole);
3298 hole_check.If(check);
3299 hole_check.Then();
3300 environment()->Push(for_hole);
3301 hole_check.Else();
3302 Node* error = BuildThrowReferenceError(variable, bailout_id);
3303 environment()->Push(error);
3304 hole_check.End();
3305 return environment()->Pop();
3306 }
3307
3308
BuildThrowIfStaticPrototype(Node * name,BailoutId bailout_id)3309 Node* AstGraphBuilder::BuildThrowIfStaticPrototype(Node* name,
3310 BailoutId bailout_id) {
3311 IfBuilder prototype_check(this);
3312 Node* prototype_string =
3313 jsgraph()->Constant(isolate()->factory()->prototype_string());
3314 Node* check = NewNode(javascript()->StrictEqual(CompareOperationHint::kAny),
3315 name, prototype_string);
3316 prototype_check.If(check);
3317 prototype_check.Then();
3318 Node* error = BuildThrowStaticPrototypeError(bailout_id);
3319 environment()->Push(error);
3320 prototype_check.Else();
3321 environment()->Push(name);
3322 prototype_check.End();
3323 return environment()->Pop();
3324 }
3325
3326
BuildVariableLoad(Variable * variable,BailoutId bailout_id,const VectorSlotPair & feedback,OutputFrameStateCombine combine,TypeofMode typeof_mode)3327 Node* AstGraphBuilder::BuildVariableLoad(Variable* variable,
3328 BailoutId bailout_id,
3329 const VectorSlotPair& feedback,
3330 OutputFrameStateCombine combine,
3331 TypeofMode typeof_mode) {
3332 Node* the_hole = jsgraph()->TheHoleConstant();
3333 switch (variable->location()) {
3334 case VariableLocation::UNALLOCATED: {
3335 // Global var, const, or let variable.
3336 Handle<Name> name = variable->name();
3337 if (Node* node = TryLoadGlobalConstant(name)) return node;
3338 Node* value = BuildGlobalLoad(name, feedback, typeof_mode);
3339 PrepareFrameState(value, bailout_id, combine);
3340 return value;
3341 }
3342 case VariableLocation::PARAMETER:
3343 case VariableLocation::LOCAL: {
3344 // Local var, const, or let variable.
3345 Node* value = environment()->Lookup(variable);
3346 if (variable->binding_needs_init()) {
3347 // Perform check for uninitialized let/const variables.
3348 if (value->op() == the_hole->op()) {
3349 value = BuildThrowReferenceError(variable, bailout_id);
3350 } else if (value->opcode() == IrOpcode::kPhi) {
3351 value = BuildHoleCheckThenThrow(value, variable, value, bailout_id);
3352 }
3353 }
3354 return value;
3355 }
3356 case VariableLocation::CONTEXT: {
3357 // Context variable (potentially up the context chain).
3358 int depth = current_scope()->ContextChainLength(variable->scope());
3359 // TODO(mstarzinger): The {maybe_assigned} flag computed during variable
3360 // resolution is highly inaccurate and cannot be trusted. We are only
3361 // taking this information into account when asm.js compilation is used.
3362 bool immutable = variable->maybe_assigned() == kNotAssigned &&
3363 info()->is_function_context_specializing();
3364 const Operator* op =
3365 javascript()->LoadContext(depth, variable->index(), immutable);
3366 Node* value = NewNode(op, current_context());
3367 // TODO(titzer): initialization checks are redundant for already
3368 // initialized immutable context loads, but only specialization knows.
3369 // Maybe specializer should be a parameter to the graph builder?
3370 if (variable->binding_needs_init()) {
3371 // Perform check for uninitialized let/const variables.
3372 value = BuildHoleCheckThenThrow(value, variable, value, bailout_id);
3373 }
3374 return value;
3375 }
3376 case VariableLocation::LOOKUP: {
3377 // Dynamic lookup of context variable (anywhere in the chain).
3378 Handle<String> name = variable->name();
3379 if (Node* node = TryLoadDynamicVariable(variable, name, bailout_id,
3380 feedback, combine, typeof_mode)) {
3381 return node;
3382 }
3383 Node* value = BuildDynamicLoad(name, typeof_mode);
3384 PrepareFrameState(value, bailout_id, combine);
3385 return value;
3386 }
3387 case VariableLocation::MODULE:
3388 UNREACHABLE();
3389 }
3390 UNREACHABLE();
3391 return nullptr;
3392 }
3393
3394
BuildVariableDelete(Variable * variable,BailoutId bailout_id,OutputFrameStateCombine combine)3395 Node* AstGraphBuilder::BuildVariableDelete(Variable* variable,
3396 BailoutId bailout_id,
3397 OutputFrameStateCombine combine) {
3398 switch (variable->location()) {
3399 case VariableLocation::UNALLOCATED: {
3400 // Global var, const, or let variable.
3401 Node* global = BuildLoadGlobalObject();
3402 Node* name = jsgraph()->Constant(variable->name());
3403 const Operator* op = javascript()->DeleteProperty(language_mode());
3404 Node* result = NewNode(op, global, name);
3405 PrepareFrameState(result, bailout_id, combine);
3406 return result;
3407 }
3408 case VariableLocation::PARAMETER:
3409 case VariableLocation::LOCAL:
3410 case VariableLocation::CONTEXT: {
3411 // Local var, const, or let variable or context variable.
3412 return jsgraph()->BooleanConstant(variable->is_this());
3413 }
3414 case VariableLocation::LOOKUP: {
3415 // Dynamic lookup of context variable (anywhere in the chain).
3416 Node* name = jsgraph()->Constant(variable->name());
3417 const Operator* op =
3418 javascript()->CallRuntime(Runtime::kDeleteLookupSlot);
3419 Node* result = NewNode(op, name);
3420 PrepareFrameState(result, bailout_id, combine);
3421 return result;
3422 }
3423 case VariableLocation::MODULE:
3424 UNREACHABLE();
3425 }
3426 UNREACHABLE();
3427 return nullptr;
3428 }
3429
BuildVariableAssignment(Variable * variable,Node * value,Token::Value op,const VectorSlotPair & feedback,BailoutId bailout_id,OutputFrameStateCombine combine)3430 Node* AstGraphBuilder::BuildVariableAssignment(
3431 Variable* variable, Node* value, Token::Value op,
3432 const VectorSlotPair& feedback, BailoutId bailout_id,
3433 OutputFrameStateCombine combine) {
3434 Node* the_hole = jsgraph()->TheHoleConstant();
3435 VariableMode mode = variable->mode();
3436 switch (variable->location()) {
3437 case VariableLocation::UNALLOCATED: {
3438 // Global var, const, or let variable.
3439 Handle<Name> name = variable->name();
3440 Node* store = BuildGlobalStore(name, value, feedback);
3441 PrepareFrameState(store, bailout_id, combine);
3442 return store;
3443 }
3444 case VariableLocation::PARAMETER:
3445 case VariableLocation::LOCAL:
3446 // Local var, const, or let variable.
3447 if (mode == LET && op == Token::INIT) {
3448 // No initialization check needed because scoping guarantees it. Note
3449 // that we still perform a lookup to keep the variable live, because
3450 // baseline code might contain debug code that inspects the variable.
3451 Node* current = environment()->Lookup(variable);
3452 CHECK_NOT_NULL(current);
3453 } else if (mode == LET && op != Token::INIT &&
3454 variable->binding_needs_init()) {
3455 // Perform an initialization check for let declared variables.
3456 Node* current = environment()->Lookup(variable);
3457 if (current->op() == the_hole->op()) {
3458 return BuildThrowReferenceError(variable, bailout_id);
3459 } else if (current->opcode() == IrOpcode::kPhi) {
3460 BuildHoleCheckThenThrow(current, variable, value, bailout_id);
3461 }
3462 } else if (mode == CONST && op == Token::INIT) {
3463 // Perform an initialization check for const {this} variables.
3464 // Note that the {this} variable is the only const variable being able
3465 // to trigger bind operations outside the TDZ, via {super} calls.
3466 Node* current = environment()->Lookup(variable);
3467 if (current->op() != the_hole->op() && variable->is_this()) {
3468 value = BuildHoleCheckElseThrow(current, variable, value, bailout_id);
3469 }
3470 } else if (mode == CONST && op != Token::INIT &&
3471 variable->is_sloppy_function_name()) {
3472 // Non-initializing assignment to sloppy function names is
3473 // - exception in strict mode.
3474 // - ignored in sloppy mode.
3475 DCHECK(!variable->binding_needs_init());
3476 if (variable->throw_on_const_assignment(language_mode())) {
3477 return BuildThrowConstAssignError(bailout_id);
3478 }
3479 return value;
3480 } else if (mode == CONST && op != Token::INIT) {
3481 if (variable->binding_needs_init()) {
3482 Node* current = environment()->Lookup(variable);
3483 if (current->op() == the_hole->op()) {
3484 return BuildThrowReferenceError(variable, bailout_id);
3485 } else if (current->opcode() == IrOpcode::kPhi) {
3486 BuildHoleCheckThenThrow(current, variable, value, bailout_id);
3487 }
3488 }
3489 // Assignment to const is exception in all modes.
3490 return BuildThrowConstAssignError(bailout_id);
3491 }
3492 environment()->Bind(variable, value);
3493 return value;
3494 case VariableLocation::CONTEXT: {
3495 // Context variable (potentially up the context chain).
3496 int depth = current_scope()->ContextChainLength(variable->scope());
3497 if (mode == LET && op != Token::INIT && variable->binding_needs_init()) {
3498 // Perform an initialization check for let declared variables.
3499 const Operator* op =
3500 javascript()->LoadContext(depth, variable->index(), false);
3501 Node* current = NewNode(op, current_context());
3502 value = BuildHoleCheckThenThrow(current, variable, value, bailout_id);
3503 } else if (mode == CONST && op == Token::INIT) {
3504 // Perform an initialization check for const {this} variables.
3505 // Note that the {this} variable is the only const variable being able
3506 // to trigger bind operations outside the TDZ, via {super} calls.
3507 if (variable->is_this()) {
3508 const Operator* op =
3509 javascript()->LoadContext(depth, variable->index(), false);
3510 Node* current = NewNode(op, current_context());
3511 value = BuildHoleCheckElseThrow(current, variable, value, bailout_id);
3512 }
3513 } else if (mode == CONST && op != Token::INIT &&
3514 variable->is_sloppy_function_name()) {
3515 // Non-initializing assignment to sloppy function names is
3516 // - exception in strict mode.
3517 // - ignored in sloppy mode.
3518 DCHECK(!variable->binding_needs_init());
3519 if (variable->throw_on_const_assignment(language_mode())) {
3520 return BuildThrowConstAssignError(bailout_id);
3521 }
3522 return value;
3523 } else if (mode == CONST && op != Token::INIT) {
3524 if (variable->binding_needs_init()) {
3525 const Operator* op =
3526 javascript()->LoadContext(depth, variable->index(), false);
3527 Node* current = NewNode(op, current_context());
3528 BuildHoleCheckThenThrow(current, variable, value, bailout_id);
3529 }
3530 // Assignment to const is exception in all modes.
3531 return BuildThrowConstAssignError(bailout_id);
3532 }
3533 const Operator* op = javascript()->StoreContext(depth, variable->index());
3534 return NewNode(op, current_context(), value);
3535 }
3536 case VariableLocation::LOOKUP: {
3537 // Dynamic lookup of context variable (anywhere in the chain).
3538 Handle<Name> name = variable->name();
3539 Node* store = BuildDynamicStore(name, value);
3540 PrepareFrameState(store, bailout_id, combine);
3541 return store;
3542 }
3543 case VariableLocation::MODULE:
3544 UNREACHABLE();
3545 }
3546 UNREACHABLE();
3547 return nullptr;
3548 }
3549
3550
BuildKeyedLoad(Node * object,Node * key,const VectorSlotPair & feedback)3551 Node* AstGraphBuilder::BuildKeyedLoad(Node* object, Node* key,
3552 const VectorSlotPair& feedback) {
3553 const Operator* op = javascript()->LoadProperty(feedback);
3554 Node* node = NewNode(op, object, key, GetFunctionClosure());
3555 return node;
3556 }
3557
3558
BuildNamedLoad(Node * object,Handle<Name> name,const VectorSlotPair & feedback)3559 Node* AstGraphBuilder::BuildNamedLoad(Node* object, Handle<Name> name,
3560 const VectorSlotPair& feedback) {
3561 const Operator* op = javascript()->LoadNamed(name, feedback);
3562 Node* node = NewNode(op, object, GetFunctionClosure());
3563 return node;
3564 }
3565
3566
BuildKeyedStore(Node * object,Node * key,Node * value,const VectorSlotPair & feedback)3567 Node* AstGraphBuilder::BuildKeyedStore(Node* object, Node* key, Node* value,
3568 const VectorSlotPair& feedback) {
3569 const Operator* op = javascript()->StoreProperty(language_mode(), feedback);
3570 Node* node = NewNode(op, object, key, value, GetFunctionClosure());
3571 return node;
3572 }
3573
3574
BuildNamedStore(Node * object,Handle<Name> name,Node * value,const VectorSlotPair & feedback)3575 Node* AstGraphBuilder::BuildNamedStore(Node* object, Handle<Name> name,
3576 Node* value,
3577 const VectorSlotPair& feedback) {
3578 const Operator* op =
3579 javascript()->StoreNamed(language_mode(), name, feedback);
3580 Node* node = NewNode(op, object, value, GetFunctionClosure());
3581 return node;
3582 }
3583
3584
BuildNamedSuperLoad(Node * receiver,Node * home_object,Handle<Name> name,const VectorSlotPair & feedback)3585 Node* AstGraphBuilder::BuildNamedSuperLoad(Node* receiver, Node* home_object,
3586 Handle<Name> name,
3587 const VectorSlotPair& feedback) {
3588 Node* name_node = jsgraph()->Constant(name);
3589 const Operator* op = javascript()->CallRuntime(Runtime::kLoadFromSuper);
3590 Node* node = NewNode(op, receiver, home_object, name_node);
3591 return node;
3592 }
3593
3594
BuildKeyedSuperLoad(Node * receiver,Node * home_object,Node * key,const VectorSlotPair & feedback)3595 Node* AstGraphBuilder::BuildKeyedSuperLoad(Node* receiver, Node* home_object,
3596 Node* key,
3597 const VectorSlotPair& feedback) {
3598 const Operator* op = javascript()->CallRuntime(Runtime::kLoadKeyedFromSuper);
3599 Node* node = NewNode(op, receiver, home_object, key);
3600 return node;
3601 }
3602
3603
BuildKeyedSuperStore(Node * receiver,Node * home_object,Node * key,Node * value)3604 Node* AstGraphBuilder::BuildKeyedSuperStore(Node* receiver, Node* home_object,
3605 Node* key, Node* value) {
3606 Runtime::FunctionId function_id = is_strict(language_mode())
3607 ? Runtime::kStoreKeyedToSuper_Strict
3608 : Runtime::kStoreKeyedToSuper_Sloppy;
3609 const Operator* op = javascript()->CallRuntime(function_id, 4);
3610 Node* node = NewNode(op, receiver, home_object, key, value);
3611 return node;
3612 }
3613
3614
BuildNamedSuperStore(Node * receiver,Node * home_object,Handle<Name> name,Node * value)3615 Node* AstGraphBuilder::BuildNamedSuperStore(Node* receiver, Node* home_object,
3616 Handle<Name> name, Node* value) {
3617 Node* name_node = jsgraph()->Constant(name);
3618 Runtime::FunctionId function_id = is_strict(language_mode())
3619 ? Runtime::kStoreToSuper_Strict
3620 : Runtime::kStoreToSuper_Sloppy;
3621 const Operator* op = javascript()->CallRuntime(function_id, 4);
3622 Node* node = NewNode(op, receiver, home_object, name_node, value);
3623 return node;
3624 }
3625
3626
BuildGlobalLoad(Handle<Name> name,const VectorSlotPair & feedback,TypeofMode typeof_mode)3627 Node* AstGraphBuilder::BuildGlobalLoad(Handle<Name> name,
3628 const VectorSlotPair& feedback,
3629 TypeofMode typeof_mode) {
3630 const Operator* op = javascript()->LoadGlobal(name, feedback, typeof_mode);
3631 Node* node = NewNode(op, GetFunctionClosure());
3632 return node;
3633 }
3634
3635
BuildGlobalStore(Handle<Name> name,Node * value,const VectorSlotPair & feedback)3636 Node* AstGraphBuilder::BuildGlobalStore(Handle<Name> name, Node* value,
3637 const VectorSlotPair& feedback) {
3638 const Operator* op =
3639 javascript()->StoreGlobal(language_mode(), name, feedback);
3640 Node* node = NewNode(op, value, GetFunctionClosure());
3641 return node;
3642 }
3643
3644
BuildDynamicLoad(Handle<Name> name,TypeofMode typeof_mode)3645 Node* AstGraphBuilder::BuildDynamicLoad(Handle<Name> name,
3646 TypeofMode typeof_mode) {
3647 Node* name_node = jsgraph()->Constant(name);
3648 const Operator* op =
3649 javascript()->CallRuntime(typeof_mode == TypeofMode::NOT_INSIDE_TYPEOF
3650 ? Runtime::kLoadLookupSlot
3651 : Runtime::kLoadLookupSlotInsideTypeof);
3652 Node* node = NewNode(op, name_node);
3653 return node;
3654 }
3655
3656
BuildDynamicStore(Handle<Name> name,Node * value)3657 Node* AstGraphBuilder::BuildDynamicStore(Handle<Name> name, Node* value) {
3658 Node* name_node = jsgraph()->Constant(name);
3659 const Operator* op = javascript()->CallRuntime(
3660 is_strict(language_mode()) ? Runtime::kStoreLookupSlot_Strict
3661 : Runtime::kStoreLookupSlot_Sloppy);
3662 Node* node = NewNode(op, name_node, value);
3663 return node;
3664 }
3665
3666
BuildLoadGlobalObject()3667 Node* AstGraphBuilder::BuildLoadGlobalObject() {
3668 return BuildLoadNativeContextField(Context::EXTENSION_INDEX);
3669 }
3670
3671
BuildLoadNativeContextField(int index)3672 Node* AstGraphBuilder::BuildLoadNativeContextField(int index) {
3673 const Operator* op =
3674 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true);
3675 Node* native_context = NewNode(op, current_context());
3676 return NewNode(javascript()->LoadContext(0, index, true), native_context);
3677 }
3678
3679
BuildToBoolean(Node * input,TypeFeedbackId feedback_id)3680 Node* AstGraphBuilder::BuildToBoolean(Node* input, TypeFeedbackId feedback_id) {
3681 if (Node* node = TryFastToBoolean(input)) return node;
3682 ToBooleanHints hints;
3683 if (!type_hint_analysis_ ||
3684 !type_hint_analysis_->GetToBooleanHints(feedback_id, &hints)) {
3685 hints = ToBooleanHint::kAny;
3686 }
3687 return NewNode(javascript()->ToBoolean(hints), input);
3688 }
3689
3690
BuildToName(Node * input,BailoutId bailout_id)3691 Node* AstGraphBuilder::BuildToName(Node* input, BailoutId bailout_id) {
3692 if (Node* node = TryFastToName(input)) return node;
3693 Node* name = NewNode(javascript()->ToName(), input);
3694 PrepareFrameState(name, bailout_id, OutputFrameStateCombine::Push());
3695 return name;
3696 }
3697
3698
BuildToObject(Node * input,BailoutId bailout_id)3699 Node* AstGraphBuilder::BuildToObject(Node* input, BailoutId bailout_id) {
3700 Node* object = NewNode(javascript()->ToObject(), input);
3701 PrepareFrameState(object, bailout_id, OutputFrameStateCombine::Push());
3702 return object;
3703 }
3704
BuildSetHomeObject(Node * value,Node * home_object,LiteralProperty * property,int slot_number)3705 Node* AstGraphBuilder::BuildSetHomeObject(Node* value, Node* home_object,
3706 LiteralProperty* property,
3707 int slot_number) {
3708 Expression* expr = property->value();
3709 if (!FunctionLiteral::NeedsHomeObject(expr)) return value;
3710 Handle<Name> name = isolate()->factory()->home_object_symbol();
3711 VectorSlotPair feedback =
3712 CreateVectorSlotPair(property->GetSlot(slot_number));
3713 Node* store = BuildNamedStore(value, name, home_object, feedback);
3714 PrepareFrameState(store, BailoutId::None(),
3715 OutputFrameStateCombine::Ignore());
3716 return store;
3717 }
3718
3719
BuildThrowError(Node * exception,BailoutId bailout_id)3720 Node* AstGraphBuilder::BuildThrowError(Node* exception, BailoutId bailout_id) {
3721 const Operator* op = javascript()->CallRuntime(Runtime::kThrow);
3722 Node* call = NewNode(op, exception);
3723 PrepareFrameState(call, bailout_id);
3724 Node* control = NewNode(common()->Throw(), call);
3725 UpdateControlDependencyToLeaveFunction(control);
3726 return call;
3727 }
3728
3729
BuildThrowReferenceError(Variable * variable,BailoutId bailout_id)3730 Node* AstGraphBuilder::BuildThrowReferenceError(Variable* variable,
3731 BailoutId bailout_id) {
3732 Node* variable_name = jsgraph()->Constant(variable->name());
3733 const Operator* op = javascript()->CallRuntime(Runtime::kThrowReferenceError);
3734 Node* call = NewNode(op, variable_name);
3735 PrepareFrameState(call, bailout_id);
3736 Node* control = NewNode(common()->Throw(), call);
3737 UpdateControlDependencyToLeaveFunction(control);
3738 return call;
3739 }
3740
3741
BuildThrowConstAssignError(BailoutId bailout_id)3742 Node* AstGraphBuilder::BuildThrowConstAssignError(BailoutId bailout_id) {
3743 const Operator* op =
3744 javascript()->CallRuntime(Runtime::kThrowConstAssignError);
3745 Node* call = NewNode(op);
3746 PrepareFrameState(call, bailout_id);
3747 Node* control = NewNode(common()->Throw(), call);
3748 UpdateControlDependencyToLeaveFunction(control);
3749 return call;
3750 }
3751
3752
BuildThrowStaticPrototypeError(BailoutId bailout_id)3753 Node* AstGraphBuilder::BuildThrowStaticPrototypeError(BailoutId bailout_id) {
3754 const Operator* op =
3755 javascript()->CallRuntime(Runtime::kThrowStaticPrototypeError);
3756 Node* call = NewNode(op);
3757 PrepareFrameState(call, bailout_id);
3758 Node* control = NewNode(common()->Throw(), call);
3759 UpdateControlDependencyToLeaveFunction(control);
3760 return call;
3761 }
3762
3763
BuildThrowUnsupportedSuperError(BailoutId bailout_id)3764 Node* AstGraphBuilder::BuildThrowUnsupportedSuperError(BailoutId bailout_id) {
3765 const Operator* op =
3766 javascript()->CallRuntime(Runtime::kThrowUnsupportedSuperError);
3767 Node* call = NewNode(op);
3768 PrepareFrameState(call, bailout_id);
3769 Node* control = NewNode(common()->Throw(), call);
3770 UpdateControlDependencyToLeaveFunction(control);
3771 return call;
3772 }
3773
3774
BuildReturn(Node * return_value)3775 Node* AstGraphBuilder::BuildReturn(Node* return_value) {
3776 // Emit tracing call if requested to do so.
3777 if (FLAG_trace) {
3778 return_value =
3779 NewNode(javascript()->CallRuntime(Runtime::kTraceExit), return_value);
3780 }
3781 Node* pop_node = jsgraph()->ZeroConstant();
3782 Node* control = NewNode(common()->Return(), pop_node, return_value);
3783 UpdateControlDependencyToLeaveFunction(control);
3784 return control;
3785 }
3786
3787
BuildThrow(Node * exception_value)3788 Node* AstGraphBuilder::BuildThrow(Node* exception_value) {
3789 NewNode(javascript()->CallRuntime(Runtime::kReThrow), exception_value);
3790 Node* control = NewNode(common()->Throw(), exception_value);
3791 UpdateControlDependencyToLeaveFunction(control);
3792 return control;
3793 }
3794
3795
BuildBinaryOp(Node * left,Node * right,Token::Value op,TypeFeedbackId feedback_id)3796 Node* AstGraphBuilder::BuildBinaryOp(Node* left, Node* right, Token::Value op,
3797 TypeFeedbackId feedback_id) {
3798 const Operator* js_op;
3799 BinaryOperationHint hint;
3800 if (!type_hint_analysis_ ||
3801 !type_hint_analysis_->GetBinaryOperationHint(feedback_id, &hint)) {
3802 hint = BinaryOperationHint::kAny;
3803 }
3804 switch (op) {
3805 case Token::BIT_OR:
3806 js_op = javascript()->BitwiseOr(hint);
3807 break;
3808 case Token::BIT_AND:
3809 js_op = javascript()->BitwiseAnd(hint);
3810 break;
3811 case Token::BIT_XOR:
3812 js_op = javascript()->BitwiseXor(hint);
3813 break;
3814 case Token::SHL:
3815 js_op = javascript()->ShiftLeft(hint);
3816 break;
3817 case Token::SAR:
3818 js_op = javascript()->ShiftRight(hint);
3819 break;
3820 case Token::SHR:
3821 js_op = javascript()->ShiftRightLogical(hint);
3822 break;
3823 case Token::ADD:
3824 js_op = javascript()->Add(hint);
3825 break;
3826 case Token::SUB:
3827 js_op = javascript()->Subtract(hint);
3828 break;
3829 case Token::MUL:
3830 js_op = javascript()->Multiply(hint);
3831 break;
3832 case Token::DIV:
3833 js_op = javascript()->Divide(hint);
3834 break;
3835 case Token::MOD:
3836 js_op = javascript()->Modulus(hint);
3837 break;
3838 default:
3839 UNREACHABLE();
3840 js_op = nullptr;
3841 }
3842 return NewNode(js_op, left, right);
3843 }
3844
3845
TryLoadGlobalConstant(Handle<Name> name)3846 Node* AstGraphBuilder::TryLoadGlobalConstant(Handle<Name> name) {
3847 // Optimize global constants like "undefined", "Infinity", and "NaN".
3848 Handle<Object> constant_value = isolate()->factory()->GlobalConstantFor(name);
3849 if (!constant_value.is_null()) return jsgraph()->Constant(constant_value);
3850 return nullptr;
3851 }
3852
TryLoadDynamicVariable(Variable * variable,Handle<String> name,BailoutId bailout_id,const VectorSlotPair & feedback,OutputFrameStateCombine combine,TypeofMode typeof_mode)3853 Node* AstGraphBuilder::TryLoadDynamicVariable(Variable* variable,
3854 Handle<String> name,
3855 BailoutId bailout_id,
3856 const VectorSlotPair& feedback,
3857 OutputFrameStateCombine combine,
3858 TypeofMode typeof_mode) {
3859 VariableMode mode = variable->mode();
3860
3861 if (mode == DYNAMIC_GLOBAL) {
3862 uint32_t bitset = ComputeBitsetForDynamicGlobal(variable);
3863 if (bitset == kFullCheckRequired) return nullptr;
3864
3865 // We are using two blocks to model fast and slow cases.
3866 BlockBuilder fast_block(this);
3867 BlockBuilder slow_block(this);
3868 environment()->Push(jsgraph()->TheHoleConstant());
3869 slow_block.BeginBlock();
3870 environment()->Pop();
3871 fast_block.BeginBlock();
3872
3873 // Perform checks whether the fast mode applies, by looking for any
3874 // extension object which might shadow the optimistic declaration.
3875 for (int depth = 0; bitset != 0; bitset >>= 1, depth++) {
3876 if ((bitset & 1) == 0) continue;
3877 Node* load = NewNode(
3878 javascript()->LoadContext(depth, Context::EXTENSION_INDEX, false),
3879 current_context());
3880 Node* check =
3881 NewNode(javascript()->StrictEqual(CompareOperationHint::kAny), load,
3882 jsgraph()->TheHoleConstant());
3883 fast_block.BreakUnless(check, BranchHint::kTrue);
3884 }
3885
3886 // Fast case, because variable is not shadowed.
3887 if (Node* constant = TryLoadGlobalConstant(name)) {
3888 environment()->Push(constant);
3889 } else {
3890 // Perform global slot load.
3891 Node* fast = BuildGlobalLoad(name, feedback, typeof_mode);
3892 PrepareFrameState(fast, bailout_id, combine);
3893 environment()->Push(fast);
3894 }
3895 slow_block.Break();
3896 environment()->Pop();
3897 fast_block.EndBlock();
3898
3899 // Slow case, because variable potentially shadowed. Perform dynamic lookup.
3900 Node* slow = BuildDynamicLoad(name, typeof_mode);
3901 PrepareFrameState(slow, bailout_id, combine);
3902 environment()->Push(slow);
3903 slow_block.EndBlock();
3904
3905 return environment()->Pop();
3906 }
3907
3908 if (mode == DYNAMIC_LOCAL) {
3909 uint32_t bitset = ComputeBitsetForDynamicContext(variable);
3910 if (bitset == kFullCheckRequired) return nullptr;
3911
3912 // We are using two blocks to model fast and slow cases.
3913 BlockBuilder fast_block(this);
3914 BlockBuilder slow_block(this);
3915 environment()->Push(jsgraph()->TheHoleConstant());
3916 slow_block.BeginBlock();
3917 environment()->Pop();
3918 fast_block.BeginBlock();
3919
3920 // Perform checks whether the fast mode applies, by looking for any
3921 // extension object which might shadow the optimistic declaration.
3922 for (int depth = 0; bitset != 0; bitset >>= 1, depth++) {
3923 if ((bitset & 1) == 0) continue;
3924 Node* load = NewNode(
3925 javascript()->LoadContext(depth, Context::EXTENSION_INDEX, false),
3926 current_context());
3927 Node* check =
3928 NewNode(javascript()->StrictEqual(CompareOperationHint::kAny), load,
3929 jsgraph()->TheHoleConstant());
3930 fast_block.BreakUnless(check, BranchHint::kTrue);
3931 }
3932
3933 // Fast case, because variable is not shadowed. Perform context slot load.
3934 Variable* local = variable->local_if_not_shadowed();
3935 DCHECK(local->location() == VariableLocation::CONTEXT); // Must be context.
3936 Node* fast =
3937 BuildVariableLoad(local, bailout_id, feedback, combine, typeof_mode);
3938 environment()->Push(fast);
3939 slow_block.Break();
3940 environment()->Pop();
3941 fast_block.EndBlock();
3942
3943 // Slow case, because variable potentially shadowed. Perform dynamic lookup.
3944 Node* slow = BuildDynamicLoad(name, typeof_mode);
3945 PrepareFrameState(slow, bailout_id, combine);
3946 environment()->Push(slow);
3947 slow_block.EndBlock();
3948
3949 return environment()->Pop();
3950 }
3951
3952 return nullptr;
3953 }
3954
3955
TryFastToBoolean(Node * input)3956 Node* AstGraphBuilder::TryFastToBoolean(Node* input) {
3957 switch (input->opcode()) {
3958 case IrOpcode::kNumberConstant: {
3959 NumberMatcher m(input);
3960 return jsgraph_->BooleanConstant(!m.Is(0) && !m.IsNaN());
3961 }
3962 case IrOpcode::kHeapConstant: {
3963 Handle<HeapObject> object = HeapObjectMatcher(input).Value();
3964 return jsgraph_->BooleanConstant(object->BooleanValue());
3965 }
3966 case IrOpcode::kJSEqual:
3967 case IrOpcode::kJSNotEqual:
3968 case IrOpcode::kJSStrictEqual:
3969 case IrOpcode::kJSStrictNotEqual:
3970 case IrOpcode::kJSLessThan:
3971 case IrOpcode::kJSLessThanOrEqual:
3972 case IrOpcode::kJSGreaterThan:
3973 case IrOpcode::kJSGreaterThanOrEqual:
3974 case IrOpcode::kJSToBoolean:
3975 case IrOpcode::kJSDeleteProperty:
3976 case IrOpcode::kJSHasProperty:
3977 case IrOpcode::kJSInstanceOf:
3978 return input;
3979 default:
3980 break;
3981 }
3982 return nullptr;
3983 }
3984
3985
TryFastToName(Node * input)3986 Node* AstGraphBuilder::TryFastToName(Node* input) {
3987 switch (input->opcode()) {
3988 case IrOpcode::kHeapConstant: {
3989 Handle<HeapObject> object = HeapObjectMatcher(input).Value();
3990 if (object->IsName()) return input;
3991 break;
3992 }
3993 case IrOpcode::kJSToString:
3994 case IrOpcode::kJSToName:
3995 case IrOpcode::kJSTypeOf:
3996 return input;
3997 default:
3998 break;
3999 }
4000 return nullptr;
4001 }
4002
4003
CheckOsrEntry(IterationStatement * stmt)4004 bool AstGraphBuilder::CheckOsrEntry(IterationStatement* stmt) {
4005 if (info()->osr_ast_id() == stmt->OsrEntryId()) {
4006 DCHECK_EQ(-1, info()->osr_expr_stack_height());
4007 info()->set_osr_expr_stack_height(environment()->stack_height());
4008 return true;
4009 }
4010 return false;
4011 }
4012
4013
PrepareFrameState(Node * node,BailoutId ast_id,OutputFrameStateCombine combine)4014 void AstGraphBuilder::PrepareFrameState(Node* node, BailoutId ast_id,
4015 OutputFrameStateCombine combine) {
4016 if (OperatorProperties::HasFrameStateInput(node->op())) {
4017 DCHECK(ast_id.IsNone() || info()->shared_info()->VerifyBailoutId(ast_id));
4018 DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
4019 DCHECK_EQ(IrOpcode::kDead,
4020 NodeProperties::GetFrameStateInput(node)->opcode());
4021 bool has_exception = NodeProperties::IsExceptionalCall(node);
4022 Node* state = environment()->Checkpoint(ast_id, combine, has_exception);
4023 NodeProperties::ReplaceFrameStateInput(node, state);
4024 }
4025 }
4026
PrepareEagerCheckpoint(BailoutId ast_id)4027 void AstGraphBuilder::PrepareEagerCheckpoint(BailoutId ast_id) {
4028 if (environment()->GetEffectDependency()->opcode() == IrOpcode::kCheckpoint) {
4029 // We skip preparing a checkpoint if there already is one the current effect
4030 // dependency. This is just an optimization and not need for correctness.
4031 return;
4032 }
4033 if (ast_id != BailoutId::None()) {
4034 DCHECK(info()->shared_info()->VerifyBailoutId(ast_id));
4035 Node* node = NewNode(common()->Checkpoint());
4036 DCHECK_EQ(IrOpcode::kDead,
4037 NodeProperties::GetFrameStateInput(node)->opcode());
4038 Node* state = environment()->Checkpoint(ast_id);
4039 NodeProperties::ReplaceFrameStateInput(node, state);
4040 }
4041 }
4042
GetVariablesAssignedInLoop(IterationStatement * stmt)4043 BitVector* AstGraphBuilder::GetVariablesAssignedInLoop(
4044 IterationStatement* stmt) {
4045 if (loop_assignment_analysis_ == nullptr) return nullptr;
4046 return loop_assignment_analysis_->GetVariablesAssignedInLoop(stmt);
4047 }
4048
4049
EnsureInputBufferSize(int size)4050 Node** AstGraphBuilder::EnsureInputBufferSize(int size) {
4051 if (size > input_buffer_size_) {
4052 size = size + kInputBufferSizeIncrement + input_buffer_size_;
4053 input_buffer_ = local_zone()->NewArray<Node*>(size);
4054 input_buffer_size_ = size;
4055 }
4056 return input_buffer_;
4057 }
4058
4059
MakeNode(const Operator * op,int value_input_count,Node ** value_inputs,bool incomplete)4060 Node* AstGraphBuilder::MakeNode(const Operator* op, int value_input_count,
4061 Node** value_inputs, bool incomplete) {
4062 DCHECK_EQ(op->ValueInputCount(), value_input_count);
4063
4064 bool has_context = OperatorProperties::HasContextInput(op);
4065 bool has_frame_state = OperatorProperties::HasFrameStateInput(op);
4066 bool has_control = op->ControlInputCount() == 1;
4067 bool has_effect = op->EffectInputCount() == 1;
4068
4069 DCHECK(op->ControlInputCount() < 2);
4070 DCHECK(op->EffectInputCount() < 2);
4071
4072 Node* result = nullptr;
4073 if (!has_context && !has_frame_state && !has_control && !has_effect) {
4074 result = graph()->NewNode(op, value_input_count, value_inputs, incomplete);
4075 } else {
4076 bool inside_try_scope = try_nesting_level_ > 0;
4077 int input_count_with_deps = value_input_count;
4078 if (has_context) ++input_count_with_deps;
4079 if (has_frame_state) ++input_count_with_deps;
4080 if (has_control) ++input_count_with_deps;
4081 if (has_effect) ++input_count_with_deps;
4082 Node** buffer = EnsureInputBufferSize(input_count_with_deps);
4083 memcpy(buffer, value_inputs, kPointerSize * value_input_count);
4084 Node** current_input = buffer + value_input_count;
4085 if (has_context) {
4086 *current_input++ = current_context();
4087 }
4088 if (has_frame_state) {
4089 // The frame state will be inserted later. Here we misuse
4090 // the {Dead} node as a sentinel to be later overwritten
4091 // with the real frame state.
4092 *current_input++ = jsgraph()->Dead();
4093 }
4094 if (has_effect) {
4095 *current_input++ = environment_->GetEffectDependency();
4096 }
4097 if (has_control) {
4098 *current_input++ = environment_->GetControlDependency();
4099 }
4100 result = graph()->NewNode(op, input_count_with_deps, buffer, incomplete);
4101 if (!environment()->IsMarkedAsUnreachable()) {
4102 // Update the current control dependency for control-producing nodes.
4103 if (NodeProperties::IsControl(result)) {
4104 environment_->UpdateControlDependency(result);
4105 }
4106 // Update the current effect dependency for effect-producing nodes.
4107 if (result->op()->EffectOutputCount() > 0) {
4108 environment_->UpdateEffectDependency(result);
4109 }
4110 // Add implicit exception continuation for throwing nodes.
4111 if (!result->op()->HasProperty(Operator::kNoThrow) && inside_try_scope) {
4112 // Copy the environment for the success continuation.
4113 Environment* success_env = environment()->CopyForConditional();
4114 const Operator* op = common()->IfException();
4115 Node* effect = environment()->GetEffectDependency();
4116 Node* on_exception = graph()->NewNode(op, effect, result);
4117 environment_->UpdateControlDependency(on_exception);
4118 environment_->UpdateEffectDependency(on_exception);
4119 execution_control()->ThrowValue(on_exception);
4120 set_environment(success_env);
4121 }
4122 // Add implicit success continuation for throwing nodes.
4123 if (!result->op()->HasProperty(Operator::kNoThrow)) {
4124 const Operator* op = common()->IfSuccess();
4125 Node* on_success = graph()->NewNode(op, result);
4126 environment_->UpdateControlDependency(on_success);
4127 }
4128 }
4129 }
4130
4131 return result;
4132 }
4133
4134
UpdateControlDependencyToLeaveFunction(Node * exit)4135 void AstGraphBuilder::UpdateControlDependencyToLeaveFunction(Node* exit) {
4136 if (environment()->IsMarkedAsUnreachable()) return;
4137 environment()->MarkAsUnreachable();
4138 exit_controls_.push_back(exit);
4139 }
4140
4141
Merge(Environment * other)4142 void AstGraphBuilder::Environment::Merge(Environment* other) {
4143 DCHECK(values_.size() == other->values_.size());
4144 DCHECK(contexts_.size() == other->contexts_.size());
4145
4146 // Nothing to do if the other environment is dead.
4147 if (other->IsMarkedAsUnreachable()) return;
4148
4149 // Resurrect a dead environment by copying the contents of the other one and
4150 // placing a singleton merge as the new control dependency.
4151 if (this->IsMarkedAsUnreachable()) {
4152 Node* other_control = other->control_dependency_;
4153 Node* inputs[] = {other_control};
4154 control_dependency_ =
4155 graph()->NewNode(common()->Merge(1), arraysize(inputs), inputs, true);
4156 effect_dependency_ = other->effect_dependency_;
4157 values_ = other->values_;
4158 contexts_ = other->contexts_;
4159 if (IsLivenessAnalysisEnabled()) {
4160 liveness_block_ =
4161 builder_->liveness_analyzer()->NewBlock(other->liveness_block());
4162 }
4163 return;
4164 }
4165
4166 // Record the merge for the local variable liveness calculation.
4167 // For loops, we are connecting a back edge into the existing block;
4168 // for merges, we create a new merged block.
4169 if (IsLivenessAnalysisEnabled()) {
4170 if (GetControlDependency()->opcode() != IrOpcode::kLoop) {
4171 liveness_block_ =
4172 builder_->liveness_analyzer()->NewBlock(liveness_block());
4173 }
4174 liveness_block()->AddPredecessor(other->liveness_block());
4175 }
4176
4177 // Create a merge of the control dependencies of both environments and update
4178 // the current environment's control dependency accordingly.
4179 Node* control = builder_->MergeControl(this->GetControlDependency(),
4180 other->GetControlDependency());
4181 UpdateControlDependency(control);
4182
4183 // Create a merge of the effect dependencies of both environments and update
4184 // the current environment's effect dependency accordingly.
4185 Node* effect = builder_->MergeEffect(this->GetEffectDependency(),
4186 other->GetEffectDependency(), control);
4187 UpdateEffectDependency(effect);
4188
4189 // Introduce Phi nodes for values that have differing input at merge points,
4190 // potentially extending an existing Phi node if possible.
4191 for (int i = 0; i < static_cast<int>(values_.size()); ++i) {
4192 values_[i] = builder_->MergeValue(values_[i], other->values_[i], control);
4193 }
4194 for (int i = 0; i < static_cast<int>(contexts_.size()); ++i) {
4195 contexts_[i] =
4196 builder_->MergeValue(contexts_[i], other->contexts_[i], control);
4197 }
4198 }
4199
PrepareForOsrEntry()4200 void AstGraphBuilder::Environment::PrepareForOsrEntry() {
4201 int size = static_cast<int>(values()->size());
4202 Graph* graph = builder_->graph();
4203
4204 // Set the control and effect to the OSR loop entry.
4205 Node* osr_loop_entry = graph->NewNode(builder_->common()->OsrLoopEntry(),
4206 graph->start(), graph->start());
4207 UpdateControlDependency(osr_loop_entry);
4208 UpdateEffectDependency(osr_loop_entry);
4209
4210 // Set OSR values.
4211 for (int i = 0; i < size; ++i) {
4212 values()->at(i) =
4213 graph->NewNode(builder_->common()->OsrValue(i), osr_loop_entry);
4214 }
4215
4216 // Set the innermost context.
4217 const Operator* op_inner =
4218 builder_->common()->OsrValue(Linkage::kOsrContextSpillSlotIndex);
4219 contexts()->back() = graph->NewNode(op_inner, osr_loop_entry);
4220
4221 // Create a checkpoint.
4222 Node* frame_state = Checkpoint(builder_->info()->osr_ast_id());
4223 Node* checkpoint = graph->NewNode(common()->Checkpoint(), frame_state,
4224 osr_loop_entry, osr_loop_entry);
4225 UpdateEffectDependency(checkpoint);
4226
4227 // Create the OSR guard nodes.
4228 const Operator* guard_op =
4229 builder_->info()->is_deoptimization_enabled()
4230 ? builder_->common()->OsrGuard(OsrGuardType::kUninitialized)
4231 : builder_->common()->OsrGuard(OsrGuardType::kAny);
4232 Node* effect = checkpoint;
4233 for (int i = 0; i < size; ++i) {
4234 values()->at(i) = effect =
4235 graph->NewNode(guard_op, values()->at(i), effect, osr_loop_entry);
4236 }
4237 contexts()->back() = effect =
4238 graph->NewNode(guard_op, contexts()->back(), effect, osr_loop_entry);
4239
4240 // The innermost context is the OSR value, and the outer contexts are
4241 // reconstructed by dynamically walking up the context chain.
4242 const Operator* load_op =
4243 builder_->javascript()->LoadContext(0, Context::PREVIOUS_INDEX, true);
4244 Node* osr_context = effect = contexts()->back();
4245 int last = static_cast<int>(contexts()->size() - 1);
4246 for (int i = last - 1; i >= 0; i--) {
4247 osr_context = effect =
4248 graph->NewNode(load_op, osr_context, osr_context, effect);
4249 contexts()->at(i) = osr_context;
4250 }
4251 UpdateEffectDependency(effect);
4252 }
4253
PrepareForLoop(BitVector * assigned)4254 void AstGraphBuilder::Environment::PrepareForLoop(BitVector* assigned) {
4255 int size = static_cast<int>(values()->size());
4256
4257 Node* control = builder_->NewLoop();
4258 if (assigned == nullptr) {
4259 // Assume that everything is updated in the loop.
4260 for (int i = 0; i < size; ++i) {
4261 values()->at(i) = builder_->NewPhi(1, values()->at(i), control);
4262 }
4263 } else {
4264 // Only build phis for those locals assigned in this loop.
4265 for (int i = 0; i < size; ++i) {
4266 if (i < assigned->length() && !assigned->Contains(i)) continue;
4267 Node* phi = builder_->NewPhi(1, values()->at(i), control);
4268 values()->at(i) = phi;
4269 }
4270 }
4271 Node* effect = builder_->NewEffectPhi(1, GetEffectDependency(), control);
4272 UpdateEffectDependency(effect);
4273
4274 // Connect the loop to end via Terminate if it's not marked as unreachable.
4275 if (!IsMarkedAsUnreachable()) {
4276 // Connect the Loop node to end via a Terminate node.
4277 Node* terminate = builder_->graph()->NewNode(
4278 builder_->common()->Terminate(), effect, control);
4279 builder_->exit_controls_.push_back(terminate);
4280 }
4281
4282 if (builder_->info()->is_osr()) {
4283 // Introduce phis for all context values in the case of an OSR graph.
4284 for (size_t i = 0; i < contexts()->size(); ++i) {
4285 Node* context = contexts()->at(i);
4286 contexts()->at(i) = builder_->NewPhi(1, context, control);
4287 }
4288 }
4289 }
4290
4291
NewPhi(int count,Node * input,Node * control)4292 Node* AstGraphBuilder::NewPhi(int count, Node* input, Node* control) {
4293 const Operator* phi_op = common()->Phi(MachineRepresentation::kTagged, count);
4294 Node** buffer = EnsureInputBufferSize(count + 1);
4295 MemsetPointer(buffer, input, count);
4296 buffer[count] = control;
4297 return graph()->NewNode(phi_op, count + 1, buffer, true);
4298 }
4299
4300
NewEffectPhi(int count,Node * input,Node * control)4301 Node* AstGraphBuilder::NewEffectPhi(int count, Node* input, Node* control) {
4302 const Operator* phi_op = common()->EffectPhi(count);
4303 Node** buffer = EnsureInputBufferSize(count + 1);
4304 MemsetPointer(buffer, input, count);
4305 buffer[count] = control;
4306 return graph()->NewNode(phi_op, count + 1, buffer, true);
4307 }
4308
4309
MergeControl(Node * control,Node * other)4310 Node* AstGraphBuilder::MergeControl(Node* control, Node* other) {
4311 int inputs = control->op()->ControlInputCount() + 1;
4312 if (control->opcode() == IrOpcode::kLoop) {
4313 // Control node for loop exists, add input.
4314 const Operator* op = common()->Loop(inputs);
4315 control->AppendInput(graph_zone(), other);
4316 NodeProperties::ChangeOp(control, op);
4317 } else if (control->opcode() == IrOpcode::kMerge) {
4318 // Control node for merge exists, add input.
4319 const Operator* op = common()->Merge(inputs);
4320 control->AppendInput(graph_zone(), other);
4321 NodeProperties::ChangeOp(control, op);
4322 } else {
4323 // Control node is a singleton, introduce a merge.
4324 const Operator* op = common()->Merge(inputs);
4325 Node* inputs[] = {control, other};
4326 control = graph()->NewNode(op, arraysize(inputs), inputs, true);
4327 }
4328 return control;
4329 }
4330
4331
MergeEffect(Node * value,Node * other,Node * control)4332 Node* AstGraphBuilder::MergeEffect(Node* value, Node* other, Node* control) {
4333 int inputs = control->op()->ControlInputCount();
4334 if (value->opcode() == IrOpcode::kEffectPhi &&
4335 NodeProperties::GetControlInput(value) == control) {
4336 // Phi already exists, add input.
4337 value->InsertInput(graph_zone(), inputs - 1, other);
4338 NodeProperties::ChangeOp(value, common()->EffectPhi(inputs));
4339 } else if (value != other) {
4340 // Phi does not exist yet, introduce one.
4341 value = NewEffectPhi(inputs, value, control);
4342 value->ReplaceInput(inputs - 1, other);
4343 }
4344 return value;
4345 }
4346
4347
MergeValue(Node * value,Node * other,Node * control)4348 Node* AstGraphBuilder::MergeValue(Node* value, Node* other, Node* control) {
4349 int inputs = control->op()->ControlInputCount();
4350 if (value->opcode() == IrOpcode::kPhi &&
4351 NodeProperties::GetControlInput(value) == control) {
4352 // Phi already exists, add input.
4353 value->InsertInput(graph_zone(), inputs - 1, other);
4354 NodeProperties::ChangeOp(
4355 value, common()->Phi(MachineRepresentation::kTagged, inputs));
4356 } else if (value != other) {
4357 // Phi does not exist yet, introduce one.
4358 value = NewPhi(inputs, value, control);
4359 value->ReplaceInput(inputs - 1, other);
4360 }
4361 return value;
4362 }
4363
AstGraphBuilderWithPositions(Zone * local_zone,CompilationInfo * info,JSGraph * jsgraph,float invocation_frequency,LoopAssignmentAnalysis * loop_assignment,TypeHintAnalysis * type_hint_analysis,SourcePositionTable * source_positions,int inlining_id)4364 AstGraphBuilderWithPositions::AstGraphBuilderWithPositions(
4365 Zone* local_zone, CompilationInfo* info, JSGraph* jsgraph,
4366 float invocation_frequency, LoopAssignmentAnalysis* loop_assignment,
4367 TypeHintAnalysis* type_hint_analysis, SourcePositionTable* source_positions,
4368 int inlining_id)
4369 : AstGraphBuilder(local_zone, info, jsgraph, invocation_frequency,
4370 loop_assignment, type_hint_analysis),
4371 source_positions_(source_positions),
4372 start_position_(info->shared_info()->start_position(), inlining_id) {}
4373
4374 } // namespace compiler
4375 } // namespace internal
4376 } // namespace v8
4377