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.
5 #include "src/compiler/ast-graph-builder.h"
7 #include "src/compiler.h"
8 #include "src/compiler/ast-loop-assignment-analyzer.h"
9 #include "src/compiler/control-builders.h"
10 #include "src/compiler/js-type-feedback.h"
11 #include "src/compiler/linkage.h"
12 #include "src/compiler/liveness-analyzer.h"
13 #include "src/compiler/machine-operator.h"
14 #include "src/compiler/node-matchers.h"
15 #include "src/compiler/node-properties.h"
16 #include "src/compiler/operator-properties.h"
17 #include "src/compiler/state-values-utils.h"
18 #include "src/full-codegen.h"
19 #include "src/parser.h"
20 #include "src/scopes.h"
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 {
31 bool IsEffect() const { return kind_ == Expression::kEffect; }
32 bool IsValue() const { return kind_ == Expression::kValue; }
33 bool IsTest() const { return kind_ == Expression::kTest; }
35 // Determines how to combine the frame state with the value
36 // that is about to be plugged into this AstContext.
37 OutputFrameStateCombine GetStateCombine() {
38 return IsEffect() ? OutputFrameStateCombine::Ignore()
39 : OutputFrameStateCombine::Push();
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(Node* value) = 0;
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;
50 // Shortcut for "context->ProduceValue(context->ConsumeValue())".
51 void ReplaceValue() { ProduceValue(ConsumeValue()); }
54 AstContext(AstGraphBuilder* owner, Expression::Context kind);
55 virtual ~AstContext();
57 AstGraphBuilder* owner() const { return owner_; }
58 Environment* environment() const { return owner_->environment(); }
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.
67 Expression::Context kind_;
68 AstGraphBuilder* owner_;
73 // Context to evaluate expression for its side effects only.
74 class AstGraphBuilder::AstEffectContext FINAL : public AstContext {
76 explicit AstEffectContext(AstGraphBuilder* owner)
77 : AstContext(owner, Expression::kEffect) {}
78 ~AstEffectContext() FINAL;
79 void ProduceValue(Node* value) FINAL;
80 Node* ConsumeValue() FINAL;
84 // Context to evaluate expression for its value (and side effects).
85 class AstGraphBuilder::AstValueContext FINAL : public AstContext {
87 explicit AstValueContext(AstGraphBuilder* owner)
88 : AstContext(owner, Expression::kValue) {}
89 ~AstValueContext() FINAL;
90 void ProduceValue(Node* value) FINAL;
91 Node* ConsumeValue() FINAL;
95 // Context to evaluate expression for a condition value (and side effects).
96 class AstGraphBuilder::AstTestContext FINAL : public AstContext {
98 explicit AstTestContext(AstGraphBuilder* owner)
99 : AstContext(owner, Expression::kTest) {}
100 ~AstTestContext() FINAL;
101 void ProduceValue(Node* value) FINAL;
102 Node* ConsumeValue() FINAL;
106 // Scoped class tracking context objects created by the visitor. Represents
107 // mutations of the context chain within the function body and allows to
108 // change the current {scope} and {context} during visitation.
109 class AstGraphBuilder::ContextScope BASE_EMBEDDED {
111 ContextScope(AstGraphBuilder* builder, Scope* scope, Node* context)
113 outer_(builder->execution_context()),
115 depth_(builder_->environment()->ContextStackDepth()) {
116 builder_->environment()->PushContext(context); // Push.
117 builder_->set_execution_context(this);
121 builder_->set_execution_context(outer_); // Pop.
122 builder_->environment()->PopContext();
123 CHECK_EQ(depth_, builder_->environment()->ContextStackDepth());
126 // Current scope during visitation.
127 Scope* scope() const { return scope_; }
130 AstGraphBuilder* builder_;
131 ContextScope* outer_;
137 // Scoped class tracking control statements entered by the visitor. There are
138 // different types of statements participating in this stack to properly track
139 // local as well as non-local control flow:
140 // - IterationStatement : Allows proper 'break' and 'continue' behavior.
141 // - BreakableStatement : Allows 'break' from block and switch statements.
142 // - TryCatchStatement : Intercepts 'throw' and implicit exceptional edges.
143 // - TryFinallyStatement: Intercepts 'break', 'continue', 'throw' and 'return'.
144 class AstGraphBuilder::ControlScope BASE_EMBEDDED {
146 explicit ControlScope(AstGraphBuilder* builder)
148 outer_(builder->execution_control()),
149 stack_height_(builder->environment()->stack_height()) {
150 builder_->set_execution_control(this); // Push.
153 virtual ~ControlScope() {
154 builder_->set_execution_control(outer_); // Pop.
157 // Either 'break' or 'continue' to the target statement.
158 void BreakTo(BreakableStatement* target);
159 void ContinueTo(BreakableStatement* target);
161 // Either 'return' or 'throw' the given value.
162 void ReturnValue(Node* return_value);
163 void ThrowValue(Node* exception_value);
165 class DeferredCommands;
168 enum Command { CMD_BREAK, CMD_CONTINUE, CMD_RETURN, CMD_THROW };
170 // Performs one of the above commands on this stack of control scopes. This
171 // walks through the stack giving each scope a chance to execute or defer the
172 // given command by overriding the {Execute} method appropriately. Note that
173 // this also drops extra operands from the environment for each skipped scope.
174 void PerformCommand(Command cmd, Statement* target, Node* value);
176 // Interface to execute a given command in this scope. Returning {true} here
177 // indicates successful execution whereas {false} requests to skip scope.
178 virtual bool Execute(Command cmd, Statement* target, Node* value) {
179 // For function-level control.
182 builder()->BuildThrow(value);
185 builder()->BuildReturn(value);
194 Environment* environment() { return builder_->environment(); }
195 AstGraphBuilder* builder() const { return builder_; }
196 int stack_height() const { return stack_height_; }
199 AstGraphBuilder* builder_;
200 ControlScope* outer_;
205 // Helper class for a try-finally control scope. It can record intercepted
206 // control-flow commands that cause entry into a finally-block, and re-apply
207 // them after again leaving that block. Special tokens are used to identify
208 // paths going through the finally-block to dispatch after leaving the block.
209 class AstGraphBuilder::ControlScope::DeferredCommands : public ZoneObject {
211 explicit DeferredCommands(AstGraphBuilder* owner)
212 : owner_(owner), deferred_(owner->zone()) {}
214 // One recorded control-flow command.
216 Command command; // The command type being applied on this path.
217 Statement* statement; // The target statement for the command or {NULL}.
218 Node* token; // A token identifying this particular path.
221 // Records a control-flow command while entering the finally-block. This also
222 // generates a new dispatch token that identifies one particular path.
223 Node* RecordCommand(Command cmd, Statement* stmt, Node* value) {
224 Node* token = NewPathTokenForDeferredCommand();
225 deferred_.push_back({cmd, stmt, token});
229 // Returns the dispatch token to be used to identify the implicit fall-through
230 // path at the end of a try-block into the corresponding finally-block.
231 Node* GetFallThroughToken() { return NewPathTokenForImplicitFallThrough(); }
233 // Applies all recorded control-flow commands after the finally-block again.
234 // This generates a dynamic dispatch on the token from the entry point.
235 void ApplyDeferredCommands(Node* token, Node* value) {
236 SwitchBuilder dispatch(owner_, static_cast<int>(deferred_.size()));
237 dispatch.BeginSwitch();
238 for (size_t i = 0; i < deferred_.size(); ++i) {
239 Node* condition = NewPathDispatchCondition(token, deferred_[i].token);
240 dispatch.BeginLabel(static_cast<int>(i), condition);
243 for (size_t i = 0; i < deferred_.size(); ++i) {
244 dispatch.BeginCase(static_cast<int>(i));
245 owner_->execution_control()->PerformCommand(
246 deferred_[i].command, deferred_[i].statement, value);
249 dispatch.EndSwitch();
253 Node* NewPathTokenForDeferredCommand() {
254 return owner_->jsgraph()->Constant(static_cast<int>(deferred_.size()));
256 Node* NewPathTokenForImplicitFallThrough() {
257 return owner_->jsgraph()->Constant(-1);
259 Node* NewPathDispatchCondition(Node* t1, Node* t2) {
260 // TODO(mstarzinger): This should be machine()->WordEqual(), but our Phi
261 // nodes all have kRepTagged|kTypeAny, which causes representation mismatch.
262 return owner_->NewNode(owner_->javascript()->StrictEqual(), t1, t2);
266 AstGraphBuilder* owner_;
267 ZoneVector<Entry> deferred_;
271 // Control scope implementation for a BreakableStatement.
272 class AstGraphBuilder::ControlScopeForBreakable : public ControlScope {
274 ControlScopeForBreakable(AstGraphBuilder* owner, BreakableStatement* target,
275 ControlBuilder* control)
276 : ControlScope(owner), target_(target), control_(control) {}
279 virtual bool Execute(Command cmd, Statement* target, Node* value) OVERRIDE {
280 if (target != target_) return false; // We are not the command target.
294 BreakableStatement* target_;
295 ControlBuilder* control_;
299 // Control scope implementation for an IterationStatement.
300 class AstGraphBuilder::ControlScopeForIteration : public ControlScope {
302 ControlScopeForIteration(AstGraphBuilder* owner, IterationStatement* target,
303 LoopBuilder* control)
304 : ControlScope(owner), target_(target), control_(control) {}
307 virtual bool Execute(Command cmd, Statement* target, Node* value) OVERRIDE {
308 if (target != target_) return false; // We are not the command target.
314 control_->Continue();
324 BreakableStatement* target_;
325 LoopBuilder* control_;
329 // Control scope implementation for a TryCatchStatement.
330 class AstGraphBuilder::ControlScopeForCatch : public ControlScope {
332 ControlScopeForCatch(AstGraphBuilder* owner, TryCatchBuilder* control)
333 : ControlScope(owner), control_(control) {
334 builder()->try_nesting_level_++; // Increment nesting.
336 ~ControlScopeForCatch() {
337 builder()->try_nesting_level_--; // Decrement nesting.
341 virtual bool Execute(Command cmd, Statement* target, Node* value) OVERRIDE {
344 control_->Throw(value);
355 TryCatchBuilder* control_;
359 // Control scope implementation for a TryFinallyStatement.
360 class AstGraphBuilder::ControlScopeForFinally : public ControlScope {
362 ControlScopeForFinally(AstGraphBuilder* owner, DeferredCommands* commands,
363 TryFinallyBuilder* control)
364 : ControlScope(owner), commands_(commands), control_(control) {
365 builder()->try_nesting_level_++; // Increment nesting.
367 ~ControlScopeForFinally() {
368 builder()->try_nesting_level_--; // Decrement nesting.
372 virtual bool Execute(Command cmd, Statement* target, Node* value) OVERRIDE {
373 Node* token = commands_->RecordCommand(cmd, target, value);
374 control_->LeaveTry(token, value);
379 DeferredCommands* commands_;
380 TryFinallyBuilder* control_;
384 AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info,
385 JSGraph* jsgraph, LoopAssignmentAnalysis* loop,
386 JSTypeFeedbackTable* js_type_feedback)
387 : local_zone_(local_zone),
390 environment_(nullptr),
391 ast_context_(nullptr),
392 globals_(0, local_zone),
393 execution_control_(nullptr),
394 execution_context_(nullptr),
395 try_nesting_level_(0),
396 input_buffer_size_(0),
397 input_buffer_(nullptr),
398 exit_control_(nullptr),
399 loop_assignment_analysis_(loop),
400 state_values_cache_(jsgraph),
401 liveness_analyzer_(static_cast<size_t>(info->scope()->num_stack_slots()),
403 js_type_feedback_(js_type_feedback) {
404 InitializeAstVisitor(info->isolate(), local_zone);
408 Node* AstGraphBuilder::GetFunctionClosure() {
409 if (!function_closure_.is_set()) {
411 common()->Parameter(Linkage::kJSFunctionCallClosureParamIndex);
412 Node* node = NewNode(op, graph()->start());
413 function_closure_.set(node);
415 return function_closure_.get();
419 void AstGraphBuilder::CreateFunctionContext(bool constant_context) {
420 function_context_.set(constant_context
421 ? jsgraph()->HeapConstant(info()->context())
422 : NewOuterContextParam());
426 Node* AstGraphBuilder::NewOuterContextParam() {
427 // Parameter (arity + 1) is special for the outer context of the function
428 const Operator* op = common()->Parameter(info()->num_parameters() + 1);
429 return NewNode(op, graph()->start());
433 Node* AstGraphBuilder::NewCurrentContextOsrValue() {
434 // TODO(titzer): use a real OSR value here; a parameter works by accident.
435 // Parameter (arity + 1) is special for the outer context of the function
436 const Operator* op = common()->Parameter(info()->num_parameters() + 1);
437 return NewNode(op, graph()->start());
441 bool AstGraphBuilder::CreateGraph(bool constant_context, bool stack_check) {
442 Scope* scope = info()->scope();
443 DCHECK(graph() != NULL);
445 // Set up the basic structure of the graph.
446 int parameter_count = info()->num_parameters();
447 graph()->SetStart(graph()->NewNode(common()->Start(parameter_count)));
449 // Initialize the top-level environment.
450 Environment env(this, scope, graph()->start());
451 set_environment(&env);
453 // Initialize control scope.
454 ControlScope control(this);
456 if (info()->is_osr()) {
457 // Use OSR normal entry as the start of the top-level environment.
458 // It will be replaced with {Dead} after typing and optimizations.
459 NewNode(common()->OsrNormalEntry());
462 // Initialize the incoming context.
463 CreateFunctionContext(constant_context);
464 ContextScope incoming(this, scope, function_context_.get());
466 // Build receiver check for sloppy mode if necessary.
467 // TODO(mstarzinger/verwaest): Should this be moved back into the CallIC?
468 Node* original_receiver = env.Lookup(scope->receiver());
469 Node* patched_receiver = BuildPatchReceiverToGlobalProxy(original_receiver);
470 env.Bind(scope->receiver(), patched_receiver);
472 // Build function context only if there are context allocated variables.
473 int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
474 if (heap_slots > 0) {
475 // Push a new inner context scope for the function.
476 Node* closure = GetFunctionClosure();
477 Node* inner_context =
478 BuildLocalFunctionContext(function_context_.get(), closure);
479 ContextScope top_context(this, scope, inner_context);
480 CreateGraphBody(stack_check);
482 // Simply use the outer function context in building the graph.
483 CreateGraphBody(stack_check);
486 // Finish the basic structure of the graph.
487 graph()->SetEnd(graph()->NewNode(common()->End(), exit_control()));
489 // Compute local variable liveness information and use it to relax
491 ClearNonLiveSlotsInFrameStates();
493 // Failures indicated by stack overflow.
494 return !HasStackOverflow();
498 void AstGraphBuilder::CreateGraphBody(bool stack_check) {
499 Scope* scope = info()->scope();
501 // Build the arguments object if it is used.
502 BuildArgumentsObject(scope->arguments());
504 // Build rest arguments array if it is used.
506 Variable* rest_parameter = scope->rest_parameter(&rest_index);
507 BuildRestArgumentsArray(rest_parameter, rest_index);
509 // Emit tracing call if requested to do so.
511 NewNode(javascript()->CallRuntime(Runtime::kTraceEnter, 0));
514 // Visit implicit declaration of the function name.
515 if (scope->is_function_scope() && scope->function() != NULL) {
516 VisitVariableDeclaration(scope->function());
519 // Visit declarations within the function scope.
520 VisitDeclarations(scope->declarations());
522 // Build a stack-check before the body.
524 Node* node = NewNode(javascript()->StackCheck());
525 PrepareFrameState(node, BailoutId::FunctionEntry());
528 // Visit statements in the function body.
529 VisitStatements(info()->function()->body());
531 // Emit tracing call if requested to do so.
533 // TODO(mstarzinger): Only traces implicit return.
534 Node* return_value = jsgraph()->UndefinedConstant();
535 NewNode(javascript()->CallRuntime(Runtime::kTraceExit, 1), return_value);
538 // Return 'undefined' in case we can fall off the end.
539 BuildReturn(jsgraph()->UndefinedConstant());
543 void AstGraphBuilder::ClearNonLiveSlotsInFrameStates() {
544 if (!FLAG_analyze_environment_liveness) return;
546 NonLiveFrameStateSlotReplacer replacer(
547 &state_values_cache_, jsgraph()->UndefinedConstant(),
548 liveness_analyzer()->local_count(), local_zone());
549 Variable* arguments = info()->scope()->arguments();
550 if (arguments != nullptr && arguments->IsStackAllocated()) {
551 replacer.MarkPermanentlyLive(arguments->index());
553 liveness_analyzer()->Run(&replacer);
554 if (FLAG_trace_environment_liveness) {
556 liveness_analyzer()->Print(os);
561 // Left-hand side can only be a property, a global or a variable slot.
562 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
565 // Determine the left-hand side kind of an assignment.
566 static LhsKind DetermineLhsKind(Expression* expr) {
567 Property* property = expr->AsProperty();
568 DCHECK(expr->IsValidReferenceExpression());
570 (property == NULL) ? VARIABLE : (property->key()->IsPropertyName())
577 AstGraphBuilder::Environment::Environment(AstGraphBuilder* builder,
579 Node* control_dependency)
581 parameters_count_(scope->num_parameters() + 1),
582 locals_count_(scope->num_stack_slots()),
583 liveness_block_(builder_->liveness_analyzer()->NewBlock()),
584 values_(builder_->local_zone()),
585 contexts_(builder_->local_zone()),
586 control_dependency_(control_dependency),
587 effect_dependency_(control_dependency),
588 parameters_node_(nullptr),
589 locals_node_(nullptr),
590 stack_node_(nullptr) {
591 DCHECK_EQ(scope->num_parameters() + 1, parameters_count());
593 // Bind the receiver variable.
594 Node* receiver = builder->graph()->NewNode(common()->Parameter(0),
595 builder->graph()->start());
596 values()->push_back(receiver);
598 // Bind all parameter variables. The parameter indices are shifted by 1
599 // (receiver is parameter index -1 but environment index 0).
600 for (int i = 0; i < scope->num_parameters(); ++i) {
601 Node* parameter = builder->graph()->NewNode(common()->Parameter(i + 1),
602 builder->graph()->start());
603 values()->push_back(parameter);
606 // Bind all local variables to undefined.
607 Node* undefined_constant = builder->jsgraph()->UndefinedConstant();
608 values()->insert(values()->end(), locals_count(), undefined_constant);
612 AstGraphBuilder::Environment::Environment(AstGraphBuilder::Environment* copy)
613 : builder_(copy->builder_),
614 parameters_count_(copy->parameters_count_),
615 locals_count_(copy->locals_count_),
616 values_(copy->zone()),
617 contexts_(copy->zone()),
618 control_dependency_(copy->control_dependency_),
619 effect_dependency_(copy->effect_dependency_),
620 parameters_node_(copy->parameters_node_),
621 locals_node_(copy->locals_node_),
622 stack_node_(copy->stack_node_) {
623 const size_t kStackEstimate = 7; // optimum from experimentation!
624 values_.reserve(copy->values_.size() + kStackEstimate);
625 values_.insert(values_.begin(), copy->values_.begin(), copy->values_.end());
626 contexts_.reserve(copy->contexts_.size());
627 contexts_.insert(contexts_.begin(), copy->contexts_.begin(),
628 copy->contexts_.end());
630 if (FLAG_analyze_environment_liveness) {
631 // Split the liveness blocks.
632 copy->liveness_block_ =
633 builder_->liveness_analyzer()->NewBlock(copy->liveness_block());
635 builder_->liveness_analyzer()->NewBlock(copy->liveness_block());
640 void AstGraphBuilder::Environment::Bind(Variable* variable, Node* node) {
641 DCHECK(variable->IsStackAllocated());
642 if (variable->IsParameter()) {
643 // The parameter indices are shifted by 1 (receiver is parameter
644 // index -1 but environment index 0).
645 values()->at(variable->index() + 1) = node;
647 DCHECK(variable->IsStackLocal());
648 values()->at(variable->index() + parameters_count_) = node;
649 if (FLAG_analyze_environment_liveness) {
650 liveness_block()->Bind(variable->index());
656 Node* AstGraphBuilder::Environment::Lookup(Variable* variable) {
657 DCHECK(variable->IsStackAllocated());
658 if (variable->IsParameter()) {
659 // The parameter indices are shifted by 1 (receiver is parameter
660 // index -1 but environment index 0).
661 return values()->at(variable->index() + 1);
663 DCHECK(variable->IsStackLocal());
664 if (FLAG_analyze_environment_liveness) {
665 liveness_block()->Lookup(variable->index());
667 return values()->at(variable->index() + parameters_count_);
672 void AstGraphBuilder::Environment::MarkAllLocalsLive() {
673 if (FLAG_analyze_environment_liveness) {
674 for (int i = 0; i < locals_count_; i++) {
675 liveness_block()->Lookup(i);
681 AstGraphBuilder::Environment*
682 AstGraphBuilder::Environment::CopyAndShareLiveness() {
683 Environment* env = new (zone()) Environment(this);
684 if (FLAG_analyze_environment_liveness) {
685 env->liveness_block_ = liveness_block();
691 void AstGraphBuilder::Environment::UpdateStateValues(Node** state_values,
692 int offset, int count) {
693 bool should_update = false;
694 Node** env_values = (count == 0) ? nullptr : &values()->at(offset);
695 if (*state_values == NULL || (*state_values)->InputCount() != count) {
696 should_update = true;
698 DCHECK(static_cast<size_t>(offset + count) <= values()->size());
699 for (int i = 0; i < count; i++) {
700 if ((*state_values)->InputAt(i) != env_values[i]) {
701 should_update = true;
707 const Operator* op = common()->StateValues(count);
708 (*state_values) = graph()->NewNode(op, count, env_values);
713 void AstGraphBuilder::Environment::UpdateStateValuesWithCache(
714 Node** state_values, int offset, int count) {
715 Node** env_values = (count == 0) ? nullptr : &values()->at(offset);
716 *state_values = builder_->state_values_cache_.GetNodeForValues(
717 env_values, static_cast<size_t>(count));
721 Node* AstGraphBuilder::Environment::Checkpoint(
722 BailoutId ast_id, OutputFrameStateCombine combine) {
723 if (!FLAG_turbo_deoptimization) return nullptr;
725 UpdateStateValues(¶meters_node_, 0, parameters_count());
726 UpdateStateValuesWithCache(&locals_node_, parameters_count(), locals_count());
727 UpdateStateValues(&stack_node_, parameters_count() + locals_count(),
730 const Operator* op = common()->FrameState(JS_FRAME, ast_id, combine);
732 Node* result = graph()->NewNode(op, parameters_node_, locals_node_,
733 stack_node_, builder()->current_context(),
734 builder()->jsgraph()->UndefinedConstant());
735 if (FLAG_analyze_environment_liveness) {
736 liveness_block()->Checkpoint(result);
742 AstGraphBuilder::AstContext::AstContext(AstGraphBuilder* own,
743 Expression::Context kind)
744 : kind_(kind), owner_(own), outer_(own->ast_context()) {
745 owner()->set_ast_context(this); // Push.
747 original_height_ = environment()->stack_height();
752 AstGraphBuilder::AstContext::~AstContext() {
753 owner()->set_ast_context(outer_); // Pop.
757 AstGraphBuilder::AstEffectContext::~AstEffectContext() {
758 DCHECK(environment()->stack_height() == original_height_);
762 AstGraphBuilder::AstValueContext::~AstValueContext() {
763 DCHECK(environment()->stack_height() == original_height_ + 1);
767 AstGraphBuilder::AstTestContext::~AstTestContext() {
768 DCHECK(environment()->stack_height() == original_height_ + 1);
772 void AstGraphBuilder::AstEffectContext::ProduceValue(Node* value) {
773 // The value is ignored.
777 void AstGraphBuilder::AstValueContext::ProduceValue(Node* value) {
778 environment()->Push(value);
782 void AstGraphBuilder::AstTestContext::ProduceValue(Node* value) {
783 environment()->Push(owner()->BuildToBoolean(value));
787 Node* AstGraphBuilder::AstEffectContext::ConsumeValue() { return NULL; }
790 Node* AstGraphBuilder::AstValueContext::ConsumeValue() {
791 return environment()->Pop();
795 Node* AstGraphBuilder::AstTestContext::ConsumeValue() {
796 return environment()->Pop();
800 Scope* AstGraphBuilder::current_scope() const {
801 return execution_context_->scope();
805 Node* AstGraphBuilder::current_context() const {
806 return environment()->Context();
810 void AstGraphBuilder::ControlScope::PerformCommand(Command command,
813 Environment* env = environment()->CopyAsUnreachable();
814 ControlScope* current = this;
815 while (current != NULL) {
816 environment()->Trim(current->stack_height());
817 if (current->Execute(command, target, value)) break;
818 current = current->outer_;
820 builder()->set_environment(env);
821 DCHECK(current != NULL); // Always handled (unless stack is malformed).
825 void AstGraphBuilder::ControlScope::BreakTo(BreakableStatement* stmt) {
826 PerformCommand(CMD_BREAK, stmt, builder()->jsgraph()->TheHoleConstant());
830 void AstGraphBuilder::ControlScope::ContinueTo(BreakableStatement* stmt) {
831 PerformCommand(CMD_CONTINUE, stmt, builder()->jsgraph()->TheHoleConstant());
835 void AstGraphBuilder::ControlScope::ReturnValue(Node* return_value) {
836 PerformCommand(CMD_RETURN, nullptr, return_value);
840 void AstGraphBuilder::ControlScope::ThrowValue(Node* exception_value) {
841 PerformCommand(CMD_THROW, nullptr, exception_value);
845 void AstGraphBuilder::VisitForValueOrNull(Expression* expr) {
847 return environment()->Push(jsgraph()->NullConstant());
853 void AstGraphBuilder::VisitForValueOrTheHole(Expression* expr) {
855 return environment()->Push(jsgraph()->TheHoleConstant());
861 void AstGraphBuilder::VisitForValues(ZoneList<Expression*>* exprs) {
862 for (int i = 0; i < exprs->length(); ++i) {
863 VisitForValue(exprs->at(i));
868 void AstGraphBuilder::VisitForValue(Expression* expr) {
869 AstValueContext for_value(this);
870 if (!CheckStackOverflow()) {
873 ast_context()->ProduceValue(jsgraph()->UndefinedConstant());
878 void AstGraphBuilder::VisitForEffect(Expression* expr) {
879 AstEffectContext for_effect(this);
880 if (!CheckStackOverflow()) {
883 ast_context()->ProduceValue(jsgraph()->UndefinedConstant());
888 void AstGraphBuilder::VisitForTest(Expression* expr) {
889 AstTestContext for_condition(this);
890 if (!CheckStackOverflow()) {
893 ast_context()->ProduceValue(jsgraph()->UndefinedConstant());
898 void AstGraphBuilder::Visit(Expression* expr) {
899 // Reuses enclosing AstContext.
900 if (!CheckStackOverflow()) {
903 ast_context()->ProduceValue(jsgraph()->UndefinedConstant());
908 void AstGraphBuilder::VisitVariableDeclaration(VariableDeclaration* decl) {
909 Variable* variable = decl->proxy()->var();
910 VariableMode mode = decl->mode();
911 bool hole_init = mode == CONST || mode == CONST_LEGACY || mode == LET;
912 switch (variable->location()) {
913 case Variable::UNALLOCATED: {
914 Handle<Oddball> value = variable->binding_needs_init()
915 ? isolate()->factory()->the_hole_value()
916 : isolate()->factory()->undefined_value();
917 globals()->push_back(variable->name());
918 globals()->push_back(value);
921 case Variable::PARAMETER:
922 case Variable::LOCAL:
924 Node* value = jsgraph()->TheHoleConstant();
925 environment()->Bind(variable, value);
928 case Variable::CONTEXT:
930 Node* value = jsgraph()->TheHoleConstant();
931 const Operator* op = javascript()->StoreContext(0, variable->index());
932 NewNode(op, current_context(), value);
935 case Variable::LOOKUP:
941 void AstGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* decl) {
942 Variable* variable = decl->proxy()->var();
943 switch (variable->location()) {
944 case Variable::UNALLOCATED: {
945 Handle<SharedFunctionInfo> function =
946 Compiler::BuildFunctionInfo(decl->fun(), info()->script(), info());
947 // Check for stack-overflow exception.
948 if (function.is_null()) return SetStackOverflow();
949 globals()->push_back(variable->name());
950 globals()->push_back(function);
953 case Variable::PARAMETER:
954 case Variable::LOCAL: {
955 VisitForValue(decl->fun());
956 Node* value = environment()->Pop();
957 environment()->Bind(variable, value);
960 case Variable::CONTEXT: {
961 VisitForValue(decl->fun());
962 Node* value = environment()->Pop();
963 const Operator* op = javascript()->StoreContext(0, variable->index());
964 NewNode(op, current_context(), value);
967 case Variable::LOOKUP:
973 void AstGraphBuilder::VisitModuleDeclaration(ModuleDeclaration* decl) {
978 void AstGraphBuilder::VisitImportDeclaration(ImportDeclaration* decl) {
983 void AstGraphBuilder::VisitExportDeclaration(ExportDeclaration* decl) {
988 void AstGraphBuilder::VisitModuleLiteral(ModuleLiteral* modl) { UNREACHABLE(); }
991 void AstGraphBuilder::VisitModulePath(ModulePath* modl) { UNREACHABLE(); }
994 void AstGraphBuilder::VisitModuleUrl(ModuleUrl* modl) { UNREACHABLE(); }
997 void AstGraphBuilder::VisitBlock(Block* stmt) {
998 BlockBuilder block(this);
999 ControlScopeForBreakable scope(this, stmt, &block);
1000 if (stmt->labels() != NULL) block.BeginBlock();
1001 if (stmt->scope() == NULL) {
1002 // Visit statements in the same scope, no declarations.
1003 VisitStatements(stmt->statements());
1005 // Visit declarations and statements in a block scope.
1006 Node* context = BuildLocalBlockContext(stmt->scope());
1007 ContextScope scope(this, stmt->scope(), context);
1008 VisitDeclarations(stmt->scope()->declarations());
1009 VisitStatements(stmt->statements());
1011 if (stmt->labels() != NULL) block.EndBlock();
1015 void AstGraphBuilder::VisitModuleStatement(ModuleStatement* stmt) {
1020 void AstGraphBuilder::VisitExpressionStatement(ExpressionStatement* stmt) {
1021 VisitForEffect(stmt->expression());
1025 void AstGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) {
1030 void AstGraphBuilder::VisitIfStatement(IfStatement* stmt) {
1031 IfBuilder compare_if(this);
1032 VisitForTest(stmt->condition());
1033 Node* condition = environment()->Pop();
1034 compare_if.If(condition);
1036 Visit(stmt->then_statement());
1038 Visit(stmt->else_statement());
1043 void AstGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) {
1044 execution_control()->ContinueTo(stmt->target());
1048 void AstGraphBuilder::VisitBreakStatement(BreakStatement* stmt) {
1049 execution_control()->BreakTo(stmt->target());
1053 void AstGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
1054 VisitForValue(stmt->expression());
1055 Node* result = environment()->Pop();
1056 execution_control()->ReturnValue(result);
1060 void AstGraphBuilder::VisitWithStatement(WithStatement* stmt) {
1061 VisitForValue(stmt->expression());
1062 Node* value = environment()->Pop();
1063 const Operator* op = javascript()->CreateWithContext();
1064 Node* context = NewNode(op, value, GetFunctionClosure());
1065 PrepareFrameState(context, stmt->EntryId());
1066 ContextScope scope(this, stmt->scope(), context);
1067 Visit(stmt->statement());
1071 void AstGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
1072 ZoneList<CaseClause*>* clauses = stmt->cases();
1073 SwitchBuilder compare_switch(this, clauses->length());
1074 ControlScopeForBreakable scope(this, stmt, &compare_switch);
1075 compare_switch.BeginSwitch();
1076 int default_index = -1;
1078 // Keep the switch value on the stack until a case matches.
1079 VisitForValue(stmt->tag());
1080 Node* tag = environment()->Top();
1082 // Iterate over all cases and create nodes for label comparison.
1083 for (int i = 0; i < clauses->length(); i++) {
1084 CaseClause* clause = clauses->at(i);
1086 // The default is not a test, remember index.
1087 if (clause->is_default()) {
1092 // Create nodes to perform label comparison as if via '==='. The switch
1093 // value is still on the operand stack while the label is evaluated.
1094 VisitForValue(clause->label());
1095 Node* label = environment()->Pop();
1096 const Operator* op = javascript()->StrictEqual();
1097 Node* condition = NewNode(op, tag, label);
1098 compare_switch.BeginLabel(i, condition);
1100 // Discard the switch value at label match.
1101 environment()->Pop();
1102 compare_switch.EndLabel();
1105 // Discard the switch value and mark the default case.
1106 environment()->Pop();
1107 if (default_index >= 0) {
1108 compare_switch.DefaultAt(default_index);
1111 // Iterate over all cases and create nodes for case bodies.
1112 for (int i = 0; i < clauses->length(); i++) {
1113 CaseClause* clause = clauses->at(i);
1114 compare_switch.BeginCase(i);
1115 VisitStatements(clause->statements());
1116 compare_switch.EndCase();
1119 compare_switch.EndSwitch();
1123 void AstGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
1124 LoopBuilder while_loop(this);
1125 while_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt));
1126 VisitIterationBody(stmt, &while_loop);
1127 while_loop.EndBody();
1128 VisitForTest(stmt->cond());
1129 Node* condition = environment()->Pop();
1130 while_loop.BreakUnless(condition);
1131 while_loop.EndLoop();
1135 void AstGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
1136 LoopBuilder while_loop(this);
1137 while_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt));
1138 VisitForTest(stmt->cond());
1139 Node* condition = environment()->Pop();
1140 while_loop.BreakUnless(condition);
1141 VisitIterationBody(stmt, &while_loop);
1142 while_loop.EndBody();
1143 while_loop.EndLoop();
1147 void AstGraphBuilder::VisitForStatement(ForStatement* stmt) {
1148 LoopBuilder for_loop(this);
1149 VisitIfNotNull(stmt->init());
1150 for_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt));
1151 if (stmt->cond() != NULL) {
1152 VisitForTest(stmt->cond());
1153 Node* condition = environment()->Pop();
1154 for_loop.BreakUnless(condition);
1156 for_loop.BreakUnless(jsgraph()->TrueConstant());
1158 VisitIterationBody(stmt, &for_loop);
1160 VisitIfNotNull(stmt->next());
1165 // TODO(dcarney): this is a big function. Try to clean up some.
1166 void AstGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
1167 VisitForValue(stmt->subject());
1168 Node* obj = environment()->Pop();
1169 // Check for undefined or null before entering loop.
1170 IfBuilder is_undefined(this);
1171 Node* is_undefined_cond =
1172 NewNode(javascript()->StrictEqual(), obj, jsgraph()->UndefinedConstant());
1173 is_undefined.If(is_undefined_cond);
1174 is_undefined.Then();
1175 is_undefined.Else();
1177 IfBuilder is_null(this);
1178 Node* is_null_cond =
1179 NewNode(javascript()->StrictEqual(), obj, jsgraph()->NullConstant());
1180 is_null.If(is_null_cond);
1183 // Convert object to jsobject.
1184 // PrepareForBailoutForId(stmt->PrepareId(), TOS_REG);
1185 obj = NewNode(javascript()->ToObject(), obj);
1186 PrepareFrameState(obj, stmt->ToObjectId(), OutputFrameStateCombine::Push());
1187 environment()->Push(obj);
1188 // TODO(dcarney): should do a fast enum cache check here to skip runtime.
1189 Node* cache_type = NewNode(
1190 javascript()->CallRuntime(Runtime::kGetPropertyNamesFast, 1), obj);
1191 PrepareFrameState(cache_type, stmt->EnumId(),
1192 OutputFrameStateCombine::Push());
1193 // TODO(dcarney): these next runtime calls should be removed in favour of
1194 // a few simplified instructions.
1195 Node* cache_pair = NewNode(
1196 javascript()->CallRuntime(Runtime::kForInInit, 2), obj, cache_type);
1197 // cache_type may have been replaced.
1198 Node* cache_array = NewNode(common()->Projection(0), cache_pair);
1199 cache_type = NewNode(common()->Projection(1), cache_pair);
1200 Node* cache_length =
1201 NewNode(javascript()->CallRuntime(Runtime::kForInCacheArrayLength, 2),
1202 cache_type, cache_array);
1204 // TODO(dcarney): this check is actually supposed to be for the
1205 // empty enum case only.
1206 IfBuilder have_no_properties(this);
1207 Node* empty_array_cond = NewNode(javascript()->StrictEqual(),
1208 cache_length, jsgraph()->ZeroConstant());
1209 have_no_properties.If(empty_array_cond);
1210 have_no_properties.Then();
1211 // Pop obj and skip loop.
1212 environment()->Pop();
1213 have_no_properties.Else();
1215 // Construct the rest of the environment.
1216 environment()->Push(cache_type);
1217 environment()->Push(cache_array);
1218 environment()->Push(cache_length);
1219 environment()->Push(jsgraph()->ZeroConstant());
1221 // Build the actual loop body.
1222 VisitForInBody(stmt);
1224 have_no_properties.End();
1232 // TODO(dcarney): this is a big function. Try to clean up some.
1233 void AstGraphBuilder::VisitForInBody(ForInStatement* stmt) {
1234 LoopBuilder for_loop(this);
1235 for_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt));
1237 // These stack values are renamed in the case of OSR, so reload them
1238 // from the environment.
1239 Node* index = environment()->Peek(0);
1240 Node* cache_length = environment()->Peek(1);
1241 Node* cache_array = environment()->Peek(2);
1242 Node* cache_type = environment()->Peek(3);
1243 Node* obj = environment()->Peek(4);
1245 // Check loop termination condition.
1246 Node* exit_cond = NewNode(javascript()->LessThan(), index, cache_length);
1247 // TODO(jarin): provide real bailout id.
1248 PrepareFrameState(exit_cond, BailoutId::None());
1249 for_loop.BreakUnless(exit_cond);
1250 Node* pair = NewNode(javascript()->CallRuntime(Runtime::kForInNext, 4), obj,
1251 cache_array, cache_type, index);
1252 Node* value = NewNode(common()->Projection(0), pair);
1253 Node* should_filter = NewNode(common()->Projection(1), pair);
1254 environment()->Push(value);
1256 // Test if FILTER_KEY needs to be called.
1257 IfBuilder test_should_filter(this);
1258 Node* should_filter_cond = NewNode(
1259 javascript()->StrictEqual(), should_filter, jsgraph()->TrueConstant());
1260 test_should_filter.If(should_filter_cond);
1261 test_should_filter.Then();
1262 value = environment()->Pop();
1263 Node* builtins = BuildLoadBuiltinsObject();
1264 Node* function = BuildLoadObjectField(
1266 JSBuiltinsObject::OffsetOfFunctionWithId(Builtins::FILTER_KEY));
1267 // result is either the string key or Smi(0) indicating the property
1269 Node* res = NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
1270 function, obj, value);
1271 // TODO(jarin): provide real bailout id.
1272 PrepareFrameState(res, BailoutId::None());
1273 Node* property_missing =
1274 NewNode(javascript()->StrictEqual(), res, jsgraph()->ZeroConstant());
1276 IfBuilder is_property_missing(this);
1277 is_property_missing.If(property_missing);
1278 is_property_missing.Then();
1279 // Inc counter and continue.
1281 NewNode(javascript()->Add(), index, jsgraph()->OneConstant());
1282 // TODO(jarin): provide real bailout id.
1283 PrepareFrameStateAfterAndBefore(index_inc, BailoutId::None(),
1284 OutputFrameStateCombine::Ignore(),
1285 jsgraph()->EmptyFrameState());
1286 environment()->Poke(0, index_inc);
1287 for_loop.Continue();
1288 is_property_missing.Else();
1289 is_property_missing.End();
1291 // Replace 'value' in environment.
1292 environment()->Push(res);
1293 test_should_filter.Else();
1294 test_should_filter.End();
1296 value = environment()->Pop();
1297 // Bind value and do loop body.
1298 VisitForInAssignment(stmt->each(), value, stmt->AssignmentId());
1299 VisitIterationBody(stmt, &for_loop);
1300 index = environment()->Peek(0);
1303 // Inc counter and continue.
1305 NewNode(javascript()->Add(), index, jsgraph()->OneConstant());
1306 // TODO(jarin): provide real bailout id.
1307 PrepareFrameStateAfterAndBefore(index_inc, BailoutId::None(),
1308 OutputFrameStateCombine::Ignore(),
1309 jsgraph()->EmptyFrameState());
1310 environment()->Poke(0, index_inc);
1312 environment()->Drop(5);
1313 // PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
1317 void AstGraphBuilder::VisitForOfStatement(ForOfStatement* stmt) {
1318 LoopBuilder for_loop(this);
1319 VisitForEffect(stmt->assign_iterator());
1320 for_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt));
1321 VisitForEffect(stmt->next_result());
1322 VisitForTest(stmt->result_done());
1323 Node* condition = environment()->Pop();
1324 for_loop.BreakWhen(condition);
1325 VisitForEffect(stmt->assign_each());
1326 VisitIterationBody(stmt, &for_loop);
1332 void AstGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) {
1333 TryCatchBuilder try_control(this);
1335 // Evaluate the try-block inside a control scope. This simulates a handler
1336 // that is intercepting 'throw' control commands.
1337 try_control.BeginTry();
1339 ControlScopeForCatch scope(this, &try_control);
1340 STATIC_ASSERT(TryBlockConstant::kElementCount == 1);
1341 environment()->Push(current_context());
1342 Visit(stmt->try_block());
1343 environment()->Pop();
1345 try_control.EndTry();
1347 // Create a catch scope that binds the exception.
1348 Node* exception = try_control.GetExceptionNode();
1349 Unique<String> name = MakeUnique(stmt->variable()->name());
1350 const Operator* op = javascript()->CreateCatchContext(name);
1351 Node* context = NewNode(op, exception, GetFunctionClosure());
1352 PrepareFrameState(context, BailoutId::None());
1354 ContextScope scope(this, stmt->scope(), context);
1355 DCHECK(stmt->scope()->declarations()->is_empty());
1356 // Evaluate the catch-block.
1357 Visit(stmt->catch_block());
1359 try_control.EndCatch();
1361 // TODO(mstarzinger): Remove bailout once everything works.
1362 if (!FLAG_turbo_exceptions) SetStackOverflow();
1366 void AstGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
1367 TryFinallyBuilder try_control(this);
1369 ExternalReference message_object =
1370 ExternalReference::address_of_pending_message_obj(isolate());
1372 // We keep a record of all paths that enter the finally-block to be able to
1373 // dispatch to the correct continuation point after the statements in the
1374 // finally-block have been evaluated.
1376 // The try-finally construct can enter the finally-block in three ways:
1377 // 1. By exiting the try-block normally, falling through at the end.
1378 // 2. By exiting the try-block with a function-local control flow transfer
1379 // (i.e. through break/continue/return statements).
1380 // 3. By exiting the try-block with a thrown exception.
1381 Node* fallthrough_result = jsgraph()->TheHoleConstant();
1382 ControlScope::DeferredCommands* commands =
1383 new (zone()) ControlScope::DeferredCommands(this);
1385 // Evaluate the try-block inside a control scope. This simulates a handler
1386 // that is intercepting all control commands.
1387 try_control.BeginTry();
1389 ControlScopeForFinally scope(this, commands, &try_control);
1390 STATIC_ASSERT(TryBlockConstant::kElementCount == 1);
1391 environment()->Push(current_context());
1392 Visit(stmt->try_block());
1393 environment()->Pop();
1395 try_control.EndTry(commands->GetFallThroughToken(), fallthrough_result);
1397 // The result value semantics depend on how the block was entered:
1398 // - ReturnStatement: It represents the return value being returned.
1399 // - ThrowStatement: It represents the exception being thrown.
1400 // - BreakStatement/ContinueStatement: Filled with the hole.
1401 // - Falling through into finally-block: Filled with the hole.
1402 Node* result = try_control.GetResultValueNode();
1403 Node* token = try_control.GetDispatchTokenNode();
1405 // The result value, dispatch token and message is expected on the operand
1406 // stack (this is in sync with FullCodeGenerator::EnterFinallyBlock).
1407 Node* message = BuildLoadExternal(message_object, kMachAnyTagged);
1408 environment()->Push(token); // TODO(mstarzinger): Cook token!
1409 environment()->Push(result);
1410 environment()->Push(message);
1412 // Evaluate the finally-block.
1413 Visit(stmt->finally_block());
1414 try_control.EndFinally();
1416 // The result value, dispatch token and message is restored from the operand
1417 // stack (this is in sync with FullCodeGenerator::ExitFinallyBlock).
1418 message = environment()->Pop();
1419 result = environment()->Pop();
1420 token = environment()->Pop(); // TODO(mstarzinger): Uncook token!
1421 BuildStoreExternal(message_object, kMachAnyTagged, message);
1423 // Dynamic dispatch after the finally-block.
1424 commands->ApplyDeferredCommands(token, result);
1426 // TODO(mstarzinger): Remove bailout once everything works.
1427 if (!FLAG_turbo_exceptions) SetStackOverflow();
1431 void AstGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
1432 Node* node = NewNode(javascript()->CallRuntime(Runtime::kDebugBreak, 0));
1433 PrepareFrameState(node, stmt->DebugBreakId());
1434 environment()->MarkAllLocalsLive();
1438 void AstGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
1439 Node* context = current_context();
1441 // Build a new shared function info if we cannot find one in the baseline
1442 // code. We also have a stack overflow if the recursive compilation did.
1443 expr->InitializeSharedInfo(handle(info()->shared_info()->code()));
1444 Handle<SharedFunctionInfo> shared_info = expr->shared_info();
1445 if (shared_info.is_null()) {
1446 shared_info = Compiler::BuildFunctionInfo(expr, info()->script(), info());
1447 CHECK(!shared_info.is_null()); // TODO(mstarzinger): Set stack overflow?
1450 // Create node to instantiate a new closure.
1451 Node* info = jsgraph()->Constant(shared_info);
1452 Node* pretenure = jsgraph()->BooleanConstant(expr->pretenure());
1453 const Operator* op = javascript()->CallRuntime(Runtime::kNewClosure, 3);
1454 Node* value = NewNode(op, context, info, pretenure);
1455 ast_context()->ProduceValue(value);
1459 void AstGraphBuilder::VisitClassLiteral(ClassLiteral* expr) {
1460 if (expr->scope() == NULL) {
1461 // Visit class literal in the same scope, no declarations.
1462 VisitClassLiteralContents(expr);
1464 // Visit declarations and class literal in a block scope.
1465 Node* context = BuildLocalBlockContext(expr->scope());
1466 ContextScope scope(this, expr->scope(), context);
1467 VisitDeclarations(expr->scope()->declarations());
1468 VisitClassLiteralContents(expr);
1473 void AstGraphBuilder::VisitClassLiteralContents(ClassLiteral* expr) {
1474 Node* class_name = expr->raw_name() ? jsgraph()->Constant(expr->name())
1475 : jsgraph()->UndefinedConstant();
1477 // The class name is expected on the operand stack.
1478 environment()->Push(class_name);
1479 VisitForValueOrTheHole(expr->extends());
1480 VisitForValue(expr->constructor());
1482 // Create node to instantiate a new class.
1483 Node* constructor = environment()->Pop();
1484 Node* extends = environment()->Pop();
1485 Node* name = environment()->Pop();
1486 Node* script = jsgraph()->Constant(info()->script());
1487 Node* start = jsgraph()->Constant(expr->start_position());
1488 Node* end = jsgraph()->Constant(expr->end_position());
1489 const Operator* opc = javascript()->CallRuntime(Runtime::kDefineClass, 6);
1490 Node* literal = NewNode(opc, name, extends, constructor, script, start, end);
1492 // The prototype is ensured to exist by Runtime_DefineClass. No access check
1493 // is needed here since the constructor is created by the class literal.
1495 BuildLoadObjectField(literal, JSFunction::kPrototypeOrInitialMapOffset);
1497 // The class literal and the prototype are both expected on the operand stack
1498 // during evaluation of the method values.
1499 environment()->Push(literal);
1500 environment()->Push(proto);
1502 // Create nodes to store method values into the literal.
1503 for (int i = 0; i < expr->properties()->length(); i++) {
1504 ObjectLiteral::Property* property = expr->properties()->at(i);
1505 environment()->Push(property->is_static() ? literal : proto);
1507 VisitForValue(property->key());
1508 Node* name = BuildToName(environment()->Pop(), expr->GetIdForProperty(i));
1509 environment()->Push(name);
1511 // The static prototype property is read only. We handle the non computed
1512 // property name case in the parser. Since this is the only case where we
1513 // need to check for an own read only property we special case this so we do
1514 // not need to do this for every property.
1515 if (property->is_static() && property->is_computed_name()) {
1516 Node* check = BuildThrowIfStaticPrototype(environment()->Pop(),
1517 expr->GetIdForProperty(i));
1518 environment()->Push(check);
1521 VisitForValue(property->value());
1522 Node* value = environment()->Pop();
1523 Node* key = environment()->Pop();
1524 Node* receiver = environment()->Pop();
1525 BuildSetHomeObject(value, receiver, property->value());
1527 switch (property->kind()) {
1528 case ObjectLiteral::Property::CONSTANT:
1529 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1530 case ObjectLiteral::Property::PROTOTYPE:
1532 case ObjectLiteral::Property::COMPUTED: {
1533 const Operator* op =
1534 javascript()->CallRuntime(Runtime::kDefineClassMethod, 3);
1535 NewNode(op, receiver, key, value);
1538 case ObjectLiteral::Property::GETTER: {
1539 Node* attr = jsgraph()->Constant(DONT_ENUM);
1540 const Operator* op = javascript()->CallRuntime(
1541 Runtime::kDefineGetterPropertyUnchecked, 4);
1542 NewNode(op, receiver, key, value, attr);
1545 case ObjectLiteral::Property::SETTER: {
1546 Node* attr = jsgraph()->Constant(DONT_ENUM);
1547 const Operator* op = javascript()->CallRuntime(
1548 Runtime::kDefineSetterPropertyUnchecked, 4);
1549 NewNode(op, receiver, key, value, attr);
1555 // Transform both the class literal and the prototype to fast properties.
1556 const Operator* op = javascript()->CallRuntime(Runtime::kToFastProperties, 1);
1557 NewNode(op, environment()->Pop()); // prototype
1558 NewNode(op, environment()->Pop()); // literal
1560 // Assign to class variable.
1561 if (expr->scope() != NULL) {
1562 DCHECK_NOT_NULL(expr->class_variable_proxy());
1563 Variable* var = expr->class_variable_proxy()->var();
1564 BuildVariableAssignment(var, literal, Token::INIT_CONST, BailoutId::None());
1567 PrepareFrameState(literal, expr->id(), ast_context()->GetStateCombine());
1568 ast_context()->ProduceValue(literal);
1572 void AstGraphBuilder::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
1577 void AstGraphBuilder::VisitConditional(Conditional* expr) {
1578 IfBuilder compare_if(this);
1579 VisitForTest(expr->condition());
1580 Node* condition = environment()->Pop();
1581 compare_if.If(condition);
1583 Visit(expr->then_expression());
1585 Visit(expr->else_expression());
1587 ast_context()->ReplaceValue();
1591 void AstGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
1592 VectorSlotPair pair = CreateVectorSlotPair(expr->VariableFeedbackSlot());
1593 Node* value = BuildVariableLoad(expr->var(), expr->id(), pair);
1594 ast_context()->ProduceValue(value);
1598 void AstGraphBuilder::VisitLiteral(Literal* expr) {
1599 Node* value = jsgraph()->Constant(expr->value());
1600 ast_context()->ProduceValue(value);
1604 void AstGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
1605 Node* closure = GetFunctionClosure();
1607 // Create node to materialize a regular expression literal.
1608 Node* literals_array =
1609 BuildLoadObjectField(closure, JSFunction::kLiteralsOffset);
1610 Node* literal_index = jsgraph()->Constant(expr->literal_index());
1611 Node* pattern = jsgraph()->Constant(expr->pattern());
1612 Node* flags = jsgraph()->Constant(expr->flags());
1613 const Operator* op =
1614 javascript()->CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
1615 Node* literal = NewNode(op, literals_array, literal_index, pattern, flags);
1616 PrepareFrameState(literal, expr->id(), ast_context()->GetStateCombine());
1617 ast_context()->ProduceValue(literal);
1621 void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
1622 Node* closure = GetFunctionClosure();
1624 // Create node to deep-copy the literal boilerplate.
1625 expr->BuildConstantProperties(isolate());
1626 Node* literals_array =
1627 BuildLoadObjectField(closure, JSFunction::kLiteralsOffset);
1628 Node* literal_index = jsgraph()->Constant(expr->literal_index());
1629 Node* constants = jsgraph()->Constant(expr->constant_properties());
1630 Node* flags = jsgraph()->Constant(expr->ComputeFlags(true));
1631 const Operator* op =
1632 javascript()->CallRuntime(Runtime::kCreateObjectLiteral, 4);
1633 Node* literal = NewNode(op, literals_array, literal_index, constants, flags);
1634 PrepareFrameState(literal, expr->CreateLiteralId(),
1635 OutputFrameStateCombine::Push());
1637 // The object is expected on the operand stack during computation of the
1638 // property values and is the value of the entire expression.
1639 environment()->Push(literal);
1641 // Mark all computed expressions that are bound to a key that is shadowed by
1642 // a later occurrence of the same key. For the marked expressions, no store
1644 expr->CalculateEmitStore(zone());
1646 // Create nodes to store computed values into the literal.
1647 int property_index = 0;
1648 AccessorTable accessor_table(zone());
1649 for (; property_index < expr->properties()->length(); property_index++) {
1650 ObjectLiteral::Property* property = expr->properties()->at(property_index);
1651 if (property->is_computed_name()) break;
1652 if (property->IsCompileTimeValue()) continue;
1654 Literal* key = property->key()->AsLiteral();
1655 switch (property->kind()) {
1656 case ObjectLiteral::Property::CONSTANT:
1658 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1659 DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value()));
1661 case ObjectLiteral::Property::COMPUTED: {
1662 // It is safe to use [[Put]] here because the boilerplate already
1663 // contains computed properties with an uninitialized value.
1664 if (key->value()->IsInternalizedString()) {
1665 if (property->emit_store()) {
1666 VisitForValue(property->value());
1667 Node* value = environment()->Pop();
1668 Handle<Name> name = key->AsPropertyName();
1670 BuildNamedStore(literal, name, value, TypeFeedbackId::None());
1671 PrepareFrameState(store, key->id());
1672 BuildSetHomeObject(value, literal, property->value());
1674 VisitForEffect(property->value());
1678 environment()->Push(literal); // Duplicate receiver.
1679 VisitForValue(property->key());
1680 VisitForValue(property->value());
1681 Node* value = environment()->Pop();
1682 Node* key = environment()->Pop();
1683 Node* receiver = environment()->Pop();
1684 if (property->emit_store()) {
1685 Node* language = jsgraph()->Constant(SLOPPY);
1686 const Operator* op =
1687 javascript()->CallRuntime(Runtime::kSetProperty, 4);
1688 NewNode(op, receiver, key, value, language);
1689 BuildSetHomeObject(value, receiver, property->value());
1693 case ObjectLiteral::Property::PROTOTYPE: {
1694 environment()->Push(literal); // Duplicate receiver.
1695 VisitForValue(property->value());
1696 Node* value = environment()->Pop();
1697 Node* receiver = environment()->Pop();
1698 DCHECK(property->emit_store());
1699 const Operator* op =
1700 javascript()->CallRuntime(Runtime::kInternalSetPrototype, 2);
1701 Node* set_prototype = NewNode(op, receiver, value);
1702 // SetPrototype should not lazy deopt on an object literal.
1703 PrepareFrameState(set_prototype, BailoutId::None());
1706 case ObjectLiteral::Property::GETTER:
1707 if (property->emit_store()) {
1708 accessor_table.lookup(key)->second->getter = property->value();
1711 case ObjectLiteral::Property::SETTER:
1712 if (property->emit_store()) {
1713 accessor_table.lookup(key)->second->setter = property->value();
1719 // Create nodes to define accessors, using only a single call to the runtime
1720 // for each pair of corresponding getters and setters.
1721 for (AccessorTable::Iterator it = accessor_table.begin();
1722 it != accessor_table.end(); ++it) {
1723 VisitForValue(it->first);
1724 VisitForValueOrNull(it->second->getter);
1725 BuildSetHomeObject(environment()->Top(), literal, it->second->getter);
1726 VisitForValueOrNull(it->second->setter);
1727 BuildSetHomeObject(environment()->Top(), literal, it->second->setter);
1728 Node* setter = environment()->Pop();
1729 Node* getter = environment()->Pop();
1730 Node* name = environment()->Pop();
1731 Node* attr = jsgraph()->Constant(NONE);
1732 const Operator* op =
1733 javascript()->CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
1734 Node* call = NewNode(op, literal, name, getter, setter, attr);
1735 // This should not lazy deopt on a new literal.
1736 PrepareFrameState(call, BailoutId::None());
1739 // Object literals have two parts. The "static" part on the left contains no
1740 // computed property names, and so we can compute its map ahead of time; see
1741 // Runtime_CreateObjectLiteralBoilerplate. The second "dynamic" part starts
1742 // with the first computed property name and continues with all properties to
1743 // its right. All the code from above initializes the static component of the
1744 // object literal, and arranges for the map of the result to reflect the
1745 // static order in which the keys appear. For the dynamic properties, we
1746 // compile them into a series of "SetOwnProperty" runtime calls. This will
1747 // preserve insertion order.
1748 for (; property_index < expr->properties()->length(); property_index++) {
1749 ObjectLiteral::Property* property = expr->properties()->at(property_index);
1751 environment()->Push(literal); // Duplicate receiver.
1752 VisitForValue(property->key());
1753 Node* name = BuildToName(environment()->Pop(),
1754 expr->GetIdForProperty(property_index));
1755 environment()->Push(name);
1756 // TODO(mstarzinger): For ObjectLiteral::Property::PROTOTYPE the key should
1757 // not be on the operand stack while the value is being evaluated. Come up
1758 // with a repro for this and fix it. Also find a nice way to do so. :)
1759 VisitForValue(property->value());
1760 Node* value = environment()->Pop();
1761 Node* key = environment()->Pop();
1762 Node* receiver = environment()->Pop();
1763 BuildSetHomeObject(value, receiver, property->value());
1765 switch (property->kind()) {
1766 case ObjectLiteral::Property::CONSTANT:
1767 case ObjectLiteral::Property::COMPUTED:
1768 case ObjectLiteral::Property::MATERIALIZED_LITERAL: {
1769 Node* attr = jsgraph()->Constant(NONE);
1770 const Operator* op =
1771 javascript()->CallRuntime(Runtime::kDefineDataPropertyUnchecked, 4);
1772 Node* call = NewNode(op, receiver, key, value, attr);
1773 PrepareFrameState(call, BailoutId::None());
1776 case ObjectLiteral::Property::PROTOTYPE: {
1777 const Operator* op =
1778 javascript()->CallRuntime(Runtime::kInternalSetPrototype, 2);
1779 Node* call = NewNode(op, receiver, value);
1780 PrepareFrameState(call, BailoutId::None());
1783 case ObjectLiteral::Property::GETTER: {
1784 Node* attr = jsgraph()->Constant(NONE);
1785 const Operator* op = javascript()->CallRuntime(
1786 Runtime::kDefineGetterPropertyUnchecked, 4);
1787 Node* call = NewNode(op, receiver, key, value, attr);
1788 PrepareFrameState(call, BailoutId::None());
1791 case ObjectLiteral::Property::SETTER: {
1792 Node* attr = jsgraph()->Constant(NONE);
1793 const Operator* op = javascript()->CallRuntime(
1794 Runtime::kDefineSetterPropertyUnchecked, 4);
1795 Node* call = NewNode(op, receiver, key, value, attr);
1796 PrepareFrameState(call, BailoutId::None());
1802 // Transform literals that contain functions to fast properties.
1803 if (expr->has_function()) {
1804 const Operator* op =
1805 javascript()->CallRuntime(Runtime::kToFastProperties, 1);
1806 NewNode(op, literal);
1809 ast_context()->ProduceValue(environment()->Pop());
1813 void AstGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
1814 Node* closure = GetFunctionClosure();
1816 // Create node to deep-copy the literal boilerplate.
1817 expr->BuildConstantElements(isolate());
1818 Node* literals_array =
1819 BuildLoadObjectField(closure, JSFunction::kLiteralsOffset);
1820 Node* literal_index = jsgraph()->Constant(expr->literal_index());
1821 Node* constants = jsgraph()->Constant(expr->constant_elements());
1822 Node* flags = jsgraph()->Constant(expr->ComputeFlags(true));
1823 const Operator* op =
1824 javascript()->CallRuntime(Runtime::kCreateArrayLiteral, 4);
1825 Node* literal = NewNode(op, literals_array, literal_index, constants, flags);
1826 PrepareFrameState(literal, expr->CreateLiteralId(),
1827 OutputFrameStateCombine::Push());
1829 // The array and the literal index are both expected on the operand stack
1830 // during computation of the element values.
1831 environment()->Push(literal);
1832 environment()->Push(literal_index);
1834 // Create nodes to evaluate all the non-constant subexpressions and to store
1835 // them into the newly cloned array.
1836 for (int i = 0; i < expr->values()->length(); i++) {
1837 Expression* subexpr = expr->values()->at(i);
1838 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
1840 VisitForValue(subexpr);
1841 Node* frame_state_before = environment()->Checkpoint(
1842 subexpr->id(), OutputFrameStateCombine::PokeAt(0));
1843 Node* value = environment()->Pop();
1844 Node* index = jsgraph()->Constant(i);
1846 BuildKeyedStore(literal, index, value, TypeFeedbackId::None());
1847 PrepareFrameStateAfterAndBefore(store, expr->GetIdForElement(i),
1848 OutputFrameStateCombine::Ignore(),
1849 frame_state_before);
1852 environment()->Pop(); // Array literal index.
1853 ast_context()->ProduceValue(environment()->Pop());
1857 void AstGraphBuilder::VisitForInAssignment(Expression* expr, Node* value,
1858 BailoutId bailout_id) {
1859 DCHECK(expr->IsValidReferenceExpression());
1861 // Left-hand side can only be a property, a global or a variable slot.
1862 Property* property = expr->AsProperty();
1863 LhsKind assign_type = DetermineLhsKind(expr);
1865 // Evaluate LHS expression and store the value.
1866 switch (assign_type) {
1868 Variable* var = expr->AsVariableProxy()->var();
1869 BuildVariableAssignment(var, value, Token::ASSIGN, bailout_id);
1872 case NAMED_PROPERTY: {
1873 environment()->Push(value);
1874 VisitForValue(property->obj());
1875 Node* object = environment()->Pop();
1876 value = environment()->Pop();
1877 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
1879 BuildNamedStore(object, name, value, TypeFeedbackId::None());
1880 PrepareFrameState(store, bailout_id);
1883 case KEYED_PROPERTY: {
1884 environment()->Push(value);
1885 VisitForValue(property->obj());
1886 VisitForValue(property->key());
1887 Node* key = environment()->Pop();
1888 Node* object = environment()->Pop();
1889 value = environment()->Pop();
1890 Node* store = BuildKeyedStore(object, key, value, TypeFeedbackId::None());
1891 // TODO(jarin) Provide a real frame state before.
1892 PrepareFrameStateAfterAndBefore(store, bailout_id,
1893 OutputFrameStateCombine::Ignore(),
1894 jsgraph()->EmptyFrameState());
1901 void AstGraphBuilder::VisitAssignment(Assignment* expr) {
1902 DCHECK(expr->target()->IsValidReferenceExpression());
1904 // Left-hand side can only be a property, a global or a variable slot.
1905 Property* property = expr->target()->AsProperty();
1906 LhsKind assign_type = DetermineLhsKind(expr->target());
1908 // Evaluate LHS expression.
1909 switch (assign_type) {
1911 // Nothing to do here.
1913 case NAMED_PROPERTY:
1914 VisitForValue(property->obj());
1916 case KEYED_PROPERTY: {
1917 VisitForValue(property->obj());
1918 VisitForValue(property->key());
1923 // Evaluate the value and potentially handle compound assignments by loading
1924 // the left-hand side value and performing a binary operation.
1925 Node* frame_state_before_store = nullptr;
1926 bool needs_frame_state_before = (assign_type == KEYED_PROPERTY);
1927 if (expr->is_compound()) {
1928 Node* old_value = NULL;
1929 switch (assign_type) {
1931 VariableProxy* proxy = expr->target()->AsVariableProxy();
1932 VectorSlotPair pair =
1933 CreateVectorSlotPair(proxy->VariableFeedbackSlot());
1934 old_value = BuildVariableLoad(proxy->var(), expr->target()->id(), pair);
1937 case NAMED_PROPERTY: {
1938 Node* object = environment()->Top();
1939 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
1940 VectorSlotPair pair =
1941 CreateVectorSlotPair(property->PropertyFeedbackSlot());
1943 BuildNamedLoad(object, name, pair, property->PropertyFeedbackId());
1944 PrepareFrameState(old_value, property->LoadId(),
1945 OutputFrameStateCombine::Push());
1948 case KEYED_PROPERTY: {
1949 Node* key = environment()->Top();
1950 Node* object = environment()->Peek(1);
1951 VectorSlotPair pair =
1952 CreateVectorSlotPair(property->PropertyFeedbackSlot());
1954 BuildKeyedLoad(object, key, pair, property->PropertyFeedbackId());
1955 PrepareFrameState(old_value, property->LoadId(),
1956 OutputFrameStateCombine::Push());
1960 environment()->Push(old_value);
1961 VisitForValue(expr->value());
1962 Node* frame_state_before = environment()->Checkpoint(expr->value()->id());
1963 Node* right = environment()->Pop();
1964 Node* left = environment()->Pop();
1965 Node* value = BuildBinaryOp(left, right, expr->binary_op());
1966 PrepareFrameStateAfterAndBefore(value, expr->binary_operation()->id(),
1967 OutputFrameStateCombine::Push(),
1968 frame_state_before);
1969 environment()->Push(value);
1970 if (needs_frame_state_before) {
1971 frame_state_before_store = environment()->Checkpoint(
1972 expr->binary_operation()->id(), OutputFrameStateCombine::PokeAt(0));
1975 VisitForValue(expr->value());
1976 if (needs_frame_state_before) {
1977 // This frame state can be used for lazy-deopting from a to-number
1978 // conversion if we are storing into a typed array. It is important
1979 // that the frame state is usable for such lazy deopt (i.e., it has
1980 // to specify how to override the value before the conversion, in this
1981 // case, it overwrites the stack top).
1982 frame_state_before_store = environment()->Checkpoint(
1983 expr->value()->id(), OutputFrameStateCombine::PokeAt(0));
1988 Node* value = environment()->Pop();
1989 switch (assign_type) {
1991 Variable* variable = expr->target()->AsVariableProxy()->var();
1992 BuildVariableAssignment(variable, value, expr->op(), expr->id(),
1993 ast_context()->GetStateCombine());
1996 case NAMED_PROPERTY: {
1997 Node* object = environment()->Pop();
1998 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
2000 BuildNamedStore(object, name, value, expr->AssignmentFeedbackId());
2001 PrepareFrameState(store, expr->id(), ast_context()->GetStateCombine());
2004 case KEYED_PROPERTY: {
2005 Node* key = environment()->Pop();
2006 Node* object = environment()->Pop();
2008 BuildKeyedStore(object, key, value, expr->AssignmentFeedbackId());
2009 PrepareFrameStateAfterAndBefore(store, expr->id(),
2010 ast_context()->GetStateCombine(),
2011 frame_state_before_store);
2016 ast_context()->ProduceValue(value);
2020 void AstGraphBuilder::VisitYield(Yield* expr) {
2021 // TODO(turbofan): Implement yield here.
2023 ast_context()->ProduceValue(jsgraph()->UndefinedConstant());
2027 void AstGraphBuilder::VisitThrow(Throw* expr) {
2028 VisitForValue(expr->exception());
2029 Node* exception = environment()->Pop();
2030 Node* value = BuildThrowError(exception, expr->id());
2031 ast_context()->ProduceValue(value);
2035 void AstGraphBuilder::VisitProperty(Property* expr) {
2037 VectorSlotPair pair = CreateVectorSlotPair(expr->PropertyFeedbackSlot());
2038 if (expr->key()->IsPropertyName()) {
2039 VisitForValue(expr->obj());
2040 Node* object = environment()->Pop();
2041 Handle<Name> name = expr->key()->AsLiteral()->AsPropertyName();
2042 value = BuildNamedLoad(object, name, pair, expr->PropertyFeedbackId());
2044 VisitForValue(expr->obj());
2045 VisitForValue(expr->key());
2046 Node* key = environment()->Pop();
2047 Node* object = environment()->Pop();
2048 value = BuildKeyedLoad(object, key, pair, expr->PropertyFeedbackId());
2050 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
2051 ast_context()->ProduceValue(value);
2055 void AstGraphBuilder::VisitCall(Call* expr) {
2056 Expression* callee = expr->expression();
2057 Call::CallType call_type = expr->GetCallType(isolate());
2059 // Prepare the callee and the receiver to the function call. This depends on
2060 // the semantics of the underlying call type.
2061 CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS;
2062 Node* receiver_value = NULL;
2063 Node* callee_value = NULL;
2064 bool possibly_eval = false;
2065 switch (call_type) {
2066 case Call::GLOBAL_CALL: {
2067 VariableProxy* proxy = callee->AsVariableProxy();
2068 VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot());
2070 BuildVariableLoad(proxy->var(), expr->expression()->id(), pair);
2071 receiver_value = jsgraph()->UndefinedConstant();
2074 case Call::LOOKUP_SLOT_CALL: {
2075 Variable* variable = callee->AsVariableProxy()->var();
2076 DCHECK(variable->location() == Variable::LOOKUP);
2077 Node* name = jsgraph()->Constant(variable->name());
2078 const Operator* op =
2079 javascript()->CallRuntime(Runtime::kLoadLookupSlot, 2);
2080 Node* pair = NewNode(op, current_context(), name);
2081 callee_value = NewNode(common()->Projection(0), pair);
2082 receiver_value = NewNode(common()->Projection(1), pair);
2084 PrepareFrameState(pair, expr->EvalOrLookupId(),
2085 OutputFrameStateCombine::Push(2));
2088 case Call::PROPERTY_CALL: {
2089 Property* property = callee->AsProperty();
2090 VisitForValue(property->obj());
2091 Node* object = environment()->Top();
2092 VectorSlotPair pair =
2093 CreateVectorSlotPair(property->PropertyFeedbackSlot());
2094 if (property->key()->IsPropertyName()) {
2095 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
2097 BuildNamedLoad(object, name, pair, property->PropertyFeedbackId());
2099 VisitForValue(property->key());
2100 Node* key = environment()->Pop();
2102 BuildKeyedLoad(object, key, pair, property->PropertyFeedbackId());
2104 PrepareFrameState(callee_value, property->LoadId(),
2105 OutputFrameStateCombine::Push());
2106 receiver_value = environment()->Pop();
2107 // Note that a PROPERTY_CALL requires the receiver to be wrapped into an
2108 // object for sloppy callees. This could also be modeled explicitly here,
2109 // thereby obsoleting the need for a flag to the call operator.
2110 flags = CALL_AS_METHOD;
2113 case Call::SUPER_CALL:
2114 // TODO(dslomov): Implement super calls.
2115 callee_value = jsgraph()->UndefinedConstant();
2116 receiver_value = jsgraph()->UndefinedConstant();
2119 case Call::POSSIBLY_EVAL_CALL:
2120 possibly_eval = true;
2122 case Call::OTHER_CALL:
2123 VisitForValue(callee);
2124 callee_value = environment()->Pop();
2125 receiver_value = jsgraph()->UndefinedConstant();
2129 // The callee and the receiver both have to be pushed onto the operand stack
2130 // before arguments are being evaluated.
2131 environment()->Push(callee_value);
2132 environment()->Push(receiver_value);
2134 // Evaluate all arguments to the function call,
2135 ZoneList<Expression*>* args = expr->arguments();
2136 VisitForValues(args);
2138 // Resolve callee and receiver for a potential direct eval call. This block
2139 // will mutate the callee and receiver values pushed onto the environment.
2140 if (possibly_eval && args->length() > 0) {
2141 int arg_count = args->length();
2143 // Extract callee and source string from the environment.
2144 Node* callee = environment()->Peek(arg_count + 1);
2145 Node* source = environment()->Peek(arg_count - 1);
2147 // Create node to ask for help resolving potential eval call. This will
2148 // provide a fully resolved callee and the corresponding receiver.
2149 Node* function = GetFunctionClosure();
2150 Node* receiver = environment()->Lookup(info()->scope()->receiver());
2151 Node* language = jsgraph()->Constant(language_mode());
2152 Node* position = jsgraph()->Constant(info()->scope()->start_position());
2153 const Operator* op =
2154 javascript()->CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
2156 NewNode(op, callee, source, function, receiver, language, position);
2157 PrepareFrameState(pair, expr->EvalOrLookupId(),
2158 OutputFrameStateCombine::PokeAt(arg_count + 1));
2159 Node* new_callee = NewNode(common()->Projection(0), pair);
2160 Node* new_receiver = NewNode(common()->Projection(1), pair);
2162 // Patch callee and receiver on the environment.
2163 environment()->Poke(arg_count + 1, new_callee);
2164 environment()->Poke(arg_count + 0, new_receiver);
2167 // Create node to perform the function call.
2168 const Operator* call = javascript()->CallFunction(args->length() + 2, flags);
2169 Node* value = ProcessArguments(call, args->length() + 2);
2170 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
2171 ast_context()->ProduceValue(value);
2175 void AstGraphBuilder::VisitCallNew(CallNew* expr) {
2176 VisitForValue(expr->expression());
2178 // Evaluate all arguments to the construct call.
2179 ZoneList<Expression*>* args = expr->arguments();
2180 VisitForValues(args);
2182 // Create node to perform the construct call.
2183 const Operator* call = javascript()->CallConstruct(args->length() + 1);
2184 Node* value = ProcessArguments(call, args->length() + 1);
2185 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
2186 ast_context()->ProduceValue(value);
2190 void AstGraphBuilder::VisitCallJSRuntime(CallRuntime* expr) {
2191 Handle<String> name = expr->name();
2193 // The callee and the receiver both have to be pushed onto the operand stack
2194 // before arguments are being evaluated.
2195 CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS;
2196 Node* receiver_value = BuildLoadBuiltinsObject();
2197 VectorSlotPair pair = CreateVectorSlotPair(expr->CallRuntimeFeedbackSlot());
2198 Node* callee_value =
2199 BuildNamedLoad(receiver_value, name, pair, expr->CallRuntimeFeedbackId());
2200 // TODO(jarin): Find/create a bailout id to deoptimize to (crankshaft
2201 // refuses to optimize functions with jsruntime calls).
2202 PrepareFrameState(callee_value, BailoutId::None(),
2203 OutputFrameStateCombine::Push());
2204 environment()->Push(callee_value);
2205 environment()->Push(receiver_value);
2207 // Evaluate all arguments to the JS runtime call.
2208 ZoneList<Expression*>* args = expr->arguments();
2209 VisitForValues(args);
2211 // Create node to perform the JS runtime call.
2212 const Operator* call = javascript()->CallFunction(args->length() + 2, flags);
2213 Node* value = ProcessArguments(call, args->length() + 2);
2214 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
2215 ast_context()->ProduceValue(value);
2219 void AstGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
2220 const Runtime::Function* function = expr->function();
2222 // Handle calls to runtime functions implemented in JavaScript separately as
2223 // the call follows JavaScript ABI and the callee is statically unknown.
2224 if (expr->is_jsruntime()) {
2225 DCHECK(function == NULL && expr->name()->length() > 0);
2226 return VisitCallJSRuntime(expr);
2229 // Evaluate all arguments to the runtime call.
2230 ZoneList<Expression*>* args = expr->arguments();
2231 VisitForValues(args);
2233 // Create node to perform the runtime call.
2234 Runtime::FunctionId functionId = function->function_id;
2235 const Operator* call = javascript()->CallRuntime(functionId, args->length());
2236 Node* value = ProcessArguments(call, args->length());
2237 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
2238 ast_context()->ProduceValue(value);
2242 void AstGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
2243 switch (expr->op()) {
2245 return VisitDelete(expr);
2247 return VisitVoid(expr);
2249 return VisitTypeof(expr);
2251 return VisitNot(expr);
2258 void AstGraphBuilder::VisitCountOperation(CountOperation* expr) {
2259 DCHECK(expr->expression()->IsValidReferenceExpression());
2261 // Left-hand side can only be a property, a global or a variable slot.
2262 Property* property = expr->expression()->AsProperty();
2263 LhsKind assign_type = DetermineLhsKind(expr->expression());
2265 // Reserve space for result of postfix operation.
2266 bool is_postfix = expr->is_postfix() && !ast_context()->IsEffect();
2267 if (is_postfix) environment()->Push(jsgraph()->UndefinedConstant());
2269 // Evaluate LHS expression and get old value.
2270 Node* old_value = NULL;
2271 int stack_depth = -1;
2272 switch (assign_type) {
2274 VariableProxy* proxy = expr->expression()->AsVariableProxy();
2275 VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot());
2277 BuildVariableLoad(proxy->var(), expr->expression()->id(), pair);
2281 case NAMED_PROPERTY: {
2282 VisitForValue(property->obj());
2283 Node* object = environment()->Top();
2284 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
2285 VectorSlotPair pair =
2286 CreateVectorSlotPair(property->PropertyFeedbackSlot());
2288 BuildNamedLoad(object, name, pair, property->PropertyFeedbackId());
2289 PrepareFrameState(old_value, property->LoadId(),
2290 OutputFrameStateCombine::Push());
2294 case KEYED_PROPERTY: {
2295 VisitForValue(property->obj());
2296 VisitForValue(property->key());
2297 Node* key = environment()->Top();
2298 Node* object = environment()->Peek(1);
2299 VectorSlotPair pair =
2300 CreateVectorSlotPair(property->PropertyFeedbackSlot());
2302 BuildKeyedLoad(object, key, pair, property->PropertyFeedbackId());
2303 PrepareFrameState(old_value, property->LoadId(),
2304 OutputFrameStateCombine::Push());
2310 // Convert old value into a number.
2311 old_value = NewNode(javascript()->ToNumber(), old_value);
2312 PrepareFrameState(old_value, expr->ToNumberId(),
2313 OutputFrameStateCombine::Push());
2315 Node* frame_state_before_store =
2316 assign_type == KEYED_PROPERTY
2317 ? environment()->Checkpoint(expr->ToNumberId())
2320 // Save result for postfix expressions at correct stack depth.
2321 if (is_postfix) environment()->Poke(stack_depth, old_value);
2323 // Create node to perform +1/-1 operation.
2325 BuildBinaryOp(old_value, jsgraph()->OneConstant(), expr->binary_op());
2326 // This should never deoptimize because we have converted to number
2328 PrepareFrameStateAfterAndBefore(value, BailoutId::None(),
2329 OutputFrameStateCombine::Ignore(),
2330 jsgraph()->EmptyFrameState());
2333 switch (assign_type) {
2335 Variable* variable = expr->expression()->AsVariableProxy()->var();
2336 environment()->Push(value);
2337 BuildVariableAssignment(variable, value, expr->op(),
2338 expr->AssignmentId());
2339 environment()->Pop();
2342 case NAMED_PROPERTY: {
2343 Node* object = environment()->Pop();
2344 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
2346 BuildNamedStore(object, name, value, expr->CountStoreFeedbackId());
2347 environment()->Push(value);
2348 PrepareFrameState(store, expr->AssignmentId());
2349 environment()->Pop();
2352 case KEYED_PROPERTY: {
2353 Node* key = environment()->Pop();
2354 Node* object = environment()->Pop();
2356 BuildKeyedStore(object, key, value, expr->CountStoreFeedbackId());
2357 environment()->Push(value);
2358 PrepareFrameStateAfterAndBefore(store, expr->AssignmentId(),
2359 OutputFrameStateCombine::Ignore(),
2360 frame_state_before_store);
2361 environment()->Pop();
2366 // Restore old value for postfix expressions.
2367 if (is_postfix) value = environment()->Pop();
2369 ast_context()->ProduceValue(value);
2373 void AstGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
2374 switch (expr->op()) {
2376 return VisitComma(expr);
2379 return VisitLogicalExpression(expr);
2381 VisitForValue(expr->left());
2382 VisitForValue(expr->right());
2383 Node* frame_state_before = environment()->Checkpoint(expr->right()->id());
2384 Node* right = environment()->Pop();
2385 Node* left = environment()->Pop();
2386 Node* value = BuildBinaryOp(left, right, expr->op());
2387 PrepareFrameStateAfterAndBefore(value, expr->id(),
2388 ast_context()->GetStateCombine(),
2389 frame_state_before);
2390 ast_context()->ProduceValue(value);
2396 void AstGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
2398 switch (expr->op()) {
2400 op = javascript()->Equal();
2403 op = javascript()->NotEqual();
2405 case Token::EQ_STRICT:
2406 op = javascript()->StrictEqual();
2408 case Token::NE_STRICT:
2409 op = javascript()->StrictNotEqual();
2412 op = javascript()->LessThan();
2415 op = javascript()->GreaterThan();
2418 op = javascript()->LessThanOrEqual();
2421 op = javascript()->GreaterThanOrEqual();
2423 case Token::INSTANCEOF:
2424 op = javascript()->InstanceOf();
2427 op = javascript()->HasProperty();
2433 VisitForValue(expr->left());
2434 VisitForValue(expr->right());
2435 Node* right = environment()->Pop();
2436 Node* left = environment()->Pop();
2437 Node* value = NewNode(op, left, right);
2438 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
2439 ast_context()->ProduceValue(value);
2443 void AstGraphBuilder::VisitThisFunction(ThisFunction* expr) {
2444 Node* value = GetFunctionClosure();
2445 ast_context()->ProduceValue(value);
2449 void AstGraphBuilder::VisitSuperReference(SuperReference* expr) {
2450 // TODO(turbofan): Implement super here.
2452 ast_context()->ProduceValue(jsgraph()->UndefinedConstant());
2456 void AstGraphBuilder::VisitCaseClause(CaseClause* expr) { UNREACHABLE(); }
2459 void AstGraphBuilder::VisitDeclarations(ZoneList<Declaration*>* declarations) {
2460 DCHECK(globals()->empty());
2461 AstVisitor::VisitDeclarations(declarations);
2462 if (globals()->empty()) return;
2463 int array_index = 0;
2464 Handle<FixedArray> data = isolate()->factory()->NewFixedArray(
2465 static_cast<int>(globals()->size()), TENURED);
2466 for (Handle<Object> obj : *globals()) data->set(array_index++, *obj);
2467 int encoded_flags = DeclareGlobalsEvalFlag::encode(info()->is_eval()) |
2468 DeclareGlobalsNativeFlag::encode(info()->is_native()) |
2469 DeclareGlobalsLanguageMode::encode(language_mode());
2470 Node* flags = jsgraph()->Constant(encoded_flags);
2471 Node* pairs = jsgraph()->Constant(data);
2472 const Operator* op = javascript()->CallRuntime(Runtime::kDeclareGlobals, 3);
2473 NewNode(op, current_context(), pairs, flags);
2478 void AstGraphBuilder::VisitIfNotNull(Statement* stmt) {
2479 if (stmt == NULL) return;
2484 void AstGraphBuilder::VisitIterationBody(IterationStatement* stmt,
2485 LoopBuilder* loop) {
2486 ControlScopeForIteration scope(this, stmt, loop);
2487 Visit(stmt->body());
2491 void AstGraphBuilder::VisitDelete(UnaryOperation* expr) {
2493 if (expr->expression()->IsVariableProxy()) {
2494 // Delete of an unqualified identifier is only allowed in classic mode but
2495 // deleting "this" is allowed in all language modes.
2496 Variable* variable = expr->expression()->AsVariableProxy()->var();
2497 DCHECK(is_sloppy(language_mode()) || variable->is_this());
2498 value = BuildVariableDelete(variable, expr->id(),
2499 ast_context()->GetStateCombine());
2500 } else if (expr->expression()->IsProperty()) {
2501 Property* property = expr->expression()->AsProperty();
2502 VisitForValue(property->obj());
2503 VisitForValue(property->key());
2504 Node* key = environment()->Pop();
2505 Node* object = environment()->Pop();
2506 value = NewNode(javascript()->DeleteProperty(language_mode()), object, key);
2507 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
2509 VisitForEffect(expr->expression());
2510 value = jsgraph()->TrueConstant();
2512 ast_context()->ProduceValue(value);
2516 void AstGraphBuilder::VisitVoid(UnaryOperation* expr) {
2517 VisitForEffect(expr->expression());
2518 Node* value = jsgraph()->UndefinedConstant();
2519 ast_context()->ProduceValue(value);
2523 void AstGraphBuilder::VisitTypeof(UnaryOperation* expr) {
2525 if (expr->expression()->IsVariableProxy()) {
2526 // Typeof does not throw a reference error on global variables, hence we
2527 // perform a non-contextual load in case the operand is a variable proxy.
2528 VariableProxy* proxy = expr->expression()->AsVariableProxy();
2529 VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot());
2530 operand = BuildVariableLoad(proxy->var(), expr->expression()->id(), pair,
2533 VisitForValue(expr->expression());
2534 operand = environment()->Pop();
2536 Node* value = NewNode(javascript()->TypeOf(), operand);
2537 ast_context()->ProduceValue(value);
2541 void AstGraphBuilder::VisitNot(UnaryOperation* expr) {
2542 VisitForValue(expr->expression());
2543 Node* operand = environment()->Pop();
2544 // TODO(mstarzinger): Possible optimization when we are in effect context.
2545 Node* value = NewNode(javascript()->UnaryNot(), operand);
2546 ast_context()->ProduceValue(value);
2550 void AstGraphBuilder::VisitComma(BinaryOperation* expr) {
2551 VisitForEffect(expr->left());
2552 Visit(expr->right());
2553 ast_context()->ReplaceValue();
2557 void AstGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) {
2558 bool is_logical_and = expr->op() == Token::AND;
2559 IfBuilder compare_if(this);
2560 VisitForValue(expr->left());
2561 Node* condition = environment()->Top();
2562 compare_if.If(BuildToBoolean(condition));
2564 if (is_logical_and) {
2565 environment()->Pop();
2566 Visit(expr->right());
2567 } else if (ast_context()->IsEffect()) {
2568 environment()->Pop();
2571 if (!is_logical_and) {
2572 environment()->Pop();
2573 Visit(expr->right());
2574 } else if (ast_context()->IsEffect()) {
2575 environment()->Pop();
2578 ast_context()->ReplaceValue();
2582 LanguageMode AstGraphBuilder::language_mode() const {
2583 return info()->language_mode();
2587 VectorSlotPair AstGraphBuilder::CreateVectorSlotPair(
2588 FeedbackVectorICSlot slot) const {
2589 return VectorSlotPair(handle(info()->shared_info()->feedback_vector()), slot);
2593 Node* AstGraphBuilder::ProcessArguments(const Operator* op, int arity) {
2594 DCHECK(environment()->stack_height() >= arity);
2595 Node** all = info()->zone()->NewArray<Node*>(arity);
2596 for (int i = arity - 1; i >= 0; --i) {
2597 all[i] = environment()->Pop();
2599 Node* value = NewNode(op, arity, all);
2604 Node* AstGraphBuilder::BuildPatchReceiverToGlobalProxy(Node* receiver) {
2605 // Sloppy mode functions and builtins need to replace the receiver with the
2606 // global proxy when called as functions (without an explicit receiver
2607 // object). Otherwise there is nothing left to do here.
2608 if (is_strict(language_mode()) || info()->is_native()) return receiver;
2610 // There is no need to perform patching if the receiver is never used. Note
2611 // that scope predicates are purely syntactical, a call to eval might still
2612 // inspect the receiver value.
2613 if (!info()->scope()->uses_this() && !info()->scope()->inner_uses_this() &&
2614 !info()->scope()->calls_sloppy_eval()) {
2618 IfBuilder receiver_check(this);
2619 Node* undefined = jsgraph()->UndefinedConstant();
2620 Node* check = NewNode(javascript()->StrictEqual(), receiver, undefined);
2621 receiver_check.If(check);
2622 receiver_check.Then();
2623 Node* proxy = BuildLoadGlobalProxy();
2624 environment()->Push(proxy);
2625 receiver_check.Else();
2626 environment()->Push(receiver);
2627 receiver_check.End();
2628 return environment()->Pop();
2632 Node* AstGraphBuilder::BuildLocalFunctionContext(Node* context, Node* closure) {
2633 // Allocate a new local context.
2634 const Operator* op = javascript()->CreateFunctionContext();
2635 Node* local_context = NewNode(op, closure);
2637 // Copy parameters into context if necessary.
2638 int num_parameters = info()->scope()->num_parameters();
2639 for (int i = 0; i < num_parameters; i++) {
2640 Variable* variable = info()->scope()->parameter(i);
2641 if (!variable->IsContextSlot()) continue;
2642 // Temporary parameter node. The parameter indices are shifted by 1
2643 // (receiver is parameter index -1 but environment index 0).
2644 Node* parameter = NewNode(common()->Parameter(i + 1), graph()->start());
2645 // Context variable (at bottom of the context chain).
2646 DCHECK_EQ(0, info()->scope()->ContextChainLength(variable->scope()));
2647 const Operator* op = javascript()->StoreContext(0, variable->index());
2648 NewNode(op, local_context, parameter);
2651 return local_context;
2655 Node* AstGraphBuilder::BuildLocalBlockContext(Scope* scope) {
2656 Node* closure = GetFunctionClosure();
2658 // Allocate a new local context.
2659 const Operator* op = javascript()->CreateBlockContext();
2660 Node* scope_info = jsgraph()->Constant(scope->GetScopeInfo(info_->isolate()));
2661 Node* local_context = NewNode(op, scope_info, closure);
2663 return local_context;
2667 Node* AstGraphBuilder::BuildArgumentsObject(Variable* arguments) {
2668 if (arguments == NULL) return NULL;
2670 // Allocate and initialize a new arguments object.
2671 Node* callee = GetFunctionClosure();
2672 const Operator* op = javascript()->CallRuntime(Runtime::kNewArguments, 1);
2673 Node* object = NewNode(op, callee);
2675 // Assign the object to the arguments variable.
2676 DCHECK(arguments->IsContextSlot() || arguments->IsStackAllocated());
2677 // This should never lazy deopt, so it is fine to send invalid bailout id.
2678 BuildVariableAssignment(arguments, object, Token::ASSIGN, BailoutId::None());
2684 Node* AstGraphBuilder::BuildRestArgumentsArray(Variable* rest, int index) {
2685 if (rest == NULL) return NULL;
2688 const Operator* op = javascript()->CallRuntime(Runtime::kNewRestParamSlow, 1);
2689 Node* object = NewNode(op, jsgraph()->SmiConstant(index));
2691 // Assign the object to the rest array
2692 DCHECK(rest->IsContextSlot() || rest->IsStackAllocated());
2693 // This should never lazy deopt, so it is fine to send invalid bailout id.
2694 BuildVariableAssignment(rest, object, Token::ASSIGN, BailoutId::None());
2700 Node* AstGraphBuilder::BuildHoleCheckSilent(Node* value, Node* for_hole,
2702 IfBuilder hole_check(this);
2703 Node* the_hole = jsgraph()->TheHoleConstant();
2704 Node* check = NewNode(javascript()->StrictEqual(), value, the_hole);
2705 hole_check.If(check);
2707 environment()->Push(for_hole);
2709 environment()->Push(not_hole);
2711 return environment()->Pop();
2715 Node* AstGraphBuilder::BuildHoleCheckThrow(Node* value, Variable* variable,
2717 BailoutId bailout_id) {
2718 IfBuilder hole_check(this);
2719 Node* the_hole = jsgraph()->TheHoleConstant();
2720 Node* check = NewNode(javascript()->StrictEqual(), value, the_hole);
2721 hole_check.If(check);
2723 Node* error = BuildThrowReferenceError(variable, bailout_id);
2724 environment()->Push(error);
2726 environment()->Push(not_hole);
2728 return environment()->Pop();
2732 Node* AstGraphBuilder::BuildThrowIfStaticPrototype(Node* name,
2733 BailoutId bailout_id) {
2734 IfBuilder prototype_check(this);
2735 Node* prototype_string =
2736 jsgraph()->Constant(isolate()->factory()->prototype_string());
2737 Node* check = NewNode(javascript()->StrictEqual(), name, prototype_string);
2738 prototype_check.If(check);
2739 prototype_check.Then();
2741 const Operator* op =
2742 javascript()->CallRuntime(Runtime::kThrowStaticPrototypeError, 0);
2743 Node* call = NewNode(op);
2744 PrepareFrameState(call, bailout_id);
2745 environment()->Push(call);
2747 prototype_check.Else();
2748 environment()->Push(name);
2749 prototype_check.End();
2750 return environment()->Pop();
2754 Node* AstGraphBuilder::BuildVariableLoad(Variable* variable,
2755 BailoutId bailout_id,
2756 const VectorSlotPair& feedback,
2757 ContextualMode contextual_mode) {
2758 Node* the_hole = jsgraph()->TheHoleConstant();
2759 VariableMode mode = variable->mode();
2760 switch (variable->location()) {
2761 case Variable::UNALLOCATED: {
2762 // Global var, const, or let variable.
2763 Node* global = BuildLoadGlobalObject();
2764 Handle<Name> name = variable->name();
2765 Node* node = BuildNamedLoad(global, name, feedback,
2766 TypeFeedbackId::None(), contextual_mode);
2767 PrepareFrameState(node, bailout_id, OutputFrameStateCombine::Push());
2770 case Variable::PARAMETER:
2771 case Variable::LOCAL: {
2772 // Local var, const, or let variable.
2773 Node* value = environment()->Lookup(variable);
2774 if (mode == CONST_LEGACY) {
2775 // Perform check for uninitialized legacy const variables.
2776 if (value->op() == the_hole->op()) {
2777 value = jsgraph()->UndefinedConstant();
2778 } else if (value->opcode() == IrOpcode::kPhi) {
2779 Node* undefined = jsgraph()->UndefinedConstant();
2780 value = BuildHoleCheckSilent(value, undefined, value);
2782 } else if (mode == LET || mode == CONST) {
2783 // Perform check for uninitialized let/const variables.
2784 if (value->op() == the_hole->op()) {
2785 value = BuildThrowReferenceError(variable, bailout_id);
2786 } else if (value->opcode() == IrOpcode::kPhi) {
2787 value = BuildHoleCheckThrow(value, variable, value, bailout_id);
2792 case Variable::CONTEXT: {
2793 // Context variable (potentially up the context chain).
2794 int depth = current_scope()->ContextChainLength(variable->scope());
2795 bool immutable = variable->maybe_assigned() == kNotAssigned;
2796 const Operator* op =
2797 javascript()->LoadContext(depth, variable->index(), immutable);
2798 Node* value = NewNode(op, current_context());
2799 // TODO(titzer): initialization checks are redundant for already
2800 // initialized immutable context loads, but only specialization knows.
2801 // Maybe specializer should be a parameter to the graph builder?
2802 if (mode == CONST_LEGACY) {
2803 // Perform check for uninitialized legacy const variables.
2804 Node* undefined = jsgraph()->UndefinedConstant();
2805 value = BuildHoleCheckSilent(value, undefined, value);
2806 } else if (mode == LET || mode == CONST) {
2807 // Perform check for uninitialized let/const variables.
2808 value = BuildHoleCheckThrow(value, variable, value, bailout_id);
2812 case Variable::LOOKUP: {
2813 // Dynamic lookup of context variable (anywhere in the chain).
2814 Node* name = jsgraph()->Constant(variable->name());
2815 Runtime::FunctionId function_id =
2816 (contextual_mode == CONTEXTUAL)
2817 ? Runtime::kLoadLookupSlot
2818 : Runtime::kLoadLookupSlotNoReferenceError;
2819 const Operator* op = javascript()->CallRuntime(function_id, 2);
2820 Node* pair = NewNode(op, current_context(), name);
2821 PrepareFrameState(pair, bailout_id, OutputFrameStateCombine::Push(1));
2822 return NewNode(common()->Projection(0), pair);
2830 Node* AstGraphBuilder::BuildVariableDelete(
2831 Variable* variable, BailoutId bailout_id,
2832 OutputFrameStateCombine state_combine) {
2833 switch (variable->location()) {
2834 case Variable::UNALLOCATED: {
2835 // Global var, const, or let variable.
2836 Node* global = BuildLoadGlobalObject();
2837 Node* name = jsgraph()->Constant(variable->name());
2838 const Operator* op = javascript()->DeleteProperty(language_mode());
2839 Node* result = NewNode(op, global, name);
2840 PrepareFrameState(result, bailout_id, state_combine);
2843 case Variable::PARAMETER:
2844 case Variable::LOCAL:
2845 case Variable::CONTEXT:
2846 // Local var, const, or let variable or context variable.
2847 return jsgraph()->BooleanConstant(variable->is_this());
2848 case Variable::LOOKUP: {
2849 // Dynamic lookup of context variable (anywhere in the chain).
2850 Node* name = jsgraph()->Constant(variable->name());
2851 const Operator* op =
2852 javascript()->CallRuntime(Runtime::kDeleteLookupSlot, 2);
2853 Node* result = NewNode(op, current_context(), name);
2854 PrepareFrameState(result, bailout_id, state_combine);
2863 Node* AstGraphBuilder::BuildVariableAssignment(
2864 Variable* variable, Node* value, Token::Value op, BailoutId bailout_id,
2865 OutputFrameStateCombine combine) {
2866 Node* the_hole = jsgraph()->TheHoleConstant();
2867 VariableMode mode = variable->mode();
2868 switch (variable->location()) {
2869 case Variable::UNALLOCATED: {
2870 // Global var, const, or let variable.
2871 Node* global = BuildLoadGlobalObject();
2872 Handle<Name> name = variable->name();
2874 BuildNamedStore(global, name, value, TypeFeedbackId::None());
2875 PrepareFrameState(store, bailout_id, combine);
2878 case Variable::PARAMETER:
2879 case Variable::LOCAL:
2880 // Local var, const, or let variable.
2881 if (mode == CONST_LEGACY && op == Token::INIT_CONST_LEGACY) {
2882 // Perform an initialization check for legacy const variables.
2883 Node* current = environment()->Lookup(variable);
2884 if (current->op() != the_hole->op()) {
2885 value = BuildHoleCheckSilent(current, value, current);
2887 } else if (mode == CONST_LEGACY && op != Token::INIT_CONST_LEGACY) {
2888 // Non-initializing assignment to legacy const is
2889 // - exception in strict mode.
2890 // - ignored in sloppy mode.
2891 if (is_strict(language_mode())) {
2892 return BuildThrowConstAssignError(bailout_id);
2895 } else if (mode == LET && op != Token::INIT_LET) {
2896 // Perform an initialization check for let declared variables.
2897 // Also note that the dynamic hole-check is only done to ensure that
2898 // this does not break in the presence of do-expressions within the
2899 // temporal dead zone of a let declared variable.
2900 Node* current = environment()->Lookup(variable);
2901 if (current->op() == the_hole->op()) {
2902 value = BuildThrowReferenceError(variable, bailout_id);
2903 } else if (value->opcode() == IrOpcode::kPhi) {
2904 value = BuildHoleCheckThrow(current, variable, value, bailout_id);
2906 } else if (mode == CONST && op != Token::INIT_CONST) {
2907 // Assignment to const is exception in all modes.
2908 Node* current = environment()->Lookup(variable);
2909 if (current->op() == the_hole->op()) {
2910 return BuildThrowReferenceError(variable, bailout_id);
2911 } else if (value->opcode() == IrOpcode::kPhi) {
2912 BuildHoleCheckThrow(current, variable, value, bailout_id);
2914 return BuildThrowConstAssignError(bailout_id);
2916 environment()->Bind(variable, value);
2918 case Variable::CONTEXT: {
2919 // Context variable (potentially up the context chain).
2920 int depth = current_scope()->ContextChainLength(variable->scope());
2921 if (mode == CONST_LEGACY && op == Token::INIT_CONST_LEGACY) {
2922 // Perform an initialization check for legacy const variables.
2923 const Operator* op =
2924 javascript()->LoadContext(depth, variable->index(), false);
2925 Node* current = NewNode(op, current_context());
2926 value = BuildHoleCheckSilent(current, value, current);
2927 } else if (mode == CONST_LEGACY && op != Token::INIT_CONST_LEGACY) {
2928 // Non-initializing assignment to legacy const is
2929 // - exception in strict mode.
2930 // - ignored in sloppy mode.
2931 if (is_strict(language_mode())) {
2932 return BuildThrowConstAssignError(bailout_id);
2935 } else if (mode == LET && op != Token::INIT_LET) {
2936 // Perform an initialization check for let declared variables.
2937 const Operator* op =
2938 javascript()->LoadContext(depth, variable->index(), false);
2939 Node* current = NewNode(op, current_context());
2940 value = BuildHoleCheckThrow(current, variable, value, bailout_id);
2941 } else if (mode == CONST && op != Token::INIT_CONST) {
2942 // Assignment to const is exception in all modes.
2943 const Operator* op =
2944 javascript()->LoadContext(depth, variable->index(), false);
2945 Node* current = NewNode(op, current_context());
2946 BuildHoleCheckThrow(current, variable, value, bailout_id);
2947 return BuildThrowConstAssignError(bailout_id);
2949 const Operator* op = javascript()->StoreContext(depth, variable->index());
2950 return NewNode(op, current_context(), value);
2952 case Variable::LOOKUP: {
2953 // Dynamic lookup of context variable (anywhere in the chain).
2954 Node* name = jsgraph()->Constant(variable->name());
2955 Node* language = jsgraph()->Constant(language_mode());
2956 // TODO(mstarzinger): Use Runtime::kInitializeLegacyConstLookupSlot for
2957 // initializations of const declarations.
2958 const Operator* op =
2959 javascript()->CallRuntime(Runtime::kStoreLookupSlot, 4);
2960 Node* store = NewNode(op, value, current_context(), name, language);
2961 PrepareFrameState(store, bailout_id, combine);
2970 static inline Node* Record(JSTypeFeedbackTable* js_type_feedback, Node* node,
2971 TypeFeedbackId id) {
2972 if (js_type_feedback) js_type_feedback->Record(node, id);
2977 Node* AstGraphBuilder::BuildKeyedLoad(Node* object, Node* key,
2978 const VectorSlotPair& feedback,
2979 TypeFeedbackId id) {
2980 const Operator* op = javascript()->LoadProperty(feedback);
2981 return Record(js_type_feedback_, NewNode(op, object, key), id);
2985 Node* AstGraphBuilder::BuildNamedLoad(Node* object, Handle<Name> name,
2986 const VectorSlotPair& feedback,
2987 TypeFeedbackId id, ContextualMode mode) {
2988 const Operator* op =
2989 javascript()->LoadNamed(MakeUnique(name), feedback, mode);
2990 return Record(js_type_feedback_, NewNode(op, object), id);
2994 Node* AstGraphBuilder::BuildKeyedStore(Node* object, Node* key, Node* value,
2995 TypeFeedbackId id) {
2996 const Operator* op = javascript()->StoreProperty(language_mode());
2997 return Record(js_type_feedback_, NewNode(op, object, key, value), id);
3001 Node* AstGraphBuilder::BuildNamedStore(Node* object, Handle<Name> name,
3002 Node* value, TypeFeedbackId id) {
3003 const Operator* op =
3004 javascript()->StoreNamed(language_mode(), MakeUnique(name));
3005 return Record(js_type_feedback_, NewNode(op, object, value), id);
3009 Node* AstGraphBuilder::BuildLoadObjectField(Node* object, int offset) {
3010 return NewNode(jsgraph()->machine()->Load(kMachAnyTagged), object,
3011 jsgraph()->IntPtrConstant(offset - kHeapObjectTag));
3015 Node* AstGraphBuilder::BuildLoadBuiltinsObject() {
3016 Node* global = BuildLoadGlobalObject();
3018 BuildLoadObjectField(global, JSGlobalObject::kBuiltinsOffset);
3023 Node* AstGraphBuilder::BuildLoadGlobalObject() {
3024 const Operator* load_op =
3025 javascript()->LoadContext(0, Context::GLOBAL_OBJECT_INDEX, true);
3026 return NewNode(load_op, function_context_.get());
3030 Node* AstGraphBuilder::BuildLoadGlobalProxy() {
3031 Node* global = BuildLoadGlobalObject();
3033 BuildLoadObjectField(global, JSGlobalObject::kGlobalProxyOffset);
3038 Node* AstGraphBuilder::BuildLoadExternal(ExternalReference reference,
3040 return NewNode(jsgraph()->machine()->Load(type),
3041 jsgraph()->ExternalConstant(reference),
3042 jsgraph()->IntPtrConstant(0));
3046 Node* AstGraphBuilder::BuildStoreExternal(ExternalReference reference,
3047 MachineType type, Node* value) {
3048 StoreRepresentation representation(type, kNoWriteBarrier);
3049 return NewNode(jsgraph()->machine()->Store(representation),
3050 jsgraph()->ExternalConstant(reference),
3051 jsgraph()->IntPtrConstant(0), value);
3055 Node* AstGraphBuilder::BuildToBoolean(Node* input) {
3056 // TODO(titzer): This should be in a JSOperatorReducer.
3057 switch (input->opcode()) {
3058 case IrOpcode::kInt32Constant:
3059 return jsgraph_->BooleanConstant(!Int32Matcher(input).Is(0));
3060 case IrOpcode::kFloat64Constant:
3061 return jsgraph_->BooleanConstant(!Float64Matcher(input).Is(0));
3062 case IrOpcode::kNumberConstant:
3063 return jsgraph_->BooleanConstant(!NumberMatcher(input).Is(0));
3064 case IrOpcode::kHeapConstant: {
3065 Handle<Object> object = HeapObjectMatcher<Object>(input).Value().handle();
3066 return jsgraph_->BooleanConstant(object->BooleanValue());
3071 if (NodeProperties::IsTyped(input)) {
3072 Type* upper = NodeProperties::GetBounds(input).upper;
3073 if (upper->Is(Type::Boolean())) return input;
3076 return NewNode(javascript()->ToBoolean(), input);
3080 Node* AstGraphBuilder::BuildToName(Node* input, BailoutId bailout_id) {
3081 // TODO(turbofan): Possible optimization is to NOP on name constants. But the
3082 // same caveat as with BuildToBoolean applies, and it should be factored out
3083 // into a JSOperatorReducer.
3084 Node* name = NewNode(javascript()->ToName(), input);
3085 PrepareFrameState(name, bailout_id);
3090 Node* AstGraphBuilder::BuildSetHomeObject(Node* value, Node* home_object,
3092 if (!FunctionLiteral::NeedsHomeObject(expr)) return value;
3093 Handle<Name> name = isolate()->factory()->home_object_symbol();
3095 BuildNamedStore(value, name, home_object, TypeFeedbackId::None());
3096 PrepareFrameState(store, BailoutId::None());
3101 Node* AstGraphBuilder::BuildThrowError(Node* exception, BailoutId bailout_id) {
3102 const Operator* op = javascript()->CallRuntime(Runtime::kThrow, 1);
3103 Node* call = NewNode(op, exception);
3104 PrepareFrameState(call, bailout_id);
3109 Node* AstGraphBuilder::BuildThrowReferenceError(Variable* variable,
3110 BailoutId bailout_id) {
3111 Node* variable_name = jsgraph()->Constant(variable->name());
3112 const Operator* op =
3113 javascript()->CallRuntime(Runtime::kThrowReferenceError, 1);
3114 Node* call = NewNode(op, variable_name);
3115 PrepareFrameState(call, bailout_id);
3120 Node* AstGraphBuilder::BuildThrowConstAssignError(BailoutId bailout_id) {
3121 const Operator* op =
3122 javascript()->CallRuntime(Runtime::kThrowConstAssignError, 0);
3123 Node* call = NewNode(op);
3124 PrepareFrameState(call, bailout_id);
3129 Node* AstGraphBuilder::BuildReturn(Node* return_value) {
3130 Node* control = NewNode(common()->Return(), return_value);
3131 UpdateControlDependencyToLeaveFunction(control);
3136 Node* AstGraphBuilder::BuildThrow(Node* exception_value) {
3137 NewNode(javascript()->CallRuntime(Runtime::kReThrow, 1), exception_value);
3138 Node* control = NewNode(common()->Throw(), exception_value);
3139 UpdateControlDependencyToLeaveFunction(control);
3144 Node* AstGraphBuilder::BuildBinaryOp(Node* left, Node* right, Token::Value op) {
3145 const Operator* js_op;
3148 js_op = javascript()->BitwiseOr();
3150 case Token::BIT_AND:
3151 js_op = javascript()->BitwiseAnd();
3153 case Token::BIT_XOR:
3154 js_op = javascript()->BitwiseXor();
3157 js_op = javascript()->ShiftLeft();
3160 js_op = javascript()->ShiftRight();
3163 js_op = javascript()->ShiftRightLogical();
3166 js_op = javascript()->Add();
3169 js_op = javascript()->Subtract();
3172 js_op = javascript()->Multiply();
3175 js_op = javascript()->Divide();
3178 js_op = javascript()->Modulus();
3184 return NewNode(js_op, left, right);
3188 bool AstGraphBuilder::CheckOsrEntry(IterationStatement* stmt) {
3189 if (info()->osr_ast_id() == stmt->OsrEntryId()) {
3190 info()->set_osr_expr_stack_height(std::max(
3191 environment()->stack_height(), info()->osr_expr_stack_height()));
3198 void AstGraphBuilder::PrepareFrameState(Node* node, BailoutId ast_id,
3199 OutputFrameStateCombine combine) {
3200 if (OperatorProperties::GetFrameStateInputCount(node->op()) > 0) {
3201 DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
3203 DCHECK_EQ(IrOpcode::kDead,
3204 NodeProperties::GetFrameStateInput(node, 0)->opcode());
3205 NodeProperties::ReplaceFrameStateInput(
3206 node, 0, environment()->Checkpoint(ast_id, combine));
3211 void AstGraphBuilder::PrepareFrameStateAfterAndBefore(
3212 Node* node, BailoutId ast_id, OutputFrameStateCombine combine,
3213 Node* frame_state_before) {
3214 if (OperatorProperties::GetFrameStateInputCount(node->op()) > 0) {
3215 DCHECK_EQ(2, OperatorProperties::GetFrameStateInputCount(node->op()));
3217 DCHECK_EQ(IrOpcode::kDead,
3218 NodeProperties::GetFrameStateInput(node, 0)->opcode());
3219 NodeProperties::ReplaceFrameStateInput(
3220 node, 0, environment()->Checkpoint(ast_id, combine));
3222 DCHECK_EQ(IrOpcode::kDead,
3223 NodeProperties::GetFrameStateInput(node, 1)->opcode());
3224 NodeProperties::ReplaceFrameStateInput(node, 1, frame_state_before);
3229 BitVector* AstGraphBuilder::GetVariablesAssignedInLoop(
3230 IterationStatement* stmt) {
3231 if (loop_assignment_analysis_ == NULL) return NULL;
3232 return loop_assignment_analysis_->GetVariablesAssignedInLoop(stmt);
3236 Node** AstGraphBuilder::EnsureInputBufferSize(int size) {
3237 if (size > input_buffer_size_) {
3238 size = size + kInputBufferSizeIncrement + input_buffer_size_;
3239 input_buffer_ = local_zone()->NewArray<Node*>(size);
3240 input_buffer_size_ = size;
3242 return input_buffer_;
3246 Node* AstGraphBuilder::MakeNode(const Operator* op, int value_input_count,
3247 Node** value_inputs, bool incomplete) {
3248 DCHECK(op->ValueInputCount() == value_input_count);
3250 bool has_context = OperatorProperties::HasContextInput(op);
3251 int frame_state_count = OperatorProperties::GetFrameStateInputCount(op);
3252 bool has_control = op->ControlInputCount() == 1;
3253 bool has_effect = op->EffectInputCount() == 1;
3255 DCHECK(op->ControlInputCount() < 2);
3256 DCHECK(op->EffectInputCount() < 2);
3258 Node* result = NULL;
3259 if (!has_context && frame_state_count == 0 && !has_control && !has_effect) {
3260 result = graph()->NewNode(op, value_input_count, value_inputs, incomplete);
3262 bool inside_try_scope = try_nesting_level_ > 0;
3263 int input_count_with_deps = value_input_count;
3264 if (has_context) ++input_count_with_deps;
3265 input_count_with_deps += frame_state_count;
3266 if (has_control) ++input_count_with_deps;
3267 if (has_effect) ++input_count_with_deps;
3268 Node** buffer = EnsureInputBufferSize(input_count_with_deps);
3269 memcpy(buffer, value_inputs, kPointerSize * value_input_count);
3270 Node** current_input = buffer + value_input_count;
3272 *current_input++ = current_context();
3274 for (int i = 0; i < frame_state_count; i++) {
3275 // The frame state will be inserted later. Here we misuse
3276 // the {DeadControl} node as a sentinel to be later overwritten
3277 // with the real frame state.
3278 *current_input++ = jsgraph()->DeadControl();
3281 *current_input++ = environment_->GetEffectDependency();
3284 *current_input++ = environment_->GetControlDependency();
3286 result = graph()->NewNode(op, input_count_with_deps, buffer, incomplete);
3288 environment_->UpdateEffectDependency(result);
3290 if (!environment()->IsMarkedAsUnreachable()) {
3291 // Update the current control dependency for control-producing nodes.
3292 if (NodeProperties::IsControl(result)) {
3293 environment_->UpdateControlDependency(result);
3295 // Add implicit exception continuation for throwing nodes.
3296 if (!result->op()->HasProperty(Operator::kNoThrow) && inside_try_scope) {
3297 Node* on_exception = graph()->NewNode(common()->IfException(), result);
3298 environment_->UpdateControlDependency(on_exception);
3299 execution_control()->ThrowValue(result);
3301 // Add implicit success continuation for throwing nodes.
3302 if (!result->op()->HasProperty(Operator::kNoThrow)) {
3303 Node* on_success = graph()->NewNode(common()->IfSuccess(), result);
3304 environment_->UpdateControlDependency(on_success);
3313 void AstGraphBuilder::UpdateControlDependencyToLeaveFunction(Node* exit) {
3314 if (environment()->IsMarkedAsUnreachable()) return;
3315 if (exit_control() != NULL) {
3316 exit = MergeControl(exit_control(), exit);
3318 environment()->MarkAsUnreachable();
3319 set_exit_control(exit);
3323 void AstGraphBuilder::Environment::Merge(Environment* other) {
3324 DCHECK(values_.size() == other->values_.size());
3325 // TODO(titzer): make context stack heights match.
3326 DCHECK(contexts_.size() <= other->contexts_.size());
3328 // Nothing to do if the other environment is dead.
3329 if (other->IsMarkedAsUnreachable()) return;
3331 // Resurrect a dead environment by copying the contents of the other one and
3332 // placing a singleton merge as the new control dependency.
3333 if (this->IsMarkedAsUnreachable()) {
3334 Node* other_control = other->control_dependency_;
3335 Node* inputs[] = {other_control};
3336 liveness_block_ = other->liveness_block_;
3337 control_dependency_ =
3338 graph()->NewNode(common()->Merge(1), arraysize(inputs), inputs, true);
3339 effect_dependency_ = other->effect_dependency_;
3340 values_ = other->values_;
3341 // TODO(titzer): make context stack heights match.
3342 size_t min = std::min(contexts_.size(), other->contexts_.size());
3343 contexts_ = other->contexts_;
3344 contexts_.resize(min, nullptr);
3348 // Record the merge for the local variable liveness calculation.
3349 // Unfortunately, we have to mirror the logic in the MergeControl method:
3350 // connect before merge or loop, or create a new merge otherwise.
3351 if (FLAG_analyze_environment_liveness) {
3352 if (GetControlDependency()->opcode() != IrOpcode::kLoop &&
3353 GetControlDependency()->opcode() != IrOpcode::kMerge) {
3355 builder_->liveness_analyzer()->NewBlock(liveness_block());
3357 liveness_block()->AddPredecessor(other->liveness_block());
3360 // Create a merge of the control dependencies of both environments and update
3361 // the current environment's control dependency accordingly.
3362 Node* control = builder_->MergeControl(this->GetControlDependency(),
3363 other->GetControlDependency());
3364 UpdateControlDependency(control);
3366 // Create a merge of the effect dependencies of both environments and update
3367 // the current environment's effect dependency accordingly.
3368 Node* effect = builder_->MergeEffect(this->GetEffectDependency(),
3369 other->GetEffectDependency(), control);
3370 UpdateEffectDependency(effect);
3372 // Introduce Phi nodes for values that have differing input at merge points,
3373 // potentially extending an existing Phi node if possible.
3374 for (int i = 0; i < static_cast<int>(values_.size()); ++i) {
3375 values_[i] = builder_->MergeValue(values_[i], other->values_[i], control);
3377 for (int i = 0; i < static_cast<int>(contexts_.size()); ++i) {
3379 builder_->MergeValue(contexts_[i], other->contexts_[i], control);
3384 void AstGraphBuilder::Environment::PrepareForLoop(BitVector* assigned,
3386 int size = static_cast<int>(values()->size());
3388 Node* control = builder_->NewLoop();
3389 if (assigned == nullptr) {
3390 // Assume that everything is updated in the loop.
3391 for (int i = 0; i < size; ++i) {
3392 values()->at(i) = builder_->NewPhi(1, values()->at(i), control);
3395 // Only build phis for those locals assigned in this loop.
3396 for (int i = 0; i < size; ++i) {
3397 if (i < assigned->length() && !assigned->Contains(i)) continue;
3398 Node* phi = builder_->NewPhi(1, values()->at(i), control);
3399 values()->at(i) = phi;
3402 Node* effect = builder_->NewEffectPhi(1, GetEffectDependency(), control);
3403 UpdateEffectDependency(effect);
3405 if (builder_->info()->is_osr()) {
3406 // Introduce phis for all context values in the case of an OSR graph.
3407 for (int i = 0; i < static_cast<int>(contexts()->size()); ++i) {
3408 Node* val = contexts()->at(i);
3409 if (!IrOpcode::IsConstantOpcode(val->opcode())) {
3410 contexts()->at(i) = builder_->NewPhi(1, val, control);
3416 // Merge OSR values as inputs to the phis of the loop.
3417 Graph* graph = builder_->graph();
3418 Node* osr_loop_entry = builder_->graph()->NewNode(
3419 builder_->common()->OsrLoopEntry(), graph->start(), graph->start());
3421 builder_->MergeControl(control, osr_loop_entry);
3422 builder_->MergeEffect(effect, osr_loop_entry, control);
3424 for (int i = 0; i < size; ++i) {
3425 Node* val = values()->at(i);
3426 if (!IrOpcode::IsConstantOpcode(val->opcode())) {
3428 graph->NewNode(builder_->common()->OsrValue(i), osr_loop_entry);
3429 values()->at(i) = builder_->MergeValue(val, osr_value, control);
3433 // Rename all the contexts in the environment.
3434 // The innermost context is the OSR value, and the outer contexts are
3435 // reconstructed by dynamically walking up the context chain.
3436 Node* osr_context = nullptr;
3437 const Operator* op =
3438 builder_->javascript()->LoadContext(0, Context::PREVIOUS_INDEX, true);
3439 int last = static_cast<int>(contexts()->size() - 1);
3440 for (int i = last; i >= 0; i--) {
3441 Node* val = contexts()->at(i);
3442 if (!IrOpcode::IsConstantOpcode(val->opcode())) {
3443 osr_context = (i == last) ? builder_->NewCurrentContextOsrValue()
3444 : graph->NewNode(op, osr_context, osr_context,
3446 contexts()->at(i) = builder_->MergeValue(val, osr_context, control);
3455 Node* AstGraphBuilder::NewPhi(int count, Node* input, Node* control) {
3456 const Operator* phi_op = common()->Phi(kMachAnyTagged, count);
3457 Node** buffer = EnsureInputBufferSize(count + 1);
3458 MemsetPointer(buffer, input, count);
3459 buffer[count] = control;
3460 return graph()->NewNode(phi_op, count + 1, buffer, true);
3464 // TODO(mstarzinger): Revisit this once we have proper effect states.
3465 Node* AstGraphBuilder::NewEffectPhi(int count, Node* input, Node* control) {
3466 const Operator* phi_op = common()->EffectPhi(count);
3467 Node** buffer = EnsureInputBufferSize(count + 1);
3468 MemsetPointer(buffer, input, count);
3469 buffer[count] = control;
3470 return graph()->NewNode(phi_op, count + 1, buffer, true);
3474 Node* AstGraphBuilder::MergeControl(Node* control, Node* other) {
3475 int inputs = control->op()->ControlInputCount() + 1;
3476 if (control->opcode() == IrOpcode::kLoop) {
3477 // Control node for loop exists, add input.
3478 const Operator* op = common()->Loop(inputs);
3479 control->AppendInput(graph_zone(), other);
3480 control->set_op(op);
3481 } else if (control->opcode() == IrOpcode::kMerge) {
3482 // Control node for merge exists, add input.
3483 const Operator* op = common()->Merge(inputs);
3484 control->AppendInput(graph_zone(), other);
3485 control->set_op(op);
3487 // Control node is a singleton, introduce a merge.
3488 const Operator* op = common()->Merge(inputs);
3489 Node* inputs[] = {control, other};
3490 control = graph()->NewNode(op, arraysize(inputs), inputs, true);
3496 Node* AstGraphBuilder::MergeEffect(Node* value, Node* other, Node* control) {
3497 int inputs = control->op()->ControlInputCount();
3498 if (value->opcode() == IrOpcode::kEffectPhi &&
3499 NodeProperties::GetControlInput(value) == control) {
3500 // Phi already exists, add input.
3501 value->set_op(common()->EffectPhi(inputs));
3502 value->InsertInput(graph_zone(), inputs - 1, other);
3503 } else if (value != other) {
3504 // Phi does not exist yet, introduce one.
3505 value = NewEffectPhi(inputs, value, control);
3506 value->ReplaceInput(inputs - 1, other);
3512 Node* AstGraphBuilder::MergeValue(Node* value, Node* other, Node* control) {
3513 int inputs = control->op()->ControlInputCount();
3514 if (value->opcode() == IrOpcode::kPhi &&
3515 NodeProperties::GetControlInput(value) == control) {
3516 // Phi already exists, add input.
3517 value->set_op(common()->Phi(kMachAnyTagged, inputs));
3518 value->InsertInput(graph_zone(), inputs - 1, other);
3519 } else if (value != other) {
3520 // Phi does not exist yet, introduce one.
3521 value = NewPhi(inputs, value, control);
3522 value->ReplaceInput(inputs - 1, other);
3527 } // namespace compiler
3528 } // namespace internal