blob: 74fb0aedbd3134d4d15ff45f18fb8130d206130b [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2014 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/compiler/ast-graph-builder.h"
6
7#include "src/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"
15
16namespace v8 {
17namespace internal {
18namespace compiler {
19
20AstGraphBuilder::AstGraphBuilder(CompilationInfo* info, JSGraph* jsgraph)
21 : StructuredGraphBuilder(jsgraph->graph(), jsgraph->common()),
22 info_(info),
23 jsgraph_(jsgraph),
24 globals_(0, info->zone()),
25 breakable_(NULL),
26 execution_context_(NULL) {
27 InitializeAstVisitor(info->zone());
28}
29
30
31Node* 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);
37 }
38 return function_closure_.get();
39}
40
41
42Node* 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);
48 }
49 return function_context_.get();
50}
51
52
53bool AstGraphBuilder::CreateGraph() {
54 Scope* scope = info()->scope();
55 DCHECK(graph() != NULL);
56
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)));
60
61 // Initialize the top-level environment.
62 Environment env(this, scope, graph()->start());
63 set_environment(&env);
64
65 // Build node to initialize local function context.
66 Node* closure = GetFunctionClosure();
67 Node* outer = GetFunctionContext();
68 Node* inner = BuildLocalFunctionContext(outer, closure);
69
70 // Push top-level function scope for the function body.
71 ContextScope top_context(this, scope, inner);
72
73 // Build the arguments object if it is used.
74 BuildArgumentsObject(scope->arguments());
75
76 // Emit tracing call if requested to do so.
77 if (FLAG_trace) {
78 NewNode(javascript()->Runtime(Runtime::kTraceEnter, 0));
79 }
80
81 // Visit implicit declaration of the function name.
82 if (scope->is_function_scope() && scope->function() != NULL) {
83 VisitVariableDeclaration(scope->function());
84 }
85
86 // Visit declarations within the function scope.
87 VisitDeclarations(scope->declarations());
88
89 // TODO(mstarzinger): This should do an inlined stack check.
90 Node* node = NewNode(javascript()->Runtime(Runtime::kStackGuard, 0));
91 PrepareFrameState(node, BailoutId::FunctionEntry());
92
93 // Visit statements in the function body.
94 VisitStatements(info()->function()->body());
95 if (HasStackOverflow()) return false;
96
97 // Emit tracing call if requested to do so.
98 if (FLAG_trace) {
99 // TODO(mstarzinger): Only traces implicit return.
100 Node* return_value = jsgraph()->UndefinedConstant();
101 NewNode(javascript()->Runtime(Runtime::kTraceExit, 1), return_value);
102 }
103
104 // Return 'undefined' in case we can fall off the end.
105 Node* control = NewNode(common()->Return(), jsgraph()->UndefinedConstant());
106 UpdateControlDependencyToLeaveFunction(control);
107
108 // Finish the basic structure of the graph.
109 environment()->UpdateControlDependency(exit_control());
110 graph()->SetEnd(NewNode(common()->End()));
111
112 return true;
113}
114
115
116// Left-hand side can only be a property, a global or a variable slot.
117enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
118
119
120// Determine the left-hand side kind of an assignment.
121static LhsKind DetermineLhsKind(Expression* expr) {
122 Property* property = expr->AsProperty();
123 DCHECK(expr->IsValidReferenceExpression());
124 LhsKind lhs_kind =
125 (property == NULL) ? VARIABLE : (property->key()->IsPropertyName())
126 ? NAMED_PROPERTY
127 : KEYED_PROPERTY;
128 return lhs_kind;
129}
130
131
132// Helper to find an existing shared function info in the baseline code for the
133// given function literal. Used to canonicalize SharedFunctionInfo objects.
134static 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);
145 }
146 }
147 }
148 return Handle<SharedFunctionInfo>();
149}
150
151
152StructuredGraphBuilder::Environment* AstGraphBuilder::CopyEnvironment(
153 StructuredGraphBuilder::Environment* env) {
154 return new (zone()) Environment(*reinterpret_cast<Environment*>(env));
155}
156
157
158AstGraphBuilder::Environment::Environment(AstGraphBuilder* builder,
159 Scope* scope,
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),
165 locals_node_(NULL),
166 stack_node_(NULL) {
167 DCHECK_EQ(scope->num_parameters() + 1, parameters_count());
168
169 // Bind the receiver variable.
170 Node* receiver = builder->graph()->NewNode(common()->Parameter(0),
171 builder->graph()->start());
172 values()->push_back(receiver);
173
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);
180 }
181
182 // Bind all local variables to undefined.
183 Node* undefined_constant = builder->jsgraph()->UndefinedConstant();
184 values()->insert(values()->end(), locals_count(), undefined_constant);
185}
186
187
188AstGraphBuilder::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_) {}
196
197
198void 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;
204 } else {
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;
209 break;
210 }
211 }
212 }
213 if (should_update) {
214 const Operator* op = common()->StateValues(count);
215 (*state_values) = graph()->NewNode(op, count, env_values);
216 }
217}
218
219
220Node* AstGraphBuilder::Environment::Checkpoint(
221 BailoutId ast_id, OutputFrameStateCombine combine) {
222 UpdateStateValues(&parameters_node_, 0, parameters_count());
223 UpdateStateValues(&locals_node_, parameters_count(), locals_count());
224 UpdateStateValues(&stack_node_, parameters_count() + locals_count(),
225 stack_height());
226
227 const Operator* op = common()->FrameState(JS_FRAME, ast_id, combine);
228
229 return graph()->NewNode(op, parameters_node_, locals_node_, stack_node_,
230 GetContext(),
231 builder()->jsgraph()->UndefinedConstant());
232}
233
234
235AstGraphBuilder::AstContext::AstContext(AstGraphBuilder* own,
236 Expression::Context kind)
237 : kind_(kind), owner_(own), outer_(own->ast_context()) {
238 owner()->set_ast_context(this); // Push.
239#ifdef DEBUG
240 original_height_ = environment()->stack_height();
241#endif
242}
243
244
245AstGraphBuilder::AstContext::~AstContext() {
246 owner()->set_ast_context(outer_); // Pop.
247}
248
249
250AstGraphBuilder::AstEffectContext::~AstEffectContext() {
251 DCHECK(environment()->stack_height() == original_height_);
252}
253
254
255AstGraphBuilder::AstValueContext::~AstValueContext() {
256 DCHECK(environment()->stack_height() == original_height_ + 1);
257}
258
259
260AstGraphBuilder::AstTestContext::~AstTestContext() {
261 DCHECK(environment()->stack_height() == original_height_ + 1);
262}
263
264
265void AstGraphBuilder::AstEffectContext::ProduceValue(Node* value) {
266 // The value is ignored.
267}
268
269
270void AstGraphBuilder::AstValueContext::ProduceValue(Node* value) {
271 environment()->Push(value);
272}
273
274
275void AstGraphBuilder::AstTestContext::ProduceValue(Node* value) {
276 environment()->Push(owner()->BuildToBoolean(value));
277}
278
279
280Node* AstGraphBuilder::AstEffectContext::ConsumeValue() { return NULL; }
281
282
283Node* AstGraphBuilder::AstValueContext::ConsumeValue() {
284 return environment()->Pop();
285}
286
287
288Node* AstGraphBuilder::AstTestContext::ConsumeValue() {
289 return environment()->Pop();
290}
291
292
293AstGraphBuilder::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_;
299 }
300 DCHECK(current != NULL); // Always found (unless stack is malformed).
301 return current;
302}
303
304
305void AstGraphBuilder::BreakableScope::BreakTarget(BreakableStatement* stmt) {
306 FindBreakable(stmt)->control_->Break();
307}
308
309
310void AstGraphBuilder::BreakableScope::ContinueTarget(BreakableStatement* stmt) {
311 FindBreakable(stmt)->control_->Continue();
312}
313
314
315void AstGraphBuilder::VisitForValueOrNull(Expression* expr) {
316 if (expr == NULL) {
317 return environment()->Push(jsgraph()->NullConstant());
318 }
319 VisitForValue(expr);
320}
321
322
323void AstGraphBuilder::VisitForValues(ZoneList<Expression*>* exprs) {
324 for (int i = 0; i < exprs->length(); ++i) {
325 VisitForValue(exprs->at(i));
326 }
327}
328
329
330void AstGraphBuilder::VisitForValue(Expression* expr) {
331 AstValueContext for_value(this);
332 if (!HasStackOverflow()) {
333 expr->Accept(this);
334 }
335}
336
337
338void AstGraphBuilder::VisitForEffect(Expression* expr) {
339 AstEffectContext for_effect(this);
340 if (!HasStackOverflow()) {
341 expr->Accept(this);
342 }
343}
344
345
346void AstGraphBuilder::VisitForTest(Expression* expr) {
347 AstTestContext for_condition(this);
348 if (!HasStackOverflow()) {
349 expr->Accept(this);
350 }
351}
352
353
354void 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());
365 break;
366 }
367 case Variable::PARAMETER:
368 case Variable::LOCAL:
369 if (hole_init) {
370 Node* value = jsgraph()->TheHoleConstant();
371 environment()->Bind(variable, value);
372 }
373 break;
374 case Variable::CONTEXT:
375 if (hole_init) {
376 Node* value = jsgraph()->TheHoleConstant();
377 const Operator* op = javascript()->StoreContext(0, variable->index());
378 NewNode(op, current_context(), value);
379 }
380 break;
381 case Variable::LOOKUP:
382 UNIMPLEMENTED();
383 }
384}
385
386
387void 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());
397 break;
398 }
399 case Variable::PARAMETER:
400 case Variable::LOCAL: {
401 VisitForValue(decl->fun());
402 Node* value = environment()->Pop();
403 environment()->Bind(variable, value);
404 break;
405 }
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);
411 break;
412 }
413 case Variable::LOOKUP:
414 UNIMPLEMENTED();
415 }
416}
417
418
419void AstGraphBuilder::VisitModuleDeclaration(ModuleDeclaration* decl) {
420 UNREACHABLE();
421}
422
423
424void AstGraphBuilder::VisitImportDeclaration(ImportDeclaration* decl) {
425 UNREACHABLE();
426}
427
428
429void AstGraphBuilder::VisitExportDeclaration(ExportDeclaration* decl) {
430 UNREACHABLE();
431}
432
433
434void AstGraphBuilder::VisitModuleLiteral(ModuleLiteral* modl) { UNREACHABLE(); }
435
436
437void AstGraphBuilder::VisitModuleVariable(ModuleVariable* modl) {
438 UNREACHABLE();
439}
440
441
442void AstGraphBuilder::VisitModulePath(ModulePath* modl) { UNREACHABLE(); }
443
444
445void AstGraphBuilder::VisitModuleUrl(ModuleUrl* modl) { UNREACHABLE(); }
446
447
448void 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());
455 } else {
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);
460
461 // Visit declarations and statements in a block scope.
462 VisitDeclarations(stmt->scope()->declarations());
463 VisitStatements(stmt->statements());
464 }
465 if (stmt->labels() != NULL) block.EndBlock();
466}
467
468
469void AstGraphBuilder::VisitModuleStatement(ModuleStatement* stmt) {
470 UNREACHABLE();
471}
472
473
474void AstGraphBuilder::VisitExpressionStatement(ExpressionStatement* stmt) {
475 VisitForEffect(stmt->expression());
476}
477
478
479void AstGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) {
480 // Do nothing.
481}
482
483
484void AstGraphBuilder::VisitIfStatement(IfStatement* stmt) {
485 IfBuilder compare_if(this);
486 VisitForTest(stmt->condition());
487 Node* condition = environment()->Pop();
488 compare_if.If(condition);
489 compare_if.Then();
490 Visit(stmt->then_statement());
491 compare_if.Else();
492 Visit(stmt->else_statement());
493 compare_if.End();
494}
495
496
497void AstGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) {
498 StructuredGraphBuilder::Environment* env = environment()->CopyAsUnreachable();
499 breakable()->ContinueTarget(stmt->target());
500 set_environment(env);
501}
502
503
504void AstGraphBuilder::VisitBreakStatement(BreakStatement* stmt) {
505 StructuredGraphBuilder::Environment* env = environment()->CopyAsUnreachable();
506 breakable()->BreakTarget(stmt->target());
507 set_environment(env);
508}
509
510
511void AstGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
512 VisitForValue(stmt->expression());
513 Node* result = environment()->Pop();
514 Node* control = NewNode(common()->Return(), result);
515 UpdateControlDependencyToLeaveFunction(control);
516}
517
518
519void 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());
526}
527
528
529void 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;
535
536 // Keep the switch value on the stack until a case matches.
537 VisitForValue(stmt->tag());
538 Node* tag = environment()->Top();
539
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);
543
544 // The default is not a test, remember index.
545 if (clause->is_default()) {
546 default_index = i;
547 continue;
548 }
549
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);
557
558 // Discard the switch value at label match.
559 environment()->Pop();
560 compare_switch.EndLabel();
561 }
562
563 // Discard the switch value and mark the default case.
564 environment()->Pop();
565 if (default_index >= 0) {
566 compare_switch.DefaultAt(default_index);
567 }
568
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();
575 }
576
577 compare_switch.EndSwitch();
578}
579
580
581void 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();
590}
591
592
593void 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();
602}
603
604
605void 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);
613 }
614 VisitIterationBody(stmt, &for_loop, 0);
615 for_loop.EndBody();
616 VisitIfNotNull(stmt->next());
617 for_loop.EndLoop();
618}
619
620
621// TODO(dcarney): this is a big function. Try to clean up some.
622void 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);
630 is_undefined.Then();
631 is_undefined.Else();
632 {
633 IfBuilder is_null(this);
634 Node* is_null_cond =
635 NewNode(javascript()->StrictEqual(), obj, jsgraph()->NullConstant());
636 is_null.If(is_null_cond);
637 is_null.Then();
638 is_null.Else();
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);
651 Node* cache_pair =
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);
660 {
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();
671 {
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);
682 Node* exit_cond =
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
689 // basically produce
690 // value = array[index]
691 environment()->Push(obj);
692 environment()->Push(cache_array);
693 environment()->Push(cache_type);
694 environment()->Push(index);
695 Node* pair =
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);
700 {
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(
711 builtins,
712 JSBuiltinsObject::OffsetOfFunctionWithId(Builtins::FILTER_KEY));
713 // Callee.
714 environment()->Push(function);
715 // Receiver.
716 environment()->Push(obj);
717 // Args.
718 environment()->Push(value);
719 // result is either the string key or Smi(0) indicating the property
720 // is gone.
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());
727 {
728 IfBuilder is_property_missing(this);
729 is_property_missing.If(property_missing);
730 is_property_missing.Then();
731 // Inc counter and continue.
732 Node* index_inc =
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);
737 for_loop.Continue();
738 is_property_missing.Else();
739 is_property_missing.End();
740 }
741 // Replace 'value' in environment.
742 environment()->Push(res);
743 test_should_filter.Else();
744 test_should_filter.End();
745 }
746 value = environment()->Pop();
747 // Bind value and do loop body.
748 VisitForInAssignment(stmt->each(), value);
749 VisitIterationBody(stmt, &for_loop, 5);
750 for_loop.EndBody();
751 // Inc counter and continue.
752 Node* index_inc =
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);
757 for_loop.EndLoop();
758 environment()->Drop(5);
759 // PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
760 }
761 have_no_properties.End();
762 }
763 is_null.End();
764 }
765 is_undefined.End();
766}
767
768
769void AstGraphBuilder::VisitForOfStatement(ForOfStatement* stmt) {
770 VisitForValue(stmt->subject());
771 environment()->Pop();
772 // TODO(turbofan): create and use loop builder.
773}
774
775
776void AstGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) {
777 UNREACHABLE();
778}
779
780
781void AstGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
782 UNREACHABLE();
783}
784
785
786void 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());
790}
791
792
793void AstGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
794 Node* context = current_context();
795
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?
803 }
804
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);
812}
813
814
815void AstGraphBuilder::VisitClassLiteral(ClassLiteral* expr) {
816 // TODO(arv): Implement.
817 UNREACHABLE();
818}
819
820
821void AstGraphBuilder::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
822 UNREACHABLE();
823}
824
825
826void AstGraphBuilder::VisitConditional(Conditional* expr) {
827 IfBuilder compare_if(this);
828 VisitForTest(expr->condition());
829 Node* condition = environment()->Pop();
830 compare_if.If(condition);
831 compare_if.Then();
832 Visit(expr->then_expression());
833 compare_if.Else();
834 Visit(expr->else_expression());
835 compare_if.End();
836 ast_context()->ReplaceValue();
837}
838
839
840void AstGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
841 Node* value = BuildVariableLoad(expr->var(), expr->id());
842 ast_context()->ProduceValue(value);
843}
844
845
846void AstGraphBuilder::VisitLiteral(Literal* expr) {
847 Node* value = jsgraph()->Constant(expr->value());
848 ast_context()->ProduceValue(value);
849}
850
851
852void AstGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
853 Node* closure = GetFunctionClosure();
854
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());
861 const Operator* op =
862 javascript()->Runtime(Runtime::kMaterializeRegExpLiteral, 4);
863 Node* literal = NewNode(op, literals_array, literal_index, pattern, flags);
864 ast_context()->ProduceValue(literal);
865}
866
867
868void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
869 Node* closure = GetFunctionClosure();
870
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);
880
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);
884
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
887 // code is emitted.
888 expr->CalculateEmitStore(zone());
889
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;
895
896 Literal* key = property->key();
897 switch (property->kind()) {
898 case ObjectLiteral::Property::CONSTANT:
899 UNREACHABLE();
900 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
901 DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value()));
902 // Fall through.
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),
912 literal, value);
913 PrepareFrameState(store, key->id());
914 } else {
915 VisitForEffect(property->value());
916 }
917 break;
918 }
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);
929 }
930 break;
931 }
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);
940 }
941 break;
942 }
943 case ObjectLiteral::Property::GETTER:
944 accessor_table.lookup(key)->second->getter = property->value();
945 break;
946 case ObjectLiteral::Property::SETTER:
947 accessor_table.lookup(key)->second->setter = property->value();
948 break;
949 }
950 }
951
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);
963 const Operator* op =
964 javascript()->Runtime(Runtime::kDefineAccessorPropertyUnchecked, 5);
965 Node* call = NewNode(op, literal, name, getter, setter, attr);
966 PrepareFrameState(call, it->first->id());
967 }
968
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);
973 }
974
975 ast_context()->ProduceValue(environment()->Pop());
976}
977
978
979void AstGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
980 Node* closure = GetFunctionClosure();
981
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);
991
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);
996
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;
1002
1003 VisitForValue(subexpr);
1004 Node* value = environment()->Pop();
1005 Node* index = jsgraph()->Constant(i);
1006 Node* store = NewNode(javascript()->StoreProperty(strict_mode()), literal,
1007 index, value);
1008 PrepareFrameState(store, expr->GetIdForElement(i));
1009 }
1010
1011 environment()->Pop(); // Array literal index.
1012 ast_context()->ProduceValue(environment()->Pop());
1013}
1014
1015
1016void AstGraphBuilder::VisitForInAssignment(Expression* expr, Node* value) {
1017 DCHECK(expr->IsValidReferenceExpression());
1018
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);
1022
1023 // Evaluate LHS expression and store the value.
1024 switch (assign_type) {
1025 case VARIABLE: {
1026 Variable* var = expr->AsVariableProxy()->var();
1027 // TODO(jarin) Fill in the correct bailout id.
1028 BuildVariableAssignment(var, value, Token::ASSIGN, BailoutId::None());
1029 break;
1030 }
1031 case NAMED_PROPERTY: {
1032 environment()->Push(value);
1033 VisitForValue(property->obj());
1034 Node* object = environment()->Pop();
1035 value = environment()->Pop();
1036 Unique<Name> name =
1037 MakeUnique(property->key()->AsLiteral()->AsPropertyName());
1038 Node* store =
1039 NewNode(javascript()->StoreNamed(strict_mode(), name), object, value);
1040 // TODO(jarin) Fill in the correct bailout id.
1041 PrepareFrameState(store, BailoutId::None());
1042 break;
1043 }
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,
1052 key, value);
1053 // TODO(jarin) Fill in the correct bailout id.
1054 PrepareFrameState(store, BailoutId::None());
1055 break;
1056 }
1057 }
1058}
1059
1060
1061void AstGraphBuilder::VisitAssignment(Assignment* expr) {
1062 DCHECK(expr->target()->IsValidReferenceExpression());
1063
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());
1067
1068 // Evaluate LHS expression.
1069 switch (assign_type) {
1070 case VARIABLE:
1071 // Nothing to do here.
1072 break;
1073 case NAMED_PROPERTY:
1074 VisitForValue(property->obj());
1075 break;
1076 case KEYED_PROPERTY: {
1077 VisitForValue(property->obj());
1078 VisitForValue(property->key());
1079 break;
1080 }
1081 }
1082
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) {
1088 case VARIABLE: {
1089 Variable* variable = expr->target()->AsVariableProxy()->var();
1090 old_value = BuildVariableLoad(variable, expr->target()->id());
1091 break;
1092 }
1093 case NAMED_PROPERTY: {
1094 Node* object = environment()->Top();
1095 Unique<Name> name =
1096 MakeUnique(property->key()->AsLiteral()->AsPropertyName());
1097 old_value = NewNode(javascript()->LoadNamed(name), object);
1098 PrepareFrameState(old_value, property->LoadId(), kPushOutput);
1099 break;
1100 }
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);
1106 break;
1107 }
1108 }
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);
1116 } else {
1117 VisitForValue(expr->value());
1118 }
1119
1120 // Store the value.
1121 Node* value = environment()->Pop();
1122 switch (assign_type) {
1123 case VARIABLE: {
1124 Variable* variable = expr->target()->AsVariableProxy()->var();
1125 BuildVariableAssignment(variable, value, expr->op(),
1126 expr->AssignmentId());
1127 break;
1128 }
1129 case NAMED_PROPERTY: {
1130 Node* object = environment()->Pop();
1131 Unique<Name> name =
1132 MakeUnique(property->key()->AsLiteral()->AsPropertyName());
1133 Node* store =
1134 NewNode(javascript()->StoreNamed(strict_mode(), name), object, value);
1135 PrepareFrameState(store, expr->AssignmentId());
1136 break;
1137 }
1138 case KEYED_PROPERTY: {
1139 Node* key = environment()->Pop();
1140 Node* object = environment()->Pop();
1141 Node* store = NewNode(javascript()->StoreProperty(strict_mode()), object,
1142 key, value);
1143 PrepareFrameState(store, expr->AssignmentId());
1144 break;
1145 }
1146 }
1147
1148 ast_context()->ProduceValue(value);
1149}
1150
1151
1152void 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());
1159}
1160
1161
1162void 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);
1168}
1169
1170
1171void AstGraphBuilder::VisitProperty(Property* expr) {
1172 Node* value;
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);
1178 } else {
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);
1184 }
1185 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
1186 ast_context()->ProduceValue(value);
1187}
1188
1189
1190void AstGraphBuilder::VisitCall(Call* expr) {
1191 Expression* callee = expr->expression();
1192 Call::CallType call_type = expr->GetCallType(isolate());
1193
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();
1205 break;
1206 }
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);
1215 break;
1216 }
1217 case Call::PROPERTY_CALL: {
1218 Property* property = callee->AsProperty();
1219 VisitForValue(property->obj());
1220 Node* object = environment()->Top();
1221 if (property->key()->IsPropertyName()) {
1222 Unique<Name> name =
1223 MakeUnique(property->key()->AsLiteral()->AsPropertyName());
1224 callee_value = NewNode(javascript()->LoadNamed(name), object);
1225 } else {
1226 VisitForValue(property->key());
1227 Node* key = environment()->Pop();
1228 callee_value = NewNode(javascript()->LoadProperty(), object, key);
1229 }
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;
1236 break;
1237 }
1238 case Call::POSSIBLY_EVAL_CALL:
1239 possibly_eval = true;
1240 // Fall through.
1241 case Call::OTHER_CALL:
1242 VisitForValue(callee);
1243 callee_value = environment()->Pop();
1244 receiver_value = jsgraph()->UndefinedConstant();
1245 break;
1246 }
1247
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);
1252
1253 // Evaluate all arguments to the function call,
1254 ZoneList<Expression*>* args = expr->arguments();
1255 VisitForValues(args);
1256
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();
1261
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);
1265
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* function = GetFunctionClosure();
1269 Node* receiver = environment()->Lookup(info()->scope()->receiver());
1270 Node* strict = jsgraph()->Constant(strict_mode());
1271 Node* position = jsgraph()->Constant(info()->scope()->start_position());
1272 const Operator* op =
1273 javascript()->Runtime(Runtime::kResolvePossiblyDirectEval, 6);
1274 Node* pair =
1275 NewNode(op, callee, source, function, receiver, strict, position);
1276 Node* new_callee = NewNode(common()->Projection(0), pair);
1277 Node* new_receiver = NewNode(common()->Projection(1), pair);
1278
1279 // Patch callee and receiver on the environment.
1280 environment()->Poke(arg_count + 1, new_callee);
1281 environment()->Poke(arg_count + 0, new_receiver);
1282 }
1283
1284 // Create node to perform the function call.
1285 const Operator* call = javascript()->Call(args->length() + 2, flags);
1286 Node* value = ProcessArguments(call, args->length() + 2);
1287 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
1288 ast_context()->ProduceValue(value);
1289}
1290
1291
1292void AstGraphBuilder::VisitCallNew(CallNew* expr) {
1293 VisitForValue(expr->expression());
1294
1295 // Evaluate all arguments to the construct call.
1296 ZoneList<Expression*>* args = expr->arguments();
1297 VisitForValues(args);
1298
1299 // Create node to perform the construct call.
1300 const Operator* call = javascript()->CallNew(args->length() + 1);
1301 Node* value = ProcessArguments(call, args->length() + 1);
1302 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
1303 ast_context()->ProduceValue(value);
1304}
1305
1306
1307void AstGraphBuilder::VisitCallJSRuntime(CallRuntime* expr) {
1308 Handle<String> name = expr->name();
1309
1310 // The callee and the receiver both have to be pushed onto the operand stack
1311 // before arguments are being evaluated.
1312 CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS;
1313 Node* receiver_value = BuildLoadBuiltinsObject();
1314 Unique<String> unique = MakeUnique(name);
1315 Node* callee_value = NewNode(javascript()->LoadNamed(unique), receiver_value);
1316 // TODO(jarin): Find/create a bailout id to deoptimize to (crankshaft
1317 // refuses to optimize functions with jsruntime calls).
1318 PrepareFrameState(callee_value, BailoutId::None(), kPushOutput);
1319 environment()->Push(callee_value);
1320 environment()->Push(receiver_value);
1321
1322 // Evaluate all arguments to the JS runtime call.
1323 ZoneList<Expression*>* args = expr->arguments();
1324 VisitForValues(args);
1325
1326 // Create node to perform the JS runtime call.
1327 const Operator* call = javascript()->Call(args->length() + 2, flags);
1328 Node* value = ProcessArguments(call, args->length() + 2);
1329 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
1330 ast_context()->ProduceValue(value);
1331}
1332
1333
1334void AstGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
1335 const Runtime::Function* function = expr->function();
1336
1337 // Handle calls to runtime functions implemented in JavaScript separately as
1338 // the call follows JavaScript ABI and the callee is statically unknown.
1339 if (expr->is_jsruntime()) {
1340 DCHECK(function == NULL && expr->name()->length() > 0);
1341 return VisitCallJSRuntime(expr);
1342 }
1343
1344 // Evaluate all arguments to the runtime call.
1345 ZoneList<Expression*>* args = expr->arguments();
1346 VisitForValues(args);
1347
1348 // Create node to perform the runtime call.
1349 Runtime::FunctionId functionId = function->function_id;
1350 const Operator* call = javascript()->Runtime(functionId, args->length());
1351 Node* value = ProcessArguments(call, args->length());
1352 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
1353 ast_context()->ProduceValue(value);
1354}
1355
1356
1357void AstGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
1358 switch (expr->op()) {
1359 case Token::DELETE:
1360 return VisitDelete(expr);
1361 case Token::VOID:
1362 return VisitVoid(expr);
1363 case Token::TYPEOF:
1364 return VisitTypeof(expr);
1365 case Token::NOT:
1366 return VisitNot(expr);
1367 default:
1368 UNREACHABLE();
1369 }
1370}
1371
1372
1373void AstGraphBuilder::VisitCountOperation(CountOperation* expr) {
1374 DCHECK(expr->expression()->IsValidReferenceExpression());
1375
1376 // Left-hand side can only be a property, a global or a variable slot.
1377 Property* property = expr->expression()->AsProperty();
1378 LhsKind assign_type = DetermineLhsKind(expr->expression());
1379
1380 // Reserve space for result of postfix operation.
1381 bool is_postfix = expr->is_postfix() && !ast_context()->IsEffect();
1382 if (is_postfix) environment()->Push(jsgraph()->UndefinedConstant());
1383
1384 // Evaluate LHS expression and get old value.
1385 Node* old_value = NULL;
1386 int stack_depth = -1;
1387 switch (assign_type) {
1388 case VARIABLE: {
1389 Variable* variable = expr->expression()->AsVariableProxy()->var();
1390 old_value = BuildVariableLoad(variable, expr->expression()->id());
1391 stack_depth = 0;
1392 break;
1393 }
1394 case NAMED_PROPERTY: {
1395 VisitForValue(property->obj());
1396 Node* object = environment()->Top();
1397 Unique<Name> name =
1398 MakeUnique(property->key()->AsLiteral()->AsPropertyName());
1399 old_value = NewNode(javascript()->LoadNamed(name), object);
1400 PrepareFrameState(old_value, property->LoadId(), kPushOutput);
1401 stack_depth = 1;
1402 break;
1403 }
1404 case KEYED_PROPERTY: {
1405 VisitForValue(property->obj());
1406 VisitForValue(property->key());
1407 Node* key = environment()->Top();
1408 Node* object = environment()->Peek(1);
1409 old_value = NewNode(javascript()->LoadProperty(), object, key);
1410 PrepareFrameState(old_value, property->LoadId(), kPushOutput);
1411 stack_depth = 2;
1412 break;
1413 }
1414 }
1415
1416 // Convert old value into a number.
1417 old_value = NewNode(javascript()->ToNumber(), old_value);
1418
1419 // Save result for postfix expressions at correct stack depth.
1420 if (is_postfix) environment()->Poke(stack_depth, old_value);
1421
1422 // Create node to perform +1/-1 operation.
1423 Node* value =
1424 BuildBinaryOp(old_value, jsgraph()->OneConstant(), expr->binary_op());
1425 // TODO(jarin) Insert proper bailout id here (will need to change
1426 // full code generator).
1427 PrepareFrameState(value, BailoutId::None());
1428
1429 // Store the value.
1430 switch (assign_type) {
1431 case VARIABLE: {
1432 Variable* variable = expr->expression()->AsVariableProxy()->var();
1433 environment()->Push(value);
1434 BuildVariableAssignment(variable, value, expr->op(),
1435 expr->AssignmentId());
1436 environment()->Pop();
1437 break;
1438 }
1439 case NAMED_PROPERTY: {
1440 Node* object = environment()->Pop();
1441 Unique<Name> name =
1442 MakeUnique(property->key()->AsLiteral()->AsPropertyName());
1443 Node* store =
1444 NewNode(javascript()->StoreNamed(strict_mode(), name), object, value);
1445 environment()->Push(value);
1446 PrepareFrameState(store, expr->AssignmentId());
1447 environment()->Pop();
1448 break;
1449 }
1450 case KEYED_PROPERTY: {
1451 Node* key = environment()->Pop();
1452 Node* object = environment()->Pop();
1453 Node* store = NewNode(javascript()->StoreProperty(strict_mode()), object,
1454 key, value);
1455 environment()->Push(value);
1456 PrepareFrameState(store, expr->AssignmentId());
1457 environment()->Pop();
1458 break;
1459 }
1460 }
1461
1462 // Restore old value for postfix expressions.
1463 if (is_postfix) value = environment()->Pop();
1464
1465 ast_context()->ProduceValue(value);
1466}
1467
1468
1469void AstGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
1470 switch (expr->op()) {
1471 case Token::COMMA:
1472 return VisitComma(expr);
1473 case Token::OR:
1474 case Token::AND:
1475 return VisitLogicalExpression(expr);
1476 default: {
1477 VisitForValue(expr->left());
1478 VisitForValue(expr->right());
1479 Node* right = environment()->Pop();
1480 Node* left = environment()->Pop();
1481 Node* value = BuildBinaryOp(left, right, expr->op());
1482 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
1483 ast_context()->ProduceValue(value);
1484 }
1485 }
1486}
1487
1488
1489void AstGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
1490 const Operator* op;
1491 switch (expr->op()) {
1492 case Token::EQ:
1493 op = javascript()->Equal();
1494 break;
1495 case Token::NE:
1496 op = javascript()->NotEqual();
1497 break;
1498 case Token::EQ_STRICT:
1499 op = javascript()->StrictEqual();
1500 break;
1501 case Token::NE_STRICT:
1502 op = javascript()->StrictNotEqual();
1503 break;
1504 case Token::LT:
1505 op = javascript()->LessThan();
1506 break;
1507 case Token::GT:
1508 op = javascript()->GreaterThan();
1509 break;
1510 case Token::LTE:
1511 op = javascript()->LessThanOrEqual();
1512 break;
1513 case Token::GTE:
1514 op = javascript()->GreaterThanOrEqual();
1515 break;
1516 case Token::INSTANCEOF:
1517 op = javascript()->InstanceOf();
1518 break;
1519 case Token::IN:
1520 op = javascript()->HasProperty();
1521 break;
1522 default:
1523 op = NULL;
1524 UNREACHABLE();
1525 }
1526 VisitForValue(expr->left());
1527 VisitForValue(expr->right());
1528 Node* right = environment()->Pop();
1529 Node* left = environment()->Pop();
1530 Node* value = NewNode(op, left, right);
1531 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
1532 ast_context()->ProduceValue(value);
1533}
1534
1535
1536void AstGraphBuilder::VisitThisFunction(ThisFunction* expr) {
1537 Node* value = GetFunctionClosure();
1538 ast_context()->ProduceValue(value);
1539}
1540
1541
1542void AstGraphBuilder::VisitSuperReference(SuperReference* expr) {
1543 UNREACHABLE();
1544}
1545
1546
1547void AstGraphBuilder::VisitCaseClause(CaseClause* expr) { UNREACHABLE(); }
1548
1549
1550void AstGraphBuilder::VisitDeclarations(ZoneList<Declaration*>* declarations) {
1551 DCHECK(globals()->is_empty());
1552 AstVisitor::VisitDeclarations(declarations);
1553 if (globals()->is_empty()) return;
1554 Handle<FixedArray> data =
1555 isolate()->factory()->NewFixedArray(globals()->length(), TENURED);
1556 for (int i = 0; i < globals()->length(); ++i) data->set(i, *globals()->at(i));
1557 int encoded_flags = DeclareGlobalsEvalFlag::encode(info()->is_eval()) |
1558 DeclareGlobalsNativeFlag::encode(info()->is_native()) |
1559 DeclareGlobalsStrictMode::encode(strict_mode());
1560 Node* flags = jsgraph()->Constant(encoded_flags);
1561 Node* pairs = jsgraph()->Constant(data);
1562 const Operator* op = javascript()->Runtime(Runtime::kDeclareGlobals, 3);
1563 NewNode(op, current_context(), pairs, flags);
1564 globals()->Rewind(0);
1565}
1566
1567
1568void AstGraphBuilder::VisitIfNotNull(Statement* stmt) {
1569 if (stmt == NULL) return;
1570 Visit(stmt);
1571}
1572
1573
1574void AstGraphBuilder::VisitIterationBody(IterationStatement* stmt,
1575 LoopBuilder* loop, int drop_extra) {
1576 BreakableScope scope(this, stmt, loop, drop_extra);
1577 Visit(stmt->body());
1578}
1579
1580
1581void AstGraphBuilder::VisitDelete(UnaryOperation* expr) {
1582 Node* value;
1583 if (expr->expression()->IsVariableProxy()) {
1584 // Delete of an unqualified identifier is only allowed in classic mode but
1585 // deleting "this" is allowed in all language modes.
1586 Variable* variable = expr->expression()->AsVariableProxy()->var();
1587 DCHECK(strict_mode() == SLOPPY || variable->is_this());
1588 value = BuildVariableDelete(variable);
1589 } else if (expr->expression()->IsProperty()) {
1590 Property* property = expr->expression()->AsProperty();
1591 VisitForValue(property->obj());
1592 VisitForValue(property->key());
1593 Node* key = environment()->Pop();
1594 Node* object = environment()->Pop();
1595 value = NewNode(javascript()->DeleteProperty(strict_mode()), object, key);
1596 } else {
1597 VisitForEffect(expr->expression());
1598 value = jsgraph()->TrueConstant();
1599 }
1600 ast_context()->ProduceValue(value);
1601}
1602
1603
1604void AstGraphBuilder::VisitVoid(UnaryOperation* expr) {
1605 VisitForEffect(expr->expression());
1606 Node* value = jsgraph()->UndefinedConstant();
1607 ast_context()->ProduceValue(value);
1608}
1609
1610
1611void AstGraphBuilder::VisitTypeof(UnaryOperation* expr) {
1612 Node* operand;
1613 if (expr->expression()->IsVariableProxy()) {
1614 // Typeof does not throw a reference error on global variables, hence we
1615 // perform a non-contextual load in case the operand is a variable proxy.
1616 Variable* variable = expr->expression()->AsVariableProxy()->var();
1617 operand =
1618 BuildVariableLoad(variable, expr->expression()->id(), NOT_CONTEXTUAL);
1619 } else {
1620 VisitForValue(expr->expression());
1621 operand = environment()->Pop();
1622 }
1623 Node* value = NewNode(javascript()->TypeOf(), operand);
1624 ast_context()->ProduceValue(value);
1625}
1626
1627
1628void AstGraphBuilder::VisitNot(UnaryOperation* expr) {
1629 VisitForValue(expr->expression());
1630 Node* operand = environment()->Pop();
1631 // TODO(mstarzinger): Possible optimization when we are in effect context.
1632 Node* value = NewNode(javascript()->UnaryNot(), operand);
1633 ast_context()->ProduceValue(value);
1634}
1635
1636
1637void AstGraphBuilder::VisitComma(BinaryOperation* expr) {
1638 VisitForEffect(expr->left());
1639 Visit(expr->right());
1640 ast_context()->ReplaceValue();
1641}
1642
1643
1644void AstGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) {
1645 bool is_logical_and = expr->op() == Token::AND;
1646 IfBuilder compare_if(this);
1647 VisitForValue(expr->left());
1648 Node* condition = environment()->Top();
1649 compare_if.If(BuildToBoolean(condition));
1650 compare_if.Then();
1651 if (is_logical_and) {
1652 environment()->Pop();
1653 Visit(expr->right());
1654 } else if (ast_context()->IsEffect()) {
1655 environment()->Pop();
1656 }
1657 compare_if.Else();
1658 if (!is_logical_and) {
1659 environment()->Pop();
1660 Visit(expr->right());
1661 } else if (ast_context()->IsEffect()) {
1662 environment()->Pop();
1663 }
1664 compare_if.End();
1665 ast_context()->ReplaceValue();
1666}
1667
1668
1669Node* AstGraphBuilder::ProcessArguments(const Operator* op, int arity) {
1670 DCHECK(environment()->stack_height() >= arity);
1671 Node** all = info()->zone()->NewArray<Node*>(arity);
1672 for (int i = arity - 1; i >= 0; --i) {
1673 all[i] = environment()->Pop();
1674 }
1675 Node* value = NewNode(op, arity, all);
1676 return value;
1677}
1678
1679
1680Node* AstGraphBuilder::BuildLocalFunctionContext(Node* context, Node* closure) {
1681 int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
1682 if (heap_slots <= 0) return context;
1683 set_current_context(context);
1684
1685 // Allocate a new local context.
1686 const Operator* op = javascript()->CreateFunctionContext();
1687 Node* local_context = NewNode(op, closure);
1688 set_current_context(local_context);
1689
1690 // Copy parameters into context if necessary.
1691 int num_parameters = info()->scope()->num_parameters();
1692 for (int i = 0; i < num_parameters; i++) {
1693 Variable* variable = info()->scope()->parameter(i);
1694 if (!variable->IsContextSlot()) continue;
1695 // Temporary parameter node. The parameter indices are shifted by 1
1696 // (receiver is parameter index -1 but environment index 0).
1697 Node* parameter = NewNode(common()->Parameter(i + 1), graph()->start());
1698 // Context variable (at bottom of the context chain).
1699 DCHECK_EQ(0, info()->scope()->ContextChainLength(variable->scope()));
1700 const Operator* op = javascript()->StoreContext(0, variable->index());
1701 NewNode(op, local_context, parameter);
1702 }
1703
1704 return local_context;
1705}
1706
1707
1708Node* AstGraphBuilder::BuildArgumentsObject(Variable* arguments) {
1709 if (arguments == NULL) return NULL;
1710
1711 // Allocate and initialize a new arguments object.
1712 Node* callee = GetFunctionClosure();
1713 const Operator* op = javascript()->Runtime(Runtime::kNewArguments, 1);
1714 Node* object = NewNode(op, callee);
1715
1716 // Assign the object to the arguments variable.
1717 DCHECK(arguments->IsContextSlot() || arguments->IsStackAllocated());
1718 // This should never lazy deopt, so it is fine to send invalid bailout id.
1719 BuildVariableAssignment(arguments, object, Token::ASSIGN, BailoutId::None());
1720
1721 return object;
1722}
1723
1724
1725Node* AstGraphBuilder::BuildHoleCheckSilent(Node* value, Node* for_hole,
1726 Node* not_hole) {
1727 IfBuilder hole_check(this);
1728 Node* the_hole = jsgraph()->TheHoleConstant();
1729 Node* check = NewNode(javascript()->StrictEqual(), value, the_hole);
1730 hole_check.If(check);
1731 hole_check.Then();
1732 environment()->Push(for_hole);
1733 hole_check.Else();
1734 environment()->Push(not_hole);
1735 hole_check.End();
1736 return environment()->Pop();
1737}
1738
1739
1740Node* AstGraphBuilder::BuildHoleCheckThrow(Node* value, Variable* variable,
1741 Node* not_hole) {
1742 IfBuilder hole_check(this);
1743 Node* the_hole = jsgraph()->TheHoleConstant();
1744 Node* check = NewNode(javascript()->StrictEqual(), value, the_hole);
1745 hole_check.If(check);
1746 hole_check.Then();
1747 environment()->Push(BuildThrowReferenceError(variable));
1748 hole_check.Else();
1749 environment()->Push(not_hole);
1750 hole_check.End();
1751 return environment()->Pop();
1752}
1753
1754
1755Node* AstGraphBuilder::BuildVariableLoad(Variable* variable,
1756 BailoutId bailout_id,
1757 ContextualMode contextual_mode) {
1758 Node* the_hole = jsgraph()->TheHoleConstant();
1759 VariableMode mode = variable->mode();
1760 switch (variable->location()) {
1761 case Variable::UNALLOCATED: {
1762 // Global var, const, or let variable.
1763 Node* global = BuildLoadGlobalObject();
1764 Unique<Name> name = MakeUnique(variable->name());
1765 const Operator* op = javascript()->LoadNamed(name, contextual_mode);
1766 Node* node = NewNode(op, global);
1767 PrepareFrameState(node, bailout_id, kPushOutput);
1768 return node;
1769 }
1770 case Variable::PARAMETER:
1771 case Variable::LOCAL: {
1772 // Local var, const, or let variable.
1773 Node* value = environment()->Lookup(variable);
1774 if (mode == CONST_LEGACY) {
1775 // Perform check for uninitialized legacy const variables.
1776 if (value->op() == the_hole->op()) {
1777 value = jsgraph()->UndefinedConstant();
1778 } else if (value->opcode() == IrOpcode::kPhi) {
1779 Node* undefined = jsgraph()->UndefinedConstant();
1780 value = BuildHoleCheckSilent(value, undefined, value);
1781 }
1782 } else if (mode == LET || mode == CONST) {
1783 // Perform check for uninitialized let/const variables.
1784 if (value->op() == the_hole->op()) {
1785 value = BuildThrowReferenceError(variable);
1786 } else if (value->opcode() == IrOpcode::kPhi) {
1787 value = BuildHoleCheckThrow(value, variable, value);
1788 }
1789 }
1790 return value;
1791 }
1792 case Variable::CONTEXT: {
1793 // Context variable (potentially up the context chain).
1794 int depth = current_scope()->ContextChainLength(variable->scope());
1795 bool immutable = variable->maybe_assigned() == kNotAssigned;
1796 const Operator* op =
1797 javascript()->LoadContext(depth, variable->index(), immutable);
1798 Node* value = NewNode(op, current_context());
1799 // TODO(titzer): initialization checks are redundant for already
1800 // initialized immutable context loads, but only specialization knows.
1801 // Maybe specializer should be a parameter to the graph builder?
1802 if (mode == CONST_LEGACY) {
1803 // Perform check for uninitialized legacy const variables.
1804 Node* undefined = jsgraph()->UndefinedConstant();
1805 value = BuildHoleCheckSilent(value, undefined, value);
1806 } else if (mode == LET || mode == CONST) {
1807 // Perform check for uninitialized let/const variables.
1808 value = BuildHoleCheckThrow(value, variable, value);
1809 }
1810 return value;
1811 }
1812 case Variable::LOOKUP: {
1813 // Dynamic lookup of context variable (anywhere in the chain).
1814 Node* name = jsgraph()->Constant(variable->name());
1815 Runtime::FunctionId function_id =
1816 (contextual_mode == CONTEXTUAL)
1817 ? Runtime::kLoadLookupSlot
1818 : Runtime::kLoadLookupSlotNoReferenceError;
1819 const Operator* op = javascript()->Runtime(function_id, 2);
1820 Node* pair = NewNode(op, current_context(), name);
1821 return NewNode(common()->Projection(0), pair);
1822 }
1823 }
1824 UNREACHABLE();
1825 return NULL;
1826}
1827
1828
1829Node* AstGraphBuilder::BuildVariableDelete(Variable* variable) {
1830 switch (variable->location()) {
1831 case Variable::UNALLOCATED: {
1832 // Global var, const, or let variable.
1833 Node* global = BuildLoadGlobalObject();
1834 Node* name = jsgraph()->Constant(variable->name());
1835 const Operator* op = javascript()->DeleteProperty(strict_mode());
1836 return NewNode(op, global, name);
1837 }
1838 case Variable::PARAMETER:
1839 case Variable::LOCAL:
1840 case Variable::CONTEXT:
1841 // Local var, const, or let variable or context variable.
1842 return variable->is_this() ? jsgraph()->TrueConstant()
1843 : jsgraph()->FalseConstant();
1844 case Variable::LOOKUP: {
1845 // Dynamic lookup of context variable (anywhere in the chain).
1846 Node* name = jsgraph()->Constant(variable->name());
1847 const Operator* op = javascript()->Runtime(Runtime::kDeleteLookupSlot, 2);
1848 return NewNode(op, current_context(), name);
1849 }
1850 }
1851 UNREACHABLE();
1852 return NULL;
1853}
1854
1855
1856Node* AstGraphBuilder::BuildVariableAssignment(Variable* variable, Node* value,
1857 Token::Value op,
1858 BailoutId bailout_id) {
1859 Node* the_hole = jsgraph()->TheHoleConstant();
1860 VariableMode mode = variable->mode();
1861 switch (variable->location()) {
1862 case Variable::UNALLOCATED: {
1863 // Global var, const, or let variable.
1864 Node* global = BuildLoadGlobalObject();
1865 Unique<Name> name = MakeUnique(variable->name());
1866 const Operator* op = javascript()->StoreNamed(strict_mode(), name);
1867 Node* store = NewNode(op, global, value);
1868 PrepareFrameState(store, bailout_id);
1869 return store;
1870 }
1871 case Variable::PARAMETER:
1872 case Variable::LOCAL:
1873 // Local var, const, or let variable.
1874 if (mode == CONST_LEGACY && op == Token::INIT_CONST_LEGACY) {
1875 // Perform an initialization check for legacy const variables.
1876 Node* current = environment()->Lookup(variable);
1877 if (current->op() != the_hole->op()) {
1878 value = BuildHoleCheckSilent(current, value, current);
1879 }
1880 } else if (mode == CONST_LEGACY && op != Token::INIT_CONST_LEGACY) {
1881 // Non-initializing assignments to legacy const is ignored.
1882 return value;
1883 } else if (mode == LET && op != Token::INIT_LET) {
1884 // Perform an initialization check for let declared variables.
1885 // Also note that the dynamic hole-check is only done to ensure that
1886 // this does not break in the presence of do-expressions within the
1887 // temporal dead zone of a let declared variable.
1888 Node* current = environment()->Lookup(variable);
1889 if (current->op() == the_hole->op()) {
1890 value = BuildThrowReferenceError(variable);
1891 } else if (value->opcode() == IrOpcode::kPhi) {
1892 value = BuildHoleCheckThrow(current, variable, value);
1893 }
1894 } else if (mode == CONST && op != Token::INIT_CONST) {
1895 // All assignments to const variables are early errors.
1896 UNREACHABLE();
1897 }
1898 environment()->Bind(variable, value);
1899 return value;
1900 case Variable::CONTEXT: {
1901 // Context variable (potentially up the context chain).
1902 int depth = current_scope()->ContextChainLength(variable->scope());
1903 if (mode == CONST_LEGACY && op == Token::INIT_CONST_LEGACY) {
1904 // Perform an initialization check for legacy const variables.
1905 const Operator* op =
1906 javascript()->LoadContext(depth, variable->index(), false);
1907 Node* current = NewNode(op, current_context());
1908 value = BuildHoleCheckSilent(current, value, current);
1909 } else if (mode == CONST_LEGACY && op != Token::INIT_CONST_LEGACY) {
1910 // Non-initializing assignments to legacy const is ignored.
1911 return value;
1912 } else if (mode == LET && op != Token::INIT_LET) {
1913 // Perform an initialization check for let declared variables.
1914 const Operator* op =
1915 javascript()->LoadContext(depth, variable->index(), false);
1916 Node* current = NewNode(op, current_context());
1917 value = BuildHoleCheckThrow(current, variable, value);
1918 } else if (mode == CONST && op != Token::INIT_CONST) {
1919 // All assignments to const variables are early errors.
1920 UNREACHABLE();
1921 }
1922 const Operator* op = javascript()->StoreContext(depth, variable->index());
1923 return NewNode(op, current_context(), value);
1924 }
1925 case Variable::LOOKUP: {
1926 // Dynamic lookup of context variable (anywhere in the chain).
1927 Node* name = jsgraph()->Constant(variable->name());
1928 Node* strict = jsgraph()->Constant(strict_mode());
1929 // TODO(mstarzinger): Use Runtime::kInitializeLegacyConstLookupSlot for
1930 // initializations of const declarations.
1931 const Operator* op = javascript()->Runtime(Runtime::kStoreLookupSlot, 4);
1932 return NewNode(op, value, current_context(), name, strict);
1933 }
1934 }
1935 UNREACHABLE();
1936 return NULL;
1937}
1938
1939
1940Node* AstGraphBuilder::BuildLoadObjectField(Node* object, int offset) {
1941 // TODO(sigurds) Use simplified load here once it is ready.
1942 Node* field_load = NewNode(jsgraph()->machine()->Load(kMachAnyTagged), object,
1943 jsgraph()->Int32Constant(offset - kHeapObjectTag));
1944 return field_load;
1945}
1946
1947
1948Node* AstGraphBuilder::BuildLoadBuiltinsObject() {
1949 Node* global = BuildLoadGlobalObject();
1950 Node* builtins =
1951 BuildLoadObjectField(global, JSGlobalObject::kBuiltinsOffset);
1952 return builtins;
1953}
1954
1955
1956Node* AstGraphBuilder::BuildLoadGlobalObject() {
1957 Node* context = GetFunctionContext();
1958 const Operator* load_op =
1959 javascript()->LoadContext(0, Context::GLOBAL_OBJECT_INDEX, true);
1960 return NewNode(load_op, context);
1961}
1962
1963
1964Node* AstGraphBuilder::BuildToBoolean(Node* value) {
1965 // TODO(mstarzinger): Possible optimization is to NOP for boolean values.
1966 return NewNode(javascript()->ToBoolean(), value);
1967}
1968
1969
1970Node* AstGraphBuilder::BuildThrowReferenceError(Variable* variable) {
1971 // TODO(mstarzinger): Should be unified with the VisitThrow implementation.
1972 Node* variable_name = jsgraph()->Constant(variable->name());
1973 const Operator* op = javascript()->Runtime(Runtime::kThrowReferenceError, 1);
1974 return NewNode(op, variable_name);
1975}
1976
1977
1978Node* AstGraphBuilder::BuildBinaryOp(Node* left, Node* right, Token::Value op) {
1979 const Operator* js_op;
1980 switch (op) {
1981 case Token::BIT_OR:
1982 js_op = javascript()->BitwiseOr();
1983 break;
1984 case Token::BIT_AND:
1985 js_op = javascript()->BitwiseAnd();
1986 break;
1987 case Token::BIT_XOR:
1988 js_op = javascript()->BitwiseXor();
1989 break;
1990 case Token::SHL:
1991 js_op = javascript()->ShiftLeft();
1992 break;
1993 case Token::SAR:
1994 js_op = javascript()->ShiftRight();
1995 break;
1996 case Token::SHR:
1997 js_op = javascript()->ShiftRightLogical();
1998 break;
1999 case Token::ADD:
2000 js_op = javascript()->Add();
2001 break;
2002 case Token::SUB:
2003 js_op = javascript()->Subtract();
2004 break;
2005 case Token::MUL:
2006 js_op = javascript()->Multiply();
2007 break;
2008 case Token::DIV:
2009 js_op = javascript()->Divide();
2010 break;
2011 case Token::MOD:
2012 js_op = javascript()->Modulus();
2013 break;
2014 default:
2015 UNREACHABLE();
2016 js_op = NULL;
2017 }
2018 return NewNode(js_op, left, right);
2019}
2020
2021
2022void AstGraphBuilder::PrepareFrameState(Node* node, BailoutId ast_id,
2023 OutputFrameStateCombine combine) {
2024 if (OperatorProperties::HasFrameStateInput(node->op())) {
2025 DCHECK(NodeProperties::GetFrameStateInput(node)->opcode() ==
2026 IrOpcode::kDead);
2027 NodeProperties::ReplaceFrameStateInput(
2028 node, environment()->Checkpoint(ast_id, combine));
2029 }
2030}
2031
2032}
2033}
2034} // namespace v8::internal::compiler