1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "src/compiler/ast-graph-builder.h"
7 #include "src/compiler.h"
8 #include "src/compiler/ast-loop-assignment-analyzer.h"
9 #include "src/compiler/control-builders.h"
10 #include "src/compiler/js-type-feedback.h"
11 #include "src/compiler/linkage.h"
12 #include "src/compiler/liveness-analyzer.h"
13 #include "src/compiler/machine-operator.h"
14 #include "src/compiler/node-matchers.h"
15 #include "src/compiler/node-properties.h"
16 #include "src/compiler/operator-properties.h"
17 #include "src/compiler/state-values-utils.h"
18 #include "src/full-codegen/full-codegen.h"
19 #include "src/parser.h"
20 #include "src/scopes.h"
27 // Each expression in the AST is evaluated in a specific context. This context
28 // decides how the evaluation result is passed up the visitor.
29 class AstGraphBuilder::AstContext BASE_EMBEDDED {
31 bool IsEffect() const { return kind_ == Expression::kEffect; }
32 bool IsValue() const { return kind_ == Expression::kValue; }
33 bool IsTest() const { return kind_ == Expression::kTest; }
35 // Determines how to combine the frame state with the value
36 // that is about to be plugged into this AstContext.
37 OutputFrameStateCombine GetStateCombine() {
38 return IsEffect() ? OutputFrameStateCombine::Ignore()
39 : OutputFrameStateCombine::Push();
42 // Plug a node into this expression context. Call this function in tail
43 // position in the Visit functions for expressions.
44 virtual void ProduceValue(Node* value) = 0;
46 // Unplugs a node from this expression context. Call this to retrieve the
47 // result of another Visit function that already plugged the context.
48 virtual Node* ConsumeValue() = 0;
50 // Shortcut for "context->ProduceValue(context->ConsumeValue())".
51 void ReplaceValue() { ProduceValue(ConsumeValue()); }
54 AstContext(AstGraphBuilder* owner, Expression::Context kind);
55 virtual ~AstContext();
57 AstGraphBuilder* owner() const { return owner_; }
58 Environment* environment() const { return owner_->environment(); }
60 // We want to be able to assert, in a context-specific way, that the stack
61 // height makes sense when the context is filled.
67 Expression::Context kind_;
68 AstGraphBuilder* owner_;
73 // Context to evaluate expression for its side effects only.
74 class AstGraphBuilder::AstEffectContext final : public AstContext {
76 explicit AstEffectContext(AstGraphBuilder* owner)
77 : AstContext(owner, Expression::kEffect) {}
78 ~AstEffectContext() final;
79 void ProduceValue(Node* value) final;
80 Node* ConsumeValue() final;
84 // Context to evaluate expression for its value (and side effects).
85 class AstGraphBuilder::AstValueContext final : public AstContext {
87 explicit AstValueContext(AstGraphBuilder* owner)
88 : AstContext(owner, Expression::kValue) {}
89 ~AstValueContext() final;
90 void ProduceValue(Node* value) final;
91 Node* ConsumeValue() final;
95 // Context to evaluate expression for a condition value (and side effects).
96 class AstGraphBuilder::AstTestContext final : public AstContext {
98 explicit AstTestContext(AstGraphBuilder* owner)
99 : AstContext(owner, Expression::kTest) {}
100 ~AstTestContext() final;
101 void ProduceValue(Node* value) final;
102 Node* ConsumeValue() final;
106 // Scoped class tracking context objects created by the visitor. Represents
107 // mutations of the context chain within the function body and allows to
108 // change the current {scope} and {context} during visitation.
109 class AstGraphBuilder::ContextScope BASE_EMBEDDED {
111 ContextScope(AstGraphBuilder* builder, Scope* scope, Node* context)
113 outer_(builder->execution_context()),
115 depth_(builder_->environment()->context_chain_length()) {
116 builder_->environment()->PushContext(context); // Push.
117 builder_->set_execution_context(this);
121 builder_->set_execution_context(outer_); // Pop.
122 builder_->environment()->PopContext();
123 CHECK_EQ(depth_, builder_->environment()->context_chain_length());
126 // Current scope during visitation.
127 Scope* scope() const { return scope_; }
130 AstGraphBuilder* builder_;
131 ContextScope* outer_;
137 // Scoped class tracking control statements entered by the visitor. There are
138 // different types of statements participating in this stack to properly track
139 // local as well as non-local control flow:
140 // - IterationStatement : Allows proper 'break' and 'continue' behavior.
141 // - BreakableStatement : Allows 'break' from block and switch statements.
142 // - TryCatchStatement : Intercepts 'throw' and implicit exceptional edges.
143 // - TryFinallyStatement: Intercepts 'break', 'continue', 'throw' and 'return'.
144 class AstGraphBuilder::ControlScope BASE_EMBEDDED {
146 explicit ControlScope(AstGraphBuilder* builder)
148 outer_(builder->execution_control()),
149 context_length_(builder->environment()->context_chain_length()),
150 stack_height_(builder->environment()->stack_height()) {
151 builder_->set_execution_control(this); // Push.
154 virtual ~ControlScope() {
155 builder_->set_execution_control(outer_); // Pop.
158 // Either 'break' or 'continue' to the target statement.
159 void BreakTo(BreakableStatement* target);
160 void ContinueTo(BreakableStatement* target);
162 // Either 'return' or 'throw' the given value.
163 void ReturnValue(Node* return_value);
164 void ThrowValue(Node* exception_value);
166 class DeferredCommands;
169 enum Command { CMD_BREAK, CMD_CONTINUE, CMD_RETURN, CMD_THROW };
171 // Performs one of the above commands on this stack of control scopes. This
172 // walks through the stack giving each scope a chance to execute or defer the
173 // given command by overriding the {Execute} method appropriately. Note that
174 // this also drops extra operands from the environment for each skipped scope.
175 void PerformCommand(Command cmd, Statement* target, Node* value);
177 // Interface to execute a given command in this scope. Returning {true} here
178 // indicates successful execution whereas {false} requests to skip scope.
179 virtual bool Execute(Command cmd, Statement* target, Node* value) {
180 // For function-level control.
183 builder()->BuildThrow(value);
186 builder()->BuildReturn(value);
195 Environment* environment() { return builder_->environment(); }
196 AstGraphBuilder* builder() const { return builder_; }
197 int context_length() const { return context_length_; }
198 int stack_height() const { return stack_height_; }
201 AstGraphBuilder* builder_;
202 ControlScope* outer_;
208 // Helper class for a try-finally control scope. It can record intercepted
209 // control-flow commands that cause entry into a finally-block, and re-apply
210 // them after again leaving that block. Special tokens are used to identify
211 // paths going through the finally-block to dispatch after leaving the block.
212 class AstGraphBuilder::ControlScope::DeferredCommands : public ZoneObject {
214 explicit DeferredCommands(AstGraphBuilder* owner)
215 : owner_(owner), deferred_(owner->zone()) {}
217 // One recorded control-flow command.
219 Command command; // The command type being applied on this path.
220 Statement* statement; // The target statement for the command or {NULL}.
221 Node* token; // A token identifying this particular path.
224 // Records a control-flow command while entering the finally-block. This also
225 // generates a new dispatch token that identifies one particular path.
226 Node* RecordCommand(Command cmd, Statement* stmt, Node* value) {
227 Node* token = NewPathTokenForDeferredCommand();
228 deferred_.push_back({cmd, stmt, token});
232 // Returns the dispatch token to be used to identify the implicit fall-through
233 // path at the end of a try-block into the corresponding finally-block.
234 Node* GetFallThroughToken() { return NewPathTokenForImplicitFallThrough(); }
236 // Applies all recorded control-flow commands after the finally-block again.
237 // This generates a dynamic dispatch on the token from the entry point.
238 void ApplyDeferredCommands(Node* token, Node* value) {
239 SwitchBuilder dispatch(owner_, static_cast<int>(deferred_.size()));
240 dispatch.BeginSwitch();
241 for (size_t i = 0; i < deferred_.size(); ++i) {
242 Node* condition = NewPathDispatchCondition(token, deferred_[i].token);
243 dispatch.BeginLabel(static_cast<int>(i), condition);
246 for (size_t i = 0; i < deferred_.size(); ++i) {
247 dispatch.BeginCase(static_cast<int>(i));
248 owner_->execution_control()->PerformCommand(
249 deferred_[i].command, deferred_[i].statement, value);
252 dispatch.EndSwitch();
256 Node* NewPathTokenForDeferredCommand() {
257 return owner_->jsgraph()->Constant(static_cast<int>(deferred_.size()));
259 Node* NewPathTokenForImplicitFallThrough() {
260 return owner_->jsgraph()->Constant(-1);
262 Node* NewPathDispatchCondition(Node* t1, Node* t2) {
263 // TODO(mstarzinger): This should be machine()->WordEqual(), but our Phi
264 // nodes all have kRepTagged|kTypeAny, which causes representation mismatch.
265 return owner_->NewNode(owner_->javascript()->StrictEqual(), t1, t2);
269 AstGraphBuilder* owner_;
270 ZoneVector<Entry> deferred_;
274 // Control scope implementation for a BreakableStatement.
275 class AstGraphBuilder::ControlScopeForBreakable : public ControlScope {
277 ControlScopeForBreakable(AstGraphBuilder* owner, BreakableStatement* target,
278 ControlBuilder* control)
279 : ControlScope(owner), target_(target), control_(control) {}
282 virtual bool Execute(Command cmd, Statement* target, Node* value) override {
283 if (target != target_) return false; // We are not the command target.
297 BreakableStatement* target_;
298 ControlBuilder* control_;
302 // Control scope implementation for an IterationStatement.
303 class AstGraphBuilder::ControlScopeForIteration : public ControlScope {
305 ControlScopeForIteration(AstGraphBuilder* owner, IterationStatement* target,
306 LoopBuilder* control)
307 : ControlScope(owner), target_(target), control_(control) {}
310 virtual bool Execute(Command cmd, Statement* target, Node* value) override {
311 if (target != target_) return false; // We are not the command target.
317 control_->Continue();
327 BreakableStatement* target_;
328 LoopBuilder* control_;
332 // Control scope implementation for a TryCatchStatement.
333 class AstGraphBuilder::ControlScopeForCatch : public ControlScope {
335 ControlScopeForCatch(AstGraphBuilder* owner, TryCatchBuilder* control)
336 : ControlScope(owner), control_(control) {
337 builder()->try_nesting_level_++; // Increment nesting.
338 builder()->try_catch_nesting_level_++;
340 ~ControlScopeForCatch() {
341 builder()->try_nesting_level_--; // Decrement nesting.
342 builder()->try_catch_nesting_level_--;
346 virtual bool Execute(Command cmd, Statement* target, Node* value) override {
349 control_->Throw(value);
360 TryCatchBuilder* control_;
364 // Control scope implementation for a TryFinallyStatement.
365 class AstGraphBuilder::ControlScopeForFinally : public ControlScope {
367 ControlScopeForFinally(AstGraphBuilder* owner, DeferredCommands* commands,
368 TryFinallyBuilder* control)
369 : ControlScope(owner), commands_(commands), control_(control) {
370 builder()->try_nesting_level_++; // Increment nesting.
372 ~ControlScopeForFinally() {
373 builder()->try_nesting_level_--; // Decrement nesting.
377 virtual bool Execute(Command cmd, Statement* target, Node* value) override {
378 Node* token = commands_->RecordCommand(cmd, target, value);
379 control_->LeaveTry(token, value);
384 DeferredCommands* commands_;
385 TryFinallyBuilder* control_;
389 // Helper for generating before and after frame states.
390 class AstGraphBuilder::FrameStateBeforeAndAfter {
392 FrameStateBeforeAndAfter(AstGraphBuilder* builder, BailoutId id_before)
393 : builder_(builder), frame_state_before_(nullptr) {
394 frame_state_before_ = id_before == BailoutId::None()
395 ? builder_->jsgraph()->EmptyFrameState()
396 : builder_->environment()->Checkpoint(id_before);
399 void AddToNode(Node* node, BailoutId id_after,
400 OutputFrameStateCombine combine) {
401 int count = OperatorProperties::GetFrameStateInputCount(node->op());
405 // Add the frame state for after the operation.
406 DCHECK_EQ(IrOpcode::kDead,
407 NodeProperties::GetFrameStateInput(node, 0)->opcode());
409 Node* frame_state_after =
410 id_after == BailoutId::None()
411 ? builder_->jsgraph()->EmptyFrameState()
412 : builder_->environment()->Checkpoint(id_after, combine);
414 NodeProperties::ReplaceFrameStateInput(node, 0, frame_state_after);
418 // Add the frame state for before the operation.
419 DCHECK_EQ(IrOpcode::kDead,
420 NodeProperties::GetFrameStateInput(node, 1)->opcode());
421 NodeProperties::ReplaceFrameStateInput(node, 1, frame_state_before_);
426 AstGraphBuilder* builder_;
427 Node* frame_state_before_;
431 AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info,
432 JSGraph* jsgraph, LoopAssignmentAnalysis* loop,
433 JSTypeFeedbackTable* js_type_feedback)
434 : local_zone_(local_zone),
437 environment_(nullptr),
438 ast_context_(nullptr),
439 globals_(0, local_zone),
440 execution_control_(nullptr),
441 execution_context_(nullptr),
442 try_catch_nesting_level_(0),
443 try_nesting_level_(0),
444 input_buffer_size_(0),
445 input_buffer_(nullptr),
446 exit_controls_(local_zone),
447 loop_assignment_analysis_(loop),
448 state_values_cache_(jsgraph),
449 liveness_analyzer_(static_cast<size_t>(info->scope()->num_stack_slots()),
451 frame_state_function_info_(common()->CreateFrameStateFunctionInfo(
452 FrameStateType::kJavaScriptFunction, info->num_parameters() + 1,
453 info->scope()->num_stack_slots(), info->shared_info(),
454 CALL_MAINTAINS_NATIVE_CONTEXT)),
455 js_type_feedback_(js_type_feedback) {
456 InitializeAstVisitor(info->isolate(), local_zone);
460 Node* AstGraphBuilder::GetFunctionClosureForContext() {
461 Scope* closure_scope = current_scope()->ClosureScope();
462 if (closure_scope->is_script_scope() ||
463 closure_scope->is_module_scope()) {
464 // Contexts nested in the native context have a canonical empty function as
465 // their closure, not the anonymous closure containing the global code.
466 // Pass a SMI sentinel and let the runtime look up the empty function.
467 return jsgraph()->SmiConstant(0);
469 DCHECK(closure_scope->is_function_scope());
470 return GetFunctionClosure();
475 Node* AstGraphBuilder::GetFunctionClosure() {
476 if (!function_closure_.is_set()) {
477 const Operator* op = common()->Parameter(
478 Linkage::kJSFunctionCallClosureParamIndex, "%closure");
479 Node* node = NewNode(op, graph()->start());
480 function_closure_.set(node);
482 return function_closure_.get();
486 Node* AstGraphBuilder::GetFunctionContext() {
487 if (!function_context_.is_set()) {
488 // Parameter (arity + 1) is special for the outer context of the function
489 const Operator* op = common()->Parameter(
490 info()->num_parameters_including_this(), "%context");
491 Node* node = NewNode(op, graph()->start());
492 function_context_.set(node);
494 return function_context_.get();
498 bool AstGraphBuilder::CreateGraph(bool stack_check) {
499 Scope* scope = info()->scope();
500 DCHECK(graph() != NULL);
502 // Set up the basic structure of the graph. Outputs for {Start} are the formal
503 // parameters (including the receiver) plus context and closure.
504 int actual_parameter_count = info()->num_parameters_including_this() + 2;
505 graph()->SetStart(graph()->NewNode(common()->Start(actual_parameter_count)));
507 // Initialize the top-level environment.
508 Environment env(this, scope, graph()->start());
509 set_environment(&env);
511 if (info()->is_osr()) {
512 // Use OSR normal entry as the start of the top-level environment.
513 // It will be replaced with {Dead} after typing and optimizations.
514 NewNode(common()->OsrNormalEntry());
517 // Initialize the incoming context.
518 ContextScope incoming(this, scope, GetFunctionContext());
520 // Initialize control scope.
521 ControlScope control(this);
523 // TODO(mstarzinger): For now we cannot assume that the {this} parameter is
524 // not {the_hole}, because for derived classes {this} has a TDZ and the
525 // JSConstructStubForDerived magically passes {the_hole} as a receiver.
526 if (scope->has_this_declaration() && scope->receiver()->is_const_mode()) {
527 env.RawParameterBind(0, jsgraph()->TheHoleConstant());
530 // Build receiver check for sloppy mode if necessary.
531 // TODO(mstarzinger/verwaest): Should this be moved back into the CallIC?
532 if (scope->has_this_declaration()) {
533 Node* original_receiver = env.RawParameterLookup(0);
534 Node* patched_receiver = BuildPatchReceiverToGlobalProxy(original_receiver);
535 env.RawParameterBind(0, patched_receiver);
538 // Build function context only if there are context allocated variables.
539 if (info()->num_heap_slots() > 0) {
540 // Push a new inner context scope for the function.
541 Node* inner_context = BuildLocalFunctionContext(GetFunctionContext());
542 ContextScope top_context(this, scope, inner_context);
543 CreateGraphBody(stack_check);
545 // Simply use the outer function context in building the graph.
546 CreateGraphBody(stack_check);
549 // Finish the basic structure of the graph.
550 DCHECK_NE(0u, exit_controls_.size());
551 int const input_count = static_cast<int>(exit_controls_.size());
552 Node** const inputs = &exit_controls_.front();
553 Node* end = graph()->NewNode(common()->End(input_count), input_count, inputs);
554 graph()->SetEnd(end);
556 // Compute local variable liveness information and use it to relax
558 ClearNonLiveSlotsInFrameStates();
560 // Failures indicated by stack overflow.
561 return !HasStackOverflow();
565 void AstGraphBuilder::CreateGraphBody(bool stack_check) {
566 Scope* scope = info()->scope();
568 // Build the arguments object if it is used.
569 BuildArgumentsObject(scope->arguments());
571 // Build rest arguments array if it is used.
573 Variable* rest_parameter = scope->rest_parameter(&rest_index);
574 BuildRestArgumentsArray(rest_parameter, rest_index);
576 // Build assignment to {.this_function} variable if it is used.
577 BuildThisFunctionVariable(scope->this_function_var());
579 // Build assignment to {new.target} variable if it is used.
580 BuildNewTargetVariable(scope->new_target_var());
582 // Emit tracing call if requested to do so.
584 NewNode(javascript()->CallRuntime(Runtime::kTraceEnter, 0));
587 // Visit illegal re-declaration and bail out if it exists.
588 if (scope->HasIllegalRedeclaration()) {
589 AstEffectContext for_effect(this);
590 scope->VisitIllegalRedeclaration(this);
594 // Visit declarations within the function scope.
595 VisitDeclarations(scope->declarations());
597 // Build a stack-check before the body.
599 Node* node = NewNode(javascript()->StackCheck());
600 PrepareFrameState(node, BailoutId::FunctionEntry());
603 // Visit statements in the function body.
604 VisitStatements(info()->function()->body());
606 // Emit tracing call if requested to do so.
608 // TODO(mstarzinger): Only traces implicit return.
609 Node* return_value = jsgraph()->UndefinedConstant();
610 NewNode(javascript()->CallRuntime(Runtime::kTraceExit, 1), return_value);
613 // Return 'undefined' in case we can fall off the end.
614 BuildReturn(jsgraph()->UndefinedConstant());
618 void AstGraphBuilder::ClearNonLiveSlotsInFrameStates() {
619 if (!FLAG_analyze_environment_liveness ||
620 !info()->is_deoptimization_enabled()) {
624 NonLiveFrameStateSlotReplacer replacer(
625 &state_values_cache_, jsgraph()->UndefinedConstant(),
626 liveness_analyzer()->local_count(), local_zone());
627 Variable* arguments = info()->scope()->arguments();
628 if (arguments != nullptr && arguments->IsStackAllocated()) {
629 replacer.MarkPermanentlyLive(arguments->index());
631 liveness_analyzer()->Run(&replacer);
632 if (FLAG_trace_environment_liveness) {
634 liveness_analyzer()->Print(os);
639 // Gets the bailout id just before reading a variable proxy, but only for
640 // unallocated variables.
641 static BailoutId BeforeId(VariableProxy* proxy) {
642 return proxy->var()->IsUnallocatedOrGlobalSlot() ? proxy->BeforeId()
647 static const char* GetDebugParameterName(Zone* zone, Scope* scope, int index) {
649 const AstRawString* name = scope->parameter(index)->raw_name();
650 if (name && name->length() > 0) {
651 char* data = zone->NewArray<char>(name->length() + 1);
652 data[name->length()] = 0;
653 memcpy(data, name->raw_data(), name->length());
661 AstGraphBuilder::Environment::Environment(AstGraphBuilder* builder,
663 Node* control_dependency)
665 parameters_count_(scope->num_parameters() + 1),
666 locals_count_(scope->num_stack_slots()),
667 liveness_block_(IsLivenessAnalysisEnabled()
668 ? builder_->liveness_analyzer()->NewBlock()
670 values_(builder_->local_zone()),
671 contexts_(builder_->local_zone()),
672 control_dependency_(control_dependency),
673 effect_dependency_(control_dependency),
674 parameters_node_(nullptr),
675 locals_node_(nullptr),
676 stack_node_(nullptr) {
677 DCHECK_EQ(scope->num_parameters() + 1, parameters_count());
679 // Bind the receiver variable.
681 if (builder->info()->is_this_defined()) {
682 const Operator* op = common()->Parameter(param_num++, "%this");
683 Node* receiver = builder->graph()->NewNode(op, builder->graph()->start());
684 values()->push_back(receiver);
686 values()->push_back(builder->jsgraph()->UndefinedConstant());
689 // Bind all parameter variables. The parameter indices are shifted by 1
690 // (receiver is parameter index -1 but environment index 0).
691 for (int i = 0; i < scope->num_parameters(); ++i) {
692 const char* debug_name = GetDebugParameterName(graph()->zone(), scope, i);
693 const Operator* op = common()->Parameter(param_num++, debug_name);
694 Node* parameter = builder->graph()->NewNode(op, builder->graph()->start());
695 values()->push_back(parameter);
698 // Bind all local variables to undefined.
699 Node* undefined_constant = builder->jsgraph()->UndefinedConstant();
700 values()->insert(values()->end(), locals_count(), undefined_constant);
704 AstGraphBuilder::Environment::Environment(AstGraphBuilder::Environment* copy,
705 LivenessAnalyzerBlock* liveness_block)
706 : builder_(copy->builder_),
707 parameters_count_(copy->parameters_count_),
708 locals_count_(copy->locals_count_),
709 liveness_block_(liveness_block),
710 values_(copy->zone()),
711 contexts_(copy->zone()),
712 control_dependency_(copy->control_dependency_),
713 effect_dependency_(copy->effect_dependency_),
714 parameters_node_(copy->parameters_node_),
715 locals_node_(copy->locals_node_),
716 stack_node_(copy->stack_node_) {
717 const size_t kStackEstimate = 7; // optimum from experimentation!
718 values_.reserve(copy->values_.size() + kStackEstimate);
719 values_.insert(values_.begin(), copy->values_.begin(), copy->values_.end());
720 contexts_.reserve(copy->contexts_.size());
721 contexts_.insert(contexts_.begin(), copy->contexts_.begin(),
722 copy->contexts_.end());
726 void AstGraphBuilder::Environment::Bind(Variable* variable, Node* node) {
727 DCHECK(variable->IsStackAllocated());
728 if (variable->IsParameter()) {
729 // The parameter indices are shifted by 1 (receiver is parameter
730 // index -1 but environment index 0).
731 values()->at(variable->index() + 1) = node;
733 DCHECK(variable->IsStackLocal());
734 values()->at(variable->index() + parameters_count_) = node;
735 DCHECK(IsLivenessBlockConsistent());
736 if (liveness_block() != nullptr) {
737 liveness_block()->Bind(variable->index());
743 Node* AstGraphBuilder::Environment::Lookup(Variable* variable) {
744 DCHECK(variable->IsStackAllocated());
745 if (variable->IsParameter()) {
746 // The parameter indices are shifted by 1 (receiver is parameter
747 // index -1 but environment index 0).
748 return values()->at(variable->index() + 1);
750 DCHECK(variable->IsStackLocal());
751 DCHECK(IsLivenessBlockConsistent());
752 if (liveness_block() != nullptr) {
753 liveness_block()->Lookup(variable->index());
755 return values()->at(variable->index() + parameters_count_);
760 void AstGraphBuilder::Environment::MarkAllLocalsLive() {
761 DCHECK(IsLivenessBlockConsistent());
762 if (liveness_block() != nullptr) {
763 for (int i = 0; i < locals_count_; i++) {
764 liveness_block()->Lookup(i);
770 void AstGraphBuilder::Environment::RawParameterBind(int index, Node* node) {
771 DCHECK_LT(index, parameters_count());
772 values()->at(index) = node;
776 Node* AstGraphBuilder::Environment::RawParameterLookup(int index) {
777 DCHECK_LT(index, parameters_count());
778 return values()->at(index);
782 AstGraphBuilder::Environment*
783 AstGraphBuilder::Environment::CopyForConditional() {
784 LivenessAnalyzerBlock* copy_liveness_block = nullptr;
785 if (liveness_block() != nullptr) {
786 copy_liveness_block =
787 builder_->liveness_analyzer()->NewBlock(liveness_block());
788 liveness_block_ = builder_->liveness_analyzer()->NewBlock(liveness_block());
790 return new (zone()) Environment(this, copy_liveness_block);
794 AstGraphBuilder::Environment*
795 AstGraphBuilder::Environment::CopyAsUnreachable() {
796 Environment* env = new (zone()) Environment(this, nullptr);
797 env->MarkAsUnreachable();
802 AstGraphBuilder::Environment*
803 AstGraphBuilder::Environment::CopyAndShareLiveness() {
804 if (liveness_block() != nullptr) {
805 // Finish the current liveness block before copying.
806 liveness_block_ = builder_->liveness_analyzer()->NewBlock(liveness_block());
808 Environment* env = new (zone()) Environment(this, liveness_block());
813 AstGraphBuilder::Environment* AstGraphBuilder::Environment::CopyForLoop(
814 BitVector* assigned, bool is_osr) {
815 PrepareForLoop(assigned, is_osr);
816 return CopyAndShareLiveness();
820 void AstGraphBuilder::Environment::UpdateStateValues(Node** state_values,
821 int offset, int count) {
822 bool should_update = false;
823 Node** env_values = (count == 0) ? nullptr : &values()->at(offset);
824 if (*state_values == NULL || (*state_values)->InputCount() != count) {
825 should_update = true;
827 DCHECK(static_cast<size_t>(offset + count) <= values()->size());
828 for (int i = 0; i < count; i++) {
829 if ((*state_values)->InputAt(i) != env_values[i]) {
830 should_update = true;
836 const Operator* op = common()->StateValues(count);
837 (*state_values) = graph()->NewNode(op, count, env_values);
842 void AstGraphBuilder::Environment::UpdateStateValuesWithCache(
843 Node** state_values, int offset, int count) {
844 Node** env_values = (count == 0) ? nullptr : &values()->at(offset);
845 *state_values = builder_->state_values_cache_.GetNodeForValues(
846 env_values, static_cast<size_t>(count));
850 Node* AstGraphBuilder::Environment::Checkpoint(
851 BailoutId ast_id, OutputFrameStateCombine combine) {
852 if (!builder()->info()->is_deoptimization_enabled()) {
853 return builder()->jsgraph()->EmptyFrameState();
856 UpdateStateValues(¶meters_node_, 0, parameters_count());
857 UpdateStateValuesWithCache(&locals_node_, parameters_count(), locals_count());
858 UpdateStateValues(&stack_node_, parameters_count() + locals_count(),
861 const Operator* op = common()->FrameState(
862 ast_id, combine, builder()->frame_state_function_info());
864 Node* result = graph()->NewNode(op, parameters_node_, locals_node_,
865 stack_node_, builder()->current_context(),
866 builder()->GetFunctionClosure(),
867 builder()->graph()->start());
869 DCHECK(IsLivenessBlockConsistent());
870 if (liveness_block() != nullptr) {
871 liveness_block()->Checkpoint(result);
877 bool AstGraphBuilder::Environment::IsLivenessAnalysisEnabled() {
878 return FLAG_analyze_environment_liveness &&
879 builder()->info()->is_deoptimization_enabled();
883 bool AstGraphBuilder::Environment::IsLivenessBlockConsistent() {
884 return (!IsLivenessAnalysisEnabled() || IsMarkedAsUnreachable()) ==
885 (liveness_block() == nullptr);
889 AstGraphBuilder::AstContext::AstContext(AstGraphBuilder* own,
890 Expression::Context kind)
891 : kind_(kind), owner_(own), outer_(own->ast_context()) {
892 owner()->set_ast_context(this); // Push.
894 original_height_ = environment()->stack_height();
899 AstGraphBuilder::AstContext::~AstContext() {
900 owner()->set_ast_context(outer_); // Pop.
904 AstGraphBuilder::AstEffectContext::~AstEffectContext() {
905 DCHECK(environment()->stack_height() == original_height_);
909 AstGraphBuilder::AstValueContext::~AstValueContext() {
910 DCHECK(environment()->stack_height() == original_height_ + 1);
914 AstGraphBuilder::AstTestContext::~AstTestContext() {
915 DCHECK(environment()->stack_height() == original_height_ + 1);
919 void AstGraphBuilder::AstEffectContext::ProduceValue(Node* value) {
920 // The value is ignored.
924 void AstGraphBuilder::AstValueContext::ProduceValue(Node* value) {
925 environment()->Push(value);
929 void AstGraphBuilder::AstTestContext::ProduceValue(Node* value) {
930 environment()->Push(owner()->BuildToBoolean(value));
934 Node* AstGraphBuilder::AstEffectContext::ConsumeValue() { return NULL; }
937 Node* AstGraphBuilder::AstValueContext::ConsumeValue() {
938 return environment()->Pop();
942 Node* AstGraphBuilder::AstTestContext::ConsumeValue() {
943 return environment()->Pop();
947 Scope* AstGraphBuilder::current_scope() const {
948 return execution_context_->scope();
952 Node* AstGraphBuilder::current_context() const {
953 return environment()->Context();
957 void AstGraphBuilder::ControlScope::PerformCommand(Command command,
960 Environment* env = environment()->CopyAsUnreachable();
961 ControlScope* current = this;
962 while (current != NULL) {
963 environment()->TrimStack(current->stack_height());
964 environment()->TrimContextChain(current->context_length());
965 if (current->Execute(command, target, value)) break;
966 current = current->outer_;
968 builder()->set_environment(env);
969 DCHECK(current != NULL); // Always handled (unless stack is malformed).
973 void AstGraphBuilder::ControlScope::BreakTo(BreakableStatement* stmt) {
974 PerformCommand(CMD_BREAK, stmt, builder()->jsgraph()->TheHoleConstant());
978 void AstGraphBuilder::ControlScope::ContinueTo(BreakableStatement* stmt) {
979 PerformCommand(CMD_CONTINUE, stmt, builder()->jsgraph()->TheHoleConstant());
983 void AstGraphBuilder::ControlScope::ReturnValue(Node* return_value) {
984 PerformCommand(CMD_RETURN, nullptr, return_value);
988 void AstGraphBuilder::ControlScope::ThrowValue(Node* exception_value) {
989 PerformCommand(CMD_THROW, nullptr, exception_value);
993 void AstGraphBuilder::VisitForValueOrNull(Expression* expr) {
995 return environment()->Push(jsgraph()->NullConstant());
1001 void AstGraphBuilder::VisitForValueOrTheHole(Expression* expr) {
1003 return environment()->Push(jsgraph()->TheHoleConstant());
1005 VisitForValue(expr);
1009 void AstGraphBuilder::VisitForValues(ZoneList<Expression*>* exprs) {
1010 for (int i = 0; i < exprs->length(); ++i) {
1011 VisitForValue(exprs->at(i));
1016 void AstGraphBuilder::VisitForValue(Expression* expr) {
1017 AstValueContext for_value(this);
1018 if (!CheckStackOverflow()) {
1021 ast_context()->ProduceValue(jsgraph()->UndefinedConstant());
1026 void AstGraphBuilder::VisitForEffect(Expression* expr) {
1027 AstEffectContext for_effect(this);
1028 if (!CheckStackOverflow()) {
1031 ast_context()->ProduceValue(jsgraph()->UndefinedConstant());
1036 void AstGraphBuilder::VisitForTest(Expression* expr) {
1037 AstTestContext for_condition(this);
1038 if (!CheckStackOverflow()) {
1041 ast_context()->ProduceValue(jsgraph()->UndefinedConstant());
1046 void AstGraphBuilder::Visit(Expression* expr) {
1047 // Reuses enclosing AstContext.
1048 if (!CheckStackOverflow()) {
1051 ast_context()->ProduceValue(jsgraph()->UndefinedConstant());
1056 void AstGraphBuilder::VisitVariableDeclaration(VariableDeclaration* decl) {
1057 Variable* variable = decl->proxy()->var();
1058 VariableMode mode = decl->mode();
1059 bool hole_init = mode == CONST || mode == CONST_LEGACY || mode == LET;
1060 switch (variable->location()) {
1061 case VariableLocation::GLOBAL:
1062 case VariableLocation::UNALLOCATED: {
1063 Handle<Oddball> value = variable->binding_needs_init()
1064 ? isolate()->factory()->the_hole_value()
1065 : isolate()->factory()->undefined_value();
1066 globals()->push_back(variable->name());
1067 globals()->push_back(value);
1070 case VariableLocation::PARAMETER:
1071 case VariableLocation::LOCAL:
1073 Node* value = jsgraph()->TheHoleConstant();
1074 environment()->Bind(variable, value);
1077 case VariableLocation::CONTEXT:
1079 Node* value = jsgraph()->TheHoleConstant();
1080 const Operator* op = javascript()->StoreContext(0, variable->index());
1081 NewNode(op, current_context(), value);
1084 case VariableLocation::LOOKUP:
1090 void AstGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* decl) {
1091 Variable* variable = decl->proxy()->var();
1092 switch (variable->location()) {
1093 case VariableLocation::GLOBAL:
1094 case VariableLocation::UNALLOCATED: {
1095 Handle<SharedFunctionInfo> function = Compiler::GetSharedFunctionInfo(
1096 decl->fun(), info()->script(), info());
1097 // Check for stack-overflow exception.
1098 if (function.is_null()) return SetStackOverflow();
1099 globals()->push_back(variable->name());
1100 globals()->push_back(function);
1103 case VariableLocation::PARAMETER:
1104 case VariableLocation::LOCAL: {
1105 VisitForValue(decl->fun());
1106 Node* value = environment()->Pop();
1107 environment()->Bind(variable, value);
1110 case VariableLocation::CONTEXT: {
1111 VisitForValue(decl->fun());
1112 Node* value = environment()->Pop();
1113 const Operator* op = javascript()->StoreContext(0, variable->index());
1114 NewNode(op, current_context(), value);
1117 case VariableLocation::LOOKUP:
1123 void AstGraphBuilder::VisitImportDeclaration(ImportDeclaration* decl) {
1128 void AstGraphBuilder::VisitExportDeclaration(ExportDeclaration* decl) {
1133 void AstGraphBuilder::VisitBlock(Block* stmt) {
1134 BlockBuilder block(this);
1135 ControlScopeForBreakable scope(this, stmt, &block);
1136 if (stmt->labels() != NULL) block.BeginBlock();
1137 if (stmt->scope() == NULL) {
1138 // Visit statements in the same scope, no declarations.
1139 VisitStatements(stmt->statements());
1141 // Visit declarations and statements in a block scope.
1142 if (stmt->scope()->ContextLocalCount() > 0) {
1143 Node* context = BuildLocalBlockContext(stmt->scope());
1144 ContextScope scope(this, stmt->scope(), context);
1145 VisitDeclarations(stmt->scope()->declarations());
1146 VisitStatements(stmt->statements());
1148 VisitDeclarations(stmt->scope()->declarations());
1149 VisitStatements(stmt->statements());
1152 if (stmt->labels() != NULL) block.EndBlock();
1156 void AstGraphBuilder::VisitExpressionStatement(ExpressionStatement* stmt) {
1157 VisitForEffect(stmt->expression());
1161 void AstGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) {
1166 void AstGraphBuilder::VisitIfStatement(IfStatement* stmt) {
1167 IfBuilder compare_if(this);
1168 VisitForTest(stmt->condition());
1169 Node* condition = environment()->Pop();
1170 compare_if.If(condition);
1172 Visit(stmt->then_statement());
1174 Visit(stmt->else_statement());
1179 void AstGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) {
1180 execution_control()->ContinueTo(stmt->target());
1184 void AstGraphBuilder::VisitBreakStatement(BreakStatement* stmt) {
1185 execution_control()->BreakTo(stmt->target());
1189 void AstGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
1190 VisitForValue(stmt->expression());
1191 Node* result = environment()->Pop();
1192 execution_control()->ReturnValue(result);
1196 void AstGraphBuilder::VisitWithStatement(WithStatement* stmt) {
1197 VisitForValue(stmt->expression());
1198 Node* value = environment()->Pop();
1199 const Operator* op = javascript()->CreateWithContext();
1200 Node* context = NewNode(op, value, GetFunctionClosureForContext());
1201 PrepareFrameState(context, stmt->EntryId());
1202 VisitInScope(stmt->statement(), stmt->scope(), context);
1206 void AstGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
1207 ZoneList<CaseClause*>* clauses = stmt->cases();
1208 SwitchBuilder compare_switch(this, clauses->length());
1209 ControlScopeForBreakable scope(this, stmt, &compare_switch);
1210 compare_switch.BeginSwitch();
1211 int default_index = -1;
1213 // Keep the switch value on the stack until a case matches.
1214 VisitForValue(stmt->tag());
1215 Node* tag = environment()->Top();
1217 // Iterate over all cases and create nodes for label comparison.
1218 for (int i = 0; i < clauses->length(); i++) {
1219 CaseClause* clause = clauses->at(i);
1221 // The default is not a test, remember index.
1222 if (clause->is_default()) {
1227 // Create nodes to perform label comparison as if via '==='. The switch
1228 // value is still on the operand stack while the label is evaluated.
1229 VisitForValue(clause->label());
1230 Node* label = environment()->Pop();
1231 const Operator* op = javascript()->StrictEqual();
1232 Node* condition = NewNode(op, tag, label);
1233 compare_switch.BeginLabel(i, condition);
1235 // Discard the switch value at label match.
1236 environment()->Pop();
1237 compare_switch.EndLabel();
1240 // Discard the switch value and mark the default case.
1241 environment()->Pop();
1242 if (default_index >= 0) {
1243 compare_switch.DefaultAt(default_index);
1246 // Iterate over all cases and create nodes for case bodies.
1247 for (int i = 0; i < clauses->length(); i++) {
1248 CaseClause* clause = clauses->at(i);
1249 compare_switch.BeginCase(i);
1250 VisitStatements(clause->statements());
1251 compare_switch.EndCase();
1254 compare_switch.EndSwitch();
1258 void AstGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) {
1259 LoopBuilder while_loop(this);
1260 while_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt));
1261 VisitIterationBody(stmt, &while_loop);
1262 while_loop.EndBody();
1263 VisitForTest(stmt->cond());
1264 Node* condition = environment()->Pop();
1265 while_loop.BreakUnless(condition);
1266 while_loop.EndLoop();
1270 void AstGraphBuilder::VisitWhileStatement(WhileStatement* stmt) {
1271 LoopBuilder while_loop(this);
1272 while_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt));
1273 VisitForTest(stmt->cond());
1274 Node* condition = environment()->Pop();
1275 while_loop.BreakUnless(condition);
1276 VisitIterationBody(stmt, &while_loop);
1277 while_loop.EndBody();
1278 while_loop.EndLoop();
1282 void AstGraphBuilder::VisitForStatement(ForStatement* stmt) {
1283 LoopBuilder for_loop(this);
1284 VisitIfNotNull(stmt->init());
1285 for_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt));
1286 if (stmt->cond() != NULL) {
1287 VisitForTest(stmt->cond());
1288 Node* condition = environment()->Pop();
1289 for_loop.BreakUnless(condition);
1291 for_loop.BreakUnless(jsgraph()->TrueConstant());
1293 VisitIterationBody(stmt, &for_loop);
1295 VisitIfNotNull(stmt->next());
1300 void AstGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
1301 VisitForValue(stmt->subject());
1302 Node* object = environment()->Pop();
1303 BlockBuilder for_block(this);
1304 for_block.BeginBlock();
1305 // Check for null or undefined before entering loop.
1306 Node* is_null_cond =
1307 NewNode(javascript()->StrictEqual(), object, jsgraph()->NullConstant());
1308 for_block.BreakWhen(is_null_cond, BranchHint::kFalse);
1309 Node* is_undefined_cond = NewNode(javascript()->StrictEqual(), object,
1310 jsgraph()->UndefinedConstant());
1311 for_block.BreakWhen(is_undefined_cond, BranchHint::kFalse);
1313 // Convert object to jsobject.
1314 object = BuildToObject(object, stmt->ToObjectId());
1315 environment()->Push(object);
1317 // Prepare for-in cache.
1318 Node* prepare = NewNode(javascript()->ForInPrepare(), object);
1319 PrepareFrameState(prepare, stmt->EnumId(), OutputFrameStateCombine::Push());
1320 Node* cache_type = NewNode(common()->Projection(0), prepare);
1321 Node* cache_array = NewNode(common()->Projection(1), prepare);
1322 Node* cache_length = NewNode(common()->Projection(2), prepare);
1324 // Construct the rest of the environment.
1325 environment()->Push(cache_type);
1326 environment()->Push(cache_array);
1327 environment()->Push(cache_length);
1328 environment()->Push(jsgraph()->ZeroConstant());
1330 // Build the actual loop body.
1331 LoopBuilder for_loop(this);
1332 for_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt));
1334 // These stack values are renamed in the case of OSR, so reload them
1335 // from the environment.
1336 Node* index = environment()->Peek(0);
1337 Node* cache_length = environment()->Peek(1);
1338 Node* cache_array = environment()->Peek(2);
1339 Node* cache_type = environment()->Peek(3);
1340 Node* object = environment()->Peek(4);
1342 // Check loop termination condition.
1343 Node* exit_cond = NewNode(javascript()->ForInDone(), index, cache_length);
1344 for_loop.BreakWhen(exit_cond);
1346 // Compute the next enumerated value.
1347 Node* value = NewNode(javascript()->ForInNext(), object, cache_array,
1349 PrepareFrameState(value, stmt->FilterId(),
1350 OutputFrameStateCombine::Push());
1351 IfBuilder test_value(this);
1352 Node* test_value_cond = NewNode(javascript()->StrictEqual(), value,
1353 jsgraph()->UndefinedConstant());
1354 test_value.If(test_value_cond, BranchHint::kFalse);
1358 // Bind value and do loop body.
1359 VectorSlotPair feedback =
1360 CreateVectorSlotPair(stmt->EachFeedbackSlot());
1361 VisitForInAssignment(stmt->each(), value, feedback,
1362 stmt->AssignmentId());
1363 VisitIterationBody(stmt, &for_loop);
1366 index = environment()->Peek(0);
1369 // Increment counter and continue.
1370 index = NewNode(javascript()->ForInStep(), index);
1371 environment()->Poke(0, index);
1374 environment()->Drop(5);
1376 for_block.EndBlock();
1380 void AstGraphBuilder::VisitForOfStatement(ForOfStatement* stmt) {
1381 LoopBuilder for_loop(this);
1382 VisitForEffect(stmt->assign_iterator());
1383 for_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt));
1384 VisitForEffect(stmt->next_result());
1385 VisitForTest(stmt->result_done());
1386 Node* condition = environment()->Pop();
1387 for_loop.BreakWhen(condition);
1388 VisitForEffect(stmt->assign_each());
1389 VisitIterationBody(stmt, &for_loop);
1395 void AstGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) {
1396 TryCatchBuilder try_control(this);
1397 ExternalReference message_object =
1398 ExternalReference::address_of_pending_message_obj(isolate());
1400 // Evaluate the try-block inside a control scope. This simulates a handler
1401 // that is intercepting 'throw' control commands.
1402 try_control.BeginTry();
1404 ControlScopeForCatch scope(this, &try_control);
1405 STATIC_ASSERT(TryBlockConstant::kElementCount == 1);
1406 environment()->Push(current_context());
1407 Visit(stmt->try_block());
1408 environment()->Pop();
1410 try_control.EndTry();
1412 // TODO(mstarzinger): We are only using a runtime call to get a lazy bailout
1413 // point, there is no need to really emit an actual call. Optimize this!
1414 Node* guard = NewNode(javascript()->CallRuntime(Runtime::kMaxSmi, 0));
1415 PrepareFrameState(guard, stmt->HandlerId());
1417 // Clear message object as we enter the catch block.
1418 Node* the_hole = jsgraph()->TheHoleConstant();
1419 BuildStoreExternal(message_object, kMachAnyTagged, the_hole);
1421 // Create a catch scope that binds the exception.
1422 Node* exception = try_control.GetExceptionNode();
1423 Unique<String> name = MakeUnique(stmt->variable()->name());
1424 const Operator* op = javascript()->CreateCatchContext(name);
1425 Node* context = NewNode(op, exception, GetFunctionClosureForContext());
1427 // Evaluate the catch-block.
1428 VisitInScope(stmt->catch_block(), stmt->scope(), context);
1429 try_control.EndCatch();
1431 // TODO(mstarzinger): Remove bailout once everything works.
1432 if (!FLAG_turbo_try_catch) SetStackOverflow();
1436 void AstGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
1437 TryFinallyBuilder try_control(this);
1438 ExternalReference message_object =
1439 ExternalReference::address_of_pending_message_obj(isolate());
1441 // We keep a record of all paths that enter the finally-block to be able to
1442 // dispatch to the correct continuation point after the statements in the
1443 // finally-block have been evaluated.
1445 // The try-finally construct can enter the finally-block in three ways:
1446 // 1. By exiting the try-block normally, falling through at the end.
1447 // 2. By exiting the try-block with a function-local control flow transfer
1448 // (i.e. through break/continue/return statements).
1449 // 3. By exiting the try-block with a thrown exception.
1450 Node* fallthrough_result = jsgraph()->TheHoleConstant();
1451 ControlScope::DeferredCommands* commands =
1452 new (zone()) ControlScope::DeferredCommands(this);
1454 // Evaluate the try-block inside a control scope. This simulates a handler
1455 // that is intercepting all control commands.
1456 try_control.BeginTry();
1458 ControlScopeForFinally scope(this, commands, &try_control);
1459 STATIC_ASSERT(TryBlockConstant::kElementCount == 1);
1460 environment()->Push(current_context());
1461 Visit(stmt->try_block());
1462 environment()->Pop();
1464 try_control.EndTry(commands->GetFallThroughToken(), fallthrough_result);
1466 // TODO(mstarzinger): We are only using a runtime call to get a lazy bailout
1467 // point, there is no need to really emit an actual call. Optimize this!
1468 Node* guard = NewNode(javascript()->CallRuntime(Runtime::kMaxSmi, 0));
1469 PrepareFrameState(guard, stmt->HandlerId());
1471 // The result value semantics depend on how the block was entered:
1472 // - ReturnStatement: It represents the return value being returned.
1473 // - ThrowStatement: It represents the exception being thrown.
1474 // - BreakStatement/ContinueStatement: Filled with the hole.
1475 // - Falling through into finally-block: Filled with the hole.
1476 Node* result = try_control.GetResultValueNode();
1477 Node* token = try_control.GetDispatchTokenNode();
1479 // The result value, dispatch token and message is expected on the operand
1480 // stack (this is in sync with FullCodeGenerator::EnterFinallyBlock).
1481 Node* message = BuildLoadExternal(message_object, kMachAnyTagged);
1482 environment()->Push(token); // TODO(mstarzinger): Cook token!
1483 environment()->Push(result);
1484 environment()->Push(message);
1486 // Clear message object as we enter the finally block.
1487 Node* the_hole = jsgraph()->TheHoleConstant();
1488 BuildStoreExternal(message_object, kMachAnyTagged, the_hole);
1490 // Evaluate the finally-block.
1491 Visit(stmt->finally_block());
1492 try_control.EndFinally();
1494 // The result value, dispatch token and message is restored from the operand
1495 // stack (this is in sync with FullCodeGenerator::ExitFinallyBlock).
1496 message = environment()->Pop();
1497 result = environment()->Pop();
1498 token = environment()->Pop(); // TODO(mstarzinger): Uncook token!
1499 BuildStoreExternal(message_object, kMachAnyTagged, message);
1501 // Dynamic dispatch after the finally-block.
1502 commands->ApplyDeferredCommands(token, result);
1504 // TODO(mstarzinger): Remove bailout once everything works.
1505 if (!FLAG_turbo_try_finally) SetStackOverflow();
1509 void AstGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) {
1511 NewNode(javascript()->CallRuntime(Runtime::kHandleDebuggerStatement, 0));
1512 PrepareFrameState(node, stmt->DebugBreakId());
1513 environment()->MarkAllLocalsLive();
1517 void AstGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
1518 Node* context = current_context();
1520 // Find or build a shared function info.
1521 Handle<SharedFunctionInfo> shared_info =
1522 Compiler::GetSharedFunctionInfo(expr, info()->script(), info());
1523 CHECK(!shared_info.is_null()); // TODO(mstarzinger): Set stack overflow?
1525 // Create node to instantiate a new closure.
1526 PretenureFlag pretenure = expr->pretenure() ? TENURED : NOT_TENURED;
1527 const Operator* op = javascript()->CreateClosure(shared_info, pretenure);
1528 Node* value = NewNode(op, context);
1529 ast_context()->ProduceValue(value);
1533 void AstGraphBuilder::VisitClassLiteral(ClassLiteral* expr) {
1534 if (expr->scope() == NULL) {
1535 // Visit class literal in the same scope, no declarations.
1536 VisitClassLiteralContents(expr);
1538 // Visit declarations and class literal in a block scope.
1539 if (expr->scope()->ContextLocalCount() > 0) {
1540 Node* context = BuildLocalBlockContext(expr->scope());
1541 ContextScope scope(this, expr->scope(), context);
1542 VisitDeclarations(expr->scope()->declarations());
1543 VisitClassLiteralContents(expr);
1545 VisitDeclarations(expr->scope()->declarations());
1546 VisitClassLiteralContents(expr);
1552 void AstGraphBuilder::VisitClassLiteralContents(ClassLiteral* expr) {
1553 Node* class_name = expr->raw_name() ? jsgraph()->Constant(expr->name())
1554 : jsgraph()->UndefinedConstant();
1556 // The class name is expected on the operand stack.
1557 environment()->Push(class_name);
1558 VisitForValueOrTheHole(expr->extends());
1559 VisitForValue(expr->constructor());
1561 // Create node to instantiate a new class.
1562 Node* constructor = environment()->Pop();
1563 Node* extends = environment()->Pop();
1564 Node* name = environment()->Pop();
1565 Node* script = jsgraph()->Constant(info()->script());
1566 Node* start = jsgraph()->Constant(expr->start_position());
1567 Node* end = jsgraph()->Constant(expr->end_position());
1568 const Operator* opc = javascript()->CallRuntime(
1569 is_strong(language_mode()) ? Runtime::kDefineClassStrong
1570 : Runtime::kDefineClass,
1572 Node* literal = NewNode(opc, name, extends, constructor, script, start, end);
1573 PrepareFrameState(literal, expr->CreateLiteralId(),
1574 OutputFrameStateCombine::Push());
1576 // The prototype is ensured to exist by Runtime_DefineClass. No access check
1577 // is needed here since the constructor is created by the class literal.
1579 BuildLoadObjectField(literal, JSFunction::kPrototypeOrInitialMapOffset);
1581 // The class literal and the prototype are both expected on the operand stack
1582 // during evaluation of the method values.
1583 environment()->Push(literal);
1584 environment()->Push(proto);
1586 // Create nodes to store method values into the literal.
1587 int store_slot_index = 0;
1588 for (int i = 0; i < expr->properties()->length(); i++) {
1589 ObjectLiteral::Property* property = expr->properties()->at(i);
1590 environment()->Push(property->is_static() ? literal : proto);
1592 VisitForValue(property->key());
1593 Node* name = BuildToName(environment()->Pop(), expr->GetIdForProperty(i));
1594 environment()->Push(name);
1596 // The static prototype property is read only. We handle the non computed
1597 // property name case in the parser. Since this is the only case where we
1598 // need to check for an own read only property we special case this so we do
1599 // not need to do this for every property.
1600 if (property->is_static() && property->is_computed_name()) {
1601 Node* check = BuildThrowIfStaticPrototype(environment()->Pop(),
1602 expr->GetIdForProperty(i));
1603 environment()->Push(check);
1606 VisitForValue(property->value());
1607 Node* value = environment()->Pop();
1608 Node* key = environment()->Pop();
1609 Node* receiver = environment()->Pop();
1610 VectorSlotPair feedback = CreateVectorSlotPair(
1611 expr->SlotForHomeObject(property->value(), &store_slot_index));
1612 BuildSetHomeObject(value, receiver, property->value(), feedback);
1614 switch (property->kind()) {
1615 case ObjectLiteral::Property::CONSTANT:
1616 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1617 case ObjectLiteral::Property::PROTOTYPE:
1619 case ObjectLiteral::Property::COMPUTED: {
1620 const Operator* op =
1621 javascript()->CallRuntime(Runtime::kDefineClassMethod, 3);
1622 NewNode(op, receiver, key, value);
1625 case ObjectLiteral::Property::GETTER: {
1626 Node* attr = jsgraph()->Constant(DONT_ENUM);
1627 const Operator* op = javascript()->CallRuntime(
1628 Runtime::kDefineGetterPropertyUnchecked, 4);
1629 NewNode(op, receiver, key, value, attr);
1632 case ObjectLiteral::Property::SETTER: {
1633 Node* attr = jsgraph()->Constant(DONT_ENUM);
1634 const Operator* op = javascript()->CallRuntime(
1635 Runtime::kDefineSetterPropertyUnchecked, 4);
1636 NewNode(op, receiver, key, value, attr);
1642 // Transform both the class literal and the prototype to fast properties.
1643 const Operator* op = javascript()->CallRuntime(Runtime::kToFastProperties, 1);
1644 NewNode(op, environment()->Pop()); // prototype
1645 NewNode(op, environment()->Pop()); // literal
1646 if (is_strong(language_mode())) {
1647 // TODO(conradw): It would be more efficient to define the properties with
1648 // the right attributes the first time round.
1649 // Freeze the prototype.
1651 NewNode(javascript()->CallRuntime(Runtime::kObjectFreeze, 1), proto);
1652 // Freezing the prototype should never deopt.
1653 PrepareFrameState(proto, BailoutId::None());
1654 // Freeze the constructor.
1656 NewNode(javascript()->CallRuntime(Runtime::kObjectFreeze, 1), literal);
1657 // Freezing the constructor should never deopt.
1658 PrepareFrameState(literal, BailoutId::None());
1661 // Assign to class variable.
1662 if (expr->scope() != NULL) {
1663 DCHECK_NOT_NULL(expr->class_variable_proxy());
1664 Variable* var = expr->class_variable_proxy()->var();
1665 FrameStateBeforeAndAfter states(this, BailoutId::None());
1666 VectorSlotPair feedback =
1667 CreateVectorSlotPair(FLAG_vector_stores && var->IsUnallocated()
1668 ? expr->GetNthSlot(store_slot_index++)
1669 : FeedbackVectorICSlot::Invalid());
1670 BuildVariableAssignment(var, literal, Token::INIT_CONST, feedback,
1671 BailoutId::None(), states);
1673 ast_context()->ProduceValue(literal);
1677 void AstGraphBuilder::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
1682 void AstGraphBuilder::VisitConditional(Conditional* expr) {
1683 IfBuilder compare_if(this);
1684 VisitForTest(expr->condition());
1685 Node* condition = environment()->Pop();
1686 compare_if.If(condition);
1688 Visit(expr->then_expression());
1690 Visit(expr->else_expression());
1692 ast_context()->ReplaceValue();
1696 void AstGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
1697 VectorSlotPair pair = CreateVectorSlotPair(expr->VariableFeedbackSlot());
1698 FrameStateBeforeAndAfter states(this, BeforeId(expr));
1699 Node* value = BuildVariableLoad(expr->var(), expr->id(), states, pair,
1700 ast_context()->GetStateCombine());
1701 ast_context()->ProduceValue(value);
1705 void AstGraphBuilder::VisitLiteral(Literal* expr) {
1706 Node* value = jsgraph()->Constant(expr->value());
1707 ast_context()->ProduceValue(value);
1711 void AstGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) {
1712 Node* closure = GetFunctionClosure();
1714 // Create node to materialize a regular expression literal.
1715 Node* literals_array =
1716 BuildLoadObjectField(closure, JSFunction::kLiteralsOffset);
1717 Node* literal_index = jsgraph()->Constant(expr->literal_index());
1718 Node* pattern = jsgraph()->Constant(expr->pattern());
1719 Node* flags = jsgraph()->Constant(expr->flags());
1720 const Operator* op =
1721 javascript()->CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
1722 Node* literal = NewNode(op, literals_array, literal_index, pattern, flags);
1723 PrepareFrameState(literal, expr->id(), ast_context()->GetStateCombine());
1724 ast_context()->ProduceValue(literal);
1728 void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
1729 Node* closure = GetFunctionClosure();
1731 // Create node to deep-copy the literal boilerplate.
1732 Node* literals_array =
1733 BuildLoadObjectField(closure, JSFunction::kLiteralsOffset);
1734 Node* literal_index = jsgraph()->Constant(expr->literal_index());
1735 Node* constants = jsgraph()->Constant(expr->constant_properties());
1736 const Operator* op =
1737 javascript()->CreateLiteralObject(expr->ComputeFlags(true));
1738 Node* literal = NewNode(op, literals_array, literal_index, constants);
1739 PrepareFrameState(literal, expr->CreateLiteralId(),
1740 OutputFrameStateCombine::Push());
1742 // The object is expected on the operand stack during computation of the
1743 // property values and is the value of the entire expression.
1744 environment()->Push(literal);
1746 // Create nodes to store computed values into the literal.
1747 int property_index = 0;
1748 int store_slot_index = 0;
1749 AccessorTable accessor_table(zone());
1750 for (; property_index < expr->properties()->length(); property_index++) {
1751 ObjectLiteral::Property* property = expr->properties()->at(property_index);
1752 if (property->is_computed_name()) break;
1753 if (property->IsCompileTimeValue()) continue;
1755 Literal* key = property->key()->AsLiteral();
1756 switch (property->kind()) {
1757 case ObjectLiteral::Property::CONSTANT:
1759 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1760 DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value()));
1762 case ObjectLiteral::Property::COMPUTED: {
1763 // It is safe to use [[Put]] here because the boilerplate already
1764 // contains computed properties with an uninitialized value.
1765 if (key->value()->IsInternalizedString()) {
1766 if (property->emit_store()) {
1767 VisitForValue(property->value());
1768 FrameStateBeforeAndAfter states(this, property->value()->id());
1769 Node* value = environment()->Pop();
1770 Handle<Name> name = key->AsPropertyName();
1771 VectorSlotPair feedback =
1773 ? CreateVectorSlotPair(expr->GetNthSlot(store_slot_index++))
1775 Node* store = BuildNamedStore(literal, name, value, feedback,
1776 TypeFeedbackId::None());
1777 states.AddToNode(store, key->id(),
1778 OutputFrameStateCombine::Ignore());
1779 VectorSlotPair home_feedback = CreateVectorSlotPair(
1780 expr->SlotForHomeObject(property->value(), &store_slot_index));
1781 BuildSetHomeObject(value, literal, property->value(),
1784 VisitForEffect(property->value());
1788 environment()->Push(literal); // Duplicate receiver.
1789 VisitForValue(property->key());
1790 VisitForValue(property->value());
1791 Node* value = environment()->Pop();
1792 Node* key = environment()->Pop();
1793 Node* receiver = environment()->Pop();
1794 if (property->emit_store()) {
1795 Node* language = jsgraph()->Constant(SLOPPY);
1796 const Operator* op =
1797 javascript()->CallRuntime(Runtime::kSetProperty, 4);
1798 Node* set_property = NewNode(op, receiver, key, value, language);
1799 // SetProperty should not lazy deopt on an object literal.
1800 PrepareFrameState(set_property, BailoutId::None());
1801 VectorSlotPair home_feedback = CreateVectorSlotPair(
1802 expr->SlotForHomeObject(property->value(), &store_slot_index));
1803 BuildSetHomeObject(value, receiver, property->value(), home_feedback);
1807 case ObjectLiteral::Property::PROTOTYPE: {
1808 environment()->Push(literal); // Duplicate receiver.
1809 VisitForValue(property->value());
1810 Node* value = environment()->Pop();
1811 Node* receiver = environment()->Pop();
1812 DCHECK(property->emit_store());
1813 const Operator* op =
1814 javascript()->CallRuntime(Runtime::kInternalSetPrototype, 2);
1815 Node* set_prototype = NewNode(op, receiver, value);
1816 // SetPrototype should not lazy deopt on an object literal.
1817 PrepareFrameState(set_prototype, BailoutId::None());
1820 case ObjectLiteral::Property::GETTER:
1821 if (property->emit_store()) {
1822 accessor_table.lookup(key)->second->getter = property->value();
1825 case ObjectLiteral::Property::SETTER:
1826 if (property->emit_store()) {
1827 accessor_table.lookup(key)->second->setter = property->value();
1833 // Create nodes to define accessors, using only a single call to the runtime
1834 // for each pair of corresponding getters and setters.
1835 for (AccessorTable::Iterator it = accessor_table.begin();
1836 it != accessor_table.end(); ++it) {
1837 VisitForValue(it->first);
1838 VisitForValueOrNull(it->second->getter);
1839 VectorSlotPair feedback_getter = CreateVectorSlotPair(
1840 expr->SlotForHomeObject(it->second->getter, &store_slot_index));
1841 BuildSetHomeObject(environment()->Top(), literal, it->second->getter,
1843 VisitForValueOrNull(it->second->setter);
1844 VectorSlotPair feedback_setter = CreateVectorSlotPair(
1845 expr->SlotForHomeObject(it->second->setter, &store_slot_index));
1846 BuildSetHomeObject(environment()->Top(), literal, it->second->setter,
1848 Node* setter = environment()->Pop();
1849 Node* getter = environment()->Pop();
1850 Node* name = environment()->Pop();
1851 Node* attr = jsgraph()->Constant(NONE);
1852 const Operator* op =
1853 javascript()->CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
1854 Node* call = NewNode(op, literal, name, getter, setter, attr);
1855 // This should not lazy deopt on a new literal.
1856 PrepareFrameState(call, BailoutId::None());
1859 // Object literals have two parts. The "static" part on the left contains no
1860 // computed property names, and so we can compute its map ahead of time; see
1861 // Runtime_CreateObjectLiteralBoilerplate. The second "dynamic" part starts
1862 // with the first computed property name and continues with all properties to
1863 // its right. All the code from above initializes the static component of the
1864 // object literal, and arranges for the map of the result to reflect the
1865 // static order in which the keys appear. For the dynamic properties, we
1866 // compile them into a series of "SetOwnProperty" runtime calls. This will
1867 // preserve insertion order.
1868 for (; property_index < expr->properties()->length(); property_index++) {
1869 ObjectLiteral::Property* property = expr->properties()->at(property_index);
1871 if (property->kind() == ObjectLiteral::Property::PROTOTYPE) {
1872 environment()->Push(literal); // Duplicate receiver.
1873 VisitForValue(property->value());
1874 Node* value = environment()->Pop();
1875 Node* receiver = environment()->Pop();
1876 const Operator* op =
1877 javascript()->CallRuntime(Runtime::kInternalSetPrototype, 2);
1878 Node* call = NewNode(op, receiver, value);
1879 PrepareFrameState(call, BailoutId::None());
1883 environment()->Push(literal); // Duplicate receiver.
1884 VisitForValue(property->key());
1885 Node* name = BuildToName(environment()->Pop(),
1886 expr->GetIdForProperty(property_index));
1887 environment()->Push(name);
1888 VisitForValue(property->value());
1889 Node* value = environment()->Pop();
1890 Node* key = environment()->Pop();
1891 Node* receiver = environment()->Pop();
1892 VectorSlotPair feedback = CreateVectorSlotPair(
1893 expr->SlotForHomeObject(property->value(), &store_slot_index));
1894 BuildSetHomeObject(value, receiver, property->value(), feedback);
1895 switch (property->kind()) {
1896 case ObjectLiteral::Property::CONSTANT:
1897 case ObjectLiteral::Property::COMPUTED:
1898 case ObjectLiteral::Property::MATERIALIZED_LITERAL: {
1899 Node* attr = jsgraph()->Constant(NONE);
1900 const Operator* op =
1901 javascript()->CallRuntime(Runtime::kDefineDataPropertyUnchecked, 4);
1902 Node* call = NewNode(op, receiver, key, value, attr);
1903 PrepareFrameState(call, BailoutId::None());
1906 case ObjectLiteral::Property::PROTOTYPE:
1907 UNREACHABLE(); // Handled specially above.
1909 case ObjectLiteral::Property::GETTER: {
1910 Node* attr = jsgraph()->Constant(NONE);
1911 const Operator* op = javascript()->CallRuntime(
1912 Runtime::kDefineGetterPropertyUnchecked, 4);
1913 Node* call = NewNode(op, receiver, key, value, attr);
1914 PrepareFrameState(call, BailoutId::None());
1917 case ObjectLiteral::Property::SETTER: {
1918 Node* attr = jsgraph()->Constant(NONE);
1919 const Operator* op = javascript()->CallRuntime(
1920 Runtime::kDefineSetterPropertyUnchecked, 4);
1921 Node* call = NewNode(op, receiver, key, value, attr);
1922 PrepareFrameState(call, BailoutId::None());
1928 // Transform literals that contain functions to fast properties.
1929 if (expr->has_function()) {
1930 const Operator* op =
1931 javascript()->CallRuntime(Runtime::kToFastProperties, 1);
1932 NewNode(op, literal);
1935 // Verify that compilation exactly consumed the number of store ic slots that
1936 // the ObjectLiteral node had to offer.
1937 DCHECK(!FLAG_vector_stores || store_slot_index == expr->slot_count());
1939 ast_context()->ProduceValue(environment()->Pop());
1943 void AstGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
1944 Node* closure = GetFunctionClosure();
1946 // Create node to deep-copy the literal boilerplate.
1947 expr->BuildConstantElements(isolate());
1948 Node* literals_array =
1949 BuildLoadObjectField(closure, JSFunction::kLiteralsOffset);
1950 Node* literal_index = jsgraph()->Constant(expr->literal_index());
1951 Node* constants = jsgraph()->Constant(expr->constant_elements());
1952 const Operator* op =
1953 javascript()->CreateLiteralArray(expr->ComputeFlags(true));
1954 Node* literal = NewNode(op, literals_array, literal_index, constants);
1955 PrepareFrameState(literal, expr->CreateLiteralId(),
1956 OutputFrameStateCombine::Push());
1958 // The array and the literal index are both expected on the operand stack
1959 // during computation of the element values.
1960 environment()->Push(literal);
1961 environment()->Push(literal_index);
1963 // Create nodes to evaluate all the non-constant subexpressions and to store
1964 // them into the newly cloned array.
1965 int array_index = 0;
1966 for (; array_index < expr->values()->length(); array_index++) {
1967 Expression* subexpr = expr->values()->at(array_index);
1968 if (subexpr->IsSpread()) break;
1969 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
1971 VisitForValue(subexpr);
1973 FrameStateBeforeAndAfter states(this, subexpr->id());
1974 Node* value = environment()->Pop();
1975 Node* index = jsgraph()->Constant(array_index);
1976 // TODO(turbofan): More efficient code could be generated here. Consider
1977 // that the store will be generic because we don't have a feedback vector
1979 Node* store = BuildKeyedStore(literal, index, value, VectorSlotPair(),
1980 TypeFeedbackId::None());
1981 states.AddToNode(store, expr->GetIdForElement(array_index),
1982 OutputFrameStateCombine::Ignore());
1986 // In case the array literal contains spread expressions it has two parts. The
1987 // first part is the "static" array which has a literal index is handled
1988 // above. The second part is the part after the first spread expression
1989 // (inclusive) and these elements gets appended to the array. Note that the
1990 // number elements an iterable produces is unknown ahead of time.
1991 environment()->Pop(); // Array literal index.
1992 for (; array_index < expr->values()->length(); array_index++) {
1993 Expression* subexpr = expr->values()->at(array_index);
1994 Node* array = environment()->Pop();
1997 if (subexpr->IsSpread()) {
1998 VisitForValue(subexpr->AsSpread()->expression());
1999 Node* iterable = environment()->Pop();
2000 Node* builtins = BuildLoadBuiltinsObject();
2001 Node* function = BuildLoadObjectField(
2002 builtins, JSBuiltinsObject::OffsetOfFunctionWithId(
2003 Builtins::CONCAT_ITERABLE_TO_ARRAY));
2004 result = NewNode(javascript()->CallFunction(3, NO_CALL_FUNCTION_FLAGS,
2006 function, array, iterable);
2008 VisitForValue(subexpr);
2009 Node* value = environment()->Pop();
2010 const Operator* op =
2011 javascript()->CallRuntime(Runtime::kAppendElement, 2);
2012 result = NewNode(op, array, value);
2015 PrepareFrameState(result, expr->GetIdForElement(array_index));
2016 environment()->Push(result);
2019 ast_context()->ProduceValue(environment()->Pop());
2023 void AstGraphBuilder::VisitForInAssignment(Expression* expr, Node* value,
2024 const VectorSlotPair& feedback,
2025 BailoutId bailout_id) {
2026 DCHECK(expr->IsValidReferenceExpressionOrThis());
2028 // Left-hand side can only be a property, a global or a variable slot.
2029 Property* property = expr->AsProperty();
2030 LhsKind assign_type = Property::GetAssignType(property);
2032 // Evaluate LHS expression and store the value.
2033 switch (assign_type) {
2035 Variable* var = expr->AsVariableProxy()->var();
2036 FrameStateBeforeAndAfter states(this, BailoutId::None());
2037 BuildVariableAssignment(var, value, Token::ASSIGN, feedback, bailout_id,
2041 case NAMED_PROPERTY: {
2042 environment()->Push(value);
2043 VisitForValue(property->obj());
2044 FrameStateBeforeAndAfter states(this, property->obj()->id());
2045 Node* object = environment()->Pop();
2046 value = environment()->Pop();
2047 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
2048 Node* store = BuildNamedStore(object, name, value, feedback,
2049 TypeFeedbackId::None());
2050 states.AddToNode(store, bailout_id, OutputFrameStateCombine::Ignore());
2053 case KEYED_PROPERTY: {
2054 environment()->Push(value);
2055 VisitForValue(property->obj());
2056 VisitForValue(property->key());
2057 FrameStateBeforeAndAfter states(this, property->key()->id());
2058 Node* key = environment()->Pop();
2059 Node* object = environment()->Pop();
2060 value = environment()->Pop();
2062 BuildKeyedStore(object, key, value, feedback, TypeFeedbackId::None());
2063 states.AddToNode(store, bailout_id, OutputFrameStateCombine::Ignore());
2066 case NAMED_SUPER_PROPERTY: {
2067 environment()->Push(value);
2068 VisitForValue(property->obj()->AsSuperPropertyReference()->this_var());
2069 VisitForValue(property->obj()->AsSuperPropertyReference()->home_object());
2070 FrameStateBeforeAndAfter states(this, property->obj()->id());
2071 Node* home_object = environment()->Pop();
2072 Node* receiver = environment()->Pop();
2073 value = environment()->Pop();
2074 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
2075 Node* store = BuildNamedSuperStore(receiver, home_object, name, value,
2076 TypeFeedbackId::None());
2077 states.AddToNode(store, bailout_id, OutputFrameStateCombine::Ignore());
2080 case KEYED_SUPER_PROPERTY: {
2081 environment()->Push(value);
2082 VisitForValue(property->obj()->AsSuperPropertyReference()->this_var());
2083 VisitForValue(property->obj()->AsSuperPropertyReference()->home_object());
2084 VisitForValue(property->key());
2085 FrameStateBeforeAndAfter states(this, property->key()->id());
2086 Node* key = environment()->Pop();
2087 Node* home_object = environment()->Pop();
2088 Node* receiver = environment()->Pop();
2089 value = environment()->Pop();
2090 Node* store = BuildKeyedSuperStore(receiver, home_object, key, value,
2091 TypeFeedbackId::None());
2092 states.AddToNode(store, bailout_id, OutputFrameStateCombine::Ignore());
2099 void AstGraphBuilder::VisitAssignment(Assignment* expr) {
2100 DCHECK(expr->target()->IsValidReferenceExpressionOrThis());
2102 // Left-hand side can only be a property, a global or a variable slot.
2103 Property* property = expr->target()->AsProperty();
2104 LhsKind assign_type = Property::GetAssignType(property);
2105 bool needs_frame_state_before = true;
2107 // Evaluate LHS expression.
2108 switch (assign_type) {
2110 Variable* variable = expr->target()->AsVariableProxy()->var();
2111 if (variable->location() == VariableLocation::PARAMETER ||
2112 variable->location() == VariableLocation::LOCAL ||
2113 variable->location() == VariableLocation::CONTEXT) {
2114 needs_frame_state_before = false;
2118 case NAMED_PROPERTY:
2119 VisitForValue(property->obj());
2121 case KEYED_PROPERTY:
2122 VisitForValue(property->obj());
2123 VisitForValue(property->key());
2125 case NAMED_SUPER_PROPERTY:
2126 VisitForValue(property->obj()->AsSuperPropertyReference()->this_var());
2127 VisitForValue(property->obj()->AsSuperPropertyReference()->home_object());
2129 case KEYED_SUPER_PROPERTY:
2130 VisitForValue(property->obj()->AsSuperPropertyReference()->this_var());
2131 VisitForValue(property->obj()->AsSuperPropertyReference()->home_object());
2132 VisitForValue(property->key());
2136 BailoutId before_store_id = BailoutId::None();
2137 // Evaluate the value and potentially handle compound assignments by loading
2138 // the left-hand side value and performing a binary operation.
2139 if (expr->is_compound()) {
2140 Node* old_value = NULL;
2141 switch (assign_type) {
2143 VariableProxy* proxy = expr->target()->AsVariableProxy();
2144 VectorSlotPair pair =
2145 CreateVectorSlotPair(proxy->VariableFeedbackSlot());
2146 FrameStateBeforeAndAfter states(this, BeforeId(proxy));
2148 BuildVariableLoad(proxy->var(), expr->target()->id(), states, pair,
2149 OutputFrameStateCombine::Push());
2152 case NAMED_PROPERTY: {
2153 Node* object = environment()->Top();
2154 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
2155 VectorSlotPair pair =
2156 CreateVectorSlotPair(property->PropertyFeedbackSlot());
2157 FrameStateBeforeAndAfter states(this, property->obj()->id());
2158 old_value = BuildNamedLoad(object, name, pair);
2159 states.AddToNode(old_value, property->LoadId(),
2160 OutputFrameStateCombine::Push());
2163 case KEYED_PROPERTY: {
2164 Node* key = environment()->Top();
2165 Node* object = environment()->Peek(1);
2166 VectorSlotPair pair =
2167 CreateVectorSlotPair(property->PropertyFeedbackSlot());
2168 FrameStateBeforeAndAfter states(this, property->key()->id());
2169 old_value = BuildKeyedLoad(object, key, pair);
2170 states.AddToNode(old_value, property->LoadId(),
2171 OutputFrameStateCombine::Push());
2174 case NAMED_SUPER_PROPERTY: {
2175 Node* home_object = environment()->Top();
2176 Node* receiver = environment()->Peek(1);
2177 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
2178 VectorSlotPair pair =
2179 CreateVectorSlotPair(property->PropertyFeedbackSlot());
2180 FrameStateBeforeAndAfter states(this, property->obj()->id());
2181 old_value = BuildNamedSuperLoad(receiver, home_object, name, pair);
2182 states.AddToNode(old_value, property->LoadId(),
2183 OutputFrameStateCombine::Push());
2186 case KEYED_SUPER_PROPERTY: {
2187 Node* key = environment()->Top();
2188 Node* home_object = environment()->Peek(1);
2189 Node* receiver = environment()->Peek(2);
2190 VectorSlotPair pair =
2191 CreateVectorSlotPair(property->PropertyFeedbackSlot());
2192 FrameStateBeforeAndAfter states(this, property->key()->id());
2193 old_value = BuildKeyedSuperLoad(receiver, home_object, key, pair);
2194 states.AddToNode(old_value, property->LoadId(),
2195 OutputFrameStateCombine::Push());
2199 environment()->Push(old_value);
2200 VisitForValue(expr->value());
2203 FrameStateBeforeAndAfter states(this, expr->value()->id());
2204 Node* right = environment()->Pop();
2205 Node* left = environment()->Pop();
2206 value = BuildBinaryOp(left, right, expr->binary_op());
2207 states.AddToNode(value, expr->binary_operation()->id(),
2208 OutputFrameStateCombine::Push());
2210 environment()->Push(value);
2211 if (needs_frame_state_before) {
2212 before_store_id = expr->binary_operation()->id();
2215 VisitForValue(expr->value());
2216 if (needs_frame_state_before) {
2217 before_store_id = expr->value()->id();
2221 FrameStateBeforeAndAfter store_states(this, before_store_id);
2223 Node* value = environment()->Pop();
2224 VectorSlotPair feedback = CreateVectorSlotPair(expr->AssignmentSlot());
2225 switch (assign_type) {
2227 Variable* variable = expr->target()->AsVariableProxy()->var();
2228 BuildVariableAssignment(variable, value, expr->op(), feedback, expr->id(),
2229 store_states, ast_context()->GetStateCombine());
2232 case NAMED_PROPERTY: {
2233 Node* object = environment()->Pop();
2234 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
2235 Node* store = BuildNamedStore(object, name, value, feedback,
2236 expr->AssignmentFeedbackId());
2237 store_states.AddToNode(store, expr->id(),
2238 ast_context()->GetStateCombine());
2241 case KEYED_PROPERTY: {
2242 Node* key = environment()->Pop();
2243 Node* object = environment()->Pop();
2244 Node* store = BuildKeyedStore(object, key, value, feedback,
2245 expr->AssignmentFeedbackId());
2246 store_states.AddToNode(store, expr->id(),
2247 ast_context()->GetStateCombine());
2250 case NAMED_SUPER_PROPERTY: {
2251 Node* home_object = environment()->Pop();
2252 Node* receiver = environment()->Pop();
2253 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
2254 Node* store = BuildNamedSuperStore(receiver, home_object, name, value,
2255 expr->AssignmentFeedbackId());
2256 store_states.AddToNode(store, expr->id(),
2257 ast_context()->GetStateCombine());
2260 case KEYED_SUPER_PROPERTY: {
2261 Node* key = environment()->Pop();
2262 Node* home_object = environment()->Pop();
2263 Node* receiver = environment()->Pop();
2264 Node* store = BuildKeyedSuperStore(receiver, home_object, key, value,
2265 expr->AssignmentFeedbackId());
2266 store_states.AddToNode(store, expr->id(),
2267 ast_context()->GetStateCombine());
2272 ast_context()->ProduceValue(value);
2276 void AstGraphBuilder::VisitYield(Yield* expr) {
2277 // TODO(turbofan): Implement yield here.
2279 ast_context()->ProduceValue(jsgraph()->UndefinedConstant());
2283 void AstGraphBuilder::VisitThrow(Throw* expr) {
2284 VisitForValue(expr->exception());
2285 Node* exception = environment()->Pop();
2286 Node* value = BuildThrowError(exception, expr->id());
2287 ast_context()->ProduceValue(value);
2291 void AstGraphBuilder::VisitProperty(Property* expr) {
2292 Node* value = nullptr;
2293 LhsKind property_kind = Property::GetAssignType(expr);
2294 VectorSlotPair pair = CreateVectorSlotPair(expr->PropertyFeedbackSlot());
2295 switch (property_kind) {
2299 case NAMED_PROPERTY: {
2300 VisitForValue(expr->obj());
2301 FrameStateBeforeAndAfter states(this, expr->obj()->id());
2302 Node* object = environment()->Pop();
2303 Handle<Name> name = expr->key()->AsLiteral()->AsPropertyName();
2304 value = BuildNamedLoad(object, name, pair);
2305 states.AddToNode(value, expr->id(), ast_context()->GetStateCombine());
2308 case KEYED_PROPERTY: {
2309 VisitForValue(expr->obj());
2310 VisitForValue(expr->key());
2311 FrameStateBeforeAndAfter states(this, expr->key()->id());
2312 Node* key = environment()->Pop();
2313 Node* object = environment()->Pop();
2314 value = BuildKeyedLoad(object, key, pair);
2315 states.AddToNode(value, expr->id(), ast_context()->GetStateCombine());
2318 case NAMED_SUPER_PROPERTY: {
2319 VisitForValue(expr->obj()->AsSuperPropertyReference()->this_var());
2320 VisitForValue(expr->obj()->AsSuperPropertyReference()->home_object());
2321 FrameStateBeforeAndAfter states(this, expr->obj()->id());
2322 Node* home_object = environment()->Pop();
2323 Node* receiver = environment()->Pop();
2324 Handle<Name> name = expr->key()->AsLiteral()->AsPropertyName();
2325 value = BuildNamedSuperLoad(receiver, home_object, name, pair);
2326 states.AddToNode(value, expr->id(), ast_context()->GetStateCombine());
2329 case KEYED_SUPER_PROPERTY: {
2330 VisitForValue(expr->obj()->AsSuperPropertyReference()->this_var());
2331 VisitForValue(expr->obj()->AsSuperPropertyReference()->home_object());
2332 VisitForValue(expr->key());
2333 FrameStateBeforeAndAfter states(this, expr->key()->id());
2334 Node* key = environment()->Pop();
2335 Node* home_object = environment()->Pop();
2336 Node* receiver = environment()->Pop();
2337 value = BuildKeyedSuperLoad(receiver, home_object, key, pair);
2338 states.AddToNode(value, expr->id(), ast_context()->GetStateCombine());
2342 ast_context()->ProduceValue(value);
2346 void AstGraphBuilder::VisitCall(Call* expr) {
2347 Expression* callee = expr->expression();
2348 Call::CallType call_type = expr->GetCallType(isolate());
2350 // Prepare the callee and the receiver to the function call. This depends on
2351 // the semantics of the underlying call type.
2352 CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS;
2353 Node* receiver_value = NULL;
2354 Node* callee_value = NULL;
2355 bool possibly_eval = false;
2356 switch (call_type) {
2357 case Call::GLOBAL_CALL: {
2358 VariableProxy* proxy = callee->AsVariableProxy();
2359 VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot());
2360 FrameStateBeforeAndAfter states(this, BeforeId(proxy));
2362 BuildVariableLoad(proxy->var(), expr->expression()->id(), states,
2363 pair, OutputFrameStateCombine::Push());
2364 receiver_value = jsgraph()->UndefinedConstant();
2367 case Call::LOOKUP_SLOT_CALL: {
2368 Variable* variable = callee->AsVariableProxy()->var();
2369 DCHECK(variable->location() == VariableLocation::LOOKUP);
2370 Node* name = jsgraph()->Constant(variable->name());
2371 const Operator* op =
2372 javascript()->CallRuntime(Runtime::kLoadLookupSlot, 2);
2373 Node* pair = NewNode(op, current_context(), name);
2374 callee_value = NewNode(common()->Projection(0), pair);
2375 receiver_value = NewNode(common()->Projection(1), pair);
2377 PrepareFrameState(pair, expr->LookupId(),
2378 OutputFrameStateCombine::Push(2));
2381 case Call::PROPERTY_CALL: {
2382 Property* property = callee->AsProperty();
2383 VectorSlotPair pair =
2384 CreateVectorSlotPair(property->PropertyFeedbackSlot());
2385 if (!property->IsSuperAccess()) {
2386 VisitForValue(property->obj());
2387 Node* object = environment()->Top();
2389 if (property->key()->IsPropertyName()) {
2390 FrameStateBeforeAndAfter states(this, property->obj()->id());
2391 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
2392 callee_value = BuildNamedLoad(object, name, pair);
2393 states.AddToNode(callee_value, property->LoadId(),
2394 OutputFrameStateCombine::Push());
2396 VisitForValue(property->key());
2397 FrameStateBeforeAndAfter states(this, property->key()->id());
2398 Node* key = environment()->Pop();
2399 callee_value = BuildKeyedLoad(object, key, pair);
2400 states.AddToNode(callee_value, property->LoadId(),
2401 OutputFrameStateCombine::Push());
2403 receiver_value = environment()->Pop();
2404 // Note that a PROPERTY_CALL requires the receiver to be wrapped into an
2405 // object for sloppy callees. This could also be modeled explicitly
2407 // thereby obsoleting the need for a flag to the call operator.
2408 flags = CALL_AS_METHOD;
2411 VisitForValue(property->obj()->AsSuperPropertyReference()->this_var());
2413 property->obj()->AsSuperPropertyReference()->home_object());
2414 Node* home_object = environment()->Pop();
2415 receiver_value = environment()->Pop();
2416 if (property->key()->IsPropertyName()) {
2417 FrameStateBeforeAndAfter states(this, property->obj()->id());
2418 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
2420 BuildNamedSuperLoad(receiver_value, home_object, name, pair);
2421 states.AddToNode(callee_value, property->LoadId(),
2422 OutputFrameStateCombine::Push());
2425 VisitForValue(property->key());
2426 FrameStateBeforeAndAfter states(this, property->key()->id());
2427 Node* key = environment()->Pop();
2429 BuildKeyedSuperLoad(receiver_value, home_object, key, pair);
2430 states.AddToNode(callee_value, property->LoadId(),
2431 OutputFrameStateCombine::Push());
2437 case Call::SUPER_CALL:
2438 return VisitCallSuper(expr);
2439 case Call::POSSIBLY_EVAL_CALL:
2440 possibly_eval = true;
2441 if (callee->AsVariableProxy()->var()->IsLookupSlot()) {
2442 Variable* variable = callee->AsVariableProxy()->var();
2443 Node* name = jsgraph()->Constant(variable->name());
2444 const Operator* op =
2445 javascript()->CallRuntime(Runtime::kLoadLookupSlot, 2);
2446 Node* pair = NewNode(op, current_context(), name);
2447 callee_value = NewNode(common()->Projection(0), pair);
2448 receiver_value = NewNode(common()->Projection(1), pair);
2449 PrepareFrameState(pair, expr->LookupId(),
2450 OutputFrameStateCombine::Push(2));
2454 case Call::OTHER_CALL:
2455 VisitForValue(callee);
2456 callee_value = environment()->Pop();
2457 receiver_value = jsgraph()->UndefinedConstant();
2461 // The callee and the receiver both have to be pushed onto the operand stack
2462 // before arguments are being evaluated.
2463 environment()->Push(callee_value);
2464 environment()->Push(receiver_value);
2466 // Evaluate all arguments to the function call,
2467 ZoneList<Expression*>* args = expr->arguments();
2468 VisitForValues(args);
2470 // Resolve callee and receiver for a potential direct eval call. This block
2471 // will mutate the callee and receiver values pushed onto the environment.
2472 if (possibly_eval && args->length() > 0) {
2473 int arg_count = args->length();
2475 // Extract callee and source string from the environment.
2476 Node* callee = environment()->Peek(arg_count + 1);
2477 Node* source = environment()->Peek(arg_count - 1);
2479 // Create node to ask for help resolving potential eval call. This will
2480 // provide a fully resolved callee and the corresponding receiver.
2481 Node* function = GetFunctionClosure();
2482 Node* language = jsgraph()->Constant(language_mode());
2483 Node* position = jsgraph()->Constant(current_scope()->start_position());
2484 const Operator* op =
2485 javascript()->CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
2487 NewNode(op, callee, source, function, language, position);
2488 PrepareFrameState(new_callee, expr->EvalId(),
2489 OutputFrameStateCombine::PokeAt(arg_count + 1));
2491 // Patch callee on the environment.
2492 environment()->Poke(arg_count + 1, new_callee);
2495 // Create node to perform the function call.
2496 VectorSlotPair feedback = CreateVectorSlotPair(expr->CallFeedbackICSlot());
2497 const Operator* call = javascript()->CallFunction(args->length() + 2, flags,
2498 language_mode(), feedback);
2499 Node* value = ProcessArguments(call, args->length() + 2);
2500 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
2501 ast_context()->ProduceValue(value);
2505 void AstGraphBuilder::VisitCallSuper(Call* expr) {
2506 SuperCallReference* super = expr->expression()->AsSuperCallReference();
2507 DCHECK_NOT_NULL(super);
2509 // Prepare the callee to the super call. The super constructor is stored as
2510 // the prototype of the constructor we are currently executing.
2511 VisitForValue(super->this_function_var());
2512 Node* this_function = environment()->Pop();
2513 const Operator* op = javascript()->CallRuntime(Runtime::kGetPrototype, 1);
2514 Node* super_function = NewNode(op, this_function);
2515 // TODO(mstarzinger): This probably needs a proper bailout id.
2516 PrepareFrameState(super_function, BailoutId::None());
2517 environment()->Push(super_function);
2519 // Evaluate all arguments to the super call.
2520 ZoneList<Expression*>* args = expr->arguments();
2521 VisitForValues(args);
2523 // Original constructor is loaded from the {new.target} variable.
2524 VisitForValue(super->new_target_var());
2526 // Create node to perform the super call.
2527 const Operator* call = javascript()->CallConstruct(args->length() + 2);
2528 Node* value = ProcessArguments(call, args->length() + 2);
2529 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
2530 ast_context()->ProduceValue(value);
2534 void AstGraphBuilder::VisitCallNew(CallNew* expr) {
2535 VisitForValue(expr->expression());
2537 // Evaluate all arguments to the construct call.
2538 ZoneList<Expression*>* args = expr->arguments();
2539 VisitForValues(args);
2541 // Original constructor is the same as the callee.
2542 environment()->Push(environment()->Peek(args->length()));
2544 // Create node to perform the construct call.
2545 const Operator* call = javascript()->CallConstruct(args->length() + 2);
2546 Node* value = ProcessArguments(call, args->length() + 2);
2547 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
2548 ast_context()->ProduceValue(value);
2552 void AstGraphBuilder::VisitCallJSRuntime(CallRuntime* expr) {
2553 Handle<String> name = expr->name();
2555 // The callee and the receiver both have to be pushed onto the operand stack
2556 // before arguments are being evaluated.
2557 CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS;
2558 Node* receiver_value = BuildLoadBuiltinsObject();
2559 VectorSlotPair pair = CreateVectorSlotPair(expr->CallRuntimeFeedbackSlot());
2560 // TODO(jarin): bailout ids for runtime calls.
2561 FrameStateBeforeAndAfter states(this, BailoutId::None());
2562 Node* callee_value = BuildNamedLoad(receiver_value, name, pair);
2563 states.AddToNode(callee_value, BailoutId::None(),
2564 OutputFrameStateCombine::Push());
2565 environment()->Push(callee_value);
2566 environment()->Push(receiver_value);
2568 // Evaluate all arguments to the JS runtime call.
2569 ZoneList<Expression*>* args = expr->arguments();
2570 VisitForValues(args);
2572 // Create node to perform the JS runtime call.
2573 const Operator* call =
2574 javascript()->CallFunction(args->length() + 2, flags, language_mode());
2575 Node* value = ProcessArguments(call, args->length() + 2);
2576 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
2577 ast_context()->ProduceValue(value);
2581 void AstGraphBuilder::VisitCallRuntime(CallRuntime* expr) {
2582 const Runtime::Function* function = expr->function();
2584 // Handle calls to runtime functions implemented in JavaScript separately as
2585 // the call follows JavaScript ABI and the callee is statically unknown.
2586 if (expr->is_jsruntime()) {
2587 DCHECK(function == NULL && expr->name()->length() > 0);
2588 return VisitCallJSRuntime(expr);
2591 // TODO(mstarzinger): This bailout is a gigantic hack, the owner is ashamed.
2592 if (function->function_id == Runtime::kInlineGeneratorNext ||
2593 function->function_id == Runtime::kInlineGeneratorThrow) {
2594 ast_context()->ProduceValue(jsgraph()->TheHoleConstant());
2595 return SetStackOverflow();
2598 // Evaluate all arguments to the runtime call.
2599 ZoneList<Expression*>* args = expr->arguments();
2600 VisitForValues(args);
2602 // Create node to perform the runtime call.
2603 Runtime::FunctionId functionId = function->function_id;
2604 const Operator* call = javascript()->CallRuntime(functionId, args->length());
2605 FrameStateBeforeAndAfter states(this, expr->CallId());
2606 Node* value = ProcessArguments(call, args->length());
2607 states.AddToNode(value, expr->id(), ast_context()->GetStateCombine());
2608 ast_context()->ProduceValue(value);
2612 void AstGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) {
2613 switch (expr->op()) {
2615 return VisitDelete(expr);
2617 return VisitVoid(expr);
2619 return VisitTypeof(expr);
2621 return VisitNot(expr);
2628 void AstGraphBuilder::VisitCountOperation(CountOperation* expr) {
2629 DCHECK(expr->expression()->IsValidReferenceExpressionOrThis());
2631 // Left-hand side can only be a property, a global or a variable slot.
2632 Property* property = expr->expression()->AsProperty();
2633 LhsKind assign_type = Property::GetAssignType(property);
2635 // Reserve space for result of postfix operation.
2636 bool is_postfix = expr->is_postfix() && !ast_context()->IsEffect();
2637 if (is_postfix) environment()->Push(jsgraph()->UndefinedConstant());
2639 // Evaluate LHS expression and get old value.
2640 Node* old_value = NULL;
2641 int stack_depth = -1;
2642 switch (assign_type) {
2644 VariableProxy* proxy = expr->expression()->AsVariableProxy();
2645 VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot());
2646 FrameStateBeforeAndAfter states(this, BeforeId(proxy));
2648 BuildVariableLoad(proxy->var(), expr->expression()->id(), states,
2649 pair, OutputFrameStateCombine::Push());
2653 case NAMED_PROPERTY: {
2654 VisitForValue(property->obj());
2655 FrameStateBeforeAndAfter states(this, property->obj()->id());
2656 Node* object = environment()->Top();
2657 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
2658 VectorSlotPair pair =
2659 CreateVectorSlotPair(property->PropertyFeedbackSlot());
2660 old_value = BuildNamedLoad(object, name, pair);
2661 states.AddToNode(old_value, property->LoadId(),
2662 OutputFrameStateCombine::Push());
2666 case KEYED_PROPERTY: {
2667 VisitForValue(property->obj());
2668 VisitForValue(property->key());
2669 FrameStateBeforeAndAfter states(this, property->key()->id());
2670 Node* key = environment()->Top();
2671 Node* object = environment()->Peek(1);
2672 VectorSlotPair pair =
2673 CreateVectorSlotPair(property->PropertyFeedbackSlot());
2674 old_value = BuildKeyedLoad(object, key, pair);
2675 states.AddToNode(old_value, property->LoadId(),
2676 OutputFrameStateCombine::Push());
2680 case NAMED_SUPER_PROPERTY: {
2681 VisitForValue(property->obj()->AsSuperPropertyReference()->this_var());
2682 VisitForValue(property->obj()->AsSuperPropertyReference()->home_object());
2683 FrameStateBeforeAndAfter states(this, property->obj()->id());
2684 Node* home_object = environment()->Top();
2685 Node* receiver = environment()->Peek(1);
2686 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
2687 VectorSlotPair pair =
2688 CreateVectorSlotPair(property->PropertyFeedbackSlot());
2689 old_value = BuildNamedSuperLoad(receiver, home_object, name, pair);
2690 states.AddToNode(old_value, property->LoadId(),
2691 OutputFrameStateCombine::Push());
2695 case KEYED_SUPER_PROPERTY: {
2696 VisitForValue(property->obj()->AsSuperPropertyReference()->this_var());
2697 VisitForValue(property->obj()->AsSuperPropertyReference()->home_object());
2698 VisitForValue(property->key());
2699 FrameStateBeforeAndAfter states(this, property->obj()->id());
2700 Node* key = environment()->Top();
2701 Node* home_object = environment()->Peek(1);
2702 Node* receiver = environment()->Peek(2);
2703 VectorSlotPair pair =
2704 CreateVectorSlotPair(property->PropertyFeedbackSlot());
2705 old_value = BuildKeyedSuperLoad(receiver, home_object, key, pair);
2706 states.AddToNode(old_value, property->LoadId(),
2707 OutputFrameStateCombine::Push());
2713 // Convert old value into a number.
2714 if (!is_strong(language_mode())) {
2715 old_value = NewNode(javascript()->ToNumber(), old_value);
2716 PrepareFrameState(old_value, expr->ToNumberId(),
2717 OutputFrameStateCombine::Push());
2720 // TODO(titzer): combine this framestate with the above?
2721 FrameStateBeforeAndAfter store_states(this, assign_type == KEYED_PROPERTY
2722 ? expr->ToNumberId()
2723 : BailoutId::None());
2725 // Save result for postfix expressions at correct stack depth.
2726 if (is_postfix) environment()->Poke(stack_depth, old_value);
2728 // Create node to perform +1/-1 operation.
2731 FrameStateBeforeAndAfter states(this, BailoutId::None());
2733 BuildBinaryOp(old_value, jsgraph()->OneConstant(), expr->binary_op());
2734 // This should never deoptimize outside strong mode because otherwise we
2735 // have converted to number before.
2736 states.AddToNode(value, is_strong(language_mode()) ? expr->ToNumberId()
2737 : BailoutId::None(),
2738 OutputFrameStateCombine::Ignore());
2742 VectorSlotPair feedback = CreateVectorSlotPair(expr->CountSlot());
2743 switch (assign_type) {
2745 Variable* variable = expr->expression()->AsVariableProxy()->var();
2746 environment()->Push(value);
2747 BuildVariableAssignment(variable, value, expr->op(), feedback,
2748 expr->AssignmentId(), store_states);
2749 environment()->Pop();
2752 case NAMED_PROPERTY: {
2753 Node* object = environment()->Pop();
2754 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
2755 Node* store = BuildNamedStore(object, name, value, feedback,
2756 expr->CountStoreFeedbackId());
2757 environment()->Push(value);
2758 store_states.AddToNode(store, expr->AssignmentId(),
2759 OutputFrameStateCombine::Ignore());
2760 environment()->Pop();
2763 case KEYED_PROPERTY: {
2764 Node* key = environment()->Pop();
2765 Node* object = environment()->Pop();
2766 Node* store = BuildKeyedStore(object, key, value, feedback,
2767 expr->CountStoreFeedbackId());
2768 environment()->Push(value);
2769 store_states.AddToNode(store, expr->AssignmentId(),
2770 OutputFrameStateCombine::Ignore());
2771 environment()->Pop();
2774 case NAMED_SUPER_PROPERTY: {
2775 Node* home_object = environment()->Pop();
2776 Node* receiver = environment()->Pop();
2777 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName();
2778 Node* store = BuildNamedSuperStore(receiver, home_object, name, value,
2779 expr->CountStoreFeedbackId());
2780 environment()->Push(value);
2781 store_states.AddToNode(store, expr->AssignmentId(),
2782 OutputFrameStateCombine::Ignore());
2783 environment()->Pop();
2786 case KEYED_SUPER_PROPERTY: {
2787 Node* key = environment()->Pop();
2788 Node* home_object = environment()->Pop();
2789 Node* receiver = environment()->Pop();
2790 Node* store = BuildKeyedSuperStore(receiver, home_object, key, value,
2791 expr->CountStoreFeedbackId());
2792 environment()->Push(value);
2793 store_states.AddToNode(store, expr->AssignmentId(),
2794 OutputFrameStateCombine::Ignore());
2795 environment()->Pop();
2800 // Restore old value for postfix expressions.
2801 if (is_postfix) value = environment()->Pop();
2803 ast_context()->ProduceValue(value);
2807 void AstGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) {
2808 switch (expr->op()) {
2810 return VisitComma(expr);
2813 return VisitLogicalExpression(expr);
2815 VisitForValue(expr->left());
2816 VisitForValue(expr->right());
2817 FrameStateBeforeAndAfter states(this, expr->right()->id());
2818 Node* right = environment()->Pop();
2819 Node* left = environment()->Pop();
2820 Node* value = BuildBinaryOp(left, right, expr->op());
2821 states.AddToNode(value, expr->id(), ast_context()->GetStateCombine());
2822 ast_context()->ProduceValue(value);
2828 void AstGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
2830 switch (expr->op()) {
2832 op = javascript()->Equal();
2835 op = javascript()->NotEqual();
2837 case Token::EQ_STRICT:
2838 op = javascript()->StrictEqual();
2840 case Token::NE_STRICT:
2841 op = javascript()->StrictNotEqual();
2844 op = javascript()->LessThan(language_mode());
2847 op = javascript()->GreaterThan(language_mode());
2850 op = javascript()->LessThanOrEqual(language_mode());
2853 op = javascript()->GreaterThanOrEqual(language_mode());
2855 case Token::INSTANCEOF:
2856 op = javascript()->InstanceOf();
2859 op = javascript()->HasProperty();
2865 VisitForValue(expr->left());
2866 VisitForValue(expr->right());
2867 FrameStateBeforeAndAfter states(this, expr->right()->id());
2868 Node* right = environment()->Pop();
2869 Node* left = environment()->Pop();
2870 Node* value = NewNode(op, left, right);
2871 states.AddToNode(value, expr->id(), ast_context()->GetStateCombine());
2872 ast_context()->ProduceValue(value);
2876 void AstGraphBuilder::VisitSpread(Spread* expr) {
2877 // Handled entirely by the parser itself.
2882 void AstGraphBuilder::VisitThisFunction(ThisFunction* expr) {
2883 Node* value = GetFunctionClosure();
2884 ast_context()->ProduceValue(value);
2888 void AstGraphBuilder::VisitSuperPropertyReference(
2889 SuperPropertyReference* expr) {
2890 Node* value = BuildThrowUnsupportedSuperError(expr->id());
2891 ast_context()->ProduceValue(value);
2895 void AstGraphBuilder::VisitSuperCallReference(SuperCallReference* expr) {
2896 // Handled by VisitCall
2901 void AstGraphBuilder::VisitCaseClause(CaseClause* expr) {
2902 // Handled entirely in VisitSwitch.
2907 void AstGraphBuilder::VisitDeclarations(ZoneList<Declaration*>* declarations) {
2908 DCHECK(globals()->empty());
2909 AstVisitor::VisitDeclarations(declarations);
2910 if (globals()->empty()) return;
2911 int array_index = 0;
2912 Handle<FixedArray> data = isolate()->factory()->NewFixedArray(
2913 static_cast<int>(globals()->size()), TENURED);
2914 for (Handle<Object> obj : *globals()) data->set(array_index++, *obj);
2915 int encoded_flags = DeclareGlobalsEvalFlag::encode(info()->is_eval()) |
2916 DeclareGlobalsNativeFlag::encode(info()->is_native()) |
2917 DeclareGlobalsLanguageMode::encode(language_mode());
2918 Node* flags = jsgraph()->Constant(encoded_flags);
2919 Node* pairs = jsgraph()->Constant(data);
2920 const Operator* op = javascript()->CallRuntime(Runtime::kDeclareGlobals, 3);
2921 Node* call = NewNode(op, current_context(), pairs, flags);
2922 PrepareFrameState(call, BailoutId::Declarations());
2927 void AstGraphBuilder::VisitIfNotNull(Statement* stmt) {
2928 if (stmt == NULL) return;
2933 void AstGraphBuilder::VisitInScope(Statement* stmt, Scope* s, Node* context) {
2934 ContextScope scope(this, s, context);
2935 DCHECK(s->declarations()->is_empty());
2940 void AstGraphBuilder::VisitIterationBody(IterationStatement* stmt,
2941 LoopBuilder* loop) {
2942 ControlScopeForIteration scope(this, stmt, loop);
2943 // TODO(mstarzinger): For now we only allow to interrupt non-asm.js code,
2944 // which is a gigantic hack and should be extended to all code at some point.
2945 if (!info()->shared_info()->asm_function()) {
2946 Node* node = NewNode(javascript()->StackCheck());
2947 PrepareFrameState(node, stmt->StackCheckId());
2949 Visit(stmt->body());
2953 void AstGraphBuilder::VisitDelete(UnaryOperation* expr) {
2955 if (expr->expression()->IsVariableProxy()) {
2956 // Delete of an unqualified identifier is only allowed in classic mode but
2957 // deleting "this" is allowed in all language modes.
2958 Variable* variable = expr->expression()->AsVariableProxy()->var();
2959 // Delete of an unqualified identifier is disallowed in strict mode but
2960 // "delete this" is allowed.
2961 DCHECK(is_sloppy(language_mode()) || variable->HasThisName(isolate()));
2962 value = BuildVariableDelete(variable, expr->id(),
2963 ast_context()->GetStateCombine());
2964 } else if (expr->expression()->IsProperty()) {
2965 Property* property = expr->expression()->AsProperty();
2966 VisitForValue(property->obj());
2967 VisitForValue(property->key());
2968 Node* key = environment()->Pop();
2969 Node* object = environment()->Pop();
2970 value = NewNode(javascript()->DeleteProperty(language_mode()), object, key);
2971 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine());
2973 VisitForEffect(expr->expression());
2974 value = jsgraph()->TrueConstant();
2976 ast_context()->ProduceValue(value);
2980 void AstGraphBuilder::VisitVoid(UnaryOperation* expr) {
2981 VisitForEffect(expr->expression());
2982 Node* value = jsgraph()->UndefinedConstant();
2983 ast_context()->ProduceValue(value);
2987 void AstGraphBuilder::VisitTypeof(UnaryOperation* expr) {
2989 if (expr->expression()->IsVariableProxy()) {
2990 // Typeof does not throw a reference error on global variables, hence we
2991 // perform a non-contextual load in case the operand is a variable proxy.
2992 VariableProxy* proxy = expr->expression()->AsVariableProxy();
2993 VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot());
2994 FrameStateBeforeAndAfter states(this, BeforeId(proxy));
2996 BuildVariableLoad(proxy->var(), expr->expression()->id(), states, pair,
2997 OutputFrameStateCombine::Push(), INSIDE_TYPEOF);
2999 VisitForValue(expr->expression());
3000 operand = environment()->Pop();
3002 Node* value = NewNode(javascript()->TypeOf(), operand);
3003 ast_context()->ProduceValue(value);
3007 void AstGraphBuilder::VisitNot(UnaryOperation* expr) {
3008 VisitForValue(expr->expression());
3009 Node* operand = environment()->Pop();
3010 // TODO(mstarzinger): Possible optimization when we are in effect context.
3011 Node* value = NewNode(javascript()->UnaryNot(), operand);
3012 ast_context()->ProduceValue(value);
3016 void AstGraphBuilder::VisitComma(BinaryOperation* expr) {
3017 VisitForEffect(expr->left());
3018 Visit(expr->right());
3019 ast_context()->ReplaceValue();
3023 void AstGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) {
3024 bool is_logical_and = expr->op() == Token::AND;
3025 IfBuilder compare_if(this);
3026 VisitForValue(expr->left());
3027 Node* condition = environment()->Top();
3028 compare_if.If(BuildToBoolean(condition));
3030 if (is_logical_and) {
3031 environment()->Pop();
3032 Visit(expr->right());
3033 } else if (ast_context()->IsEffect()) {
3034 environment()->Pop();
3035 } else if (ast_context()->IsTest()) {
3036 environment()->Poke(0, jsgraph()->TrueConstant());
3039 if (!is_logical_and) {
3040 environment()->Pop();
3041 Visit(expr->right());
3042 } else if (ast_context()->IsEffect()) {
3043 environment()->Pop();
3044 } else if (ast_context()->IsTest()) {
3045 environment()->Poke(0, jsgraph()->FalseConstant());
3048 ast_context()->ReplaceValue();
3052 LanguageMode AstGraphBuilder::language_mode() const {
3053 return info()->language_mode();
3057 VectorSlotPair AstGraphBuilder::CreateVectorSlotPair(
3058 FeedbackVectorICSlot slot) const {
3059 return VectorSlotPair(handle(info()->shared_info()->feedback_vector()), slot);
3063 uint32_t AstGraphBuilder::ComputeBitsetForDynamicGlobal(Variable* variable) {
3064 DCHECK_EQ(DYNAMIC_GLOBAL, variable->mode());
3065 bool found_eval_scope = false;
3066 uint32_t check_depths = 0;
3067 for (Scope* s = current_scope(); s != nullptr; s = s->outer_scope()) {
3068 if (s->num_heap_slots() <= 0) continue;
3069 // TODO(mstarzinger): If we have reached an eval scope, we check all
3070 // extensions from this point. Replicated from full-codegen, figure out
3071 // whether this is still needed. If not, drop {found_eval_scope} below.
3072 if (s->is_eval_scope()) found_eval_scope = true;
3073 if (!s->calls_sloppy_eval() && !found_eval_scope) continue;
3074 int depth = current_scope()->ContextChainLength(s);
3075 if (depth > DynamicGlobalAccess::kMaxCheckDepth) {
3076 return DynamicGlobalAccess::kFullCheckRequired;
3078 check_depths |= 1 << depth;
3080 return check_depths;
3084 uint32_t AstGraphBuilder::ComputeBitsetForDynamicContext(Variable* variable) {
3085 DCHECK_EQ(DYNAMIC_LOCAL, variable->mode());
3086 uint32_t check_depths = 0;
3087 for (Scope* s = current_scope(); s != nullptr; s = s->outer_scope()) {
3088 if (s->num_heap_slots() <= 0) continue;
3089 if (!s->calls_sloppy_eval() && s != variable->scope()) continue;
3090 int depth = current_scope()->ContextChainLength(s);
3091 if (depth > DynamicContextAccess::kMaxCheckDepth) {
3092 return DynamicContextAccess::kFullCheckRequired;
3094 check_depths |= 1 << depth;
3095 if (s == variable->scope()) break;
3097 return check_depths;
3101 Node* AstGraphBuilder::ProcessArguments(const Operator* op, int arity) {
3102 DCHECK(environment()->stack_height() >= arity);
3103 Node** all = info()->zone()->NewArray<Node*>(arity);
3104 for (int i = arity - 1; i >= 0; --i) {
3105 all[i] = environment()->Pop();
3107 Node* value = NewNode(op, arity, all);
3112 Node* AstGraphBuilder::BuildPatchReceiverToGlobalProxy(Node* receiver) {
3113 // Sloppy mode functions and builtins need to replace the receiver with the
3114 // global proxy when called as functions (without an explicit receiver
3115 // object). Otherwise there is nothing left to do here.
3116 if (is_strict(language_mode()) || info()->is_native()) return receiver;
3118 // There is no need to perform patching if the receiver will never be used.
3119 if (!info()->MayUseThis()) return receiver;
3121 IfBuilder receiver_check(this);
3122 Node* undefined = jsgraph()->UndefinedConstant();
3123 Node* check = NewNode(javascript()->StrictEqual(), receiver, undefined);
3124 receiver_check.If(check);
3125 receiver_check.Then();
3126 Node* proxy = BuildLoadGlobalProxy();
3127 environment()->Push(proxy);
3128 receiver_check.Else();
3129 environment()->Push(receiver);
3130 receiver_check.End();
3131 return environment()->Pop();
3135 Node* AstGraphBuilder::BuildLocalFunctionContext(Node* context) {
3136 Scope* scope = info()->scope();
3137 Node* closure = GetFunctionClosure();
3139 // Allocate a new local context.
3140 Node* local_context =
3141 scope->is_script_scope()
3142 ? BuildLocalScriptContext(scope)
3143 : NewNode(javascript()->CreateFunctionContext(), closure);
3145 if (scope->has_this_declaration() && scope->receiver()->IsContextSlot()) {
3146 Node* receiver = environment()->RawParameterLookup(0);
3147 // Context variable (at bottom of the context chain).
3148 Variable* variable = scope->receiver();
3149 DCHECK_EQ(0, scope->ContextChainLength(variable->scope()));
3150 const Operator* op = javascript()->StoreContext(0, variable->index());
3151 NewNode(op, local_context, receiver);
3154 // Copy parameters into context if necessary.
3155 int num_parameters = scope->num_parameters();
3156 for (int i = 0; i < num_parameters; i++) {
3157 Variable* variable = scope->parameter(i);
3158 if (!variable->IsContextSlot()) continue;
3159 Node* parameter = environment()->RawParameterLookup(i + 1);
3160 // Context variable (at bottom of the context chain).
3161 DCHECK_EQ(0, scope->ContextChainLength(variable->scope()));
3162 const Operator* op = javascript()->StoreContext(0, variable->index());
3163 NewNode(op, local_context, parameter);
3166 return local_context;
3170 Node* AstGraphBuilder::BuildLocalScriptContext(Scope* scope) {
3171 DCHECK(scope->is_script_scope());
3173 // Allocate a new local context.
3174 const Operator* op = javascript()->CreateScriptContext();
3175 Node* scope_info = jsgraph()->Constant(scope->GetScopeInfo(isolate()));
3176 Node* local_context = NewNode(op, GetFunctionClosure(), scope_info);
3177 PrepareFrameState(local_context, BailoutId::FunctionEntry());
3179 return local_context;
3183 Node* AstGraphBuilder::BuildLocalBlockContext(Scope* scope) {
3184 DCHECK(scope->is_block_scope());
3186 // Allocate a new local context.
3187 const Operator* op = javascript()->CreateBlockContext();
3188 Node* scope_info = jsgraph()->Constant(scope->GetScopeInfo(isolate()));
3189 Node* local_context = NewNode(op, scope_info, GetFunctionClosureForContext());
3191 return local_context;
3195 Node* AstGraphBuilder::BuildArgumentsObject(Variable* arguments) {
3196 if (arguments == NULL) return NULL;
3198 // Allocate and initialize a new arguments object.
3199 Node* callee = GetFunctionClosure();
3200 const Operator* op = javascript()->CallRuntime(Runtime::kNewArguments, 1);
3201 Node* object = NewNode(op, callee);
3203 // Assign the object to the arguments variable.
3204 DCHECK(arguments->IsContextSlot() || arguments->IsStackAllocated());
3205 // This should never lazy deopt, so it is fine to send invalid bailout id.
3206 FrameStateBeforeAndAfter states(this, BailoutId::None());
3207 BuildVariableAssignment(arguments, object, Token::ASSIGN, VectorSlotPair(),
3208 BailoutId::None(), states);
3213 Node* AstGraphBuilder::BuildRestArgumentsArray(Variable* rest, int index) {
3214 if (rest == NULL) return NULL;
3217 const Operator* op = javascript()->CallRuntime(Runtime::kNewRestParamSlow, 2);
3218 Node* object = NewNode(op, jsgraph()->SmiConstant(index),
3219 jsgraph()->SmiConstant(language_mode()));
3221 // Assign the object to the rest parameter variable.
3222 DCHECK(rest->IsContextSlot() || rest->IsStackAllocated());
3223 // This should never lazy deopt, so it is fine to send invalid bailout id.
3224 FrameStateBeforeAndAfter states(this, BailoutId::None());
3225 BuildVariableAssignment(rest, object, Token::ASSIGN, VectorSlotPair(),
3226 BailoutId::None(), states);
3231 Node* AstGraphBuilder::BuildThisFunctionVariable(Variable* this_function_var) {
3232 if (this_function_var == nullptr) return nullptr;
3234 // Retrieve the closure we were called with.
3235 Node* this_function = GetFunctionClosure();
3237 // Assign the object to the {.this_function} variable.
3238 FrameStateBeforeAndAfter states(this, BailoutId::None());
3239 BuildVariableAssignment(this_function_var, this_function, Token::INIT_CONST,
3240 VectorSlotPair(), BailoutId::None(), states);
3241 return this_function;
3245 Node* AstGraphBuilder::BuildNewTargetVariable(Variable* new_target_var) {
3246 if (new_target_var == nullptr) return nullptr;
3248 // Retrieve the original constructor in case we are called as a constructor.
3249 const Operator* op =
3250 javascript()->CallRuntime(Runtime::kGetOriginalConstructor, 0);
3251 Node* object = NewNode(op);
3253 // Assign the object to the {new.target} variable.
3254 FrameStateBeforeAndAfter states(this, BailoutId::None());
3255 BuildVariableAssignment(new_target_var, object, Token::INIT_CONST,
3256 VectorSlotPair(), BailoutId::None(), states);
3261 Node* AstGraphBuilder::BuildHoleCheckSilent(Node* value, Node* for_hole,
3263 Node* the_hole = jsgraph()->TheHoleConstant();
3264 Node* check = NewNode(javascript()->StrictEqual(), value, the_hole);
3265 return NewNode(common()->Select(kMachAnyTagged, BranchHint::kFalse), check,
3266 for_hole, not_hole);
3270 Node* AstGraphBuilder::BuildHoleCheckThenThrow(Node* value, Variable* variable,
3272 BailoutId bailout_id) {
3273 IfBuilder hole_check(this);
3274 Node* the_hole = jsgraph()->TheHoleConstant();
3275 Node* check = NewNode(javascript()->StrictEqual(), value, the_hole);
3276 hole_check.If(check);
3278 Node* error = BuildThrowReferenceError(variable, bailout_id);
3279 environment()->Push(error);
3281 environment()->Push(not_hole);
3283 return environment()->Pop();
3287 Node* AstGraphBuilder::BuildHoleCheckElseThrow(Node* value, Variable* variable,
3289 BailoutId bailout_id) {
3290 IfBuilder hole_check(this);
3291 Node* the_hole = jsgraph()->TheHoleConstant();
3292 Node* check = NewNode(javascript()->StrictEqual(), value, the_hole);
3293 hole_check.If(check);
3295 environment()->Push(for_hole);
3297 Node* error = BuildThrowReferenceError(variable, bailout_id);
3298 environment()->Push(error);
3300 return environment()->Pop();
3304 Node* AstGraphBuilder::BuildThrowIfStaticPrototype(Node* name,
3305 BailoutId bailout_id) {
3306 IfBuilder prototype_check(this);
3307 Node* prototype_string =
3308 jsgraph()->Constant(isolate()->factory()->prototype_string());
3309 Node* check = NewNode(javascript()->StrictEqual(), name, prototype_string);
3310 prototype_check.If(check);
3311 prototype_check.Then();
3312 Node* error = BuildThrowStaticPrototypeError(bailout_id);
3313 environment()->Push(error);
3314 prototype_check.Else();
3315 environment()->Push(name);
3316 prototype_check.End();
3317 return environment()->Pop();
3321 Node* AstGraphBuilder::BuildVariableLoad(Variable* variable,
3322 BailoutId bailout_id,
3323 FrameStateBeforeAndAfter& states,
3324 const VectorSlotPair& feedback,
3325 OutputFrameStateCombine combine,
3326 TypeofMode typeof_mode) {
3327 Node* the_hole = jsgraph()->TheHoleConstant();
3328 VariableMode mode = variable->mode();
3329 switch (variable->location()) {
3330 case VariableLocation::GLOBAL:
3331 case VariableLocation::UNALLOCATED: {
3332 // Global var, const, or let variable.
3333 Node* script_context = current_context();
3334 int slot_index = -1;
3335 if (variable->index() > 0) {
3336 DCHECK(variable->IsStaticGlobalObjectProperty());
3337 slot_index = variable->index();
3338 int depth = current_scope()->ContextChainLength(variable->scope());
3340 const Operator* op = javascript()->LoadContext(
3341 depth - 1, Context::PREVIOUS_INDEX, true);
3342 script_context = NewNode(op, current_context());
3345 Node* global = BuildLoadGlobalObject();
3346 Handle<Name> name = variable->name();
3347 Node* value = BuildGlobalLoad(script_context, global, name, feedback,
3348 typeof_mode, slot_index);
3349 states.AddToNode(value, bailout_id, combine);
3352 case VariableLocation::PARAMETER:
3353 case VariableLocation::LOCAL: {
3354 // Local var, const, or let variable.
3355 Node* value = environment()->Lookup(variable);
3356 if (mode == CONST_LEGACY) {
3357 // Perform check for uninitialized legacy const variables.
3358 if (value->op() == the_hole->op()) {
3359 value = jsgraph()->UndefinedConstant();
3360 } else if (value->opcode() == IrOpcode::kPhi) {
3361 Node* undefined = jsgraph()->UndefinedConstant();
3362 value = BuildHoleCheckSilent(value, undefined, value);
3364 } else if (mode == LET || mode == CONST) {
3365 // Perform check for uninitialized let/const variables.
3366 if (value->op() == the_hole->op()) {
3367 value = BuildThrowReferenceError(variable, bailout_id);
3368 } else if (value->opcode() == IrOpcode::kPhi) {
3369 value = BuildHoleCheckThenThrow(value, variable, value, bailout_id);
3374 case VariableLocation::CONTEXT: {
3375 // Context variable (potentially up the context chain).
3376 int depth = current_scope()->ContextChainLength(variable->scope());
3377 bool immutable = variable->maybe_assigned() == kNotAssigned;
3378 const Operator* op =
3379 javascript()->LoadContext(depth, variable->index(), immutable);
3380 Node* value = NewNode(op, current_context());
3381 // TODO(titzer): initialization checks are redundant for already
3382 // initialized immutable context loads, but only specialization knows.
3383 // Maybe specializer should be a parameter to the graph builder?
3384 if (mode == CONST_LEGACY) {
3385 // Perform check for uninitialized legacy const variables.
3386 Node* undefined = jsgraph()->UndefinedConstant();
3387 value = BuildHoleCheckSilent(value, undefined, value);
3388 } else if (mode == LET || mode == CONST) {
3389 // Perform check for uninitialized let/const variables.
3390 value = BuildHoleCheckThenThrow(value, variable, value, bailout_id);
3394 case VariableLocation::LOOKUP: {
3395 // Dynamic lookup of context variable (anywhere in the chain).
3396 Node* value = jsgraph()->TheHoleConstant();
3397 Handle<String> name = variable->name();
3398 if (mode == DYNAMIC_GLOBAL) {
3399 uint32_t check_bitset = ComputeBitsetForDynamicGlobal(variable);
3400 const Operator* op = javascript()->LoadDynamicGlobal(
3401 name, check_bitset, feedback, typeof_mode);
3402 value = NewNode(op, BuildLoadFeedbackVector(), current_context());
3403 states.AddToNode(value, bailout_id, combine);
3404 } else if (mode == DYNAMIC_LOCAL) {
3405 Variable* local = variable->local_if_not_shadowed();
3406 DCHECK(local->location() ==
3407 VariableLocation::CONTEXT); // Must be context.
3408 int depth = current_scope()->ContextChainLength(local->scope());
3409 uint32_t check_bitset = ComputeBitsetForDynamicContext(variable);
3410 const Operator* op = javascript()->LoadDynamicContext(
3411 name, check_bitset, depth, local->index());
3412 value = NewNode(op, current_context());
3413 PrepareFrameState(value, bailout_id, combine);
3414 VariableMode local_mode = local->mode();
3415 if (local_mode == CONST_LEGACY) {
3416 // Perform check for uninitialized legacy const variables.
3417 Node* undefined = jsgraph()->UndefinedConstant();
3418 value = BuildHoleCheckSilent(value, undefined, value);
3419 } else if (local_mode == LET || local_mode == CONST) {
3420 // Perform check for uninitialized let/const variables.
3421 value = BuildHoleCheckThenThrow(value, local, value, bailout_id);
3423 } else if (mode == DYNAMIC) {
3424 uint32_t check_bitset = DynamicGlobalAccess::kFullCheckRequired;
3425 const Operator* op = javascript()->LoadDynamicGlobal(
3426 name, check_bitset, feedback, typeof_mode);
3427 value = NewNode(op, BuildLoadFeedbackVector(), current_context());
3428 states.AddToNode(value, bailout_id, combine);
3438 Node* AstGraphBuilder::BuildVariableDelete(Variable* variable,
3439 BailoutId bailout_id,
3440 OutputFrameStateCombine combine) {
3441 switch (variable->location()) {
3442 case VariableLocation::GLOBAL:
3443 case VariableLocation::UNALLOCATED: {
3444 // Global var, const, or let variable.
3445 Node* global = BuildLoadGlobalObject();
3446 Node* name = jsgraph()->Constant(variable->name());
3447 const Operator* op = javascript()->DeleteProperty(language_mode());
3448 Node* result = NewNode(op, global, name);
3449 PrepareFrameState(result, bailout_id, combine);
3452 case VariableLocation::PARAMETER:
3453 case VariableLocation::LOCAL:
3454 case VariableLocation::CONTEXT: {
3455 // Local var, const, or let variable or context variable.
3456 return jsgraph()->BooleanConstant(variable->HasThisName(isolate()));
3458 case VariableLocation::LOOKUP: {
3459 // Dynamic lookup of context variable (anywhere in the chain).
3460 Node* name = jsgraph()->Constant(variable->name());
3461 const Operator* op =
3462 javascript()->CallRuntime(Runtime::kDeleteLookupSlot, 2);
3463 Node* result = NewNode(op, current_context(), name);
3464 PrepareFrameState(result, bailout_id, combine);
3473 Node* AstGraphBuilder::BuildVariableAssignment(
3474 Variable* variable, Node* value, Token::Value op,
3475 const VectorSlotPair& feedback, BailoutId bailout_id,
3476 FrameStateBeforeAndAfter& states, OutputFrameStateCombine combine) {
3477 Node* the_hole = jsgraph()->TheHoleConstant();
3478 VariableMode mode = variable->mode();
3479 switch (variable->location()) {
3480 case VariableLocation::GLOBAL:
3481 case VariableLocation::UNALLOCATED: {
3482 // Global var, const, or let variable.
3483 Node* script_context = current_context();
3484 int slot_index = -1;
3485 if (variable->index() > 0) {
3486 DCHECK(variable->IsStaticGlobalObjectProperty());
3487 slot_index = variable->index();
3488 int depth = current_scope()->ContextChainLength(variable->scope());
3490 const Operator* op = javascript()->LoadContext(
3491 depth - 1, Context::PREVIOUS_INDEX, true);
3492 script_context = NewNode(op, current_context());
3495 Node* global = BuildLoadGlobalObject();
3496 Handle<Name> name = variable->name();
3498 BuildGlobalStore(script_context, global, name, value, feedback,
3499 TypeFeedbackId::None(), slot_index);
3500 states.AddToNode(store, bailout_id, combine);
3503 case VariableLocation::PARAMETER:
3504 case VariableLocation::LOCAL:
3505 // Local var, const, or let variable.
3506 if (mode == CONST_LEGACY && op == Token::INIT_CONST_LEGACY) {
3507 // Perform an initialization check for legacy const variables.
3508 Node* current = environment()->Lookup(variable);
3509 if (current->op() != the_hole->op()) {
3510 value = BuildHoleCheckSilent(current, value, current);
3512 } else if (mode == CONST_LEGACY && op != Token::INIT_CONST_LEGACY) {
3513 // Non-initializing assignment to legacy const is
3514 // - exception in strict mode.
3515 // - ignored in sloppy mode.
3516 if (is_strict(language_mode())) {
3517 return BuildThrowConstAssignError(bailout_id);
3520 } else if (mode == LET && op != Token::INIT_LET) {
3521 // Perform an initialization check for let declared variables.
3522 // Also note that the dynamic hole-check is only done to ensure that
3523 // this does not break in the presence of do-expressions within the
3524 // temporal dead zone of a let declared variable.
3525 Node* current = environment()->Lookup(variable);
3526 if (current->op() == the_hole->op()) {
3527 value = BuildThrowReferenceError(variable, bailout_id);
3528 } else if (value->opcode() == IrOpcode::kPhi) {
3529 value = BuildHoleCheckThenThrow(current, variable, value, bailout_id);
3531 } else if (mode == CONST && op == Token::INIT_CONST) {
3532 // Perform an initialization check for const {this} variables.
3533 // Note that the {this} variable is the only const variable being able
3534 // to trigger bind operations outside the TDZ, via {super} calls.
3535 Node* current = environment()->Lookup(variable);
3536 if (current->op() != the_hole->op() && variable->is_this()) {
3537 value = BuildHoleCheckElseThrow(current, variable, value, bailout_id);
3539 } else if (mode == CONST && op != Token::INIT_CONST) {
3540 // Assignment to const is exception in all modes.
3541 Node* current = environment()->Lookup(variable);
3542 if (current->op() == the_hole->op()) {
3543 return BuildThrowReferenceError(variable, bailout_id);
3544 } else if (value->opcode() == IrOpcode::kPhi) {
3545 BuildHoleCheckThenThrow(current, variable, value, bailout_id);
3547 return BuildThrowConstAssignError(bailout_id);
3549 environment()->Bind(variable, value);
3551 case VariableLocation::CONTEXT: {
3552 // Context variable (potentially up the context chain).
3553 int depth = current_scope()->ContextChainLength(variable->scope());
3554 if (mode == CONST_LEGACY && op == Token::INIT_CONST_LEGACY) {
3555 // Perform an initialization check for legacy const variables.
3556 const Operator* op =
3557 javascript()->LoadContext(depth, variable->index(), false);
3558 Node* current = NewNode(op, current_context());
3559 value = BuildHoleCheckSilent(current, value, current);
3560 } else if (mode == CONST_LEGACY && op != Token::INIT_CONST_LEGACY) {
3561 // Non-initializing assignment to legacy const is
3562 // - exception in strict mode.
3563 // - ignored in sloppy mode.
3564 if (is_strict(language_mode())) {
3565 return BuildThrowConstAssignError(bailout_id);
3568 } else if (mode == LET && op != Token::INIT_LET) {
3569 // Perform an initialization check for let declared variables.
3570 const Operator* op =
3571 javascript()->LoadContext(depth, variable->index(), false);
3572 Node* current = NewNode(op, current_context());
3573 value = BuildHoleCheckThenThrow(current, variable, value, bailout_id);
3574 } else if (mode == CONST && op == Token::INIT_CONST) {
3575 // Perform an initialization check for const {this} variables.
3576 // Note that the {this} variable is the only const variable being able
3577 // to trigger bind operations outside the TDZ, via {super} calls.
3578 if (variable->is_this()) {
3579 const Operator* op =
3580 javascript()->LoadContext(depth, variable->index(), false);
3581 Node* current = NewNode(op, current_context());
3582 value = BuildHoleCheckElseThrow(current, variable, value, bailout_id);
3584 } else if (mode == CONST && op != Token::INIT_CONST) {
3585 // Assignment to const is exception in all modes.
3586 const Operator* op =
3587 javascript()->LoadContext(depth, variable->index(), false);
3588 Node* current = NewNode(op, current_context());
3589 BuildHoleCheckThenThrow(current, variable, value, bailout_id);
3590 return BuildThrowConstAssignError(bailout_id);
3592 const Operator* op = javascript()->StoreContext(depth, variable->index());
3593 return NewNode(op, current_context(), value);
3595 case VariableLocation::LOOKUP: {
3596 // Dynamic lookup of context variable (anywhere in the chain).
3597 Node* name = jsgraph()->Constant(variable->name());
3598 Node* language = jsgraph()->Constant(language_mode());
3599 // TODO(mstarzinger): Use Runtime::kInitializeLegacyConstLookupSlot for
3600 // initializations of const declarations.
3601 const Operator* op =
3602 javascript()->CallRuntime(Runtime::kStoreLookupSlot, 4);
3603 Node* store = NewNode(op, value, current_context(), name, language);
3604 PrepareFrameState(store, bailout_id, combine);
3613 static inline Node* Record(JSTypeFeedbackTable* js_type_feedback, Node* node,
3614 FeedbackVectorICSlot slot) {
3615 if (js_type_feedback) {
3616 js_type_feedback->Record(node, slot);
3622 static inline Node* Record(JSTypeFeedbackTable* js_type_feedback, Node* node,
3623 TypeFeedbackId id) {
3624 if (js_type_feedback) {
3625 js_type_feedback->Record(node, id);
3631 Node* AstGraphBuilder::BuildKeyedLoad(Node* object, Node* key,
3632 const VectorSlotPair& feedback) {
3633 const Operator* op = javascript()->LoadProperty(feedback, language_mode());
3634 Node* node = NewNode(op, object, key, BuildLoadFeedbackVector());
3635 return Record(js_type_feedback_, node, feedback.slot());
3639 Node* AstGraphBuilder::BuildNamedLoad(Node* object, Handle<Name> name,
3640 const VectorSlotPair& feedback) {
3641 const Operator* op =
3642 javascript()->LoadNamed(MakeUnique(name), feedback, language_mode());
3643 Node* node = NewNode(op, object, BuildLoadFeedbackVector());
3644 return Record(js_type_feedback_, node, feedback.slot());
3648 Node* AstGraphBuilder::BuildKeyedStore(Node* object, Node* key, Node* value,
3649 const VectorSlotPair& feedback,
3650 TypeFeedbackId id) {
3651 const Operator* op = javascript()->StoreProperty(language_mode(), feedback);
3652 Node* node = NewNode(op, object, key, value, BuildLoadFeedbackVector());
3653 if (FLAG_vector_stores) {
3654 return Record(js_type_feedback_, node, feedback.slot());
3656 return Record(js_type_feedback_, node, id);
3660 Node* AstGraphBuilder::BuildNamedStore(Node* object, Handle<Name> name,
3662 const VectorSlotPair& feedback,
3663 TypeFeedbackId id) {
3664 const Operator* op =
3665 javascript()->StoreNamed(language_mode(), MakeUnique(name), feedback);
3666 Node* node = NewNode(op, object, value, BuildLoadFeedbackVector());
3667 if (FLAG_vector_stores) {
3668 return Record(js_type_feedback_, node, feedback.slot());
3670 return Record(js_type_feedback_, node, id);
3674 Node* AstGraphBuilder::BuildNamedSuperLoad(Node* receiver, Node* home_object,
3676 const VectorSlotPair& feedback) {
3677 Node* name_node = jsgraph()->Constant(name);
3678 Node* language = jsgraph()->Constant(language_mode());
3679 const Operator* op = javascript()->CallRuntime(Runtime::kLoadFromSuper, 4);
3680 Node* node = NewNode(op, receiver, home_object, name_node, language);
3681 return Record(js_type_feedback_, node, feedback.slot());
3685 Node* AstGraphBuilder::BuildKeyedSuperLoad(Node* receiver, Node* home_object,
3687 const VectorSlotPair& feedback) {
3688 Node* language = jsgraph()->Constant(language_mode());
3689 const Operator* op =
3690 javascript()->CallRuntime(Runtime::kLoadKeyedFromSuper, 4);
3691 Node* node = NewNode(op, receiver, home_object, key, language);
3692 return Record(js_type_feedback_, node, feedback.slot());
3696 Node* AstGraphBuilder::BuildKeyedSuperStore(Node* receiver, Node* home_object,
3697 Node* key, Node* value,
3698 TypeFeedbackId id) {
3699 Runtime::FunctionId function_id = is_strict(language_mode())
3700 ? Runtime::kStoreKeyedToSuper_Strict
3701 : Runtime::kStoreKeyedToSuper_Sloppy;
3702 const Operator* op = javascript()->CallRuntime(function_id, 4);
3703 Node* node = NewNode(op, receiver, home_object, key, value);
3704 return Record(js_type_feedback_, node, id);
3708 Node* AstGraphBuilder::BuildNamedSuperStore(Node* receiver, Node* home_object,
3709 Handle<Name> name, Node* value,
3710 TypeFeedbackId id) {
3711 Node* name_node = jsgraph()->Constant(name);
3712 Runtime::FunctionId function_id = is_strict(language_mode())
3713 ? Runtime::kStoreToSuper_Strict
3714 : Runtime::kStoreToSuper_Sloppy;
3715 const Operator* op = javascript()->CallRuntime(function_id, 4);
3716 Node* node = NewNode(op, receiver, home_object, name_node, value);
3717 return Record(js_type_feedback_, node, id);
3721 Node* AstGraphBuilder::BuildGlobalLoad(Node* script_context, Node* global,
3723 const VectorSlotPair& feedback,
3724 TypeofMode typeof_mode, int slot_index) {
3725 const Operator* op = javascript()->LoadGlobal(MakeUnique(name), feedback,
3726 typeof_mode, slot_index);
3727 Node* node = NewNode(op, script_context, global, BuildLoadFeedbackVector());
3728 return Record(js_type_feedback_, node, feedback.slot());
3732 Node* AstGraphBuilder::BuildGlobalStore(Node* script_context, Node* global,
3733 Handle<Name> name, Node* value,
3734 const VectorSlotPair& feedback,
3735 TypeFeedbackId id, int slot_index) {
3736 const Operator* op = javascript()->StoreGlobal(
3737 language_mode(), MakeUnique(name), feedback, slot_index);
3739 NewNode(op, script_context, global, value, BuildLoadFeedbackVector());
3740 if (FLAG_vector_stores) {
3741 return Record(js_type_feedback_, node, feedback.slot());
3743 return Record(js_type_feedback_, node, id);
3747 Node* AstGraphBuilder::BuildLoadObjectField(Node* object, int offset) {
3748 return NewNode(jsgraph()->machine()->Load(kMachAnyTagged), object,
3749 jsgraph()->IntPtrConstant(offset - kHeapObjectTag));
3753 Node* AstGraphBuilder::BuildLoadImmutableObjectField(Node* object, int offset) {
3754 return graph()->NewNode(jsgraph()->machine()->Load(kMachAnyTagged), object,
3755 jsgraph()->IntPtrConstant(offset - kHeapObjectTag),
3756 graph()->start(), graph()->start());
3760 Node* AstGraphBuilder::BuildLoadBuiltinsObject() {
3761 Node* global = BuildLoadGlobalObject();
3763 BuildLoadObjectField(global, JSGlobalObject::kBuiltinsOffset);
3768 Node* AstGraphBuilder::BuildLoadGlobalObject() {
3769 const Operator* load_op =
3770 javascript()->LoadContext(0, Context::GLOBAL_OBJECT_INDEX, true);
3771 return NewNode(load_op, GetFunctionContext());
3775 Node* AstGraphBuilder::BuildLoadGlobalProxy() {
3776 Node* global = BuildLoadGlobalObject();
3778 BuildLoadObjectField(global, JSGlobalObject::kGlobalProxyOffset);
3783 Node* AstGraphBuilder::BuildLoadFeedbackVector() {
3784 if (!feedback_vector_.is_set()) {
3785 Node* closure = GetFunctionClosure();
3786 Node* shared = BuildLoadImmutableObjectField(
3787 closure, JSFunction::kSharedFunctionInfoOffset);
3788 Node* vector = BuildLoadImmutableObjectField(
3789 shared, SharedFunctionInfo::kFeedbackVectorOffset);
3790 feedback_vector_.set(vector);
3792 return feedback_vector_.get();
3796 Node* AstGraphBuilder::BuildLoadExternal(ExternalReference reference,
3798 return NewNode(jsgraph()->machine()->Load(type),
3799 jsgraph()->ExternalConstant(reference),
3800 jsgraph()->IntPtrConstant(0));
3804 Node* AstGraphBuilder::BuildStoreExternal(ExternalReference reference,
3805 MachineType type, Node* value) {
3806 StoreRepresentation representation(type, kNoWriteBarrier);
3807 return NewNode(jsgraph()->machine()->Store(representation),
3808 jsgraph()->ExternalConstant(reference),
3809 jsgraph()->IntPtrConstant(0), value);
3813 Node* AstGraphBuilder::BuildToBoolean(Node* input) {
3814 // TODO(bmeurer, mstarzinger): Refactor this into a separate optimization
3816 switch (input->opcode()) {
3817 case IrOpcode::kNumberConstant: {
3818 NumberMatcher m(input);
3819 return jsgraph_->BooleanConstant(!m.Is(0) && !m.IsNaN());
3821 case IrOpcode::kHeapConstant: {
3822 Handle<HeapObject> object = HeapObjectMatcher(input).Value().handle();
3823 return jsgraph_->BooleanConstant(object->BooleanValue());
3825 case IrOpcode::kJSEqual:
3826 case IrOpcode::kJSNotEqual:
3827 case IrOpcode::kJSStrictEqual:
3828 case IrOpcode::kJSStrictNotEqual:
3829 case IrOpcode::kJSLessThan:
3830 case IrOpcode::kJSLessThanOrEqual:
3831 case IrOpcode::kJSGreaterThan:
3832 case IrOpcode::kJSGreaterThanOrEqual:
3833 case IrOpcode::kJSUnaryNot:
3834 case IrOpcode::kJSToBoolean:
3835 case IrOpcode::kJSDeleteProperty:
3836 case IrOpcode::kJSHasProperty:
3837 case IrOpcode::kJSInstanceOf:
3842 return NewNode(javascript()->ToBoolean(), input);
3846 Node* AstGraphBuilder::BuildToName(Node* input, BailoutId bailout_id) {
3847 // TODO(turbofan): Possible optimization is to NOP on name constants. But the
3848 // same caveat as with BuildToBoolean applies, and it should be factored out
3849 // into a JSOperatorReducer.
3850 Node* name = NewNode(javascript()->ToName(), input);
3851 PrepareFrameState(name, bailout_id);
3856 Node* AstGraphBuilder::BuildToObject(Node* input, BailoutId bailout_id) {
3857 Node* object = NewNode(javascript()->ToObject(), input);
3858 PrepareFrameState(object, bailout_id, OutputFrameStateCombine::Push());
3863 Node* AstGraphBuilder::BuildSetHomeObject(Node* value, Node* home_object,
3865 const VectorSlotPair& feedback) {
3866 if (!FunctionLiteral::NeedsHomeObject(expr)) return value;
3867 Handle<Name> name = isolate()->factory()->home_object_symbol();
3868 FrameStateBeforeAndAfter states(this, BailoutId::None());
3869 Node* store = BuildNamedStore(value, name, home_object, feedback,
3870 TypeFeedbackId::None());
3871 states.AddToNode(store, BailoutId::None(), OutputFrameStateCombine::Ignore());
3876 Node* AstGraphBuilder::BuildThrowError(Node* exception, BailoutId bailout_id) {
3877 const Operator* op = javascript()->CallRuntime(Runtime::kThrow, 1);
3878 Node* call = NewNode(op, exception);
3879 PrepareFrameState(call, bailout_id);
3880 Node* control = NewNode(common()->Throw(), call);
3881 UpdateControlDependencyToLeaveFunction(control);
3886 Node* AstGraphBuilder::BuildThrowReferenceError(Variable* variable,
3887 BailoutId bailout_id) {
3888 Node* variable_name = jsgraph()->Constant(variable->name());
3889 const Operator* op =
3890 javascript()->CallRuntime(Runtime::kThrowReferenceError, 1);
3891 Node* call = NewNode(op, variable_name);
3892 PrepareFrameState(call, bailout_id);
3893 Node* control = NewNode(common()->Throw(), call);
3894 UpdateControlDependencyToLeaveFunction(control);
3899 Node* AstGraphBuilder::BuildThrowConstAssignError(BailoutId bailout_id) {
3900 const Operator* op =
3901 javascript()->CallRuntime(Runtime::kThrowConstAssignError, 0);
3902 Node* call = NewNode(op);
3903 PrepareFrameState(call, bailout_id);
3904 Node* control = NewNode(common()->Throw(), call);
3905 UpdateControlDependencyToLeaveFunction(control);
3910 Node* AstGraphBuilder::BuildThrowStaticPrototypeError(BailoutId bailout_id) {
3911 const Operator* op =
3912 javascript()->CallRuntime(Runtime::kThrowStaticPrototypeError, 0);
3913 Node* call = NewNode(op);
3914 PrepareFrameState(call, bailout_id);
3915 Node* control = NewNode(common()->Throw(), call);
3916 UpdateControlDependencyToLeaveFunction(control);
3921 Node* AstGraphBuilder::BuildThrowUnsupportedSuperError(BailoutId bailout_id) {
3922 const Operator* op =
3923 javascript()->CallRuntime(Runtime::kThrowUnsupportedSuperError, 0);
3924 Node* call = NewNode(op);
3925 PrepareFrameState(call, bailout_id);
3926 Node* control = NewNode(common()->Throw(), call);
3927 UpdateControlDependencyToLeaveFunction(control);
3932 Node* AstGraphBuilder::BuildReturn(Node* return_value) {
3933 Node* control = NewNode(common()->Return(), return_value);
3934 UpdateControlDependencyToLeaveFunction(control);
3939 Node* AstGraphBuilder::BuildThrow(Node* exception_value) {
3940 NewNode(javascript()->CallRuntime(Runtime::kReThrow, 1), exception_value);
3941 Node* control = NewNode(common()->Throw(), exception_value);
3942 UpdateControlDependencyToLeaveFunction(control);
3947 Node* AstGraphBuilder::BuildBinaryOp(Node* left, Node* right, Token::Value op) {
3948 const Operator* js_op;
3951 js_op = javascript()->BitwiseOr(language_mode());
3953 case Token::BIT_AND:
3954 js_op = javascript()->BitwiseAnd(language_mode());
3956 case Token::BIT_XOR:
3957 js_op = javascript()->BitwiseXor(language_mode());
3960 js_op = javascript()->ShiftLeft(language_mode());
3963 js_op = javascript()->ShiftRight(language_mode());
3966 js_op = javascript()->ShiftRightLogical(language_mode());
3969 js_op = javascript()->Add(language_mode());
3972 js_op = javascript()->Subtract(language_mode());
3975 js_op = javascript()->Multiply(language_mode());
3978 js_op = javascript()->Divide(language_mode());
3981 js_op = javascript()->Modulus(language_mode());
3987 return NewNode(js_op, left, right);
3991 bool AstGraphBuilder::CheckOsrEntry(IterationStatement* stmt) {
3992 if (info()->osr_ast_id() == stmt->OsrEntryId()) {
3993 info()->set_osr_expr_stack_height(std::max(
3994 environment()->stack_height(), info()->osr_expr_stack_height()));
4001 void AstGraphBuilder::PrepareFrameState(Node* node, BailoutId ast_id,
4002 OutputFrameStateCombine combine) {
4003 if (OperatorProperties::GetFrameStateInputCount(node->op()) > 0) {
4004 DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));
4006 DCHECK_EQ(IrOpcode::kDead,
4007 NodeProperties::GetFrameStateInput(node, 0)->opcode());
4008 NodeProperties::ReplaceFrameStateInput(
4009 node, 0, environment()->Checkpoint(ast_id, combine));
4014 BitVector* AstGraphBuilder::GetVariablesAssignedInLoop(
4015 IterationStatement* stmt) {
4016 if (loop_assignment_analysis_ == NULL) return NULL;
4017 return loop_assignment_analysis_->GetVariablesAssignedInLoop(stmt);
4021 Node** AstGraphBuilder::EnsureInputBufferSize(int size) {
4022 if (size > input_buffer_size_) {
4023 size = size + kInputBufferSizeIncrement + input_buffer_size_;
4024 input_buffer_ = local_zone()->NewArray<Node*>(size);
4025 input_buffer_size_ = size;
4027 return input_buffer_;
4031 Node* AstGraphBuilder::MakeNode(const Operator* op, int value_input_count,
4032 Node** value_inputs, bool incomplete) {
4033 DCHECK_EQ(op->ValueInputCount(), value_input_count);
4035 bool has_context = OperatorProperties::HasContextInput(op);
4036 int frame_state_count = OperatorProperties::GetFrameStateInputCount(op);
4037 bool has_control = op->ControlInputCount() == 1;
4038 bool has_effect = op->EffectInputCount() == 1;
4040 DCHECK(op->ControlInputCount() < 2);
4041 DCHECK(op->EffectInputCount() < 2);
4043 Node* result = NULL;
4044 if (!has_context && frame_state_count == 0 && !has_control && !has_effect) {
4045 result = graph()->NewNode(op, value_input_count, value_inputs, incomplete);
4047 bool inside_try_scope = try_nesting_level_ > 0;
4048 int input_count_with_deps = value_input_count;
4049 if (has_context) ++input_count_with_deps;
4050 input_count_with_deps += frame_state_count;
4051 if (has_control) ++input_count_with_deps;
4052 if (has_effect) ++input_count_with_deps;
4053 Node** buffer = EnsureInputBufferSize(input_count_with_deps);
4054 memcpy(buffer, value_inputs, kPointerSize * value_input_count);
4055 Node** current_input = buffer + value_input_count;
4057 *current_input++ = current_context();
4059 for (int i = 0; i < frame_state_count; i++) {
4060 // The frame state will be inserted later. Here we misuse
4061 // the {Dead} node as a sentinel to be later overwritten
4062 // with the real frame state.
4063 *current_input++ = jsgraph()->Dead();
4066 *current_input++ = environment_->GetEffectDependency();
4069 *current_input++ = environment_->GetControlDependency();
4071 result = graph()->NewNode(op, input_count_with_deps, buffer, incomplete);
4072 if (!environment()->IsMarkedAsUnreachable()) {
4073 // Update the current control dependency for control-producing nodes.
4074 if (NodeProperties::IsControl(result)) {
4075 environment_->UpdateControlDependency(result);
4077 // Update the current effect dependency for effect-producing nodes.
4078 if (result->op()->EffectOutputCount() > 0) {
4079 environment_->UpdateEffectDependency(result);
4081 // Add implicit exception continuation for throwing nodes.
4082 if (!result->op()->HasProperty(Operator::kNoThrow) && inside_try_scope) {
4083 // Conservative prediction whether caught locally.
4084 IfExceptionHint hint = try_catch_nesting_level_ > 0
4085 ? IfExceptionHint::kLocallyCaught
4086 : IfExceptionHint::kLocallyUncaught;
4087 // Copy the environment for the success continuation.
4088 Environment* success_env = environment()->CopyForConditional();
4089 const Operator* op = common()->IfException(hint);
4090 Node* effect = environment()->GetEffectDependency();
4091 Node* on_exception = graph()->NewNode(op, effect, result);
4092 environment_->UpdateControlDependency(on_exception);
4093 environment_->UpdateEffectDependency(on_exception);
4094 execution_control()->ThrowValue(on_exception);
4095 set_environment(success_env);
4097 // Add implicit success continuation for throwing nodes.
4098 if (!result->op()->HasProperty(Operator::kNoThrow)) {
4099 const Operator* op = common()->IfSuccess();
4100 Node* on_success = graph()->NewNode(op, result);
4101 environment_->UpdateControlDependency(on_success);
4110 void AstGraphBuilder::UpdateControlDependencyToLeaveFunction(Node* exit) {
4111 if (environment()->IsMarkedAsUnreachable()) return;
4112 environment()->MarkAsUnreachable();
4113 exit_controls_.push_back(exit);
4117 void AstGraphBuilder::Environment::Merge(Environment* other) {
4118 DCHECK(values_.size() == other->values_.size());
4119 DCHECK(contexts_.size() == other->contexts_.size());
4121 // Nothing to do if the other environment is dead.
4122 if (other->IsMarkedAsUnreachable()) return;
4124 // Resurrect a dead environment by copying the contents of the other one and
4125 // placing a singleton merge as the new control dependency.
4126 if (this->IsMarkedAsUnreachable()) {
4127 Node* other_control = other->control_dependency_;
4128 Node* inputs[] = {other_control};
4129 control_dependency_ =
4130 graph()->NewNode(common()->Merge(1), arraysize(inputs), inputs, true);
4131 effect_dependency_ = other->effect_dependency_;
4132 values_ = other->values_;
4133 contexts_ = other->contexts_;
4134 if (IsLivenessAnalysisEnabled()) {
4136 builder_->liveness_analyzer()->NewBlock(other->liveness_block());
4141 // Record the merge for the local variable liveness calculation.
4142 // For loops, we are connecting a back edge into the existing block;
4143 // for merges, we create a new merged block.
4144 if (IsLivenessAnalysisEnabled()) {
4145 if (GetControlDependency()->opcode() != IrOpcode::kLoop) {
4147 builder_->liveness_analyzer()->NewBlock(liveness_block());
4149 liveness_block()->AddPredecessor(other->liveness_block());
4152 // Create a merge of the control dependencies of both environments and update
4153 // the current environment's control dependency accordingly.
4154 Node* control = builder_->MergeControl(this->GetControlDependency(),
4155 other->GetControlDependency());
4156 UpdateControlDependency(control);
4158 // Create a merge of the effect dependencies of both environments and update
4159 // the current environment's effect dependency accordingly.
4160 Node* effect = builder_->MergeEffect(this->GetEffectDependency(),
4161 other->GetEffectDependency(), control);
4162 UpdateEffectDependency(effect);
4164 // Introduce Phi nodes for values that have differing input at merge points,
4165 // potentially extending an existing Phi node if possible.
4166 for (int i = 0; i < static_cast<int>(values_.size()); ++i) {
4167 values_[i] = builder_->MergeValue(values_[i], other->values_[i], control);
4169 for (int i = 0; i < static_cast<int>(contexts_.size()); ++i) {
4171 builder_->MergeValue(contexts_[i], other->contexts_[i], control);
4176 void AstGraphBuilder::Environment::PrepareForLoop(BitVector* assigned,
4178 int size = static_cast<int>(values()->size());
4180 Node* control = builder_->NewLoop();
4181 if (assigned == nullptr) {
4182 // Assume that everything is updated in the loop.
4183 for (int i = 0; i < size; ++i) {
4184 values()->at(i) = builder_->NewPhi(1, values()->at(i), control);
4187 // Only build phis for those locals assigned in this loop.
4188 for (int i = 0; i < size; ++i) {
4189 if (i < assigned->length() && !assigned->Contains(i)) continue;
4190 Node* phi = builder_->NewPhi(1, values()->at(i), control);
4191 values()->at(i) = phi;
4194 Node* effect = builder_->NewEffectPhi(1, GetEffectDependency(), control);
4195 UpdateEffectDependency(effect);
4197 // Connect the loop to end via Terminate if it's not marked as unreachable.
4198 if (!IsMarkedAsUnreachable()) {
4199 // Connect the Loop node to end via a Terminate node.
4200 Node* terminate = builder_->graph()->NewNode(
4201 builder_->common()->Terminate(), effect, control);
4202 builder_->exit_controls_.push_back(terminate);
4205 if (builder_->info()->is_osr()) {
4206 // Introduce phis for all context values in the case of an OSR graph.
4207 for (size_t i = 0; i < contexts()->size(); ++i) {
4208 Node* context = contexts()->at(i);
4209 contexts()->at(i) = builder_->NewPhi(1, context, control);
4214 // Merge OSR values as inputs to the phis of the loop.
4215 Graph* graph = builder_->graph();
4216 Node* osr_loop_entry = builder_->graph()->NewNode(
4217 builder_->common()->OsrLoopEntry(), graph->start(), graph->start());
4219 builder_->MergeControl(control, osr_loop_entry);
4220 builder_->MergeEffect(effect, osr_loop_entry, control);
4222 for (int i = 0; i < size; ++i) {
4223 Node* value = values()->at(i);
4225 graph->NewNode(builder_->common()->OsrValue(i), osr_loop_entry);
4226 values()->at(i) = builder_->MergeValue(value, osr_value, control);
4229 // Rename all the contexts in the environment.
4230 // The innermost context is the OSR value, and the outer contexts are
4231 // reconstructed by dynamically walking up the context chain.
4232 Node* osr_context = nullptr;
4233 const Operator* op =
4234 builder_->javascript()->LoadContext(0, Context::PREVIOUS_INDEX, true);
4235 const Operator* op_inner =
4236 builder_->common()->OsrValue(Linkage::kOsrContextSpillSlotIndex);
4237 int last = static_cast<int>(contexts()->size() - 1);
4238 for (int i = last; i >= 0; i--) {
4239 Node* context = contexts()->at(i);
4240 osr_context = (i == last) ? graph->NewNode(op_inner, osr_loop_entry)
4241 : graph->NewNode(op, osr_context, osr_context,
4243 contexts()->at(i) = builder_->MergeValue(context, osr_context, control);
4249 Node* AstGraphBuilder::NewPhi(int count, Node* input, Node* control) {
4250 const Operator* phi_op = common()->Phi(kMachAnyTagged, count);
4251 Node** buffer = EnsureInputBufferSize(count + 1);
4252 MemsetPointer(buffer, input, count);
4253 buffer[count] = control;
4254 return graph()->NewNode(phi_op, count + 1, buffer, true);
4258 // TODO(mstarzinger): Revisit this once we have proper effect states.
4259 Node* AstGraphBuilder::NewEffectPhi(int count, Node* input, Node* control) {
4260 const Operator* phi_op = common()->EffectPhi(count);
4261 Node** buffer = EnsureInputBufferSize(count + 1);
4262 MemsetPointer(buffer, input, count);
4263 buffer[count] = control;
4264 return graph()->NewNode(phi_op, count + 1, buffer, true);
4268 Node* AstGraphBuilder::MergeControl(Node* control, Node* other) {
4269 int inputs = control->op()->ControlInputCount() + 1;
4270 if (control->opcode() == IrOpcode::kLoop) {
4271 // Control node for loop exists, add input.
4272 const Operator* op = common()->Loop(inputs);
4273 control->AppendInput(graph_zone(), other);
4274 control->set_op(op);
4275 } else if (control->opcode() == IrOpcode::kMerge) {
4276 // Control node for merge exists, add input.
4277 const Operator* op = common()->Merge(inputs);
4278 control->AppendInput(graph_zone(), other);
4279 control->set_op(op);
4281 // Control node is a singleton, introduce a merge.
4282 const Operator* op = common()->Merge(inputs);
4283 Node* inputs[] = {control, other};
4284 control = graph()->NewNode(op, arraysize(inputs), inputs, true);
4290 Node* AstGraphBuilder::MergeEffect(Node* value, Node* other, Node* control) {
4291 int inputs = control->op()->ControlInputCount();
4292 if (value->opcode() == IrOpcode::kEffectPhi &&
4293 NodeProperties::GetControlInput(value) == control) {
4294 // Phi already exists, add input.
4295 value->set_op(common()->EffectPhi(inputs));
4296 value->InsertInput(graph_zone(), inputs - 1, other);
4297 } else if (value != other) {
4298 // Phi does not exist yet, introduce one.
4299 value = NewEffectPhi(inputs, value, control);
4300 value->ReplaceInput(inputs - 1, other);
4306 Node* AstGraphBuilder::MergeValue(Node* value, Node* other, Node* control) {
4307 int inputs = control->op()->ControlInputCount();
4308 if (value->opcode() == IrOpcode::kPhi &&
4309 NodeProperties::GetControlInput(value) == control) {
4310 // Phi already exists, add input.
4311 value->set_op(common()->Phi(kMachAnyTagged, inputs));
4312 value->InsertInput(graph_zone(), inputs - 1, other);
4313 } else if (value != other) {
4314 // Phi does not exist yet, introduce one.
4315 value = NewPhi(inputs, value, control);
4316 value->ReplaceInput(inputs - 1, other);
4321 } // namespace compiler
4322 } // namespace internal