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/control-builders.h"
9 #include "src/compiler/machine-operator.h"
10 #include "src/compiler/node-properties.h"
11 #include "src/compiler/node-properties-inl.h"
12 #include "src/full-codegen.h"
13 #include "src/parser.h"
14 #include "src/scopes.h"
20 AstGraphBuilder::AstGraphBuilder(CompilationInfo* info, JSGraph* jsgraph)
21 : StructuredGraphBuilder(jsgraph->graph(), jsgraph->common()),
24 globals_(0, info->zone()),
26 execution_context_(NULL) {
27 InitializeAstVisitor(info->zone());
31 Node* AstGraphBuilder::GetFunctionClosure() {
32 if (!function_closure_.is_set()) {
33 // Parameter -1 is special for the function closure
34 const Operator* op = common()->Parameter(-1);
35 Node* node = NewNode(op, graph()->start());
36 function_closure_.set(node);
38 return function_closure_.get();
42 Node* AstGraphBuilder::GetFunctionContext() {
43 if (!function_context_.is_set()) {
44 // Parameter (arity + 1) is special for the outer context of the function
45 const Operator* op = common()->Parameter(info()->num_parameters() + 1);
46 Node* node = NewNode(op, graph()->start());
47 function_context_.set(node);
49 return function_context_.get();
53 bool AstGraphBuilder::CreateGraph() {
54 Scope* scope = info()->scope();
55 DCHECK(graph() != NULL);
57 // Set up the basic structure of the graph.
58 int parameter_count = info()->num_parameters();
59 graph()->SetStart(graph()->NewNode(common()->Start(parameter_count)));
61 // Initialize the top-level environment.
62 Environment env(this, scope, graph()->start());
63 set_environment(&env);
65 // Build node to initialize local function context.
66 Node* closure = GetFunctionClosure();
67 Node* outer = GetFunctionContext();
68 Node* inner = BuildLocalFunctionContext(outer, closure);
70 // Push top-level function scope for the function body.
71 ContextScope top_context(this, scope, inner);
73 // Build the arguments object if it is used.
74 BuildArgumentsObject(scope->arguments());
76 // Emit tracing call if requested to do so.
78 NewNode(javascript()->Runtime(Runtime::kTraceEnter, 0));
81 // Visit implicit declaration of the function name.
82 if (scope->is_function_scope() && scope->function() != NULL) {
83 VisitVariableDeclaration(scope->function());
86 // Visit declarations within the function scope.
87 VisitDeclarations(scope->declarations());
89 // TODO(mstarzinger): This should do an inlined stack check.
90 Node* node = NewNode(javascript()->Runtime(Runtime::kStackGuard, 0));
91 PrepareFrameState(node, BailoutId::FunctionEntry());
93 // Visit statements in the function body.
94 VisitStatements(info()->function()->body());
95 if (HasStackOverflow()) return false;
97 // Emit tracing call if requested to do so.
99 // TODO(mstarzinger): Only traces implicit return.
100 Node* return_value = jsgraph()->UndefinedConstant();
101 NewNode(javascript()->Runtime(Runtime::kTraceExit, 1), return_value);
104 // Return 'undefined' in case we can fall off the end.
105 Node* control = NewNode(common()->Return(), jsgraph()->UndefinedConstant());
106 UpdateControlDependencyToLeaveFunction(control);
108 // Finish the basic structure of the graph.
109 environment()->UpdateControlDependency(exit_control());
110 graph()->SetEnd(NewNode(common()->End()));
116 // Left-hand side can only be a property, a global or a variable slot.
117 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
120 // Determine the left-hand side kind of an assignment.
121 static LhsKind DetermineLhsKind(Expression* expr) {
122 Property* property = expr->AsProperty();
123 DCHECK(expr->IsValidReferenceExpression());
125 (property == NULL) ? VARIABLE : (property->key()->IsPropertyName())
132 // Helper to find an existing shared function info in the baseline code for the
133 // given function literal. Used to canonicalize SharedFunctionInfo objects.
134 static Handle<SharedFunctionInfo> SearchSharedFunctionInfo(
135 Code* unoptimized_code, FunctionLiteral* expr) {
136 int start_position = expr->start_position();
137 for (RelocIterator it(unoptimized_code); !it.done(); it.next()) {
138 RelocInfo* rinfo = it.rinfo();
139 if (rinfo->rmode() != RelocInfo::EMBEDDED_OBJECT) continue;
140 Object* obj = rinfo->target_object();
141 if (obj->IsSharedFunctionInfo()) {
142 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
143 if (shared->start_position() == start_position) {
144 return Handle<SharedFunctionInfo>(shared);
148 return Handle<SharedFunctionInfo>();
152 StructuredGraphBuilder::Environment* AstGraphBuilder::CopyEnvironment(
153 StructuredGraphBuilder::Environment* env) {
154 return new (zone()) Environment(*reinterpret_cast<Environment*>(env));
158 AstGraphBuilder::Environment::Environment(AstGraphBuilder* builder,
160 Node* control_dependency)
161 : StructuredGraphBuilder::Environment(builder, control_dependency),
162 parameters_count_(scope->num_parameters() + 1),
163 locals_count_(scope->num_stack_slots()),
164 parameters_node_(NULL),
167 DCHECK_EQ(scope->num_parameters() + 1, parameters_count());
169 // Bind the receiver variable.
170 Node* receiver = builder->graph()->NewNode(common()->Parameter(0),
171 builder->graph()->start());
172 values()->push_back(receiver);
174 // Bind all parameter variables. The parameter indices are shifted by 1
175 // (receiver is parameter index -1 but environment index 0).
176 for (int i = 0; i < scope->num_parameters(); ++i) {
177 Node* parameter = builder->graph()->NewNode(common()->Parameter(i + 1),
178 builder->graph()->start());
179 values()->push_back(parameter);
182 // Bind all local variables to undefined.
183 Node* undefined_constant = builder->jsgraph()->UndefinedConstant();
184 values()->insert(values()->end(), locals_count(), undefined_constant);
188 AstGraphBuilder::Environment::Environment(const Environment& copy)
189 : StructuredGraphBuilder::Environment(
190 static_cast<StructuredGraphBuilder::Environment>(copy)),
191 parameters_count_(copy.parameters_count_),
192 locals_count_(copy.locals_count_),
193 parameters_node_(copy.parameters_node_),
194 locals_node_(copy.locals_node_),
195 stack_node_(copy.stack_node_) {}
198 void AstGraphBuilder::Environment::UpdateStateValues(Node** state_values,
199 int offset, int count) {
200 bool should_update = false;
201 Node** env_values = (count == 0) ? NULL : &values()->at(offset);
202 if (*state_values == NULL || (*state_values)->InputCount() != count) {
203 should_update = true;
205 DCHECK(static_cast<size_t>(offset + count) <= values()->size());
206 for (int i = 0; i < count; i++) {
207 if ((*state_values)->InputAt(i) != env_values[i]) {
208 should_update = true;
214 const Operator* op = common()->StateValues(count);
215 (*state_values) = graph()->NewNode(op, count, env_values);
220 Node* AstGraphBuilder::Environment::Checkpoint(
221 BailoutId ast_id, OutputFrameStateCombine combine) {
222 UpdateStateValues(¶meters_node_, 0, parameters_count());
223 UpdateStateValues(&locals_node_, parameters_count(), locals_count());
224 UpdateStateValues(&stack_node_, parameters_count() + locals_count(),
227 const Operator* op = common()->FrameState(JS_FRAME, ast_id, combine);
229 return graph()->NewNode(op, parameters_node_, locals_node_, stack_node_,
231 builder()->jsgraph()->UndefinedConstant());
235 AstGraphBuilder::AstContext::AstContext(AstGraphBuilder* own,
236 Expression::Context kind)
237 : kind_(kind), owner_(own), outer_(own->ast_context()) {
238 owner()->set_ast_context(this); // Push.
240 original_height_ = environment()->stack_height();
245 AstGraphBuilder::AstContext::~AstContext() {
246 owner()->set_ast_context(outer_); // Pop.
250 AstGraphBuilder::AstEffectContext::~AstEffectContext() {
251 DCHECK(environment()->stack_height() == original_height_);
255 AstGraphBuilder::AstValueContext::~AstValueContext() {
256 DCHECK(environment()->stack_height() == original_height_ + 1);
260 AstGraphBuilder::AstTestContext::~AstTestContext() {
261 DCHECK(environment()->stack_height() == original_height_ + 1);
265 void AstGraphBuilder::AstEffectContext::ProduceValue(Node* value) {
266 // The value is ignored.
270 void AstGraphBuilder::AstValueContext::ProduceValue(Node* value) {
271 environment()->Push(value);
275 void AstGraphBuilder::AstTestContext::ProduceValue(Node* value) {
276 environment()->Push(owner()->BuildToBoolean(value));
280 Node* AstGraphBuilder::AstEffectContext::ConsumeValue() { return NULL; }
283 Node* AstGraphBuilder::AstValueContext::ConsumeValue() {
284 return environment()->Pop();
288 Node* AstGraphBuilder::AstTestContext::ConsumeValue() {
289 return environment()->Pop();
293 AstGraphBuilder::BreakableScope* AstGraphBuilder::BreakableScope::FindBreakable(
294 BreakableStatement* target) {
295 BreakableScope* current = this;
296 while (current != NULL && current->target_ != target) {
297 owner_->environment()->Drop(current->drop_extra_);
298 current = current->next_;
300 DCHECK(current != NULL); // Always found (unless stack is malformed).
305 void AstGraphBuilder::BreakableScope::BreakTarget(BreakableStatement* stmt) {
306 FindBreakable(stmt)->control_->Break();
310 void AstGraphBuilder::BreakableScope::ContinueTarget(BreakableStatement* stmt) {
311 FindBreakable(stmt)->control_->Continue();
315 void AstGraphBuilder::VisitForValueOrNull(Expression* expr) {
317 return environment()->Push(jsgraph()->NullConstant());
323 void AstGraphBuilder::VisitForValues(ZoneList<Expression*>* exprs) {
324 for (int i = 0; i < exprs->length(); ++i) {
325 VisitForValue(exprs->at(i));
330 void AstGraphBuilder::VisitForValue(Expression* expr) {
331 AstValueContext for_value(this);
332 if (!HasStackOverflow()) {
338 void AstGraphBuilder::VisitForEffect(Expression* expr) {
339 AstEffectContext for_effect(this);
340 if (!HasStackOverflow()) {
346 void AstGraphBuilder::VisitForTest(Expression* expr) {
347 AstTestContext for_condition(this);
348 if (!HasStackOverflow()) {
354 void AstGraphBuilder::VisitVariableDeclaration(VariableDeclaration* decl) {
355 Variable* variable = decl->proxy()->var();
356 VariableMode mode = decl->mode();
357 bool hole_init = mode == CONST || mode == CONST_LEGACY || mode == LET;
358 switch (variable->location()) {
359 case Variable::UNALLOCATED: {
360 Handle<Oddball> value = variable->binding_needs_init()
361 ? isolate()->factory()->the_hole_value()
362 : isolate()->factory()->undefined_value();
363 globals()->Add(variable->name(), zone());
364 globals()->Add(value, zone());
367 case Variable::PARAMETER:
368 case Variable::LOCAL:
370 Node* value = jsgraph()->TheHoleConstant();
371 environment()->Bind(variable, value);
374 case Variable::CONTEXT:
376 Node* value = jsgraph()->TheHoleConstant();
377 const Operator* op = javascript()->StoreContext(0, variable->index());
378 NewNode(op, current_context(), value);
381 case Variable::LOOKUP:
387 void AstGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* decl) {
388 Variable* variable = decl->proxy()->var();
389 switch (variable->location()) {
390 case Variable::UNALLOCATED: {
391 Handle<SharedFunctionInfo> function =
392 Compiler::BuildFunctionInfo(decl->fun(), info()->script(), info());
393 // Check for stack-overflow exception.
394 if (function.is_null()) return SetStackOverflow();
395 globals()->Add(variable->name(), zone());
396 globals()->Add(function, zone());
399 case Variable::PARAMETER:
400 case Variable::LOCAL: {
401 VisitForValue(decl->fun());
402 Node* value = environment()->Pop();
403 environment()->Bind(variable, value);
406 case Variable::CONTEXT: {
407 VisitForValue(decl->fun());
408 Node* value = environment()->Pop();
409 const Operator* op = javascript()->StoreContext(0, variable->index());
410 NewNode(op, current_context(), value);
413 case Variable::LOOKUP:
419 void AstGraphBuilder::VisitModuleDeclaration(ModuleDeclaration* decl) {
424 void AstGraphBuilder::VisitImportDeclaration(ImportDeclaration* decl) {
429 void AstGraphBuilder::VisitExportDeclaration(ExportDeclaration* decl) {
434 void AstGraphBuilder::VisitModuleLiteral(ModuleLiteral* modl) { UNREACHABLE(); }
437 void AstGraphBuilder::VisitModuleVariable(ModuleVariable* modl) {
442 void AstGraphBuilder::VisitModulePath(ModulePath* modl) { UNREACHABLE(); }
445 void AstGraphBuilder::VisitModuleUrl(ModuleUrl* modl) { UNREACHABLE(); }
448 void AstGraphBuilder::VisitBlock(Block* stmt) {
449 BlockBuilder block(this);
450 BreakableScope scope(this, stmt, &block, 0);
451 if (stmt->labels() != NULL) block.BeginBlock();
452 if (stmt->scope() == NULL) {
453 // Visit statements in the same scope, no declarations.
454 VisitStatements(stmt->statements());
456 const Operator* op = javascript()->CreateBlockContext();
457 Node* scope_info = jsgraph()->Constant(stmt->scope()->GetScopeInfo());
458 Node* context = NewNode(op, scope_info, GetFunctionClosure());
459 ContextScope scope(this, stmt->scope(), context);
461 // Visit declarations and statements in a block scope.
462 VisitDeclarations(stmt->scope()->declarations());
463 VisitStatements(stmt->statements());
465 if (stmt->labels() != NULL) block.EndBlock();
469 void AstGraphBuilder::VisitModuleStatement(ModuleStatement* stmt) {
474 void AstGraphBuilder::VisitExpressionStatement(ExpressionStatement* stmt) {
475 VisitForEffect(stmt->expression());
479 void AstGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) {
484 void AstGraphBuilder::VisitIfStatement(IfStatement* stmt) {
485 IfBuilder compare_if(this);
486 VisitForTest(stmt->condition());
487 Node* condition = environment()->Pop();
488 compare_if.If(condition);
490 Visit(stmt->then_statement());
492 Visit(stmt->else_statement());
497 void AstGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) {
498 StructuredGraphBuilder::Environment* env = environment()->CopyAsUnreachable();
499 breakable()->ContinueTarget(stmt->target());
500 set_environment(env);
504 void AstGraphBuilder::VisitBreakStatement(BreakStatement* stmt) {
505 StructuredGraphBuilder::Environment* env = environment()->CopyAsUnreachable();
506 breakable()->BreakTarget(stmt->target());
507 set_environment(env);
511 void AstGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
512 VisitForValue(stmt->expression());
513 Node* result = environment()->Pop();
514 Node* control = NewNode(common()->Return(), result);
515 UpdateControlDependencyToLeaveFunction(control);
519 void AstGraphBuilder::VisitWithStatement(WithStatement* stmt) {
520 VisitForValue(stmt->expression());
521 Node* value = environment()->Pop();
522 const Operator* op = javascript()->CreateWithContext();
523 Node* context = NewNode(op, value, GetFunctionClosure());
524 ContextScope scope(this, stmt->scope(), context);
525 Visit(stmt->statement());
529 void AstGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
530 ZoneList<CaseClause*>* clauses = stmt->cases();
531 SwitchBuilder compare_switch(this, clauses->length());
532 BreakableScope scope(this, stmt, &compare_switch, 0);
533 compare_switch.BeginSwitch();
534 int default_index = -1;
536 // Keep the switch value on the stack until a case matches.
537 VisitForValue(stmt->tag());
538 Node* tag = environment()->Top();
540 // Iterate over all cases and create nodes for label comparison.
541 for (int i = 0; i < clauses->length(); i++) {
542 CaseClause* clause = clauses->at(i);
544 // The default is not a test, remember index.
545 if (clause->is_default()) {
550 // Create nodes to perform label comparison as if via '==='. The switch
551 // value is still on the operand stack while the label is evaluated.
552 VisitForValue(clause->label());
553 Node* label = environment()->Pop();
554 const Operator* op = javascript()->StrictEqual();
555 Node* condition = NewNode(op, tag, label);
556 compare_switch.BeginLabel(i, condition);
558 // Discard the switch value at label match.
559 environment()->Pop();
560 compare_switch.EndLabel();
563 // Discard the switch value and mark the default case.
564 environment()->Pop();
565 if (default_index >= 0) {
566 compare_switch.DefaultAt(default_index);
569 // Iterate over all cases and create nodes for case bodies.
570 for (int i = 0; i < clauses->length(); i++) {
571 CaseClause* clause = clauses->at(i);
572 compare_switch.BeginCase(i);
573 VisitStatements(clause->statements());
574 compare_switch.EndCase();
577 compare_switch.EndSwitch();
581 void AstGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
582 LoopBuilder while_loop(this);
583 while_loop.BeginLoop();
584 VisitIterationBody(stmt, &while_loop, 0);
585 while_loop.EndBody();
586 VisitForTest(stmt->cond());
587 Node* condition = environment()->Pop();
588 while_loop.BreakUnless(condition);
589 while_loop.EndLoop();
593 void AstGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
594 LoopBuilder while_loop(this);
595 while_loop.BeginLoop();
596 VisitForTest(stmt->cond());
597 Node* condition = environment()->Pop();
598 while_loop.BreakUnless(condition);
599 VisitIterationBody(stmt, &while_loop, 0);
600 while_loop.EndBody();
601 while_loop.EndLoop();
605 void AstGraphBuilder::VisitForStatement(ForStatement* stmt) {
606 LoopBuilder for_loop(this);
607 VisitIfNotNull(stmt->init());
608 for_loop.BeginLoop();
609 if (stmt->cond() != NULL) {
610 VisitForTest(stmt->cond());
611 Node* condition = environment()->Pop();
612 for_loop.BreakUnless(condition);
614 VisitIterationBody(stmt, &for_loop, 0);
616 VisitIfNotNull(stmt->next());
621 // TODO(dcarney): this is a big function. Try to clean up some.
622 void AstGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
623 VisitForValue(stmt->subject());
624 Node* obj = environment()->Pop();
625 // Check for undefined or null before entering loop.
626 IfBuilder is_undefined(this);
627 Node* is_undefined_cond =
628 NewNode(javascript()->StrictEqual(), obj, jsgraph()->UndefinedConstant());
629 is_undefined.If(is_undefined_cond);
633 IfBuilder is_null(this);
635 NewNode(javascript()->StrictEqual(), obj, jsgraph()->NullConstant());
636 is_null.If(is_null_cond);
639 // Convert object to jsobject.
640 // PrepareForBailoutForId(stmt->PrepareId(), TOS_REG);
641 obj = NewNode(javascript()->ToObject(), obj);
642 environment()->Push(obj);
643 // TODO(dcarney): should do a fast enum cache check here to skip runtime.
644 environment()->Push(obj);
645 Node* cache_type = ProcessArguments(
646 javascript()->Runtime(Runtime::kGetPropertyNamesFast, 1), 1);
647 // TODO(dcarney): these next runtime calls should be removed in favour of
648 // a few simplified instructions.
649 environment()->Push(obj);
650 environment()->Push(cache_type);
652 ProcessArguments(javascript()->Runtime(Runtime::kForInInit, 2), 2);
653 // cache_type may have been replaced.
654 Node* cache_array = NewNode(common()->Projection(0), cache_pair);
655 cache_type = NewNode(common()->Projection(1), cache_pair);
656 environment()->Push(cache_type);
657 environment()->Push(cache_array);
658 Node* cache_length = ProcessArguments(
659 javascript()->Runtime(Runtime::kForInCacheArrayLength, 2), 2);
661 // TODO(dcarney): this check is actually supposed to be for the
662 // empty enum case only.
663 IfBuilder have_no_properties(this);
664 Node* empty_array_cond = NewNode(javascript()->StrictEqual(),
665 cache_length, jsgraph()->ZeroConstant());
666 have_no_properties.If(empty_array_cond);
667 have_no_properties.Then();
668 // Pop obj and skip loop.
669 environment()->Pop();
670 have_no_properties.Else();
672 // Construct the rest of the environment.
673 environment()->Push(cache_type);
674 environment()->Push(cache_array);
675 environment()->Push(cache_length);
676 environment()->Push(jsgraph()->ZeroConstant());
677 // PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
678 LoopBuilder for_loop(this);
679 for_loop.BeginLoop();
680 // Check loop termination condition.
681 Node* index = environment()->Peek(0);
683 NewNode(javascript()->LessThan(), index, cache_length);
684 // TODO(jarin): provide real bailout id.
685 PrepareFrameState(exit_cond, BailoutId::None());
686 for_loop.BreakUnless(exit_cond);
687 // TODO(dcarney): this runtime call should be a handful of
688 // simplified instructions that
690 // value = array[index]
691 environment()->Push(obj);
692 environment()->Push(cache_array);
693 environment()->Push(cache_type);
694 environment()->Push(index);
696 ProcessArguments(javascript()->Runtime(Runtime::kForInNext, 4), 4);
697 Node* value = NewNode(common()->Projection(0), pair);
698 Node* should_filter = NewNode(common()->Projection(1), pair);
699 environment()->Push(value);
701 // Test if FILTER_KEY needs to be called.
702 IfBuilder test_should_filter(this);
703 Node* should_filter_cond =
704 NewNode(javascript()->StrictEqual(), should_filter,
705 jsgraph()->TrueConstant());
706 test_should_filter.If(should_filter_cond);
707 test_should_filter.Then();
708 value = environment()->Pop();
709 Node* builtins = BuildLoadBuiltinsObject();
710 Node* function = BuildLoadObjectField(
712 JSBuiltinsObject::OffsetOfFunctionWithId(Builtins::FILTER_KEY));
714 environment()->Push(function);
716 environment()->Push(obj);
718 environment()->Push(value);
719 // result is either the string key or Smi(0) indicating the property
721 Node* res = ProcessArguments(
722 javascript()->Call(3, NO_CALL_FUNCTION_FLAGS), 3);
723 // TODO(jarin): provide real bailout id.
724 PrepareFrameState(res, BailoutId::None());
725 Node* property_missing = NewNode(javascript()->StrictEqual(), res,
726 jsgraph()->ZeroConstant());
728 IfBuilder is_property_missing(this);
729 is_property_missing.If(property_missing);
730 is_property_missing.Then();
731 // Inc counter and continue.
733 NewNode(javascript()->Add(), index, jsgraph()->OneConstant());
734 // TODO(jarin): provide real bailout id.
735 PrepareFrameState(index_inc, BailoutId::None());
736 environment()->Poke(0, index_inc);
738 is_property_missing.Else();
739 is_property_missing.End();
741 // Replace 'value' in environment.
742 environment()->Push(res);
743 test_should_filter.Else();
744 test_should_filter.End();
746 value = environment()->Pop();
747 // Bind value and do loop body.
748 VisitForInAssignment(stmt->each(), value);
749 VisitIterationBody(stmt, &for_loop, 5);
751 // Inc counter and continue.
753 NewNode(javascript()->Add(), index, jsgraph()->OneConstant());
754 // TODO(jarin): provide real bailout id.
755 PrepareFrameState(index_inc, BailoutId::None());
756 environment()->Poke(0, index_inc);
758 environment()->Drop(5);
759 // PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
761 have_no_properties.End();
769 void AstGraphBuilder::VisitForOfStatement(ForOfStatement* stmt) {
770 VisitForValue(stmt->subject());
771 environment()->Pop();
772 // TODO(turbofan): create and use loop builder.
776 void AstGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) {
781 void AstGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
786 void AstGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
787 // TODO(turbofan): Do we really need a separate reloc-info for this?
788 Node* node = NewNode(javascript()->Runtime(Runtime::kDebugBreak, 0));
789 PrepareFrameState(node, stmt->DebugBreakId());
793 void AstGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
794 Node* context = current_context();
796 // Build a new shared function info if we cannot find one in the baseline
797 // code. We also have a stack overflow if the recursive compilation did.
798 Handle<SharedFunctionInfo> shared_info =
799 SearchSharedFunctionInfo(info()->shared_info()->code(), expr);
800 if (shared_info.is_null()) {
801 shared_info = Compiler::BuildFunctionInfo(expr, info()->script(), info());
802 CHECK(!shared_info.is_null()); // TODO(mstarzinger): Set stack overflow?
805 // Create node to instantiate a new closure.
806 Node* info = jsgraph()->Constant(shared_info);
807 Node* pretenure = expr->pretenure() ? jsgraph()->TrueConstant()
808 : jsgraph()->FalseConstant();
809 const Operator* op = javascript()->Runtime(Runtime::kNewClosure, 3);
810 Node* value = NewNode(op, context, info, pretenure);
811 ast_context()->ProduceValue(value);
815 void AstGraphBuilder::VisitClassLiteral(ClassLiteral* expr) {
816 // TODO(arv): Implement.
821 void AstGraphBuilder::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
826 void AstGraphBuilder::VisitConditional(Conditional* expr) {
827 IfBuilder compare_if(this);
828 VisitForTest(expr->condition());
829 Node* condition = environment()->Pop();
830 compare_if.If(condition);
832 Visit(expr->then_expression());
834 Visit(expr->else_expression());
836 ast_context()->ReplaceValue();
840 void AstGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
841 Node* value = BuildVariableLoad(expr->var(), expr->id());
842 ast_context()->ProduceValue(value);
846 void AstGraphBuilder::VisitLiteral(Literal* expr) {
847 Node* value = jsgraph()->Constant(expr->value());
848 ast_context()->ProduceValue(value);
852 void AstGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
853 Node* closure = GetFunctionClosure();
855 // Create node to materialize a regular expression literal.
856 Node* literals_array =
857 BuildLoadObjectField(closure, JSFunction::kLiteralsOffset);
858 Node* literal_index = jsgraph()->Constant(expr->literal_index());
859 Node* pattern = jsgraph()->Constant(expr->pattern());
860 Node* flags = jsgraph()->Constant(expr->flags());
862 javascript()->Runtime(Runtime::kMaterializeRegExpLiteral, 4);
863 Node* literal = NewNode(op, literals_array, literal_index, pattern, flags);
864 ast_context()->ProduceValue(literal);
868 void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
869 Node* closure = GetFunctionClosure();
871 // Create node to deep-copy the literal boilerplate.
872 expr->BuildConstantProperties(isolate());
873 Node* literals_array =
874 BuildLoadObjectField(closure, JSFunction::kLiteralsOffset);
875 Node* literal_index = jsgraph()->Constant(expr->literal_index());
876 Node* constants = jsgraph()->Constant(expr->constant_properties());
877 Node* flags = jsgraph()->Constant(expr->ComputeFlags());
878 const Operator* op = javascript()->Runtime(Runtime::kCreateObjectLiteral, 4);
879 Node* literal = NewNode(op, literals_array, literal_index, constants, flags);
881 // The object is expected on the operand stack during computation of the
882 // property values and is the value of the entire expression.
883 environment()->Push(literal);
885 // Mark all computed expressions that are bound to a key that is shadowed by
886 // a later occurrence of the same key. For the marked expressions, no store
888 expr->CalculateEmitStore(zone());
890 // Create nodes to store computed values into the literal.
891 AccessorTable accessor_table(zone());
892 for (int i = 0; i < expr->properties()->length(); i++) {
893 ObjectLiteral::Property* property = expr->properties()->at(i);
894 if (property->IsCompileTimeValue()) continue;
896 Literal* key = property->key();
897 switch (property->kind()) {
898 case ObjectLiteral::Property::CONSTANT:
900 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
901 DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value()));
903 case ObjectLiteral::Property::COMPUTED: {
904 // It is safe to use [[Put]] here because the boilerplate already
905 // contains computed properties with an uninitialized value.
906 if (key->value()->IsInternalizedString()) {
907 if (property->emit_store()) {
908 VisitForValue(property->value());
909 Node* value = environment()->Pop();
910 Unique<Name> name = MakeUnique(key->AsPropertyName());
911 Node* store = NewNode(javascript()->StoreNamed(strict_mode(), name),
913 PrepareFrameState(store, key->id());
915 VisitForEffect(property->value());
919 environment()->Push(literal); // Duplicate receiver.
920 VisitForValue(property->key());
921 VisitForValue(property->value());
922 Node* value = environment()->Pop();
923 Node* key = environment()->Pop();
924 Node* receiver = environment()->Pop();
925 if (property->emit_store()) {
926 Node* strict = jsgraph()->Constant(SLOPPY);
927 const Operator* op = javascript()->Runtime(Runtime::kSetProperty, 4);
928 NewNode(op, receiver, key, value, strict);
932 case ObjectLiteral::Property::PROTOTYPE: {
933 environment()->Push(literal); // Duplicate receiver.
934 VisitForValue(property->value());
935 Node* value = environment()->Pop();
936 Node* receiver = environment()->Pop();
937 if (property->emit_store()) {
938 const Operator* op = javascript()->Runtime(Runtime::kSetPrototype, 2);
939 NewNode(op, receiver, value);
943 case ObjectLiteral::Property::GETTER:
944 accessor_table.lookup(key)->second->getter = property->value();
946 case ObjectLiteral::Property::SETTER:
947 accessor_table.lookup(key)->second->setter = property->value();
952 // Create nodes to define accessors, using only a single call to the runtime
953 // for each pair of corresponding getters and setters.
954 for (AccessorTable::Iterator it = accessor_table.begin();
955 it != accessor_table.end(); ++it) {
956 VisitForValue(it->first);
957 VisitForValueOrNull(it->second->getter);
958 VisitForValueOrNull(it->second->setter);
959 Node* setter = environment()->Pop();
960 Node* getter = environment()->Pop();
961 Node* name = environment()->Pop();
962 Node* attr = jsgraph()->Constant(NONE);
964 javascript()->Runtime(Runtime::kDefineAccessorPropertyUnchecked, 5);
965 Node* call = NewNode(op, literal, name, getter, setter, attr);
966 PrepareFrameState(call, it->first->id());
969 // Transform literals that contain functions to fast properties.
970 if (expr->has_function()) {
971 const Operator* op = javascript()->Runtime(Runtime::kToFastProperties, 1);
972 NewNode(op, literal);
975 ast_context()->ProduceValue(environment()->Pop());
979 void AstGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
980 Node* closure = GetFunctionClosure();
982 // Create node to deep-copy the literal boilerplate.
983 expr->BuildConstantElements(isolate());
984 Node* literals_array =
985 BuildLoadObjectField(closure, JSFunction::kLiteralsOffset);
986 Node* literal_index = jsgraph()->Constant(expr->literal_index());
987 Node* constants = jsgraph()->Constant(expr->constant_elements());
988 Node* flags = jsgraph()->Constant(expr->ComputeFlags());
989 const Operator* op = javascript()->Runtime(Runtime::kCreateArrayLiteral, 4);
990 Node* literal = NewNode(op, literals_array, literal_index, constants, flags);
992 // The array and the literal index are both expected on the operand stack
993 // during computation of the element values.
994 environment()->Push(literal);
995 environment()->Push(literal_index);
997 // Create nodes to evaluate all the non-constant subexpressions and to store
998 // them into the newly cloned array.
999 for (int i = 0; i < expr->values()->length(); i++) {
1000 Expression* subexpr = expr->values()->at(i);
1001 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
1003 VisitForValue(subexpr);
1004 Node* value = environment()->Pop();
1005 Node* index = jsgraph()->Constant(i);
1006 Node* store = NewNode(javascript()->StoreProperty(strict_mode()), literal,
1008 PrepareFrameState(store, expr->GetIdForElement(i));
1011 environment()->Pop(); // Array literal index.
1012 ast_context()->ProduceValue(environment()->Pop());
1016 void AstGraphBuilder::VisitForInAssignment(Expression* expr, Node* value) {
1017 DCHECK(expr->IsValidReferenceExpression());
1019 // Left-hand side can only be a property, a global or a variable slot.
1020 Property* property = expr->AsProperty();
1021 LhsKind assign_type = DetermineLhsKind(expr);
1023 // Evaluate LHS expression and store the value.
1024 switch (assign_type) {
1026 Variable* var = expr->AsVariableProxy()->var();
1027 // TODO(jarin) Fill in the correct bailout id.
1028 BuildVariableAssignment(var, value, Token::ASSIGN, BailoutId::None());
1031 case NAMED_PROPERTY: {
1032 environment()->Push(value);
1033 VisitForValue(property->obj());
1034 Node* object = environment()->Pop();
1035 value = environment()->Pop();
1037 MakeUnique(property->key()->AsLiteral()->AsPropertyName());
1039 NewNode(javascript()->StoreNamed(strict_mode(), name), object, value);
1040 // TODO(jarin) Fill in the correct bailout id.
1041 PrepareFrameState(store, BailoutId::None());
1044 case KEYED_PROPERTY: {
1045 environment()->Push(value);
1046 VisitForValue(property->obj());
1047 VisitForValue(property->key());
1048 Node* key = environment()->Pop();
1049 Node* object = environment()->Pop();
1050 value = environment()->Pop();
1051 Node* store = NewNode(javascript()->StoreProperty(strict_mode()), object,
1053 // TODO(jarin) Fill in the correct bailout id.
1054 PrepareFrameState(store, BailoutId::None());
1061 void AstGraphBuilder::VisitAssignment(Assignment* expr) {
1062 DCHECK(expr->target()->IsValidReferenceExpression());
1064 // Left-hand side can only be a property, a global or a variable slot.
1065 Property* property = expr->target()->AsProperty();
1066 LhsKind assign_type = DetermineLhsKind(expr->target());
1068 // Evaluate LHS expression.
1069 switch (assign_type) {
1071 // Nothing to do here.
1073 case NAMED_PROPERTY:
1074 VisitForValue(property->obj());
1076 case KEYED_PROPERTY: {
1077 VisitForValue(property->obj());
1078 VisitForValue(property->key());
1083 // Evaluate the value and potentially handle compound assignments by loading
1084 // the left-hand side value and performing a binary operation.
1085 if (expr->is_compound()) {
1086 Node* old_value = NULL;
1087 switch (assign_type) {
1089 Variable* variable = expr->target()->AsVariableProxy()->var();
1090 old_value = BuildVariableLoad(variable, expr->target()->id());
1093 case NAMED_PROPERTY: {
1094 Node* object = environment()->Top();
1096 MakeUnique(property->key()->AsLiteral()->AsPropertyName());
1097 old_value = NewNode(javascript()->LoadNamed(name), object);
1098 PrepareFrameState(old_value, property->LoadId(), kPushOutput);
1101 case KEYED_PROPERTY: {
1102 Node* key = environment()->Top();
1103 Node* object = environment()->Peek(1);
1104 old_value = NewNode(javascript()->LoadProperty(), object, key);
1105 PrepareFrameState(old_value, property->LoadId(), kPushOutput);
1109 environment()->Push(old_value);
1110 VisitForValue(expr->value());
1111 Node* right = environment()->Pop();
1112 Node* left = environment()->Pop();
1113 Node* value = BuildBinaryOp(left, right, expr->binary_op());
1114 PrepareFrameState(value, expr->binary_operation()->id(), kPushOutput);
1115 environment()->Push(value);
1117 VisitForValue(expr->value());
1121 Node* value = environment()->Pop();
1122 switch (assign_type) {
1124 Variable* variable = expr->target()->AsVariableProxy()->var();
1125 BuildVariableAssignment(variable, value, expr->op(),
1126 expr->AssignmentId());
1129 case NAMED_PROPERTY: {
1130 Node* object = environment()->Pop();
1132 MakeUnique(property->key()->AsLiteral()->AsPropertyName());
1134 NewNode(javascript()->StoreNamed(strict_mode(), name), object, value);
1135 PrepareFrameState(store, expr->AssignmentId());
1138 case KEYED_PROPERTY: {
1139 Node* key = environment()->Pop();
1140 Node* object = environment()->Pop();
1141 Node* store = NewNode(javascript()->StoreProperty(strict_mode()), object,
1143 PrepareFrameState(store, expr->AssignmentId());
1148 ast_context()->ProduceValue(value);
1152 void AstGraphBuilder::VisitYield(Yield* expr) {
1153 VisitForValue(expr->generator_object());
1154 VisitForValue(expr->expression());
1155 environment()->Pop();
1156 environment()->Pop();
1157 // TODO(turbofan): VisitYield
1158 ast_context()->ProduceValue(jsgraph()->UndefinedConstant());
1162 void AstGraphBuilder::VisitThrow(Throw* expr) {
1163 VisitForValue(expr->exception());
1164 Node* exception = environment()->Pop();
1165 const Operator* op = javascript()->Runtime(Runtime::kThrow, 1);
1166 Node* value = NewNode(op, exception);
1167 ast_context()->ProduceValue(value);
1171 void AstGraphBuilder::VisitProperty(Property* expr) {
1173 if (expr->key()->IsPropertyName()) {
1174 VisitForValue(expr->obj());
1175 Node* object = environment()->Pop();
1176 Unique<Name> name = MakeUnique(expr->key()->AsLiteral()->AsPropertyName());
1177 value = NewNode(javascript()->LoadNamed(name), object);
1179 VisitForValue(expr->obj());
1180 VisitForValue(expr->key());
1181 Node* key = environment()->Pop();
1182 Node* object = environment()->Pop();
1183 value = NewNode(javascript()->LoadProperty(), object, key);
1185 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
1186 ast_context()->ProduceValue(value);
1190 void AstGraphBuilder::VisitCall(Call* expr) {
1191 Expression* callee = expr->expression();
1192 Call::CallType call_type = expr->GetCallType(isolate());
1194 // Prepare the callee and the receiver to the function call. This depends on
1195 // the semantics of the underlying call type.
1196 CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS;
1197 Node* receiver_value = NULL;
1198 Node* callee_value = NULL;
1199 bool possibly_eval = false;
1200 switch (call_type) {
1201 case Call::GLOBAL_CALL: {
1202 Variable* variable = callee->AsVariableProxy()->var();
1203 callee_value = BuildVariableLoad(variable, expr->expression()->id());
1204 receiver_value = jsgraph()->UndefinedConstant();
1207 case Call::LOOKUP_SLOT_CALL: {
1208 Variable* variable = callee->AsVariableProxy()->var();
1209 DCHECK(variable->location() == Variable::LOOKUP);
1210 Node* name = jsgraph()->Constant(variable->name());
1211 const Operator* op = javascript()->Runtime(Runtime::kLoadLookupSlot, 2);
1212 Node* pair = NewNode(op, current_context(), name);
1213 callee_value = NewNode(common()->Projection(0), pair);
1214 receiver_value = NewNode(common()->Projection(1), pair);
1217 case Call::PROPERTY_CALL: {
1218 Property* property = callee->AsProperty();
1219 VisitForValue(property->obj());
1220 Node* object = environment()->Top();
1221 if (property->key()->IsPropertyName()) {
1223 MakeUnique(property->key()->AsLiteral()->AsPropertyName());
1224 callee_value = NewNode(javascript()->LoadNamed(name), object);
1226 VisitForValue(property->key());
1227 Node* key = environment()->Pop();
1228 callee_value = NewNode(javascript()->LoadProperty(), object, key);
1230 PrepareFrameState(callee_value, property->LoadId(), kPushOutput);
1231 receiver_value = environment()->Pop();
1232 // Note that a PROPERTY_CALL requires the receiver to be wrapped into an
1233 // object for sloppy callees. This could also be modeled explicitly here,
1234 // thereby obsoleting the need for a flag to the call operator.
1235 flags = CALL_AS_METHOD;
1238 case Call::POSSIBLY_EVAL_CALL:
1239 possibly_eval = true;
1241 case Call::OTHER_CALL:
1242 VisitForValue(callee);
1243 callee_value = environment()->Pop();
1244 receiver_value = jsgraph()->UndefinedConstant();
1248 // The callee and the receiver both have to be pushed onto the operand stack
1249 // before arguments are being evaluated.
1250 environment()->Push(callee_value);
1251 environment()->Push(receiver_value);
1253 // Evaluate all arguments to the function call,
1254 ZoneList<Expression*>* args = expr->arguments();
1255 VisitForValues(args);
1257 // Resolve callee and receiver for a potential direct eval call. This block
1258 // will mutate the callee and receiver values pushed onto the environment.
1259 if (possibly_eval && args->length() > 0) {
1260 int arg_count = args->length();
1262 // Extract callee and source string from the environment.
1263 Node* callee = environment()->Peek(arg_count + 1);
1264 Node* source = environment()->Peek(arg_count - 1);
1266 // Create node to ask for help resolving potential eval call. This will
1267 // provide a fully resolved callee and the corresponding receiver.
1268 Node* receiver = environment()->Lookup(info()->scope()->receiver());
1269 Node* strict = jsgraph()->Constant(strict_mode());
1270 Node* position = jsgraph()->Constant(info()->scope()->start_position());
1271 const Operator* op =
1272 javascript()->Runtime(Runtime::kResolvePossiblyDirectEval, 5);
1273 Node* pair = NewNode(op, callee, source, receiver, strict, position);
1274 Node* new_callee = NewNode(common()->Projection(0), pair);
1275 Node* new_receiver = NewNode(common()->Projection(1), pair);
1277 // Patch callee and receiver on the environment.
1278 environment()->Poke(arg_count + 1, new_callee);
1279 environment()->Poke(arg_count + 0, new_receiver);
1282 // Create node to perform the function call.
1283 const Operator* call = javascript()->Call(args->length() + 2, flags);
1284 Node* value = ProcessArguments(call, args->length() + 2);
1285 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
1286 ast_context()->ProduceValue(value);
1290 void AstGraphBuilder::VisitCallNew(CallNew* expr) {
1291 VisitForValue(expr->expression());
1293 // Evaluate all arguments to the construct call.
1294 ZoneList<Expression*>* args = expr->arguments();
1295 VisitForValues(args);
1297 // Create node to perform the construct call.
1298 const Operator* call = javascript()->CallNew(args->length() + 1);
1299 Node* value = ProcessArguments(call, args->length() + 1);
1300 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
1301 ast_context()->ProduceValue(value);
1305 void AstGraphBuilder::VisitCallJSRuntime(CallRuntime* expr) {
1306 Handle<String> name = expr->name();
1308 // The callee and the receiver both have to be pushed onto the operand stack
1309 // before arguments are being evaluated.
1310 CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS;
1311 Node* receiver_value = BuildLoadBuiltinsObject();
1312 Unique<String> unique = MakeUnique(name);
1313 Node* callee_value = NewNode(javascript()->LoadNamed(unique), receiver_value);
1314 // TODO(jarin): Find/create a bailout id to deoptimize to (crankshaft
1315 // refuses to optimize functions with jsruntime calls).
1316 PrepareFrameState(callee_value, BailoutId::None(), kPushOutput);
1317 environment()->Push(callee_value);
1318 environment()->Push(receiver_value);
1320 // Evaluate all arguments to the JS runtime call.
1321 ZoneList<Expression*>* args = expr->arguments();
1322 VisitForValues(args);
1324 // Create node to perform the JS runtime call.
1325 const Operator* call = javascript()->Call(args->length() + 2, flags);
1326 Node* value = ProcessArguments(call, args->length() + 2);
1327 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
1328 ast_context()->ProduceValue(value);
1332 void AstGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
1333 const Runtime::Function* function = expr->function();
1335 // Handle calls to runtime functions implemented in JavaScript separately as
1336 // the call follows JavaScript ABI and the callee is statically unknown.
1337 if (expr->is_jsruntime()) {
1338 DCHECK(function == NULL && expr->name()->length() > 0);
1339 return VisitCallJSRuntime(expr);
1342 // Evaluate all arguments to the runtime call.
1343 ZoneList<Expression*>* args = expr->arguments();
1344 VisitForValues(args);
1346 // Create node to perform the runtime call.
1347 Runtime::FunctionId functionId = function->function_id;
1348 const Operator* call = javascript()->Runtime(functionId, args->length());
1349 Node* value = ProcessArguments(call, args->length());
1350 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
1351 ast_context()->ProduceValue(value);
1355 void AstGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
1356 switch (expr->op()) {
1358 return VisitDelete(expr);
1360 return VisitVoid(expr);
1362 return VisitTypeof(expr);
1364 return VisitNot(expr);
1371 void AstGraphBuilder::VisitCountOperation(CountOperation* expr) {
1372 DCHECK(expr->expression()->IsValidReferenceExpression());
1374 // Left-hand side can only be a property, a global or a variable slot.
1375 Property* property = expr->expression()->AsProperty();
1376 LhsKind assign_type = DetermineLhsKind(expr->expression());
1378 // Reserve space for result of postfix operation.
1379 bool is_postfix = expr->is_postfix() && !ast_context()->IsEffect();
1380 if (is_postfix) environment()->Push(jsgraph()->UndefinedConstant());
1382 // Evaluate LHS expression and get old value.
1383 Node* old_value = NULL;
1384 int stack_depth = -1;
1385 switch (assign_type) {
1387 Variable* variable = expr->expression()->AsVariableProxy()->var();
1388 old_value = BuildVariableLoad(variable, expr->expression()->id());
1392 case NAMED_PROPERTY: {
1393 VisitForValue(property->obj());
1394 Node* object = environment()->Top();
1396 MakeUnique(property->key()->AsLiteral()->AsPropertyName());
1397 old_value = NewNode(javascript()->LoadNamed(name), object);
1398 PrepareFrameState(old_value, property->LoadId(), kPushOutput);
1402 case KEYED_PROPERTY: {
1403 VisitForValue(property->obj());
1404 VisitForValue(property->key());
1405 Node* key = environment()->Top();
1406 Node* object = environment()->Peek(1);
1407 old_value = NewNode(javascript()->LoadProperty(), object, key);
1408 PrepareFrameState(old_value, property->LoadId(), kPushOutput);
1414 // Convert old value into a number.
1415 old_value = NewNode(javascript()->ToNumber(), old_value);
1417 // Save result for postfix expressions at correct stack depth.
1418 if (is_postfix) environment()->Poke(stack_depth, old_value);
1420 // Create node to perform +1/-1 operation.
1422 BuildBinaryOp(old_value, jsgraph()->OneConstant(), expr->binary_op());
1423 // TODO(jarin) Insert proper bailout id here (will need to change
1424 // full code generator).
1425 PrepareFrameState(value, BailoutId::None());
1428 switch (assign_type) {
1430 Variable* variable = expr->expression()->AsVariableProxy()->var();
1431 environment()->Push(value);
1432 BuildVariableAssignment(variable, value, expr->op(),
1433 expr->AssignmentId());
1434 environment()->Pop();
1437 case NAMED_PROPERTY: {
1438 Node* object = environment()->Pop();
1440 MakeUnique(property->key()->AsLiteral()->AsPropertyName());
1442 NewNode(javascript()->StoreNamed(strict_mode(), name), object, value);
1443 environment()->Push(value);
1444 PrepareFrameState(store, expr->AssignmentId());
1445 environment()->Pop();
1448 case KEYED_PROPERTY: {
1449 Node* key = environment()->Pop();
1450 Node* object = environment()->Pop();
1451 Node* store = NewNode(javascript()->StoreProperty(strict_mode()), object,
1453 environment()->Push(value);
1454 PrepareFrameState(store, expr->AssignmentId());
1455 environment()->Pop();
1460 // Restore old value for postfix expressions.
1461 if (is_postfix) value = environment()->Pop();
1463 ast_context()->ProduceValue(value);
1467 void AstGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
1468 switch (expr->op()) {
1470 return VisitComma(expr);
1473 return VisitLogicalExpression(expr);
1475 VisitForValue(expr->left());
1476 VisitForValue(expr->right());
1477 Node* right = environment()->Pop();
1478 Node* left = environment()->Pop();
1479 Node* value = BuildBinaryOp(left, right, expr->op());
1480 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
1481 ast_context()->ProduceValue(value);
1487 void AstGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
1489 switch (expr->op()) {
1491 op = javascript()->Equal();
1494 op = javascript()->NotEqual();
1496 case Token::EQ_STRICT:
1497 op = javascript()->StrictEqual();
1499 case Token::NE_STRICT:
1500 op = javascript()->StrictNotEqual();
1503 op = javascript()->LessThan();
1506 op = javascript()->GreaterThan();
1509 op = javascript()->LessThanOrEqual();
1512 op = javascript()->GreaterThanOrEqual();
1514 case Token::INSTANCEOF:
1515 op = javascript()->InstanceOf();
1518 op = javascript()->HasProperty();
1524 VisitForValue(expr->left());
1525 VisitForValue(expr->right());
1526 Node* right = environment()->Pop();
1527 Node* left = environment()->Pop();
1528 Node* value = NewNode(op, left, right);
1529 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
1530 ast_context()->ProduceValue(value);
1534 void AstGraphBuilder::VisitThisFunction(ThisFunction* expr) {
1535 Node* value = GetFunctionClosure();
1536 ast_context()->ProduceValue(value);
1540 void AstGraphBuilder::VisitSuperReference(SuperReference* expr) {
1545 void AstGraphBuilder::VisitCaseClause(CaseClause* expr) { UNREACHABLE(); }
1548 void AstGraphBuilder::VisitDeclarations(ZoneList<Declaration*>* declarations) {
1549 DCHECK(globals()->is_empty());
1550 AstVisitor::VisitDeclarations(declarations);
1551 if (globals()->is_empty()) return;
1552 Handle<FixedArray> data =
1553 isolate()->factory()->NewFixedArray(globals()->length(), TENURED);
1554 for (int i = 0; i < globals()->length(); ++i) data->set(i, *globals()->at(i));
1555 int encoded_flags = DeclareGlobalsEvalFlag::encode(info()->is_eval()) |
1556 DeclareGlobalsNativeFlag::encode(info()->is_native()) |
1557 DeclareGlobalsStrictMode::encode(strict_mode());
1558 Node* flags = jsgraph()->Constant(encoded_flags);
1559 Node* pairs = jsgraph()->Constant(data);
1560 const Operator* op = javascript()->Runtime(Runtime::kDeclareGlobals, 3);
1561 NewNode(op, current_context(), pairs, flags);
1562 globals()->Rewind(0);
1566 void AstGraphBuilder::VisitIfNotNull(Statement* stmt) {
1567 if (stmt == NULL) return;
1572 void AstGraphBuilder::VisitIterationBody(IterationStatement* stmt,
1573 LoopBuilder* loop, int drop_extra) {
1574 BreakableScope scope(this, stmt, loop, drop_extra);
1575 Visit(stmt->body());
1579 void AstGraphBuilder::VisitDelete(UnaryOperation* expr) {
1581 if (expr->expression()->IsVariableProxy()) {
1582 // Delete of an unqualified identifier is only allowed in classic mode but
1583 // deleting "this" is allowed in all language modes.
1584 Variable* variable = expr->expression()->AsVariableProxy()->var();
1585 DCHECK(strict_mode() == SLOPPY || variable->is_this());
1586 value = BuildVariableDelete(variable);
1587 } else if (expr->expression()->IsProperty()) {
1588 Property* property = expr->expression()->AsProperty();
1589 VisitForValue(property->obj());
1590 VisitForValue(property->key());
1591 Node* key = environment()->Pop();
1592 Node* object = environment()->Pop();
1593 value = NewNode(javascript()->DeleteProperty(strict_mode()), object, key);
1595 VisitForEffect(expr->expression());
1596 value = jsgraph()->TrueConstant();
1598 ast_context()->ProduceValue(value);
1602 void AstGraphBuilder::VisitVoid(UnaryOperation* expr) {
1603 VisitForEffect(expr->expression());
1604 Node* value = jsgraph()->UndefinedConstant();
1605 ast_context()->ProduceValue(value);
1609 void AstGraphBuilder::VisitTypeof(UnaryOperation* expr) {
1611 if (expr->expression()->IsVariableProxy()) {
1612 // Typeof does not throw a reference error on global variables, hence we
1613 // perform a non-contextual load in case the operand is a variable proxy.
1614 Variable* variable = expr->expression()->AsVariableProxy()->var();
1616 BuildVariableLoad(variable, expr->expression()->id(), NOT_CONTEXTUAL);
1618 VisitForValue(expr->expression());
1619 operand = environment()->Pop();
1621 Node* value = NewNode(javascript()->TypeOf(), operand);
1622 ast_context()->ProduceValue(value);
1626 void AstGraphBuilder::VisitNot(UnaryOperation* expr) {
1627 VisitForValue(expr->expression());
1628 Node* operand = environment()->Pop();
1629 // TODO(mstarzinger): Possible optimization when we are in effect context.
1630 Node* value = NewNode(javascript()->UnaryNot(), operand);
1631 ast_context()->ProduceValue(value);
1635 void AstGraphBuilder::VisitComma(BinaryOperation* expr) {
1636 VisitForEffect(expr->left());
1637 Visit(expr->right());
1638 ast_context()->ReplaceValue();
1642 void AstGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) {
1643 bool is_logical_and = expr->op() == Token::AND;
1644 IfBuilder compare_if(this);
1645 VisitForValue(expr->left());
1646 Node* condition = environment()->Top();
1647 compare_if.If(BuildToBoolean(condition));
1649 if (is_logical_and) {
1650 environment()->Pop();
1651 Visit(expr->right());
1652 } else if (ast_context()->IsEffect()) {
1653 environment()->Pop();
1656 if (!is_logical_and) {
1657 environment()->Pop();
1658 Visit(expr->right());
1659 } else if (ast_context()->IsEffect()) {
1660 environment()->Pop();
1663 ast_context()->ReplaceValue();
1667 Node* AstGraphBuilder::ProcessArguments(const Operator* op, int arity) {
1668 DCHECK(environment()->stack_height() >= arity);
1669 Node** all = info()->zone()->NewArray<Node*>(arity);
1670 for (int i = arity - 1; i >= 0; --i) {
1671 all[i] = environment()->Pop();
1673 Node* value = NewNode(op, arity, all);
1678 Node* AstGraphBuilder::BuildLocalFunctionContext(Node* context, Node* closure) {
1679 int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
1680 if (heap_slots <= 0) return context;
1681 set_current_context(context);
1683 // Allocate a new local context.
1684 const Operator* op = javascript()->CreateFunctionContext();
1685 Node* local_context = NewNode(op, closure);
1686 set_current_context(local_context);
1688 // Copy parameters into context if necessary.
1689 int num_parameters = info()->scope()->num_parameters();
1690 for (int i = 0; i < num_parameters; i++) {
1691 Variable* variable = info()->scope()->parameter(i);
1692 if (!variable->IsContextSlot()) continue;
1693 // Temporary parameter node. The parameter indices are shifted by 1
1694 // (receiver is parameter index -1 but environment index 0).
1695 Node* parameter = NewNode(common()->Parameter(i + 1), graph()->start());
1696 // Context variable (at bottom of the context chain).
1697 DCHECK_EQ(0, info()->scope()->ContextChainLength(variable->scope()));
1698 const Operator* op = javascript()->StoreContext(0, variable->index());
1699 NewNode(op, local_context, parameter);
1702 return local_context;
1706 Node* AstGraphBuilder::BuildArgumentsObject(Variable* arguments) {
1707 if (arguments == NULL) return NULL;
1709 // Allocate and initialize a new arguments object.
1710 Node* callee = GetFunctionClosure();
1711 const Operator* op = javascript()->Runtime(Runtime::kNewArguments, 1);
1712 Node* object = NewNode(op, callee);
1714 // Assign the object to the arguments variable.
1715 DCHECK(arguments->IsContextSlot() || arguments->IsStackAllocated());
1716 // This should never lazy deopt, so it is fine to send invalid bailout id.
1717 BuildVariableAssignment(arguments, object, Token::ASSIGN, BailoutId::None());
1723 Node* AstGraphBuilder::BuildHoleCheckSilent(Node* value, Node* for_hole,
1725 IfBuilder hole_check(this);
1726 Node* the_hole = jsgraph()->TheHoleConstant();
1727 Node* check = NewNode(javascript()->StrictEqual(), value, the_hole);
1728 hole_check.If(check);
1730 environment()->Push(for_hole);
1732 environment()->Push(not_hole);
1734 return environment()->Pop();
1738 Node* AstGraphBuilder::BuildHoleCheckThrow(Node* value, Variable* variable,
1740 IfBuilder hole_check(this);
1741 Node* the_hole = jsgraph()->TheHoleConstant();
1742 Node* check = NewNode(javascript()->StrictEqual(), value, the_hole);
1743 hole_check.If(check);
1745 environment()->Push(BuildThrowReferenceError(variable));
1747 environment()->Push(not_hole);
1749 return environment()->Pop();
1753 Node* AstGraphBuilder::BuildVariableLoad(Variable* variable,
1754 BailoutId bailout_id,
1755 ContextualMode contextual_mode) {
1756 Node* the_hole = jsgraph()->TheHoleConstant();
1757 VariableMode mode = variable->mode();
1758 switch (variable->location()) {
1759 case Variable::UNALLOCATED: {
1760 // Global var, const, or let variable.
1761 Node* global = BuildLoadGlobalObject();
1762 Unique<Name> name = MakeUnique(variable->name());
1763 const Operator* op = javascript()->LoadNamed(name, contextual_mode);
1764 Node* node = NewNode(op, global);
1765 PrepareFrameState(node, bailout_id, kPushOutput);
1768 case Variable::PARAMETER:
1769 case Variable::LOCAL: {
1770 // Local var, const, or let variable.
1771 Node* value = environment()->Lookup(variable);
1772 if (mode == CONST_LEGACY) {
1773 // Perform check for uninitialized legacy const variables.
1774 if (value->op() == the_hole->op()) {
1775 value = jsgraph()->UndefinedConstant();
1776 } else if (value->opcode() == IrOpcode::kPhi) {
1777 Node* undefined = jsgraph()->UndefinedConstant();
1778 value = BuildHoleCheckSilent(value, undefined, value);
1780 } else if (mode == LET || mode == CONST) {
1781 // Perform check for uninitialized let/const variables.
1782 if (value->op() == the_hole->op()) {
1783 value = BuildThrowReferenceError(variable);
1784 } else if (value->opcode() == IrOpcode::kPhi) {
1785 value = BuildHoleCheckThrow(value, variable, value);
1790 case Variable::CONTEXT: {
1791 // Context variable (potentially up the context chain).
1792 int depth = current_scope()->ContextChainLength(variable->scope());
1793 bool immutable = variable->maybe_assigned() == kNotAssigned;
1794 const Operator* op =
1795 javascript()->LoadContext(depth, variable->index(), immutable);
1796 Node* value = NewNode(op, current_context());
1797 // TODO(titzer): initialization checks are redundant for already
1798 // initialized immutable context loads, but only specialization knows.
1799 // Maybe specializer should be a parameter to the graph builder?
1800 if (mode == CONST_LEGACY) {
1801 // Perform check for uninitialized legacy const variables.
1802 Node* undefined = jsgraph()->UndefinedConstant();
1803 value = BuildHoleCheckSilent(value, undefined, value);
1804 } else if (mode == LET || mode == CONST) {
1805 // Perform check for uninitialized let/const variables.
1806 value = BuildHoleCheckThrow(value, variable, value);
1810 case Variable::LOOKUP: {
1811 // Dynamic lookup of context variable (anywhere in the chain).
1812 Node* name = jsgraph()->Constant(variable->name());
1813 Runtime::FunctionId function_id =
1814 (contextual_mode == CONTEXTUAL)
1815 ? Runtime::kLoadLookupSlot
1816 : Runtime::kLoadLookupSlotNoReferenceError;
1817 const Operator* op = javascript()->Runtime(function_id, 2);
1818 Node* pair = NewNode(op, current_context(), name);
1819 return NewNode(common()->Projection(0), pair);
1827 Node* AstGraphBuilder::BuildVariableDelete(Variable* variable) {
1828 switch (variable->location()) {
1829 case Variable::UNALLOCATED: {
1830 // Global var, const, or let variable.
1831 Node* global = BuildLoadGlobalObject();
1832 Node* name = jsgraph()->Constant(variable->name());
1833 const Operator* op = javascript()->DeleteProperty(strict_mode());
1834 return NewNode(op, global, name);
1836 case Variable::PARAMETER:
1837 case Variable::LOCAL:
1838 case Variable::CONTEXT:
1839 // Local var, const, or let variable or context variable.
1840 return variable->is_this() ? jsgraph()->TrueConstant()
1841 : jsgraph()->FalseConstant();
1842 case Variable::LOOKUP: {
1843 // Dynamic lookup of context variable (anywhere in the chain).
1844 Node* name = jsgraph()->Constant(variable->name());
1845 const Operator* op = javascript()->Runtime(Runtime::kDeleteLookupSlot, 2);
1846 return NewNode(op, current_context(), name);
1854 Node* AstGraphBuilder::BuildVariableAssignment(Variable* variable, Node* value,
1856 BailoutId bailout_id) {
1857 Node* the_hole = jsgraph()->TheHoleConstant();
1858 VariableMode mode = variable->mode();
1859 switch (variable->location()) {
1860 case Variable::UNALLOCATED: {
1861 // Global var, const, or let variable.
1862 Node* global = BuildLoadGlobalObject();
1863 Unique<Name> name = MakeUnique(variable->name());
1864 const Operator* op = javascript()->StoreNamed(strict_mode(), name);
1865 Node* store = NewNode(op, global, value);
1866 PrepareFrameState(store, bailout_id);
1869 case Variable::PARAMETER:
1870 case Variable::LOCAL:
1871 // Local var, const, or let variable.
1872 if (mode == CONST_LEGACY && op == Token::INIT_CONST_LEGACY) {
1873 // Perform an initialization check for legacy const variables.
1874 Node* current = environment()->Lookup(variable);
1875 if (current->op() != the_hole->op()) {
1876 value = BuildHoleCheckSilent(current, value, current);
1878 } else if (mode == CONST_LEGACY && op != Token::INIT_CONST_LEGACY) {
1879 // Non-initializing assignments to legacy const is ignored.
1881 } else if (mode == LET && op != Token::INIT_LET) {
1882 // Perform an initialization check for let declared variables.
1883 // Also note that the dynamic hole-check is only done to ensure that
1884 // this does not break in the presence of do-expressions within the
1885 // temporal dead zone of a let declared variable.
1886 Node* current = environment()->Lookup(variable);
1887 if (current->op() == the_hole->op()) {
1888 value = BuildThrowReferenceError(variable);
1889 } else if (value->opcode() == IrOpcode::kPhi) {
1890 value = BuildHoleCheckThrow(current, variable, value);
1892 } else if (mode == CONST && op != Token::INIT_CONST) {
1893 // All assignments to const variables are early errors.
1896 environment()->Bind(variable, value);
1898 case Variable::CONTEXT: {
1899 // Context variable (potentially up the context chain).
1900 int depth = current_scope()->ContextChainLength(variable->scope());
1901 if (mode == CONST_LEGACY && op == Token::INIT_CONST_LEGACY) {
1902 // Perform an initialization check for legacy const variables.
1903 const Operator* op =
1904 javascript()->LoadContext(depth, variable->index(), false);
1905 Node* current = NewNode(op, current_context());
1906 value = BuildHoleCheckSilent(current, value, current);
1907 } else if (mode == CONST_LEGACY && op != Token::INIT_CONST_LEGACY) {
1908 // Non-initializing assignments to legacy const is ignored.
1910 } else if (mode == LET && op != Token::INIT_LET) {
1911 // Perform an initialization check for let declared variables.
1912 const Operator* op =
1913 javascript()->LoadContext(depth, variable->index(), false);
1914 Node* current = NewNode(op, current_context());
1915 value = BuildHoleCheckThrow(current, variable, value);
1916 } else if (mode == CONST && op != Token::INIT_CONST) {
1917 // All assignments to const variables are early errors.
1920 const Operator* op = javascript()->StoreContext(depth, variable->index());
1921 return NewNode(op, current_context(), value);
1923 case Variable::LOOKUP: {
1924 // Dynamic lookup of context variable (anywhere in the chain).
1925 Node* name = jsgraph()->Constant(variable->name());
1926 Node* strict = jsgraph()->Constant(strict_mode());
1927 // TODO(mstarzinger): Use Runtime::kInitializeLegacyConstLookupSlot for
1928 // initializations of const declarations.
1929 const Operator* op = javascript()->Runtime(Runtime::kStoreLookupSlot, 4);
1930 return NewNode(op, value, current_context(), name, strict);
1938 Node* AstGraphBuilder::BuildLoadObjectField(Node* object, int offset) {
1939 // TODO(sigurds) Use simplified load here once it is ready.
1940 Node* field_load = NewNode(jsgraph()->machine()->Load(kMachAnyTagged), object,
1941 jsgraph()->Int32Constant(offset - kHeapObjectTag));
1946 Node* AstGraphBuilder::BuildLoadBuiltinsObject() {
1947 Node* global = BuildLoadGlobalObject();
1949 BuildLoadObjectField(global, JSGlobalObject::kBuiltinsOffset);
1954 Node* AstGraphBuilder::BuildLoadGlobalObject() {
1955 Node* context = GetFunctionContext();
1956 const Operator* load_op =
1957 javascript()->LoadContext(0, Context::GLOBAL_OBJECT_INDEX, true);
1958 return NewNode(load_op, context);
1962 Node* AstGraphBuilder::BuildToBoolean(Node* value) {
1963 // TODO(mstarzinger): Possible optimization is to NOP for boolean values.
1964 return NewNode(javascript()->ToBoolean(), value);
1968 Node* AstGraphBuilder::BuildThrowReferenceError(Variable* variable) {
1969 // TODO(mstarzinger): Should be unified with the VisitThrow implementation.
1970 Node* variable_name = jsgraph()->Constant(variable->name());
1971 const Operator* op = javascript()->Runtime(Runtime::kThrowReferenceError, 1);
1972 return NewNode(op, variable_name);
1976 Node* AstGraphBuilder::BuildBinaryOp(Node* left, Node* right, Token::Value op) {
1977 const Operator* js_op;
1980 js_op = javascript()->BitwiseOr();
1982 case Token::BIT_AND:
1983 js_op = javascript()->BitwiseAnd();
1985 case Token::BIT_XOR:
1986 js_op = javascript()->BitwiseXor();
1989 js_op = javascript()->ShiftLeft();
1992 js_op = javascript()->ShiftRight();
1995 js_op = javascript()->ShiftRightLogical();
1998 js_op = javascript()->Add();
2001 js_op = javascript()->Subtract();
2004 js_op = javascript()->Multiply();
2007 js_op = javascript()->Divide();
2010 js_op = javascript()->Modulus();
2016 return NewNode(js_op, left, right);
2020 void AstGraphBuilder::PrepareFrameState(Node* node, BailoutId ast_id,
2021 OutputFrameStateCombine combine) {
2022 if (OperatorProperties::HasFrameStateInput(node->op())) {
2023 DCHECK(NodeProperties::GetFrameStateInput(node)->opcode() ==
2025 NodeProperties::ReplaceFrameStateInput(
2026 node, environment()->Checkpoint(ast_id, combine));
2032 } // namespace v8::internal::compiler