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/linkage.h"
11 #include "src/compiler/machine-operator.h"
12 #include "src/compiler/node-matchers.h"
13 #include "src/compiler/node-properties.h"
14 #include "src/compiler/operator-properties.h"
15 #include "src/full-codegen.h"
16 #include "src/parser.h"
17 #include "src/scopes.h"
24 // Each expression in the AST is evaluated in a specific context. This context
25 // decides how the evaluation result is passed up the visitor.
26 class AstGraphBuilder::AstContext BASE_EMBEDDED {
28 bool IsEffect() const { return kind_ == Expression::kEffect; }
29 bool IsValue() const { return kind_ == Expression::kValue; }
30 bool IsTest() const { return kind_ == Expression::kTest; }
32 // Determines how to combine the frame state with the value
33 // that is about to be plugged into this AstContext.
34 OutputFrameStateCombine GetStateCombine() {
35 return IsEffect() ? OutputFrameStateCombine::Ignore()
36 : OutputFrameStateCombine::Push();
39 // Plug a node into this expression context. Call this function in tail
40 // position in the Visit functions for expressions.
41 virtual void ProduceValue(Node* value) = 0;
43 // Unplugs a node from this expression context. Call this to retrieve the
44 // result of another Visit function that already plugged the context.
45 virtual Node* ConsumeValue() = 0;
47 // Shortcut for "context->ProduceValue(context->ConsumeValue())".
48 void ReplaceValue() { ProduceValue(ConsumeValue()); }
51 AstContext(AstGraphBuilder* owner, Expression::Context kind);
52 virtual ~AstContext();
54 AstGraphBuilder* owner() const { return owner_; }
55 Environment* environment() const { return owner_->environment(); }
57 // We want to be able to assert, in a context-specific way, that the stack
58 // height makes sense when the context is filled.
64 Expression::Context kind_;
65 AstGraphBuilder* owner_;
70 // Context to evaluate expression for its side effects only.
71 class AstGraphBuilder::AstEffectContext FINAL : public AstContext {
73 explicit AstEffectContext(AstGraphBuilder* owner)
74 : AstContext(owner, Expression::kEffect) {}
75 ~AstEffectContext() FINAL;
76 void ProduceValue(Node* value) FINAL;
77 Node* ConsumeValue() FINAL;
81 // Context to evaluate expression for its value (and side effects).
82 class AstGraphBuilder::AstValueContext FINAL : public AstContext {
84 explicit AstValueContext(AstGraphBuilder* owner)
85 : AstContext(owner, Expression::kValue) {}
86 ~AstValueContext() FINAL;
87 void ProduceValue(Node* value) FINAL;
88 Node* ConsumeValue() FINAL;
92 // Context to evaluate expression for a condition value (and side effects).
93 class AstGraphBuilder::AstTestContext FINAL : public AstContext {
95 explicit AstTestContext(AstGraphBuilder* owner)
96 : AstContext(owner, Expression::kTest) {}
97 ~AstTestContext() FINAL;
98 void ProduceValue(Node* value) FINAL;
99 Node* ConsumeValue() FINAL;
103 // Scoped class tracking context objects created by the visitor. Represents
104 // mutations of the context chain within the function body and allows to
105 // change the current {scope} and {context} during visitation.
106 class AstGraphBuilder::ContextScope BASE_EMBEDDED {
108 ContextScope(AstGraphBuilder* builder, Scope* scope, Node* context)
110 outer_(builder->execution_context()),
112 depth_(builder_->environment()->ContextStackDepth()) {
113 builder_->environment()->PushContext(context); // Push.
114 builder_->set_execution_context(this);
118 builder_->set_execution_context(outer_); // Pop.
119 builder_->environment()->PopContext();
120 CHECK_EQ(depth_, builder_->environment()->ContextStackDepth());
123 // Current scope during visitation.
124 Scope* scope() const { return scope_; }
127 AstGraphBuilder* builder_;
128 ContextScope* outer_;
134 // Scoped class tracking control statements entered by the visitor. There are
135 // different types of statements participating in this stack to properly track
136 // local as well as non-local control flow:
137 // - IterationStatement : Allows proper 'break' and 'continue' behavior.
138 // - BreakableStatement : Allows 'break' from block and switch statements.
139 // - TryCatchStatement : Intercepts 'throw' and implicit exceptional edges.
140 // - TryFinallyStatement: Intercepts 'break', 'continue', 'throw' and 'return'.
141 class AstGraphBuilder::ControlScope BASE_EMBEDDED {
143 ControlScope(AstGraphBuilder* builder, int stack_delta)
145 outer_(builder->execution_control()),
146 stack_delta_(stack_delta) {
147 builder_->set_execution_control(this); // Push.
150 virtual ~ControlScope() {
151 builder_->set_execution_control(outer_); // Pop.
154 // Either 'break' or 'continue' to the target statement.
155 void BreakTo(BreakableStatement* target);
156 void ContinueTo(BreakableStatement* target);
158 // Either 'return' or 'throw' the given value.
159 void ReturnValue(Node* return_value);
160 void ThrowValue(Node* exception_value);
162 class DeferredCommands;
165 enum Command { CMD_BREAK, CMD_CONTINUE, CMD_RETURN, CMD_THROW };
167 // Performs one of the above commands on this stack of control scopes. This
168 // walks through the stack giving each scope a chance to execute or defer the
169 // given command by overriding the {Execute} method appropriately. Note that
170 // this also drops extra operands from the environment for each skipped scope.
171 void PerformCommand(Command cmd, Statement* target, Node* value);
173 // Interface to execute a given command in this scope. Returning {true} here
174 // indicates successful execution whereas {false} requests to skip scope.
175 virtual bool Execute(Command cmd, Statement* target, Node* value) {
176 // For function-level control.
179 builder()->BuildThrow(value);
182 builder()->BuildReturn(value);
191 Environment* environment() { return builder_->environment(); }
192 AstGraphBuilder* builder() const { return builder_; }
193 int stack_delta() const { return stack_delta_; }
196 AstGraphBuilder* builder_;
197 ControlScope* outer_;
202 // Helper class for a try-finally control scope. It can record intercepted
203 // control-flow commands that cause entry into a finally-block, and re-apply
204 // them after again leaving that block. Special tokens are used to identify
205 // paths going through the finally-block to dispatch after leaving the block.
206 class AstGraphBuilder::ControlScope::DeferredCommands : public ZoneObject {
208 explicit DeferredCommands(AstGraphBuilder* owner)
209 : owner_(owner), deferred_(owner->zone()) {}
211 // One recorded control-flow command.
213 Command command; // The command type being applied on this path.
214 Statement* statement; // The target statement for the command or {NULL}.
215 Node* value; // The passed value node for the command or {NULL}.
216 Node* token; // A token identifying this particular path.
219 // Records a control-flow command while entering the finally-block. This also
220 // generates a new dispatch token that identifies one particular path.
221 Node* RecordCommand(Command cmd, Statement* stmt, Node* value) {
222 Node* token = NewPathTokenForDeferredCommand();
223 deferred_.push_back({cmd, stmt, value, token});
227 // Returns the dispatch token to be used to identify the implicit fall-through
228 // path at the end of a try-block into the corresponding finally-block.
229 Node* GetFallThroughToken() { return NewPathTokenForImplicitFallThrough(); }
231 // Applies all recorded control-flow commands after the finally-block again.
232 // This generates a dynamic dispatch on the token from the entry point.
233 void ApplyDeferredCommands(Node* token) {
234 SwitchBuilder dispatch(owner_, static_cast<int>(deferred_.size()));
235 dispatch.BeginSwitch();
236 for (size_t i = 0; i < deferred_.size(); ++i) {
237 Node* condition = NewPathDispatchCondition(token, deferred_[i].token);
238 dispatch.BeginLabel(static_cast<int>(i), condition);
241 for (size_t i = 0; i < deferred_.size(); ++i) {
242 dispatch.BeginCase(static_cast<int>(i));
243 owner_->execution_control()->PerformCommand(
244 deferred_[i].command, deferred_[i].statement, deferred_[i].value);
247 dispatch.EndSwitch();
251 Node* NewPathTokenForDeferredCommand() {
252 return owner_->jsgraph()->Constant(static_cast<int>(deferred_.size()));
254 Node* NewPathTokenForImplicitFallThrough() {
255 return owner_->jsgraph()->Constant(-1);
257 Node* NewPathDispatchCondition(Node* t1, Node* t2) {
258 // TODO(mstarzinger): This should be machine()->WordEqual(), but our Phi
259 // nodes all have kRepTagged|kTypeAny, which causes representation mismatch.
260 return owner_->NewNode(owner_->javascript()->StrictEqual(), t1, t2);
264 AstGraphBuilder* owner_;
265 ZoneVector<Entry> deferred_;
269 // Control scope implementation for a BreakableStatement.
270 class AstGraphBuilder::ControlScopeForBreakable : public ControlScope {
272 ControlScopeForBreakable(AstGraphBuilder* owner, BreakableStatement* target,
273 ControlBuilder* control)
274 : ControlScope(owner, 0), target_(target), control_(control) {}
277 virtual bool Execute(Command cmd, Statement* target, Node* value) OVERRIDE {
278 if (target != target_) return false; // We are not the command target.
292 BreakableStatement* target_;
293 ControlBuilder* control_;
297 // Control scope implementation for an IterationStatement.
298 class AstGraphBuilder::ControlScopeForIteration : public ControlScope {
300 ControlScopeForIteration(AstGraphBuilder* owner, IterationStatement* target,
301 LoopBuilder* control, int stack_delta)
302 : ControlScope(owner, stack_delta), target_(target), control_(control) {}
305 virtual bool Execute(Command cmd, Statement* target, Node* value) OVERRIDE {
306 if (target != target_) return false; // We are not the command target.
312 control_->Continue();
322 BreakableStatement* target_;
323 LoopBuilder* control_;
327 // Control scope implementation for a TryCatchStatement.
328 class AstGraphBuilder::ControlScopeForCatch : public ControlScope {
330 ControlScopeForCatch(AstGraphBuilder* owner, TryCatchBuilder* control)
331 : ControlScope(owner, 0), control_(control) {}
334 virtual bool Execute(Command cmd, Statement* target, Node* value) OVERRIDE {
337 control_->Throw(value);
348 TryCatchBuilder* control_;
352 // Control scope implementation for a TryFinallyStatement.
353 class AstGraphBuilder::ControlScopeForFinally : public ControlScope {
355 ControlScopeForFinally(AstGraphBuilder* owner, DeferredCommands* commands,
356 TryFinallyBuilder* control)
357 : ControlScope(owner, 0), commands_(commands), control_(control) {}
360 virtual bool Execute(Command cmd, Statement* target, Node* value) OVERRIDE {
361 Node* token = commands_->RecordCommand(cmd, target, value);
362 control_->LeaveTry(token);
367 DeferredCommands* commands_;
368 TryFinallyBuilder* control_;
372 AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info,
373 JSGraph* jsgraph, LoopAssignmentAnalysis* loop)
374 : local_zone_(local_zone),
377 environment_(nullptr),
378 ast_context_(nullptr),
379 globals_(0, local_zone),
380 execution_control_(nullptr),
381 execution_context_(nullptr),
382 input_buffer_size_(0),
383 input_buffer_(nullptr),
384 exit_control_(nullptr),
385 loop_assignment_analysis_(loop) {
386 InitializeAstVisitor(info->isolate(), local_zone);
390 Node* AstGraphBuilder::GetFunctionClosure() {
391 if (!function_closure_.is_set()) {
393 common()->Parameter(Linkage::kJSFunctionCallClosureParamIndex);
394 Node* node = NewNode(op, graph()->start());
395 function_closure_.set(node);
397 return function_closure_.get();
401 void AstGraphBuilder::CreateFunctionContext(bool constant_context) {
402 function_context_.set(constant_context
403 ? jsgraph()->HeapConstant(info()->context())
404 : NewOuterContextParam());
408 Node* AstGraphBuilder::NewOuterContextParam() {
409 // Parameter (arity + 1) is special for the outer context of the function
410 const Operator* op = common()->Parameter(info()->num_parameters() + 1);
411 return NewNode(op, graph()->start());
415 Node* AstGraphBuilder::NewCurrentContextOsrValue() {
416 // TODO(titzer): use a real OSR value here; a parameter works by accident.
417 // Parameter (arity + 1) is special for the outer context of the function
418 const Operator* op = common()->Parameter(info()->num_parameters() + 1);
419 return NewNode(op, graph()->start());
423 bool AstGraphBuilder::CreateGraph(bool constant_context) {
424 Scope* scope = info()->scope();
425 DCHECK(graph() != NULL);
427 // Set up the basic structure of the graph.
428 int parameter_count = info()->num_parameters();
429 graph()->SetStart(graph()->NewNode(common()->Start(parameter_count)));
431 // Initialize control scope.
432 ControlScope control(this, 0);
434 // Initialize the top-level environment.
435 Environment env(this, scope, graph()->start());
436 set_environment(&env);
438 if (info()->is_osr()) {
439 // Use OSR normal entry as the start of the top-level environment.
440 // It will be replaced with {Dead} after typing and optimizations.
441 NewNode(common()->OsrNormalEntry());
444 // Initialize the incoming context.
445 CreateFunctionContext(constant_context);
446 ContextScope incoming(this, scope, function_context_.get());
448 // Build receiver check for sloppy mode if necessary.
449 // TODO(mstarzinger/verwaest): Should this be moved back into the CallIC?
450 Node* original_receiver = env.Lookup(scope->receiver());
451 Node* patched_receiver = BuildPatchReceiverToGlobalProxy(original_receiver);
452 env.Bind(scope->receiver(), patched_receiver);
454 // Build function context only if there are context allocated variables.
455 int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
456 if (heap_slots > 0) {
457 // Push a new inner context scope for the function.
458 Node* closure = GetFunctionClosure();
459 Node* inner_context =
460 BuildLocalFunctionContext(function_context_.get(), closure);
461 ContextScope top_context(this, scope, inner_context);
464 // Simply use the outer function context in building the graph.
468 // Finish the basic structure of the graph.
469 graph()->SetEnd(graph()->NewNode(common()->End(), exit_control()));
471 // Failures indicated by stack overflow.
472 return !HasStackOverflow();
476 void AstGraphBuilder::CreateGraphBody() {
477 Scope* scope = info()->scope();
479 // Build the arguments object if it is used.
480 BuildArgumentsObject(scope->arguments());
482 // Build rest arguments array if it is used.
484 Variable* rest_parameter = scope->rest_parameter(&rest_index);
485 BuildRestArgumentsArray(rest_parameter, rest_index);
487 // Emit tracing call if requested to do so.
489 NewNode(javascript()->CallRuntime(Runtime::kTraceEnter, 0));
492 // Visit implicit declaration of the function name.
493 if (scope->is_function_scope() && scope->function() != NULL) {
494 VisitVariableDeclaration(scope->function());
497 // Visit declarations within the function scope.
498 VisitDeclarations(scope->declarations());
500 // Build a stack-check before the body.
501 Node* node = BuildStackCheck();
502 PrepareFrameState(node, BailoutId::FunctionEntry());
504 // Visit statements in the function body.
505 VisitStatements(info()->function()->body());
507 // Emit tracing call if requested to do so.
509 // TODO(mstarzinger): Only traces implicit return.
510 Node* return_value = jsgraph()->UndefinedConstant();
511 NewNode(javascript()->CallRuntime(Runtime::kTraceExit, 1), return_value);
514 // Return 'undefined' in case we can fall off the end.
515 BuildReturn(jsgraph()->UndefinedConstant());
519 // Left-hand side can only be a property, a global or a variable slot.
520 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
523 // Determine the left-hand side kind of an assignment.
524 static LhsKind DetermineLhsKind(Expression* expr) {
525 Property* property = expr->AsProperty();
526 DCHECK(expr->IsValidReferenceExpression());
528 (property == NULL) ? VARIABLE : (property->key()->IsPropertyName())
535 AstGraphBuilder::Environment::Environment(AstGraphBuilder* builder,
537 Node* control_dependency)
539 parameters_count_(scope->num_parameters() + 1),
540 locals_count_(scope->num_stack_slots()),
541 values_(builder_->local_zone()),
542 contexts_(builder_->local_zone()),
543 control_dependency_(control_dependency),
544 effect_dependency_(control_dependency),
545 parameters_node_(nullptr),
546 locals_node_(nullptr),
547 stack_node_(nullptr) {
548 DCHECK_EQ(scope->num_parameters() + 1, parameters_count());
550 // Bind the receiver variable.
551 Node* receiver = builder->graph()->NewNode(common()->Parameter(0),
552 builder->graph()->start());
553 values()->push_back(receiver);
555 // Bind all parameter variables. The parameter indices are shifted by 1
556 // (receiver is parameter index -1 but environment index 0).
557 for (int i = 0; i < scope->num_parameters(); ++i) {
558 Node* parameter = builder->graph()->NewNode(common()->Parameter(i + 1),
559 builder->graph()->start());
560 values()->push_back(parameter);
563 // Bind all local variables to undefined.
564 Node* undefined_constant = builder->jsgraph()->UndefinedConstant();
565 values()->insert(values()->end(), locals_count(), undefined_constant);
569 AstGraphBuilder::Environment::Environment(
570 const AstGraphBuilder::Environment* copy)
571 : builder_(copy->builder_),
572 parameters_count_(copy->parameters_count_),
573 locals_count_(copy->locals_count_),
574 values_(copy->zone()),
575 contexts_(copy->zone()),
576 control_dependency_(copy->control_dependency_),
577 effect_dependency_(copy->effect_dependency_),
578 parameters_node_(copy->parameters_node_),
579 locals_node_(copy->locals_node_),
580 stack_node_(copy->stack_node_) {
581 const size_t kStackEstimate = 7; // optimum from experimentation!
582 values_.reserve(copy->values_.size() + kStackEstimate);
583 values_.insert(values_.begin(), copy->values_.begin(), copy->values_.end());
584 contexts_.reserve(copy->contexts_.size());
585 contexts_.insert(contexts_.begin(), copy->contexts_.begin(),
586 copy->contexts_.end());
590 void AstGraphBuilder::Environment::UpdateStateValues(Node** state_values,
591 int offset, int count) {
592 bool should_update = false;
593 Node** env_values = (count == 0) ? NULL : &values()->at(offset);
594 if (*state_values == NULL || (*state_values)->InputCount() != count) {
595 should_update = true;
597 DCHECK(static_cast<size_t>(offset + count) <= values()->size());
598 for (int i = 0; i < count; i++) {
599 if ((*state_values)->InputAt(i) != env_values[i]) {
600 should_update = true;
606 const Operator* op = common()->StateValues(count);
607 (*state_values) = graph()->NewNode(op, count, env_values);
612 Node* AstGraphBuilder::Environment::Checkpoint(
613 BailoutId ast_id, OutputFrameStateCombine combine) {
614 UpdateStateValues(¶meters_node_, 0, parameters_count());
615 UpdateStateValues(&locals_node_, parameters_count(), locals_count());
616 UpdateStateValues(&stack_node_, parameters_count() + locals_count(),
619 const Operator* op = common()->FrameState(JS_FRAME, ast_id, combine);
621 return graph()->NewNode(op, parameters_node_, locals_node_, stack_node_,
622 builder()->current_context(),
623 builder()->jsgraph()->UndefinedConstant());
627 AstGraphBuilder::AstContext::AstContext(AstGraphBuilder* own,
628 Expression::Context kind)
629 : kind_(kind), owner_(own), outer_(own->ast_context()) {
630 owner()->set_ast_context(this); // Push.
632 original_height_ = environment()->stack_height();
637 AstGraphBuilder::AstContext::~AstContext() {
638 owner()->set_ast_context(outer_); // Pop.
642 AstGraphBuilder::AstEffectContext::~AstEffectContext() {
643 DCHECK(environment()->stack_height() == original_height_);
647 AstGraphBuilder::AstValueContext::~AstValueContext() {
648 DCHECK(environment()->stack_height() == original_height_ + 1);
652 AstGraphBuilder::AstTestContext::~AstTestContext() {
653 DCHECK(environment()->stack_height() == original_height_ + 1);
657 void AstGraphBuilder::AstEffectContext::ProduceValue(Node* value) {
658 // The value is ignored.
662 void AstGraphBuilder::AstValueContext::ProduceValue(Node* value) {
663 environment()->Push(value);
667 void AstGraphBuilder::AstTestContext::ProduceValue(Node* value) {
668 environment()->Push(owner()->BuildToBoolean(value));
672 Node* AstGraphBuilder::AstEffectContext::ConsumeValue() { return NULL; }
675 Node* AstGraphBuilder::AstValueContext::ConsumeValue() {
676 return environment()->Pop();
680 Node* AstGraphBuilder::AstTestContext::ConsumeValue() {
681 return environment()->Pop();
685 Scope* AstGraphBuilder::current_scope() const {
686 return execution_context_->scope();
690 Node* AstGraphBuilder::current_context() const {
691 return environment()->Context();
695 void AstGraphBuilder::ControlScope::PerformCommand(Command command,
698 Environment* env = environment()->CopyAsUnreachable();
699 ControlScope* current = this;
700 while (current != NULL) {
701 if (current->Execute(command, target, value)) break;
702 environment()->Drop(current->stack_delta());
703 current = current->outer_;
705 builder()->set_environment(env);
706 DCHECK(current != NULL); // Always handled (unless stack is malformed).
710 void AstGraphBuilder::ControlScope::BreakTo(BreakableStatement* stmt) {
711 PerformCommand(CMD_BREAK, stmt, nullptr);
715 void AstGraphBuilder::ControlScope::ContinueTo(BreakableStatement* stmt) {
716 PerformCommand(CMD_CONTINUE, stmt, nullptr);
720 void AstGraphBuilder::ControlScope::ReturnValue(Node* return_value) {
721 PerformCommand(CMD_RETURN, nullptr, return_value);
725 void AstGraphBuilder::ControlScope::ThrowValue(Node* exception_value) {
726 PerformCommand(CMD_THROW, nullptr, exception_value);
730 void AstGraphBuilder::VisitForValueOrNull(Expression* expr) {
732 return environment()->Push(jsgraph()->NullConstant());
738 void AstGraphBuilder::VisitForValueOrTheHole(Expression* expr) {
740 return environment()->Push(jsgraph()->TheHoleConstant());
746 void AstGraphBuilder::VisitForValues(ZoneList<Expression*>* exprs) {
747 for (int i = 0; i < exprs->length(); ++i) {
748 VisitForValue(exprs->at(i));
753 void AstGraphBuilder::VisitForValue(Expression* expr) {
754 AstValueContext for_value(this);
755 if (!CheckStackOverflow()) {
758 ast_context()->ProduceValue(jsgraph()->UndefinedConstant());
763 void AstGraphBuilder::VisitForEffect(Expression* expr) {
764 AstEffectContext for_effect(this);
765 if (!CheckStackOverflow()) {
768 ast_context()->ProduceValue(jsgraph()->UndefinedConstant());
773 void AstGraphBuilder::VisitForTest(Expression* expr) {
774 AstTestContext for_condition(this);
775 if (!CheckStackOverflow()) {
778 ast_context()->ProduceValue(jsgraph()->UndefinedConstant());
783 void AstGraphBuilder::Visit(Expression* expr) {
784 // Reuses enclosing AstContext.
785 if (!CheckStackOverflow()) {
788 ast_context()->ProduceValue(jsgraph()->UndefinedConstant());
793 void AstGraphBuilder::VisitVariableDeclaration(VariableDeclaration* decl) {
794 Variable* variable = decl->proxy()->var();
795 VariableMode mode = decl->mode();
796 bool hole_init = mode == CONST || mode == CONST_LEGACY || mode == LET;
797 switch (variable->location()) {
798 case Variable::UNALLOCATED: {
799 Handle<Oddball> value = variable->binding_needs_init()
800 ? isolate()->factory()->the_hole_value()
801 : isolate()->factory()->undefined_value();
802 globals()->push_back(variable->name());
803 globals()->push_back(value);
806 case Variable::PARAMETER:
807 case Variable::LOCAL:
809 Node* value = jsgraph()->TheHoleConstant();
810 environment()->Bind(variable, value);
813 case Variable::CONTEXT:
815 Node* value = jsgraph()->TheHoleConstant();
816 const Operator* op = javascript()->StoreContext(0, variable->index());
817 NewNode(op, current_context(), value);
820 case Variable::LOOKUP:
826 void AstGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* decl) {
827 Variable* variable = decl->proxy()->var();
828 switch (variable->location()) {
829 case Variable::UNALLOCATED: {
830 Handle<SharedFunctionInfo> function =
831 Compiler::BuildFunctionInfo(decl->fun(), info()->script(), info());
832 // Check for stack-overflow exception.
833 if (function.is_null()) return SetStackOverflow();
834 globals()->push_back(variable->name());
835 globals()->push_back(function);
838 case Variable::PARAMETER:
839 case Variable::LOCAL: {
840 VisitForValue(decl->fun());
841 Node* value = environment()->Pop();
842 environment()->Bind(variable, value);
845 case Variable::CONTEXT: {
846 VisitForValue(decl->fun());
847 Node* value = environment()->Pop();
848 const Operator* op = javascript()->StoreContext(0, variable->index());
849 NewNode(op, current_context(), value);
852 case Variable::LOOKUP:
858 void AstGraphBuilder::VisitModuleDeclaration(ModuleDeclaration* decl) {
863 void AstGraphBuilder::VisitImportDeclaration(ImportDeclaration* decl) {
868 void AstGraphBuilder::VisitExportDeclaration(ExportDeclaration* decl) {
873 void AstGraphBuilder::VisitModuleLiteral(ModuleLiteral* modl) { UNREACHABLE(); }
876 void AstGraphBuilder::VisitModulePath(ModulePath* modl) { UNREACHABLE(); }
879 void AstGraphBuilder::VisitModuleUrl(ModuleUrl* modl) { UNREACHABLE(); }
882 void AstGraphBuilder::VisitBlock(Block* stmt) {
883 BlockBuilder block(this);
884 ControlScopeForBreakable scope(this, stmt, &block);
885 if (stmt->labels() != NULL) block.BeginBlock();
886 if (stmt->scope() == NULL) {
887 // Visit statements in the same scope, no declarations.
888 VisitStatements(stmt->statements());
890 // Visit declarations and statements in a block scope.
891 Node* context = BuildLocalBlockContext(stmt->scope());
892 ContextScope scope(this, stmt->scope(), context);
893 VisitDeclarations(stmt->scope()->declarations());
894 VisitStatements(stmt->statements());
896 if (stmt->labels() != NULL) block.EndBlock();
900 void AstGraphBuilder::VisitModuleStatement(ModuleStatement* stmt) {
905 void AstGraphBuilder::VisitExpressionStatement(ExpressionStatement* stmt) {
906 VisitForEffect(stmt->expression());
910 void AstGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) {
915 void AstGraphBuilder::VisitIfStatement(IfStatement* stmt) {
916 IfBuilder compare_if(this);
917 VisitForTest(stmt->condition());
918 Node* condition = environment()->Pop();
919 compare_if.If(condition);
921 Visit(stmt->then_statement());
923 Visit(stmt->else_statement());
928 void AstGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) {
929 execution_control()->ContinueTo(stmt->target());
933 void AstGraphBuilder::VisitBreakStatement(BreakStatement* stmt) {
934 execution_control()->BreakTo(stmt->target());
938 void AstGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
939 VisitForValue(stmt->expression());
940 Node* result = environment()->Pop();
941 execution_control()->ReturnValue(result);
945 void AstGraphBuilder::VisitWithStatement(WithStatement* stmt) {
946 VisitForValue(stmt->expression());
947 Node* value = environment()->Pop();
948 const Operator* op = javascript()->CreateWithContext();
949 Node* context = NewNode(op, value, GetFunctionClosure());
950 PrepareFrameState(context, stmt->EntryId());
951 ContextScope scope(this, stmt->scope(), context);
952 Visit(stmt->statement());
956 void AstGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
957 ZoneList<CaseClause*>* clauses = stmt->cases();
958 SwitchBuilder compare_switch(this, clauses->length());
959 ControlScopeForBreakable scope(this, stmt, &compare_switch);
960 compare_switch.BeginSwitch();
961 int default_index = -1;
963 // Keep the switch value on the stack until a case matches.
964 VisitForValue(stmt->tag());
965 Node* tag = environment()->Top();
967 // Iterate over all cases and create nodes for label comparison.
968 for (int i = 0; i < clauses->length(); i++) {
969 CaseClause* clause = clauses->at(i);
971 // The default is not a test, remember index.
972 if (clause->is_default()) {
977 // Create nodes to perform label comparison as if via '==='. The switch
978 // value is still on the operand stack while the label is evaluated.
979 VisitForValue(clause->label());
980 Node* label = environment()->Pop();
981 const Operator* op = javascript()->StrictEqual();
982 Node* condition = NewNode(op, tag, label);
983 compare_switch.BeginLabel(i, condition);
985 // Discard the switch value at label match.
986 environment()->Pop();
987 compare_switch.EndLabel();
990 // Discard the switch value and mark the default case.
991 environment()->Pop();
992 if (default_index >= 0) {
993 compare_switch.DefaultAt(default_index);
996 // Iterate over all cases and create nodes for case bodies.
997 for (int i = 0; i < clauses->length(); i++) {
998 CaseClause* clause = clauses->at(i);
999 compare_switch.BeginCase(i);
1000 VisitStatements(clause->statements());
1001 compare_switch.EndCase();
1004 compare_switch.EndSwitch();
1008 void AstGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
1009 LoopBuilder while_loop(this);
1010 while_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt));
1011 VisitIterationBody(stmt, &while_loop, 0);
1012 while_loop.EndBody();
1013 VisitForTest(stmt->cond());
1014 Node* condition = environment()->Pop();
1015 while_loop.BreakUnless(condition);
1016 while_loop.EndLoop();
1020 void AstGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
1021 LoopBuilder while_loop(this);
1022 while_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt));
1023 VisitForTest(stmt->cond());
1024 Node* condition = environment()->Pop();
1025 while_loop.BreakUnless(condition);
1026 VisitIterationBody(stmt, &while_loop, 0);
1027 while_loop.EndBody();
1028 while_loop.EndLoop();
1032 void AstGraphBuilder::VisitForStatement(ForStatement* stmt) {
1033 LoopBuilder for_loop(this);
1034 VisitIfNotNull(stmt->init());
1035 for_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt));
1036 if (stmt->cond() != NULL) {
1037 VisitForTest(stmt->cond());
1038 Node* condition = environment()->Pop();
1039 for_loop.BreakUnless(condition);
1041 for_loop.BreakUnless(jsgraph()->TrueConstant());
1043 VisitIterationBody(stmt, &for_loop, 0);
1045 VisitIfNotNull(stmt->next());
1050 // TODO(dcarney): this is a big function. Try to clean up some.
1051 void AstGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
1052 VisitForValue(stmt->subject());
1053 Node* obj = environment()->Pop();
1054 // Check for undefined or null before entering loop.
1055 IfBuilder is_undefined(this);
1056 Node* is_undefined_cond =
1057 NewNode(javascript()->StrictEqual(), obj, jsgraph()->UndefinedConstant());
1058 is_undefined.If(is_undefined_cond);
1059 is_undefined.Then();
1060 is_undefined.Else();
1062 IfBuilder is_null(this);
1063 Node* is_null_cond =
1064 NewNode(javascript()->StrictEqual(), obj, jsgraph()->NullConstant());
1065 is_null.If(is_null_cond);
1068 // Convert object to jsobject.
1069 // PrepareForBailoutForId(stmt->PrepareId(), TOS_REG);
1070 obj = NewNode(javascript()->ToObject(), obj);
1071 PrepareFrameState(obj, stmt->ToObjectId(), OutputFrameStateCombine::Push());
1072 environment()->Push(obj);
1073 // TODO(dcarney): should do a fast enum cache check here to skip runtime.
1074 Node* cache_type = NewNode(
1075 javascript()->CallRuntime(Runtime::kGetPropertyNamesFast, 1), obj);
1076 PrepareFrameState(cache_type, stmt->EnumId(),
1077 OutputFrameStateCombine::Push());
1078 // TODO(dcarney): these next runtime calls should be removed in favour of
1079 // a few simplified instructions.
1080 Node* cache_pair = NewNode(
1081 javascript()->CallRuntime(Runtime::kForInInit, 2), obj, cache_type);
1082 // cache_type may have been replaced.
1083 Node* cache_array = NewNode(common()->Projection(0), cache_pair);
1084 cache_type = NewNode(common()->Projection(1), cache_pair);
1085 Node* cache_length =
1086 NewNode(javascript()->CallRuntime(Runtime::kForInCacheArrayLength, 2),
1087 cache_type, cache_array);
1089 // TODO(dcarney): this check is actually supposed to be for the
1090 // empty enum case only.
1091 IfBuilder have_no_properties(this);
1092 Node* empty_array_cond = NewNode(javascript()->StrictEqual(),
1093 cache_length, jsgraph()->ZeroConstant());
1094 have_no_properties.If(empty_array_cond);
1095 have_no_properties.Then();
1096 // Pop obj and skip loop.
1097 environment()->Pop();
1098 have_no_properties.Else();
1100 // Construct the rest of the environment.
1101 environment()->Push(cache_type);
1102 environment()->Push(cache_array);
1103 environment()->Push(cache_length);
1104 environment()->Push(jsgraph()->ZeroConstant());
1106 // Build the actual loop body.
1107 VisitForInBody(stmt);
1109 have_no_properties.End();
1117 // TODO(dcarney): this is a big function. Try to clean up some.
1118 void AstGraphBuilder::VisitForInBody(ForInStatement* stmt) {
1119 LoopBuilder for_loop(this);
1120 for_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt));
1122 // These stack values are renamed in the case of OSR, so reload them
1123 // from the environment.
1124 Node* index = environment()->Peek(0);
1125 Node* cache_length = environment()->Peek(1);
1126 Node* cache_array = environment()->Peek(2);
1127 Node* cache_type = environment()->Peek(3);
1128 Node* obj = environment()->Peek(4);
1130 // Check loop termination condition.
1131 Node* exit_cond = NewNode(javascript()->LessThan(), index, cache_length);
1132 // TODO(jarin): provide real bailout id.
1133 PrepareFrameState(exit_cond, BailoutId::None());
1134 for_loop.BreakUnless(exit_cond);
1135 Node* pair = NewNode(javascript()->CallRuntime(Runtime::kForInNext, 4), obj,
1136 cache_array, cache_type, index);
1137 Node* value = NewNode(common()->Projection(0), pair);
1138 Node* should_filter = NewNode(common()->Projection(1), pair);
1139 environment()->Push(value);
1141 // Test if FILTER_KEY needs to be called.
1142 IfBuilder test_should_filter(this);
1143 Node* should_filter_cond = NewNode(
1144 javascript()->StrictEqual(), should_filter, jsgraph()->TrueConstant());
1145 test_should_filter.If(should_filter_cond);
1146 test_should_filter.Then();
1147 value = environment()->Pop();
1148 Node* builtins = BuildLoadBuiltinsObject();
1149 Node* function = BuildLoadObjectField(
1151 JSBuiltinsObject::OffsetOfFunctionWithId(Builtins::FILTER_KEY));
1152 // result is either the string key or Smi(0) indicating the property
1154 Node* res = NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS),
1155 function, obj, value);
1156 // TODO(jarin): provide real bailout id.
1157 PrepareFrameState(res, BailoutId::None());
1158 Node* property_missing =
1159 NewNode(javascript()->StrictEqual(), res, jsgraph()->ZeroConstant());
1161 IfBuilder is_property_missing(this);
1162 is_property_missing.If(property_missing);
1163 is_property_missing.Then();
1164 // Inc counter and continue.
1166 NewNode(javascript()->Add(), index, jsgraph()->OneConstant());
1167 // TODO(jarin): provide real bailout id.
1168 PrepareFrameState(index_inc, BailoutId::None());
1169 environment()->Poke(0, index_inc);
1170 for_loop.Continue();
1171 is_property_missing.Else();
1172 is_property_missing.End();
1174 // Replace 'value' in environment.
1175 environment()->Push(res);
1176 test_should_filter.Else();
1177 test_should_filter.End();
1179 value = environment()->Pop();
1180 // Bind value and do loop body.
1181 VisitForInAssignment(stmt->each(), value, stmt->AssignmentId());
1182 VisitIterationBody(stmt, &for_loop, 5);
1184 // Inc counter and continue.
1186 NewNode(javascript()->Add(), index, jsgraph()->OneConstant());
1187 // TODO(jarin): provide real bailout id.
1188 PrepareFrameState(index_inc, BailoutId::None());
1189 environment()->Poke(0, index_inc);
1191 environment()->Drop(5);
1192 // PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
1196 void AstGraphBuilder::VisitForOfStatement(ForOfStatement* stmt) {
1197 LoopBuilder for_loop(this);
1198 VisitForEffect(stmt->assign_iterator());
1199 for_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt));
1200 VisitForEffect(stmt->next_result());
1201 VisitForTest(stmt->result_done());
1202 Node* condition = environment()->Pop();
1203 for_loop.BreakWhen(condition);
1204 VisitForEffect(stmt->assign_each());
1205 VisitIterationBody(stmt, &for_loop, 0);
1211 void AstGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) {
1212 TryCatchBuilder try_control(this);
1214 // Evaluate the try-block inside a control scope. This simulates a handler
1215 // that is intercepting 'throw' control commands.
1216 try_control.BeginTry();
1218 ControlScopeForCatch scope(this, &try_control);
1219 Visit(stmt->try_block());
1221 try_control.EndTry();
1223 // Create a catch scope that binds the exception.
1224 Node* exception = try_control.GetExceptionNode();
1225 Unique<String> name = MakeUnique(stmt->variable()->name());
1226 const Operator* op = javascript()->CreateCatchContext(name);
1227 Node* context = NewNode(op, exception, GetFunctionClosure());
1228 PrepareFrameState(context, BailoutId::None());
1230 ContextScope scope(this, stmt->scope(), context);
1231 DCHECK(stmt->scope()->declarations()->is_empty());
1232 // Evaluate the catch-block.
1233 Visit(stmt->catch_block());
1235 try_control.EndCatch();
1237 // TODO(mstarzinger): Remove bailout once everything works.
1238 if (!FLAG_turbo_exceptions) SetStackOverflow();
1242 void AstGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
1243 TryFinallyBuilder try_control(this);
1245 // We keep a record of all paths that enter the finally-block to be able to
1246 // dispatch to the correct continuation point after the statements in the
1247 // finally-block have been evaluated.
1249 // The try-finally construct can enter the finally-block in three ways:
1250 // 1. By exiting the try-block normally, falling through at the end.
1251 // 2. By exiting the try-block with a function-local control flow transfer
1252 // (i.e. through break/continue/return statements).
1253 // 3. By exiting the try-block with a thrown exception.
1254 ControlScope::DeferredCommands* commands =
1255 new (zone()) ControlScope::DeferredCommands(this);
1257 // Evaluate the try-block inside a control scope. This simulates a handler
1258 // that is intercepting all control commands.
1259 try_control.BeginTry();
1261 ControlScopeForFinally scope(this, commands, &try_control);
1262 Visit(stmt->try_block());
1264 try_control.EndTry(commands->GetFallThroughToken());
1266 // Evaluate the finally-block.
1267 Visit(stmt->finally_block());
1268 try_control.EndFinally();
1270 // Dynamic dispatch after the finally-block.
1271 Node* token = try_control.GetDispatchTokenNode();
1272 commands->ApplyDeferredCommands(token);
1274 // TODO(mstarzinger): Remove bailout once everything works.
1275 if (!FLAG_turbo_exceptions) SetStackOverflow();
1279 void AstGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
1280 // TODO(turbofan): Do we really need a separate reloc-info for this?
1281 Node* node = NewNode(javascript()->CallRuntime(Runtime::kDebugBreak, 0));
1282 PrepareFrameState(node, stmt->DebugBreakId());
1286 void AstGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
1287 Node* context = current_context();
1289 // Build a new shared function info if we cannot find one in the baseline
1290 // code. We also have a stack overflow if the recursive compilation did.
1291 expr->InitializeSharedInfo(handle(info()->shared_info()->code()));
1292 Handle<SharedFunctionInfo> shared_info = expr->shared_info();
1293 if (shared_info.is_null()) {
1294 shared_info = Compiler::BuildFunctionInfo(expr, info()->script(), info());
1295 CHECK(!shared_info.is_null()); // TODO(mstarzinger): Set stack overflow?
1298 // Create node to instantiate a new closure.
1299 Node* info = jsgraph()->Constant(shared_info);
1300 Node* pretenure = jsgraph()->BooleanConstant(expr->pretenure());
1301 const Operator* op = javascript()->CallRuntime(Runtime::kNewClosure, 3);
1302 Node* value = NewNode(op, context, info, pretenure);
1303 ast_context()->ProduceValue(value);
1307 void AstGraphBuilder::VisitClassLiteral(ClassLiteral* expr) {
1308 if (expr->scope() == NULL) {
1309 // Visit class literal in the same scope, no declarations.
1310 VisitClassLiteralContents(expr);
1312 // Visit declarations and class literal in a block scope.
1313 Node* context = BuildLocalBlockContext(expr->scope());
1314 ContextScope scope(this, expr->scope(), context);
1315 VisitDeclarations(expr->scope()->declarations());
1316 VisitClassLiteralContents(expr);
1321 void AstGraphBuilder::VisitClassLiteralContents(ClassLiteral* expr) {
1322 Node* class_name = expr->raw_name() ? jsgraph()->Constant(expr->name())
1323 : jsgraph()->UndefinedConstant();
1325 // The class name is expected on the operand stack.
1326 environment()->Push(class_name);
1327 VisitForValueOrTheHole(expr->extends());
1328 VisitForValue(expr->constructor());
1330 // Create node to instantiate a new class.
1331 Node* constructor = environment()->Pop();
1332 Node* extends = environment()->Pop();
1333 Node* name = environment()->Pop();
1334 Node* script = jsgraph()->Constant(info()->script());
1335 Node* start = jsgraph()->Constant(expr->start_position());
1336 Node* end = jsgraph()->Constant(expr->end_position());
1337 const Operator* opc = javascript()->CallRuntime(Runtime::kDefineClass, 6);
1338 Node* literal = NewNode(opc, name, extends, constructor, script, start, end);
1340 // The prototype is ensured to exist by Runtime_DefineClass. No access check
1341 // is needed here since the constructor is created by the class literal.
1343 BuildLoadObjectField(literal, JSFunction::kPrototypeOrInitialMapOffset);
1345 // The class literal and the prototype are both expected on the operand stack
1346 // during evaluation of the method values.
1347 environment()->Push(literal);
1348 environment()->Push(proto);
1350 // Create nodes to store method values into the literal.
1351 for (int i = 0; i < expr->properties()->length(); i++) {
1352 ObjectLiteral::Property* property = expr->properties()->at(i);
1353 environment()->Push(property->is_static() ? literal : proto);
1355 VisitForValue(property->key());
1356 environment()->Push(
1357 BuildToName(environment()->Pop(), expr->GetIdForProperty(i)));
1358 VisitForValue(property->value());
1359 Node* value = environment()->Pop();
1360 Node* key = environment()->Pop();
1361 Node* receiver = environment()->Pop();
1362 BuildSetHomeObject(value, receiver, property->value());
1364 switch (property->kind()) {
1365 case ObjectLiteral::Property::CONSTANT:
1366 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1367 case ObjectLiteral::Property::PROTOTYPE:
1369 case ObjectLiteral::Property::COMPUTED: {
1370 const Operator* op =
1371 javascript()->CallRuntime(Runtime::kDefineClassMethod, 3);
1372 NewNode(op, receiver, key, value);
1375 case ObjectLiteral::Property::GETTER: {
1376 Node* attr = jsgraph()->Constant(DONT_ENUM);
1377 const Operator* op = javascript()->CallRuntime(
1378 Runtime::kDefineGetterPropertyUnchecked, 4);
1379 NewNode(op, receiver, key, value, attr);
1382 case ObjectLiteral::Property::SETTER: {
1383 Node* attr = jsgraph()->Constant(DONT_ENUM);
1384 const Operator* op = javascript()->CallRuntime(
1385 Runtime::kDefineSetterPropertyUnchecked, 4);
1386 NewNode(op, receiver, key, value, attr);
1392 // Transform both the class literal and the prototype to fast properties.
1393 const Operator* op = javascript()->CallRuntime(Runtime::kToFastProperties, 1);
1394 NewNode(op, environment()->Pop()); // prototype
1395 NewNode(op, environment()->Pop()); // literal
1397 // Assign to class variable.
1398 if (expr->scope() != NULL) {
1399 DCHECK_NOT_NULL(expr->class_variable_proxy());
1400 Variable* var = expr->class_variable_proxy()->var();
1401 BuildVariableAssignment(var, literal, Token::INIT_CONST, BailoutId::None());
1404 PrepareFrameState(literal, expr->id(), ast_context()->GetStateCombine());
1405 ast_context()->ProduceValue(literal);
1409 void AstGraphBuilder::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
1414 void AstGraphBuilder::VisitConditional(Conditional* expr) {
1415 IfBuilder compare_if(this);
1416 VisitForTest(expr->condition());
1417 Node* condition = environment()->Pop();
1418 compare_if.If(condition);
1420 Visit(expr->then_expression());
1422 Visit(expr->else_expression());
1424 ast_context()->ReplaceValue();
1428 void AstGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
1429 VectorSlotPair pair = CreateVectorSlotPair(expr->VariableFeedbackSlot());
1430 Node* value = BuildVariableLoad(expr->var(), expr->id(), pair);
1431 ast_context()->ProduceValue(value);
1435 void AstGraphBuilder::VisitLiteral(Literal* expr) {
1436 Node* value = jsgraph()->Constant(expr->value());
1437 ast_context()->ProduceValue(value);
1441 void AstGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
1442 Node* closure = GetFunctionClosure();
1444 // Create node to materialize a regular expression literal.
1445 Node* literals_array =
1446 BuildLoadObjectField(closure, JSFunction::kLiteralsOffset);
1447 Node* literal_index = jsgraph()->Constant(expr->literal_index());
1448 Node* pattern = jsgraph()->Constant(expr->pattern());
1449 Node* flags = jsgraph()->Constant(expr->flags());
1450 const Operator* op =
1451 javascript()->CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
1452 Node* literal = NewNode(op, literals_array, literal_index, pattern, flags);
1453 PrepareFrameState(literal, expr->id(), ast_context()->GetStateCombine());
1454 ast_context()->ProduceValue(literal);
1458 void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
1459 Node* closure = GetFunctionClosure();
1461 // Create node to deep-copy the literal boilerplate.
1462 expr->BuildConstantProperties(isolate());
1463 Node* literals_array =
1464 BuildLoadObjectField(closure, JSFunction::kLiteralsOffset);
1465 Node* literal_index = jsgraph()->Constant(expr->literal_index());
1466 Node* constants = jsgraph()->Constant(expr->constant_properties());
1467 Node* flags = jsgraph()->Constant(expr->ComputeFlags(true));
1468 const Operator* op =
1469 javascript()->CallRuntime(Runtime::kCreateObjectLiteral, 4);
1470 Node* literal = NewNode(op, literals_array, literal_index, constants, flags);
1471 PrepareFrameState(literal, expr->CreateLiteralId(),
1472 OutputFrameStateCombine::Push());
1474 // The object is expected on the operand stack during computation of the
1475 // property values and is the value of the entire expression.
1476 environment()->Push(literal);
1478 // Mark all computed expressions that are bound to a key that is shadowed by
1479 // a later occurrence of the same key. For the marked expressions, no store
1481 expr->CalculateEmitStore(zone());
1483 // Create nodes to store computed values into the literal.
1484 int property_index = 0;
1485 AccessorTable accessor_table(zone());
1486 for (; property_index < expr->properties()->length(); property_index++) {
1487 ObjectLiteral::Property* property = expr->properties()->at(property_index);
1488 if (property->is_computed_name()) break;
1489 if (property->IsCompileTimeValue()) continue;
1491 Literal* key = property->key()->AsLiteral();
1492 switch (property->kind()) {
1493 case ObjectLiteral::Property::CONSTANT:
1495 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1496 DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value()));
1498 case ObjectLiteral::Property::COMPUTED: {
1499 // It is safe to use [[Put]] here because the boilerplate already
1500 // contains computed properties with an uninitialized value.
1501 if (key->value()->IsInternalizedString()) {
1502 if (property->emit_store()) {
1503 VisitForValue(property->value());
1504 Node* value = environment()->Pop();
1505 Unique<Name> name = MakeUnique(key->AsPropertyName());
1507 NewNode(javascript()->StoreNamed(language_mode(), name),
1509 PrepareFrameState(store, key->id());
1510 BuildSetHomeObject(value, literal, property->value());
1512 VisitForEffect(property->value());
1516 environment()->Push(literal); // Duplicate receiver.
1517 VisitForValue(property->key());
1518 VisitForValue(property->value());
1519 Node* value = environment()->Pop();
1520 Node* key = environment()->Pop();
1521 Node* receiver = environment()->Pop();
1522 if (property->emit_store()) {
1523 Node* language = jsgraph()->Constant(SLOPPY);
1524 const Operator* op =
1525 javascript()->CallRuntime(Runtime::kSetProperty, 4);
1526 NewNode(op, receiver, key, value, language);
1527 BuildSetHomeObject(value, receiver, property->value());
1531 case ObjectLiteral::Property::PROTOTYPE: {
1532 environment()->Push(literal); // Duplicate receiver.
1533 VisitForValue(property->value());
1534 Node* value = environment()->Pop();
1535 Node* receiver = environment()->Pop();
1536 DCHECK(property->emit_store());
1537 const Operator* op =
1538 javascript()->CallRuntime(Runtime::kInternalSetPrototype, 2);
1539 Node* set_prototype = NewNode(op, receiver, value);
1540 // SetPrototype should not lazy deopt on an object literal.
1541 PrepareFrameState(set_prototype, BailoutId::None());
1544 case ObjectLiteral::Property::GETTER:
1545 if (property->emit_store()) {
1546 accessor_table.lookup(key)->second->getter = property->value();
1549 case ObjectLiteral::Property::SETTER:
1550 if (property->emit_store()) {
1551 accessor_table.lookup(key)->second->setter = property->value();
1557 // Create nodes to define accessors, using only a single call to the runtime
1558 // for each pair of corresponding getters and setters.
1559 for (AccessorTable::Iterator it = accessor_table.begin();
1560 it != accessor_table.end(); ++it) {
1561 VisitForValue(it->first);
1562 VisitForValueOrNull(it->second->getter);
1563 BuildSetHomeObject(environment()->Top(), literal, it->second->getter);
1564 VisitForValueOrNull(it->second->setter);
1565 BuildSetHomeObject(environment()->Top(), literal, it->second->setter);
1566 Node* setter = environment()->Pop();
1567 Node* getter = environment()->Pop();
1568 Node* name = environment()->Pop();
1569 Node* attr = jsgraph()->Constant(NONE);
1570 const Operator* op =
1571 javascript()->CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
1572 Node* call = NewNode(op, literal, name, getter, setter, attr);
1573 // This should not lazy deopt on a new literal.
1574 PrepareFrameState(call, BailoutId::None());
1577 // Object literals have two parts. The "static" part on the left contains no
1578 // computed property names, and so we can compute its map ahead of time; see
1579 // Runtime_CreateObjectLiteralBoilerplate. The second "dynamic" part starts
1580 // with the first computed property name and continues with all properties to
1581 // its right. All the code from above initializes the static component of the
1582 // object literal, and arranges for the map of the result to reflect the
1583 // static order in which the keys appear. For the dynamic properties, we
1584 // compile them into a series of "SetOwnProperty" runtime calls. This will
1585 // preserve insertion order.
1586 for (; property_index < expr->properties()->length(); property_index++) {
1587 ObjectLiteral::Property* property = expr->properties()->at(property_index);
1589 environment()->Push(literal); // Duplicate receiver.
1590 VisitForValue(property->key());
1591 environment()->Push(BuildToName(environment()->Pop(),
1592 expr->GetIdForProperty(property_index)));
1593 // TODO(mstarzinger): For ObjectLiteral::Property::PROTOTYPE the key should
1594 // not be on the operand stack while the value is being evaluated. Come up
1595 // with a repro for this and fix it. Also find a nice way to do so. :)
1596 VisitForValue(property->value());
1597 Node* value = environment()->Pop();
1598 Node* key = environment()->Pop();
1599 Node* receiver = environment()->Pop();
1600 BuildSetHomeObject(value, receiver, property->value());
1602 switch (property->kind()) {
1603 case ObjectLiteral::Property::CONSTANT:
1604 case ObjectLiteral::Property::COMPUTED:
1605 case ObjectLiteral::Property::MATERIALIZED_LITERAL: {
1606 Node* attr = jsgraph()->Constant(NONE);
1607 const Operator* op =
1608 javascript()->CallRuntime(Runtime::kDefineDataPropertyUnchecked, 4);
1609 Node* call = NewNode(op, receiver, key, value, attr);
1610 PrepareFrameState(call, BailoutId::None());
1613 case ObjectLiteral::Property::PROTOTYPE: {
1614 const Operator* op =
1615 javascript()->CallRuntime(Runtime::kInternalSetPrototype, 2);
1616 Node* call = NewNode(op, receiver, value);
1617 PrepareFrameState(call, BailoutId::None());
1620 case ObjectLiteral::Property::GETTER: {
1621 Node* attr = jsgraph()->Constant(NONE);
1622 const Operator* op = javascript()->CallRuntime(
1623 Runtime::kDefineGetterPropertyUnchecked, 4);
1624 Node* call = NewNode(op, receiver, key, value, attr);
1625 PrepareFrameState(call, BailoutId::None());
1628 case ObjectLiteral::Property::SETTER: {
1629 Node* attr = jsgraph()->Constant(NONE);
1630 const Operator* op = javascript()->CallRuntime(
1631 Runtime::kDefineSetterPropertyUnchecked, 4);
1632 Node* call = NewNode(op, receiver, key, value, attr);
1633 PrepareFrameState(call, BailoutId::None());
1639 // Transform literals that contain functions to fast properties.
1640 if (expr->has_function()) {
1641 const Operator* op =
1642 javascript()->CallRuntime(Runtime::kToFastProperties, 1);
1643 NewNode(op, literal);
1646 ast_context()->ProduceValue(environment()->Pop());
1650 void AstGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
1651 Node* closure = GetFunctionClosure();
1653 // Create node to deep-copy the literal boilerplate.
1654 expr->BuildConstantElements(isolate());
1655 Node* literals_array =
1656 BuildLoadObjectField(closure, JSFunction::kLiteralsOffset);
1657 Node* literal_index = jsgraph()->Constant(expr->literal_index());
1658 Node* constants = jsgraph()->Constant(expr->constant_elements());
1659 Node* flags = jsgraph()->Constant(expr->ComputeFlags(true));
1660 const Operator* op =
1661 javascript()->CallRuntime(Runtime::kCreateArrayLiteral, 4);
1662 Node* literal = NewNode(op, literals_array, literal_index, constants, flags);
1663 PrepareFrameState(literal, expr->CreateLiteralId(),
1664 OutputFrameStateCombine::Push());
1666 // The array and the literal index are both expected on the operand stack
1667 // during computation of the element values.
1668 environment()->Push(literal);
1669 environment()->Push(literal_index);
1671 // Create nodes to evaluate all the non-constant subexpressions and to store
1672 // them into the newly cloned array.
1673 for (int i = 0; i < expr->values()->length(); i++) {
1674 Expression* subexpr = expr->values()->at(i);
1675 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
1677 VisitForValue(subexpr);
1678 Node* value = environment()->Pop();
1679 Node* index = jsgraph()->Constant(i);
1680 Node* store = NewNode(javascript()->StoreProperty(language_mode()), literal,
1682 PrepareFrameState(store, expr->GetIdForElement(i));
1685 environment()->Pop(); // Array literal index.
1686 ast_context()->ProduceValue(environment()->Pop());
1690 void AstGraphBuilder::VisitForInAssignment(Expression* expr, Node* value,
1691 BailoutId bailout_id) {
1692 DCHECK(expr->IsValidReferenceExpression());
1694 // Left-hand side can only be a property, a global or a variable slot.
1695 Property* property = expr->AsProperty();
1696 LhsKind assign_type = DetermineLhsKind(expr);
1698 // Evaluate LHS expression and store the value.
1699 switch (assign_type) {
1701 Variable* var = expr->AsVariableProxy()->var();
1702 BuildVariableAssignment(var, value, Token::ASSIGN, bailout_id);
1705 case NAMED_PROPERTY: {
1706 environment()->Push(value);
1707 VisitForValue(property->obj());
1708 Node* object = environment()->Pop();
1709 value = environment()->Pop();
1711 MakeUnique(property->key()->AsLiteral()->AsPropertyName());
1712 Node* store = NewNode(javascript()->StoreNamed(language_mode(), name),
1714 PrepareFrameState(store, bailout_id);
1717 case KEYED_PROPERTY: {
1718 environment()->Push(value);
1719 VisitForValue(property->obj());
1720 VisitForValue(property->key());
1721 Node* key = environment()->Pop();
1722 Node* object = environment()->Pop();
1723 value = environment()->Pop();
1724 Node* store = NewNode(javascript()->StoreProperty(language_mode()),
1725 object, key, value);
1726 PrepareFrameState(store, bailout_id);
1733 void AstGraphBuilder::VisitAssignment(Assignment* expr) {
1734 DCHECK(expr->target()->IsValidReferenceExpression());
1736 // Left-hand side can only be a property, a global or a variable slot.
1737 Property* property = expr->target()->AsProperty();
1738 LhsKind assign_type = DetermineLhsKind(expr->target());
1740 // Evaluate LHS expression.
1741 switch (assign_type) {
1743 // Nothing to do here.
1745 case NAMED_PROPERTY:
1746 VisitForValue(property->obj());
1748 case KEYED_PROPERTY: {
1749 VisitForValue(property->obj());
1750 VisitForValue(property->key());
1755 // Evaluate the value and potentially handle compound assignments by loading
1756 // the left-hand side value and performing a binary operation.
1757 if (expr->is_compound()) {
1758 Node* old_value = NULL;
1759 switch (assign_type) {
1761 VariableProxy* proxy = expr->target()->AsVariableProxy();
1762 VectorSlotPair pair =
1763 CreateVectorSlotPair(proxy->VariableFeedbackSlot());
1764 old_value = BuildVariableLoad(proxy->var(), expr->target()->id(), pair);
1767 case NAMED_PROPERTY: {
1768 Node* object = environment()->Top();
1770 MakeUnique(property->key()->AsLiteral()->AsPropertyName());
1771 VectorSlotPair pair =
1772 CreateVectorSlotPair(property->PropertyFeedbackSlot());
1773 old_value = NewNode(javascript()->LoadNamed(name, pair), object);
1774 PrepareFrameState(old_value, property->LoadId(),
1775 OutputFrameStateCombine::Push());
1778 case KEYED_PROPERTY: {
1779 Node* key = environment()->Top();
1780 Node* object = environment()->Peek(1);
1781 VectorSlotPair pair =
1782 CreateVectorSlotPair(property->PropertyFeedbackSlot());
1783 old_value = NewNode(javascript()->LoadProperty(pair), object, key);
1784 PrepareFrameState(old_value, property->LoadId(),
1785 OutputFrameStateCombine::Push());
1789 environment()->Push(old_value);
1790 VisitForValue(expr->value());
1791 Node* right = environment()->Pop();
1792 Node* left = environment()->Pop();
1793 Node* value = BuildBinaryOp(left, right, expr->binary_op());
1794 PrepareFrameState(value, expr->binary_operation()->id(),
1795 OutputFrameStateCombine::Push());
1796 environment()->Push(value);
1798 VisitForValue(expr->value());
1802 Node* value = environment()->Pop();
1803 switch (assign_type) {
1805 Variable* variable = expr->target()->AsVariableProxy()->var();
1806 BuildVariableAssignment(variable, value, expr->op(), expr->AssignmentId(),
1807 ast_context()->GetStateCombine());
1810 case NAMED_PROPERTY: {
1811 Node* object = environment()->Pop();
1813 MakeUnique(property->key()->AsLiteral()->AsPropertyName());
1814 Node* store = NewNode(javascript()->StoreNamed(language_mode(), name),
1816 PrepareFrameState(store, expr->AssignmentId(),
1817 ast_context()->GetStateCombine());
1820 case KEYED_PROPERTY: {
1821 Node* key = environment()->Pop();
1822 Node* object = environment()->Pop();
1823 Node* store = NewNode(javascript()->StoreProperty(language_mode()),
1824 object, key, value);
1825 PrepareFrameState(store, expr->AssignmentId(),
1826 ast_context()->GetStateCombine());
1831 ast_context()->ProduceValue(value);
1835 void AstGraphBuilder::VisitYield(Yield* expr) {
1836 // TODO(turbofan): Implement yield here.
1838 ast_context()->ProduceValue(jsgraph()->UndefinedConstant());
1842 void AstGraphBuilder::VisitThrow(Throw* expr) {
1843 VisitForValue(expr->exception());
1844 Node* exception = environment()->Pop();
1845 if (FLAG_turbo_exceptions) {
1846 execution_control()->ThrowValue(exception);
1847 ast_context()->ProduceValue(exception);
1849 // TODO(mstarzinger): Temporary workaround for bailout-id for debugger.
1850 const Operator* op = javascript()->CallRuntime(Runtime::kThrow, 1);
1851 Node* value = NewNode(op, exception);
1852 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
1853 ast_context()->ProduceValue(value);
1858 void AstGraphBuilder::VisitProperty(Property* expr) {
1860 VectorSlotPair pair = CreateVectorSlotPair(expr->PropertyFeedbackSlot());
1861 if (expr->key()->IsPropertyName()) {
1862 VisitForValue(expr->obj());
1863 Node* object = environment()->Pop();
1864 Unique<Name> name = MakeUnique(expr->key()->AsLiteral()->AsPropertyName());
1865 value = NewNode(javascript()->LoadNamed(name, pair), object);
1867 VisitForValue(expr->obj());
1868 VisitForValue(expr->key());
1869 Node* key = environment()->Pop();
1870 Node* object = environment()->Pop();
1871 value = NewNode(javascript()->LoadProperty(pair), object, key);
1873 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
1874 ast_context()->ProduceValue(value);
1878 void AstGraphBuilder::VisitCall(Call* expr) {
1879 Expression* callee = expr->expression();
1880 Call::CallType call_type = expr->GetCallType(isolate());
1882 // Prepare the callee and the receiver to the function call. This depends on
1883 // the semantics of the underlying call type.
1884 CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS;
1885 Node* receiver_value = NULL;
1886 Node* callee_value = NULL;
1887 bool possibly_eval = false;
1888 switch (call_type) {
1889 case Call::GLOBAL_CALL: {
1890 VariableProxy* proxy = callee->AsVariableProxy();
1891 VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot());
1893 BuildVariableLoad(proxy->var(), expr->expression()->id(), pair);
1894 receiver_value = jsgraph()->UndefinedConstant();
1897 case Call::LOOKUP_SLOT_CALL: {
1898 Variable* variable = callee->AsVariableProxy()->var();
1899 DCHECK(variable->location() == Variable::LOOKUP);
1900 Node* name = jsgraph()->Constant(variable->name());
1901 const Operator* op =
1902 javascript()->CallRuntime(Runtime::kLoadLookupSlot, 2);
1903 Node* pair = NewNode(op, current_context(), name);
1904 callee_value = NewNode(common()->Projection(0), pair);
1905 receiver_value = NewNode(common()->Projection(1), pair);
1907 PrepareFrameState(pair, expr->EvalOrLookupId(),
1908 OutputFrameStateCombine::Push(2));
1911 case Call::PROPERTY_CALL: {
1912 Property* property = callee->AsProperty();
1913 VisitForValue(property->obj());
1914 Node* object = environment()->Top();
1915 VectorSlotPair pair =
1916 CreateVectorSlotPair(property->PropertyFeedbackSlot());
1917 if (property->key()->IsPropertyName()) {
1919 MakeUnique(property->key()->AsLiteral()->AsPropertyName());
1920 callee_value = NewNode(javascript()->LoadNamed(name, pair), object);
1922 VisitForValue(property->key());
1923 Node* key = environment()->Pop();
1924 callee_value = NewNode(javascript()->LoadProperty(pair), object, key);
1926 PrepareFrameState(callee_value, property->LoadId(),
1927 OutputFrameStateCombine::Push());
1928 receiver_value = environment()->Pop();
1929 // Note that a PROPERTY_CALL requires the receiver to be wrapped into an
1930 // object for sloppy callees. This could also be modeled explicitly here,
1931 // thereby obsoleting the need for a flag to the call operator.
1932 flags = CALL_AS_METHOD;
1935 case Call::SUPER_CALL:
1936 // TODO(dslomov): Implement super calls.
1937 callee_value = jsgraph()->UndefinedConstant();
1938 receiver_value = jsgraph()->UndefinedConstant();
1941 case Call::POSSIBLY_EVAL_CALL:
1942 possibly_eval = true;
1944 case Call::OTHER_CALL:
1945 VisitForValue(callee);
1946 callee_value = environment()->Pop();
1947 receiver_value = jsgraph()->UndefinedConstant();
1951 // The callee and the receiver both have to be pushed onto the operand stack
1952 // before arguments are being evaluated.
1953 environment()->Push(callee_value);
1954 environment()->Push(receiver_value);
1956 // Evaluate all arguments to the function call,
1957 ZoneList<Expression*>* args = expr->arguments();
1958 VisitForValues(args);
1960 // Resolve callee and receiver for a potential direct eval call. This block
1961 // will mutate the callee and receiver values pushed onto the environment.
1962 if (possibly_eval && args->length() > 0) {
1963 int arg_count = args->length();
1965 // Extract callee and source string from the environment.
1966 Node* callee = environment()->Peek(arg_count + 1);
1967 Node* source = environment()->Peek(arg_count - 1);
1969 // Create node to ask for help resolving potential eval call. This will
1970 // provide a fully resolved callee and the corresponding receiver.
1971 Node* function = GetFunctionClosure();
1972 Node* receiver = environment()->Lookup(info()->scope()->receiver());
1973 Node* language = jsgraph()->Constant(language_mode());
1974 Node* position = jsgraph()->Constant(info()->scope()->start_position());
1975 const Operator* op =
1976 javascript()->CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
1978 NewNode(op, callee, source, function, receiver, language, position);
1979 PrepareFrameState(pair, expr->EvalOrLookupId(),
1980 OutputFrameStateCombine::PokeAt(arg_count + 1));
1981 Node* new_callee = NewNode(common()->Projection(0), pair);
1982 Node* new_receiver = NewNode(common()->Projection(1), pair);
1984 // Patch callee and receiver on the environment.
1985 environment()->Poke(arg_count + 1, new_callee);
1986 environment()->Poke(arg_count + 0, new_receiver);
1989 // Create node to perform the function call.
1990 const Operator* call = javascript()->CallFunction(args->length() + 2, flags);
1991 Node* value = ProcessArguments(call, args->length() + 2);
1992 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
1993 ast_context()->ProduceValue(value);
1997 void AstGraphBuilder::VisitCallNew(CallNew* expr) {
1998 VisitForValue(expr->expression());
2000 // Evaluate all arguments to the construct call.
2001 ZoneList<Expression*>* args = expr->arguments();
2002 VisitForValues(args);
2004 // Create node to perform the construct call.
2005 const Operator* call = javascript()->CallConstruct(args->length() + 1);
2006 Node* value = ProcessArguments(call, args->length() + 1);
2007 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
2008 ast_context()->ProduceValue(value);
2012 void AstGraphBuilder::VisitCallJSRuntime(CallRuntime* expr) {
2013 Handle<String> name = expr->name();
2015 // The callee and the receiver both have to be pushed onto the operand stack
2016 // before arguments are being evaluated.
2017 CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS;
2018 Node* receiver_value = BuildLoadBuiltinsObject();
2019 Unique<String> unique = MakeUnique(name);
2020 VectorSlotPair pair = CreateVectorSlotPair(expr->CallRuntimeFeedbackSlot());
2021 Node* callee_value =
2022 NewNode(javascript()->LoadNamed(unique, pair), receiver_value);
2023 // TODO(jarin): Find/create a bailout id to deoptimize to (crankshaft
2024 // refuses to optimize functions with jsruntime calls).
2025 PrepareFrameState(callee_value, BailoutId::None(),
2026 OutputFrameStateCombine::Push());
2027 environment()->Push(callee_value);
2028 environment()->Push(receiver_value);
2030 // Evaluate all arguments to the JS runtime call.
2031 ZoneList<Expression*>* args = expr->arguments();
2032 VisitForValues(args);
2034 // Create node to perform the JS runtime call.
2035 const Operator* call = javascript()->CallFunction(args->length() + 2, flags);
2036 Node* value = ProcessArguments(call, args->length() + 2);
2037 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
2038 ast_context()->ProduceValue(value);
2042 void AstGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
2043 const Runtime::Function* function = expr->function();
2045 // Handle calls to runtime functions implemented in JavaScript separately as
2046 // the call follows JavaScript ABI and the callee is statically unknown.
2047 if (expr->is_jsruntime()) {
2048 DCHECK(function == NULL && expr->name()->length() > 0);
2049 return VisitCallJSRuntime(expr);
2052 // Evaluate all arguments to the runtime call.
2053 ZoneList<Expression*>* args = expr->arguments();
2054 VisitForValues(args);
2056 // Create node to perform the runtime call.
2057 Runtime::FunctionId functionId = function->function_id;
2058 const Operator* call = javascript()->CallRuntime(functionId, args->length());
2059 Node* value = ProcessArguments(call, args->length());
2060 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
2061 ast_context()->ProduceValue(value);
2065 void AstGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
2066 switch (expr->op()) {
2068 return VisitDelete(expr);
2070 return VisitVoid(expr);
2072 return VisitTypeof(expr);
2074 return VisitNot(expr);
2081 void AstGraphBuilder::VisitCountOperation(CountOperation* expr) {
2082 DCHECK(expr->expression()->IsValidReferenceExpression());
2084 // Left-hand side can only be a property, a global or a variable slot.
2085 Property* property = expr->expression()->AsProperty();
2086 LhsKind assign_type = DetermineLhsKind(expr->expression());
2088 // Reserve space for result of postfix operation.
2089 bool is_postfix = expr->is_postfix() && !ast_context()->IsEffect();
2090 if (is_postfix) environment()->Push(jsgraph()->UndefinedConstant());
2092 // Evaluate LHS expression and get old value.
2093 Node* old_value = NULL;
2094 int stack_depth = -1;
2095 switch (assign_type) {
2097 VariableProxy* proxy = expr->expression()->AsVariableProxy();
2098 VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot());
2100 BuildVariableLoad(proxy->var(), expr->expression()->id(), pair);
2104 case NAMED_PROPERTY: {
2105 VisitForValue(property->obj());
2106 Node* object = environment()->Top();
2108 MakeUnique(property->key()->AsLiteral()->AsPropertyName());
2109 VectorSlotPair pair =
2110 CreateVectorSlotPair(property->PropertyFeedbackSlot());
2111 old_value = NewNode(javascript()->LoadNamed(name, pair), object);
2112 PrepareFrameState(old_value, property->LoadId(),
2113 OutputFrameStateCombine::Push());
2117 case KEYED_PROPERTY: {
2118 VisitForValue(property->obj());
2119 VisitForValue(property->key());
2120 Node* key = environment()->Top();
2121 Node* object = environment()->Peek(1);
2122 VectorSlotPair pair =
2123 CreateVectorSlotPair(property->PropertyFeedbackSlot());
2124 old_value = NewNode(javascript()->LoadProperty(pair), object, key);
2125 PrepareFrameState(old_value, property->LoadId(),
2126 OutputFrameStateCombine::Push());
2132 // Convert old value into a number.
2133 old_value = NewNode(javascript()->ToNumber(), old_value);
2134 PrepareFrameState(old_value, expr->ToNumberId(),
2135 OutputFrameStateCombine::Push());
2137 // Save result for postfix expressions at correct stack depth.
2138 if (is_postfix) environment()->Poke(stack_depth, old_value);
2140 // Create node to perform +1/-1 operation.
2142 BuildBinaryOp(old_value, jsgraph()->OneConstant(), expr->binary_op());
2143 // TODO(jarin) Insert proper bailout id here (will need to change
2144 // full code generator).
2145 PrepareFrameState(value, BailoutId::None());
2148 switch (assign_type) {
2150 Variable* variable = expr->expression()->AsVariableProxy()->var();
2151 environment()->Push(value);
2152 BuildVariableAssignment(variable, value, expr->op(),
2153 expr->AssignmentId());
2154 environment()->Pop();
2157 case NAMED_PROPERTY: {
2158 Node* object = environment()->Pop();
2160 MakeUnique(property->key()->AsLiteral()->AsPropertyName());
2161 Node* store = NewNode(javascript()->StoreNamed(language_mode(), name),
2163 environment()->Push(value);
2164 PrepareFrameState(store, expr->AssignmentId());
2165 environment()->Pop();
2168 case KEYED_PROPERTY: {
2169 Node* key = environment()->Pop();
2170 Node* object = environment()->Pop();
2171 Node* store = NewNode(javascript()->StoreProperty(language_mode()),
2172 object, key, value);
2173 environment()->Push(value);
2174 PrepareFrameState(store, expr->AssignmentId());
2175 environment()->Pop();
2180 // Restore old value for postfix expressions.
2181 if (is_postfix) value = environment()->Pop();
2183 ast_context()->ProduceValue(value);
2187 void AstGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
2188 switch (expr->op()) {
2190 return VisitComma(expr);
2193 return VisitLogicalExpression(expr);
2195 VisitForValue(expr->left());
2196 VisitForValue(expr->right());
2197 Node* right = environment()->Pop();
2198 Node* left = environment()->Pop();
2199 Node* value = BuildBinaryOp(left, right, expr->op());
2200 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
2201 ast_context()->ProduceValue(value);
2207 void AstGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
2209 switch (expr->op()) {
2211 op = javascript()->Equal();
2214 op = javascript()->NotEqual();
2216 case Token::EQ_STRICT:
2217 op = javascript()->StrictEqual();
2219 case Token::NE_STRICT:
2220 op = javascript()->StrictNotEqual();
2223 op = javascript()->LessThan();
2226 op = javascript()->GreaterThan();
2229 op = javascript()->LessThanOrEqual();
2232 op = javascript()->GreaterThanOrEqual();
2234 case Token::INSTANCEOF:
2235 op = javascript()->InstanceOf();
2238 op = javascript()->HasProperty();
2244 VisitForValue(expr->left());
2245 VisitForValue(expr->right());
2246 Node* right = environment()->Pop();
2247 Node* left = environment()->Pop();
2248 Node* value = NewNode(op, left, right);
2249 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
2250 ast_context()->ProduceValue(value);
2254 void AstGraphBuilder::VisitThisFunction(ThisFunction* expr) {
2255 Node* value = GetFunctionClosure();
2256 ast_context()->ProduceValue(value);
2260 void AstGraphBuilder::VisitSuperReference(SuperReference* expr) {
2261 // TODO(turbofan): Implement super here.
2263 ast_context()->ProduceValue(jsgraph()->UndefinedConstant());
2267 void AstGraphBuilder::VisitCaseClause(CaseClause* expr) { UNREACHABLE(); }
2270 void AstGraphBuilder::VisitDeclarations(ZoneList<Declaration*>* declarations) {
2271 DCHECK(globals()->empty());
2272 AstVisitor::VisitDeclarations(declarations);
2273 if (globals()->empty()) return;
2274 int array_index = 0;
2275 Handle<FixedArray> data = isolate()->factory()->NewFixedArray(
2276 static_cast<int>(globals()->size()), TENURED);
2277 for (Handle<Object> obj : *globals()) data->set(array_index++, *obj);
2278 int encoded_flags = DeclareGlobalsEvalFlag::encode(info()->is_eval()) |
2279 DeclareGlobalsNativeFlag::encode(info()->is_native()) |
2280 DeclareGlobalsLanguageMode::encode(language_mode());
2281 Node* flags = jsgraph()->Constant(encoded_flags);
2282 Node* pairs = jsgraph()->Constant(data);
2283 const Operator* op = javascript()->CallRuntime(Runtime::kDeclareGlobals, 3);
2284 NewNode(op, current_context(), pairs, flags);
2289 void AstGraphBuilder::VisitIfNotNull(Statement* stmt) {
2290 if (stmt == NULL) return;
2295 void AstGraphBuilder::VisitIterationBody(IterationStatement* stmt,
2296 LoopBuilder* loop, int stack_delta) {
2297 ControlScopeForIteration scope(this, stmt, loop, stack_delta);
2298 Visit(stmt->body());
2302 void AstGraphBuilder::VisitDelete(UnaryOperation* expr) {
2304 if (expr->expression()->IsVariableProxy()) {
2305 // Delete of an unqualified identifier is only allowed in classic mode but
2306 // deleting "this" is allowed in all language modes.
2307 Variable* variable = expr->expression()->AsVariableProxy()->var();
2308 DCHECK(is_sloppy(language_mode()) || variable->is_this());
2309 value = BuildVariableDelete(variable, expr->id(),
2310 ast_context()->GetStateCombine());
2311 } else if (expr->expression()->IsProperty()) {
2312 Property* property = expr->expression()->AsProperty();
2313 VisitForValue(property->obj());
2314 VisitForValue(property->key());
2315 Node* key = environment()->Pop();
2316 Node* object = environment()->Pop();
2317 value = NewNode(javascript()->DeleteProperty(language_mode()), object, key);
2318 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
2320 VisitForEffect(expr->expression());
2321 value = jsgraph()->TrueConstant();
2323 ast_context()->ProduceValue(value);
2327 void AstGraphBuilder::VisitVoid(UnaryOperation* expr) {
2328 VisitForEffect(expr->expression());
2329 Node* value = jsgraph()->UndefinedConstant();
2330 ast_context()->ProduceValue(value);
2334 void AstGraphBuilder::VisitTypeof(UnaryOperation* expr) {
2336 if (expr->expression()->IsVariableProxy()) {
2337 // Typeof does not throw a reference error on global variables, hence we
2338 // perform a non-contextual load in case the operand is a variable proxy.
2339 VariableProxy* proxy = expr->expression()->AsVariableProxy();
2340 VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot());
2341 operand = BuildVariableLoad(proxy->var(), expr->expression()->id(), pair,
2344 VisitForValue(expr->expression());
2345 operand = environment()->Pop();
2347 Node* value = NewNode(javascript()->TypeOf(), operand);
2348 ast_context()->ProduceValue(value);
2352 void AstGraphBuilder::VisitNot(UnaryOperation* expr) {
2353 VisitForValue(expr->expression());
2354 Node* operand = environment()->Pop();
2355 // TODO(mstarzinger): Possible optimization when we are in effect context.
2356 Node* value = NewNode(javascript()->UnaryNot(), operand);
2357 ast_context()->ProduceValue(value);
2361 void AstGraphBuilder::VisitComma(BinaryOperation* expr) {
2362 VisitForEffect(expr->left());
2363 Visit(expr->right());
2364 ast_context()->ReplaceValue();
2368 void AstGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) {
2369 bool is_logical_and = expr->op() == Token::AND;
2370 IfBuilder compare_if(this);
2371 VisitForValue(expr->left());
2372 Node* condition = environment()->Top();
2373 compare_if.If(BuildToBoolean(condition));
2375 if (is_logical_and) {
2376 environment()->Pop();
2377 Visit(expr->right());
2378 } else if (ast_context()->IsEffect()) {
2379 environment()->Pop();
2382 if (!is_logical_and) {
2383 environment()->Pop();
2384 Visit(expr->right());
2385 } else if (ast_context()->IsEffect()) {
2386 environment()->Pop();
2389 ast_context()->ReplaceValue();
2393 LanguageMode AstGraphBuilder::language_mode() const {
2394 return info()->language_mode();
2398 VectorSlotPair AstGraphBuilder::CreateVectorSlotPair(
2399 FeedbackVectorICSlot slot) const {
2400 return VectorSlotPair(handle(info()->shared_info()->feedback_vector()), slot);
2404 Node* AstGraphBuilder::ProcessArguments(const Operator* op, int arity) {
2405 DCHECK(environment()->stack_height() >= arity);
2406 Node** all = info()->zone()->NewArray<Node*>(arity);
2407 for (int i = arity - 1; i >= 0; --i) {
2408 all[i] = environment()->Pop();
2410 Node* value = NewNode(op, arity, all);
2415 Node* AstGraphBuilder::BuildPatchReceiverToGlobalProxy(Node* receiver) {
2416 // Sloppy mode functions and builtins need to replace the receiver with the
2417 // global proxy when called as functions (without an explicit receiver
2418 // object). Otherwise there is nothing left to do here.
2419 if (is_strict(language_mode()) || info()->is_native()) return receiver;
2421 // There is no need to perform patching if the receiver is never used. Note
2422 // that scope predicates are purely syntactical, a call to eval might still
2423 // inspect the receiver value.
2424 if (!info()->scope()->uses_this() && !info()->scope()->inner_uses_this() &&
2425 !info()->scope()->calls_sloppy_eval()) {
2429 IfBuilder receiver_check(this);
2430 Node* undefined = jsgraph()->UndefinedConstant();
2431 Node* check = NewNode(javascript()->StrictEqual(), receiver, undefined);
2432 receiver_check.If(check);
2433 receiver_check.Then();
2434 environment()->Push(BuildLoadGlobalProxy());
2435 receiver_check.Else();
2436 environment()->Push(receiver);
2437 receiver_check.End();
2438 return environment()->Pop();
2442 Node* AstGraphBuilder::BuildLocalFunctionContext(Node* context, Node* closure) {
2443 // Allocate a new local context.
2444 const Operator* op = javascript()->CreateFunctionContext();
2445 Node* local_context = NewNode(op, closure);
2447 // Copy parameters into context if necessary.
2448 int num_parameters = info()->scope()->num_parameters();
2449 for (int i = 0; i < num_parameters; i++) {
2450 Variable* variable = info()->scope()->parameter(i);
2451 if (!variable->IsContextSlot()) continue;
2452 // Temporary parameter node. The parameter indices are shifted by 1
2453 // (receiver is parameter index -1 but environment index 0).
2454 Node* parameter = NewNode(common()->Parameter(i + 1), graph()->start());
2455 // Context variable (at bottom of the context chain).
2456 DCHECK_EQ(0, info()->scope()->ContextChainLength(variable->scope()));
2457 const Operator* op = javascript()->StoreContext(0, variable->index());
2458 NewNode(op, local_context, parameter);
2461 return local_context;
2465 Node* AstGraphBuilder::BuildLocalBlockContext(Scope* scope) {
2466 Node* closure = GetFunctionClosure();
2468 // Allocate a new local context.
2469 const Operator* op = javascript()->CreateBlockContext();
2470 Node* scope_info = jsgraph()->Constant(scope->GetScopeInfo(info_->isolate()));
2471 Node* local_context = NewNode(op, scope_info, closure);
2473 return local_context;
2477 Node* AstGraphBuilder::BuildArgumentsObject(Variable* arguments) {
2478 if (arguments == NULL) return NULL;
2480 // Allocate and initialize a new arguments object.
2481 Node* callee = GetFunctionClosure();
2482 const Operator* op = javascript()->CallRuntime(Runtime::kNewArguments, 1);
2483 Node* object = NewNode(op, callee);
2485 // Assign the object to the arguments variable.
2486 DCHECK(arguments->IsContextSlot() || arguments->IsStackAllocated());
2487 // This should never lazy deopt, so it is fine to send invalid bailout id.
2488 BuildVariableAssignment(arguments, object, Token::ASSIGN, BailoutId::None());
2494 Node* AstGraphBuilder::BuildRestArgumentsArray(Variable* rest, int index) {
2495 if (rest == NULL) return NULL;
2498 const Operator* op = javascript()->CallRuntime(Runtime::kNewRestParamSlow, 1);
2499 Node* object = NewNode(op, jsgraph()->SmiConstant(index));
2501 // Assign the object to the rest array
2502 DCHECK(rest->IsContextSlot() || rest->IsStackAllocated());
2503 // This should never lazy deopt, so it is fine to send invalid bailout id.
2504 BuildVariableAssignment(rest, object, Token::ASSIGN, BailoutId::None());
2510 Node* AstGraphBuilder::BuildHoleCheckSilent(Node* value, Node* for_hole,
2512 IfBuilder hole_check(this);
2513 Node* the_hole = jsgraph()->TheHoleConstant();
2514 Node* check = NewNode(javascript()->StrictEqual(), value, the_hole);
2515 hole_check.If(check);
2517 environment()->Push(for_hole);
2519 environment()->Push(not_hole);
2521 return environment()->Pop();
2525 Node* AstGraphBuilder::BuildHoleCheckThrow(Node* value, Variable* variable,
2527 BailoutId bailout_id) {
2528 IfBuilder hole_check(this);
2529 Node* the_hole = jsgraph()->TheHoleConstant();
2530 Node* check = NewNode(javascript()->StrictEqual(), value, the_hole);
2531 hole_check.If(check);
2533 environment()->Push(BuildThrowReferenceError(variable, bailout_id));
2535 environment()->Push(not_hole);
2537 return environment()->Pop();
2541 Node* AstGraphBuilder::BuildVariableLoad(Variable* variable,
2542 BailoutId bailout_id,
2543 const VectorSlotPair& feedback,
2544 ContextualMode contextual_mode) {
2545 Node* the_hole = jsgraph()->TheHoleConstant();
2546 VariableMode mode = variable->mode();
2547 switch (variable->location()) {
2548 case Variable::UNALLOCATED: {
2549 // Global var, const, or let variable.
2550 Node* global = BuildLoadGlobalObject();
2551 Unique<Name> name = MakeUnique(variable->name());
2552 const Operator* op =
2553 javascript()->LoadNamed(name, feedback, contextual_mode);
2554 Node* node = NewNode(op, global);
2555 PrepareFrameState(node, bailout_id, OutputFrameStateCombine::Push());
2558 case Variable::PARAMETER:
2559 case Variable::LOCAL: {
2560 // Local var, const, or let variable.
2561 Node* value = environment()->Lookup(variable);
2562 if (mode == CONST_LEGACY) {
2563 // Perform check for uninitialized legacy const variables.
2564 if (value->op() == the_hole->op()) {
2565 value = jsgraph()->UndefinedConstant();
2566 } else if (value->opcode() == IrOpcode::kPhi) {
2567 Node* undefined = jsgraph()->UndefinedConstant();
2568 value = BuildHoleCheckSilent(value, undefined, value);
2570 } else if (mode == LET || mode == CONST) {
2571 // Perform check for uninitialized let/const variables.
2572 if (value->op() == the_hole->op()) {
2573 value = BuildThrowReferenceError(variable, bailout_id);
2574 } else if (value->opcode() == IrOpcode::kPhi) {
2575 value = BuildHoleCheckThrow(value, variable, value, bailout_id);
2580 case Variable::CONTEXT: {
2581 // Context variable (potentially up the context chain).
2582 int depth = current_scope()->ContextChainLength(variable->scope());
2583 bool immutable = variable->maybe_assigned() == kNotAssigned;
2584 const Operator* op =
2585 javascript()->LoadContext(depth, variable->index(), immutable);
2586 Node* value = NewNode(op, current_context());
2587 // TODO(titzer): initialization checks are redundant for already
2588 // initialized immutable context loads, but only specialization knows.
2589 // Maybe specializer should be a parameter to the graph builder?
2590 if (mode == CONST_LEGACY) {
2591 // Perform check for uninitialized legacy const variables.
2592 Node* undefined = jsgraph()->UndefinedConstant();
2593 value = BuildHoleCheckSilent(value, undefined, value);
2594 } else if (mode == LET || mode == CONST) {
2595 // Perform check for uninitialized let/const variables.
2596 value = BuildHoleCheckThrow(value, variable, value, bailout_id);
2600 case Variable::LOOKUP: {
2601 // Dynamic lookup of context variable (anywhere in the chain).
2602 Node* name = jsgraph()->Constant(variable->name());
2603 Runtime::FunctionId function_id =
2604 (contextual_mode == CONTEXTUAL)
2605 ? Runtime::kLoadLookupSlot
2606 : Runtime::kLoadLookupSlotNoReferenceError;
2607 const Operator* op = javascript()->CallRuntime(function_id, 2);
2608 Node* pair = NewNode(op, current_context(), name);
2609 PrepareFrameState(pair, bailout_id, OutputFrameStateCombine::Push(1));
2610 return NewNode(common()->Projection(0), pair);
2618 Node* AstGraphBuilder::BuildVariableDelete(
2619 Variable* variable, BailoutId bailout_id,
2620 OutputFrameStateCombine state_combine) {
2621 switch (variable->location()) {
2622 case Variable::UNALLOCATED: {
2623 // Global var, const, or let variable.
2624 Node* global = BuildLoadGlobalObject();
2625 Node* name = jsgraph()->Constant(variable->name());
2626 const Operator* op = javascript()->DeleteProperty(language_mode());
2627 Node* result = NewNode(op, global, name);
2628 PrepareFrameState(result, bailout_id, state_combine);
2631 case Variable::PARAMETER:
2632 case Variable::LOCAL:
2633 case Variable::CONTEXT:
2634 // Local var, const, or let variable or context variable.
2635 return jsgraph()->BooleanConstant(variable->is_this());
2636 case Variable::LOOKUP: {
2637 // Dynamic lookup of context variable (anywhere in the chain).
2638 Node* name = jsgraph()->Constant(variable->name());
2639 const Operator* op =
2640 javascript()->CallRuntime(Runtime::kDeleteLookupSlot, 2);
2641 Node* result = NewNode(op, current_context(), name);
2642 PrepareFrameState(result, bailout_id, state_combine);
2651 Node* AstGraphBuilder::BuildVariableAssignment(
2652 Variable* variable, Node* value, Token::Value op, BailoutId bailout_id,
2653 OutputFrameStateCombine combine) {
2654 Node* the_hole = jsgraph()->TheHoleConstant();
2655 VariableMode mode = variable->mode();
2656 switch (variable->location()) {
2657 case Variable::UNALLOCATED: {
2658 // Global var, const, or let variable.
2659 Node* global = BuildLoadGlobalObject();
2660 Unique<Name> name = MakeUnique(variable->name());
2661 const Operator* op = javascript()->StoreNamed(language_mode(), name);
2662 Node* store = NewNode(op, global, value);
2663 PrepareFrameState(store, bailout_id, combine);
2666 case Variable::PARAMETER:
2667 case Variable::LOCAL:
2668 // Local var, const, or let variable.
2669 if (mode == CONST_LEGACY && op == Token::INIT_CONST_LEGACY) {
2670 // Perform an initialization check for legacy const variables.
2671 Node* current = environment()->Lookup(variable);
2672 if (current->op() != the_hole->op()) {
2673 value = BuildHoleCheckSilent(current, value, current);
2675 } else if (mode == CONST_LEGACY && op != Token::INIT_CONST_LEGACY) {
2676 // Non-initializing assignments to legacy const is
2677 // - exception in strict mode.
2678 // - ignored in sloppy mode.
2679 if (is_strict(language_mode())) {
2680 return BuildThrowConstAssignError(bailout_id);
2683 } else if (mode == LET && op != Token::INIT_LET) {
2684 // Perform an initialization check for let declared variables.
2685 // Also note that the dynamic hole-check is only done to ensure that
2686 // this does not break in the presence of do-expressions within the
2687 // temporal dead zone of a let declared variable.
2688 Node* current = environment()->Lookup(variable);
2689 if (current->op() == the_hole->op()) {
2690 value = BuildThrowReferenceError(variable, bailout_id);
2691 } else if (value->opcode() == IrOpcode::kPhi) {
2692 value = BuildHoleCheckThrow(current, variable, value, bailout_id);
2694 } else if (mode == CONST && op != Token::INIT_CONST) {
2695 // Non-initializing assignments to const is exception in all modes.
2696 return BuildThrowConstAssignError(bailout_id);
2698 environment()->Bind(variable, value);
2700 case Variable::CONTEXT: {
2701 // Context variable (potentially up the context chain).
2702 int depth = current_scope()->ContextChainLength(variable->scope());
2703 if (mode == CONST_LEGACY && op == Token::INIT_CONST_LEGACY) {
2704 // Perform an initialization check for legacy const variables.
2705 const Operator* op =
2706 javascript()->LoadContext(depth, variable->index(), false);
2707 Node* current = NewNode(op, current_context());
2708 value = BuildHoleCheckSilent(current, value, current);
2709 } else if (mode == CONST_LEGACY && op != Token::INIT_CONST_LEGACY) {
2710 // Non-initializing assignments to legacy const is
2711 // - exception in strict mode.
2712 // - ignored in sloppy mode.
2713 if (is_strict(language_mode())) {
2714 return BuildThrowConstAssignError(bailout_id);
2717 } else if (mode == LET && op != Token::INIT_LET) {
2718 // Perform an initialization check for let declared variables.
2719 const Operator* op =
2720 javascript()->LoadContext(depth, variable->index(), false);
2721 Node* current = NewNode(op, current_context());
2722 value = BuildHoleCheckThrow(current, variable, value, bailout_id);
2723 } else if (mode == CONST && op != Token::INIT_CONST) {
2724 // Non-initializing assignments to const is exception in all modes.
2725 return BuildThrowConstAssignError(bailout_id);
2727 const Operator* op = javascript()->StoreContext(depth, variable->index());
2728 return NewNode(op, current_context(), value);
2730 case Variable::LOOKUP: {
2731 // Dynamic lookup of context variable (anywhere in the chain).
2732 Node* name = jsgraph()->Constant(variable->name());
2733 Node* language = jsgraph()->Constant(language_mode());
2734 // TODO(mstarzinger): Use Runtime::kInitializeLegacyConstLookupSlot for
2735 // initializations of const declarations.
2736 const Operator* op =
2737 javascript()->CallRuntime(Runtime::kStoreLookupSlot, 4);
2738 Node* store = NewNode(op, value, current_context(), name, language);
2739 PrepareFrameState(store, bailout_id, combine);
2748 Node* AstGraphBuilder::BuildLoadObjectField(Node* object, int offset) {
2749 Node* field_load = NewNode(jsgraph()->machine()->Load(kMachAnyTagged), object,
2750 jsgraph()->Int32Constant(offset - kHeapObjectTag));
2755 Node* AstGraphBuilder::BuildLoadBuiltinsObject() {
2756 Node* global = BuildLoadGlobalObject();
2758 BuildLoadObjectField(global, JSGlobalObject::kBuiltinsOffset);
2763 Node* AstGraphBuilder::BuildLoadGlobalObject() {
2764 const Operator* load_op =
2765 javascript()->LoadContext(0, Context::GLOBAL_OBJECT_INDEX, true);
2766 return NewNode(load_op, function_context_.get());
2770 Node* AstGraphBuilder::BuildLoadGlobalProxy() {
2771 Node* global = BuildLoadGlobalObject();
2773 BuildLoadObjectField(global, JSGlobalObject::kGlobalProxyOffset);
2778 Node* AstGraphBuilder::BuildToBoolean(Node* input) {
2779 // TODO(titzer): This should be in a JSOperatorReducer.
2780 switch (input->opcode()) {
2781 case IrOpcode::kInt32Constant:
2782 return jsgraph_->BooleanConstant(!Int32Matcher(input).Is(0));
2783 case IrOpcode::kFloat64Constant:
2784 return jsgraph_->BooleanConstant(!Float64Matcher(input).Is(0));
2785 case IrOpcode::kNumberConstant:
2786 return jsgraph_->BooleanConstant(!NumberMatcher(input).Is(0));
2787 case IrOpcode::kHeapConstant: {
2788 Handle<Object> object = HeapObjectMatcher<Object>(input).Value().handle();
2789 return jsgraph_->BooleanConstant(object->BooleanValue());
2794 if (NodeProperties::IsTyped(input)) {
2795 Type* upper = NodeProperties::GetBounds(input).upper;
2796 if (upper->Is(Type::Boolean())) return input;
2799 return NewNode(javascript()->ToBoolean(), input);
2803 Node* AstGraphBuilder::BuildToName(Node* input, BailoutId bailout_id) {
2804 // TODO(turbofan): Possible optimization is to NOP on name constants. But the
2805 // same caveat as with BuildToBoolean applies, and it should be factored out
2806 // into a JSOperatorReducer.
2807 Node* name = NewNode(javascript()->ToName(), input);
2808 PrepareFrameState(name, bailout_id);
2813 Node* AstGraphBuilder::BuildSetHomeObject(Node* value, Node* home_object,
2815 if (!FunctionLiteral::NeedsHomeObject(expr)) return value;
2816 Unique<Name> name = MakeUnique(isolate()->factory()->home_object_symbol());
2817 const Operator* op = javascript()->StoreNamed(language_mode(), name);
2818 Node* store = NewNode(op, value, home_object);
2819 PrepareFrameState(store, BailoutId::None());
2824 Node* AstGraphBuilder::BuildThrowReferenceError(Variable* variable,
2825 BailoutId bailout_id) {
2826 // TODO(mstarzinger): Should be unified with the VisitThrow implementation.
2827 Node* variable_name = jsgraph()->Constant(variable->name());
2828 const Operator* op =
2829 javascript()->CallRuntime(Runtime::kThrowReferenceError, 1);
2830 Node* call = NewNode(op, variable_name);
2831 PrepareFrameState(call, bailout_id);
2836 Node* AstGraphBuilder::BuildThrowConstAssignError(BailoutId bailout_id) {
2837 // TODO(mstarzinger): Should be unified with the VisitThrow implementation.
2838 const Operator* op =
2839 javascript()->CallRuntime(Runtime::kThrowConstAssignError, 0);
2840 Node* call = NewNode(op);
2841 PrepareFrameState(call, bailout_id);
2846 Node* AstGraphBuilder::BuildReturn(Node* return_value) {
2847 Node* control = NewNode(common()->Return(), return_value);
2848 UpdateControlDependencyToLeaveFunction(control);
2853 Node* AstGraphBuilder::BuildThrow(Node* exception_value) {
2854 NewNode(javascript()->CallRuntime(Runtime::kReThrow, 1), exception_value);
2855 Node* control = NewNode(common()->Throw(), exception_value);
2856 UpdateControlDependencyToLeaveFunction(control);
2861 Node* AstGraphBuilder::BuildBinaryOp(Node* left, Node* right, Token::Value op) {
2862 const Operator* js_op;
2865 js_op = javascript()->BitwiseOr();
2867 case Token::BIT_AND:
2868 js_op = javascript()->BitwiseAnd();
2870 case Token::BIT_XOR:
2871 js_op = javascript()->BitwiseXor();
2874 js_op = javascript()->ShiftLeft();
2877 js_op = javascript()->ShiftRight();
2880 js_op = javascript()->ShiftRightLogical();
2883 js_op = javascript()->Add();
2886 js_op = javascript()->Subtract();
2889 js_op = javascript()->Multiply();
2892 js_op = javascript()->Divide();
2895 js_op = javascript()->Modulus();
2901 return NewNode(js_op, left, right);
2905 Node* AstGraphBuilder::BuildStackCheck() {
2906 IfBuilder stack_check(this);
2908 NewNode(jsgraph()->machine()->Load(kMachPtr),
2909 jsgraph()->ExternalConstant(
2910 ExternalReference::address_of_stack_limit(isolate())),
2911 jsgraph()->ZeroConstant());
2912 Node* stack = NewNode(jsgraph()->machine()->LoadStackPointer());
2913 Node* tag = NewNode(jsgraph()->machine()->UintLessThan(), limit, stack);
2914 stack_check.If(tag, BranchHint::kTrue);
2917 Node* guard = NewNode(javascript()->CallRuntime(Runtime::kStackGuard, 0));
2923 bool AstGraphBuilder::CheckOsrEntry(IterationStatement* stmt) {
2924 if (info()->osr_ast_id() == stmt->OsrEntryId()) {
2925 info()->set_osr_expr_stack_height(std::max(
2926 environment()->stack_height(), info()->osr_expr_stack_height()));
2933 void AstGraphBuilder::PrepareFrameState(Node* node, BailoutId ast_id,
2934 OutputFrameStateCombine combine) {
2935 if (OperatorProperties::HasFrameStateInput(node->op())) {
2936 DCHECK(NodeProperties::GetFrameStateInput(node)->opcode() ==
2938 NodeProperties::ReplaceFrameStateInput(
2939 node, environment()->Checkpoint(ast_id, combine));
2944 BitVector* AstGraphBuilder::GetVariablesAssignedInLoop(
2945 IterationStatement* stmt) {
2946 if (loop_assignment_analysis_ == NULL) return NULL;
2947 return loop_assignment_analysis_->GetVariablesAssignedInLoop(stmt);
2951 Node** AstGraphBuilder::EnsureInputBufferSize(int size) {
2952 if (size > input_buffer_size_) {
2953 size = size + kInputBufferSizeIncrement + input_buffer_size_;
2954 input_buffer_ = local_zone()->NewArray<Node*>(size);
2955 input_buffer_size_ = size;
2957 return input_buffer_;
2961 Node* AstGraphBuilder::MakeNode(const Operator* op, int value_input_count,
2962 Node** value_inputs, bool incomplete) {
2963 DCHECK(op->ValueInputCount() == value_input_count);
2965 bool has_context = OperatorProperties::HasContextInput(op);
2966 bool has_framestate = OperatorProperties::HasFrameStateInput(op);
2967 bool has_control = op->ControlInputCount() == 1;
2968 bool has_effect = op->EffectInputCount() == 1;
2970 DCHECK(op->ControlInputCount() < 2);
2971 DCHECK(op->EffectInputCount() < 2);
2973 Node* result = NULL;
2974 if (!has_context && !has_framestate && !has_control && !has_effect) {
2975 result = graph()->NewNode(op, value_input_count, value_inputs, incomplete);
2977 int input_count_with_deps = value_input_count;
2978 if (has_context) ++input_count_with_deps;
2979 if (has_framestate) ++input_count_with_deps;
2980 if (has_control) ++input_count_with_deps;
2981 if (has_effect) ++input_count_with_deps;
2982 Node** buffer = EnsureInputBufferSize(input_count_with_deps);
2983 memcpy(buffer, value_inputs, kPointerSize * value_input_count);
2984 Node** current_input = buffer + value_input_count;
2986 *current_input++ = current_context();
2988 if (has_framestate) {
2989 // The frame state will be inserted later. Here we misuse
2990 // the {DeadControl} node as a sentinel to be later overwritten
2991 // with the real frame state.
2992 *current_input++ = jsgraph()->DeadControl();
2995 *current_input++ = environment_->GetEffectDependency();
2998 *current_input++ = environment_->GetControlDependency();
3000 result = graph()->NewNode(op, input_count_with_deps, buffer, incomplete);
3002 environment_->UpdateEffectDependency(result);
3004 if (result->op()->ControlOutputCount() > 0 &&
3005 !environment()->IsMarkedAsUnreachable()) {
3006 environment_->UpdateControlDependency(result);
3014 void AstGraphBuilder::UpdateControlDependencyToLeaveFunction(Node* exit) {
3015 if (environment()->IsMarkedAsUnreachable()) return;
3016 if (exit_control() != NULL) {
3017 exit = MergeControl(exit_control(), exit);
3019 environment()->MarkAsUnreachable();
3020 set_exit_control(exit);
3024 void AstGraphBuilder::Environment::Merge(Environment* other) {
3025 DCHECK(values_.size() == other->values_.size());
3026 // TODO(titzer): make context stack heights match.
3027 DCHECK(contexts_.size() <= other->contexts_.size());
3029 // Nothing to do if the other environment is dead.
3030 if (other->IsMarkedAsUnreachable()) return;
3032 // Resurrect a dead environment by copying the contents of the other one and
3033 // placing a singleton merge as the new control dependency.
3034 if (this->IsMarkedAsUnreachable()) {
3035 Node* other_control = other->control_dependency_;
3036 Node* inputs[] = {other_control};
3037 control_dependency_ =
3038 graph()->NewNode(common()->Merge(1), arraysize(inputs), inputs, true);
3039 effect_dependency_ = other->effect_dependency_;
3040 values_ = other->values_;
3041 // TODO(titzer): make context stack heights match.
3042 size_t min = std::min(contexts_.size(), other->contexts_.size());
3043 contexts_ = other->contexts_;
3044 contexts_.resize(min, nullptr);
3048 // Create a merge of the control dependencies of both environments and update
3049 // the current environment's control dependency accordingly.
3050 Node* control = builder_->MergeControl(this->GetControlDependency(),
3051 other->GetControlDependency());
3052 UpdateControlDependency(control);
3054 // Create a merge of the effect dependencies of both environments and update
3055 // the current environment's effect dependency accordingly.
3056 Node* effect = builder_->MergeEffect(this->GetEffectDependency(),
3057 other->GetEffectDependency(), control);
3058 UpdateEffectDependency(effect);
3060 // Introduce Phi nodes for values that have differing input at merge points,
3061 // potentially extending an existing Phi node if possible.
3062 for (int i = 0; i < static_cast<int>(values_.size()); ++i) {
3063 values_[i] = builder_->MergeValue(values_[i], other->values_[i], control);
3065 for (int i = 0; i < static_cast<int>(contexts_.size()); ++i) {
3067 builder_->MergeValue(contexts_[i], other->contexts_[i], control);
3072 void AstGraphBuilder::Environment::PrepareForLoop(BitVector* assigned,
3074 int size = static_cast<int>(values()->size());
3076 Node* control = builder_->NewLoop();
3077 if (assigned == nullptr) {
3078 // Assume that everything is updated in the loop.
3079 for (int i = 0; i < size; ++i) {
3080 values()->at(i) = builder_->NewPhi(1, values()->at(i), control);
3083 // Only build phis for those locals assigned in this loop.
3084 for (int i = 0; i < size; ++i) {
3085 if (i < assigned->length() && !assigned->Contains(i)) continue;
3086 Node* phi = builder_->NewPhi(1, values()->at(i), control);
3087 values()->at(i) = phi;
3090 Node* effect = builder_->NewEffectPhi(1, GetEffectDependency(), control);
3091 UpdateEffectDependency(effect);
3093 if (builder_->info()->is_osr()) {
3094 // Introduce phis for all context values in the case of an OSR graph.
3095 for (int i = 0; i < static_cast<int>(contexts()->size()); ++i) {
3096 Node* val = contexts()->at(i);
3097 if (!IrOpcode::IsConstantOpcode(val->opcode())) {
3098 contexts()->at(i) = builder_->NewPhi(1, val, control);
3104 // Merge OSR values as inputs to the phis of the loop.
3105 Graph* graph = builder_->graph();
3106 Node* osr_loop_entry = builder_->graph()->NewNode(
3107 builder_->common()->OsrLoopEntry(), graph->start(), graph->start());
3109 builder_->MergeControl(control, osr_loop_entry);
3110 builder_->MergeEffect(effect, osr_loop_entry, control);
3112 for (int i = 0; i < size; ++i) {
3113 Node* val = values()->at(i);
3114 if (!IrOpcode::IsConstantOpcode(val->opcode())) {
3116 graph->NewNode(builder_->common()->OsrValue(i), osr_loop_entry);
3117 values()->at(i) = builder_->MergeValue(val, osr_value, control);
3121 // Rename all the contexts in the environment.
3122 // The innermost context is the OSR value, and the outer contexts are
3123 // reconstructed by dynamically walking up the context chain.
3124 Node* osr_context = nullptr;
3125 const Operator* op =
3126 builder_->javascript()->LoadContext(0, Context::PREVIOUS_INDEX, true);
3127 int last = static_cast<int>(contexts()->size() - 1);
3128 for (int i = last; i >= 0; i--) {
3129 Node* val = contexts()->at(i);
3130 if (!IrOpcode::IsConstantOpcode(val->opcode())) {
3131 osr_context = (i == last) ? builder_->NewCurrentContextOsrValue()
3132 : graph->NewNode(op, osr_context, osr_context,
3134 contexts()->at(i) = builder_->MergeValue(val, osr_context, control);
3143 Node* AstGraphBuilder::NewPhi(int count, Node* input, Node* control) {
3144 const Operator* phi_op = common()->Phi(kMachAnyTagged, count);
3145 Node** buffer = EnsureInputBufferSize(count + 1);
3146 MemsetPointer(buffer, input, count);
3147 buffer[count] = control;
3148 return graph()->NewNode(phi_op, count + 1, buffer, true);
3152 // TODO(mstarzinger): Revisit this once we have proper effect states.
3153 Node* AstGraphBuilder::NewEffectPhi(int count, Node* input, Node* control) {
3154 const Operator* phi_op = common()->EffectPhi(count);
3155 Node** buffer = EnsureInputBufferSize(count + 1);
3156 MemsetPointer(buffer, input, count);
3157 buffer[count] = control;
3158 return graph()->NewNode(phi_op, count + 1, buffer, true);
3162 Node* AstGraphBuilder::MergeControl(Node* control, Node* other) {
3163 int inputs = control->op()->ControlInputCount() + 1;
3164 if (control->opcode() == IrOpcode::kLoop) {
3165 // Control node for loop exists, add input.
3166 const Operator* op = common()->Loop(inputs);
3167 control->AppendInput(graph_zone(), other);
3168 control->set_op(op);
3169 } else if (control->opcode() == IrOpcode::kMerge) {
3170 // Control node for merge exists, add input.
3171 const Operator* op = common()->Merge(inputs);
3172 control->AppendInput(graph_zone(), other);
3173 control->set_op(op);
3175 // Control node is a singleton, introduce a merge.
3176 const Operator* op = common()->Merge(inputs);
3177 Node* inputs[] = {control, other};
3178 control = graph()->NewNode(op, arraysize(inputs), inputs, true);
3184 Node* AstGraphBuilder::MergeEffect(Node* value, Node* other, Node* control) {
3185 int inputs = control->op()->ControlInputCount();
3186 if (value->opcode() == IrOpcode::kEffectPhi &&
3187 NodeProperties::GetControlInput(value) == control) {
3188 // Phi already exists, add input.
3189 value->set_op(common()->EffectPhi(inputs));
3190 value->InsertInput(graph_zone(), inputs - 1, other);
3191 } else if (value != other) {
3192 // Phi does not exist yet, introduce one.
3193 value = NewEffectPhi(inputs, value, control);
3194 value->ReplaceInput(inputs - 1, other);
3200 Node* AstGraphBuilder::MergeValue(Node* value, Node* other, Node* control) {
3201 int inputs = control->op()->ControlInputCount();
3202 if (value->opcode() == IrOpcode::kPhi &&
3203 NodeProperties::GetControlInput(value) == control) {
3204 // Phi already exists, add input.
3205 value->set_op(common()->Phi(kMachAnyTagged, inputs));
3206 value->InsertInput(graph_zone(), inputs - 1, other);
3207 } else if (value != other) {
3208 // Phi does not exist yet, introduce one.
3209 value = NewPhi(inputs, value, control);
3210 value->ReplaceInput(inputs - 1, other);
3215 } // namespace compiler
3216 } // namespace internal