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. 4 5 #include "src/compiler/ast-graph-builder.h" 6 7 #include "src/ast/compile-time-value.h" 8 #include "src/ast/scopes.h" 9 #include "src/compilation-info.h" 10 #include "src/compiler.h" 11 #include "src/compiler/ast-loop-assignment-analyzer.h" 12 #include "src/compiler/control-builders.h" 13 #include "src/compiler/linkage.h" 14 #include "src/compiler/liveness-analyzer.h" 15 #include "src/compiler/machine-operator.h" 16 #include "src/compiler/node-matchers.h" 17 #include "src/compiler/node-properties.h" 18 #include "src/compiler/operator-properties.h" 19 #include "src/compiler/state-values-utils.h" 20 #include "src/compiler/type-hint-analyzer.h" 21 22 namespace v8 { 23 namespace internal { 24 namespace compiler { 25 26 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 { 30 public: 31 bool IsEffect() const { return kind_ == Expression::kEffect; } 32 bool IsValue() const { return kind_ == Expression::kValue; } 33 bool IsTest() const { return kind_ == Expression::kTest; } 34 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(); 40 } 41 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(Expression* expr, Node* value) = 0; 45 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; 49 50 // Shortcut for "context->ProduceValue(context->ConsumeValue())". 51 void ReplaceValue(Expression* expr) { ProduceValue(expr, ConsumeValue()); } 52 53 protected: 54 AstContext(AstGraphBuilder* owner, Expression::Context kind); 55 virtual ~AstContext(); 56 57 AstGraphBuilder* owner() const { return owner_; } 58 Environment* environment() const { return owner_->environment(); } 59 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. 62 #ifdef DEBUG 63 int original_height_; 64 #endif 65 66 private: 67 Expression::Context kind_; 68 AstGraphBuilder* owner_; 69 AstContext* outer_; 70 }; 71 72 73 // Context to evaluate expression for its side effects only. 74 class AstGraphBuilder::AstEffectContext final : public AstContext { 75 public: 76 explicit AstEffectContext(AstGraphBuilder* owner) 77 : AstContext(owner, Expression::kEffect) {} 78 ~AstEffectContext() final; 79 void ProduceValue(Expression* expr, Node* value) final; 80 Node* ConsumeValue() final; 81 }; 82 83 84 // Context to evaluate expression for its value (and side effects). 85 class AstGraphBuilder::AstValueContext final : public AstContext { 86 public: 87 explicit AstValueContext(AstGraphBuilder* owner) 88 : AstContext(owner, Expression::kValue) {} 89 ~AstValueContext() final; 90 void ProduceValue(Expression* expr, Node* value) final; 91 Node* ConsumeValue() final; 92 }; 93 94 95 // Context to evaluate expression for a condition value (and side effects). 96 class AstGraphBuilder::AstTestContext final : public AstContext { 97 public: 98 AstTestContext(AstGraphBuilder* owner, TypeFeedbackId feedback_id) 99 : AstContext(owner, Expression::kTest), feedback_id_(feedback_id) {} 100 ~AstTestContext() final; 101 void ProduceValue(Expression* expr, Node* value) final; 102 Node* ConsumeValue() final; 103 104 private: 105 TypeFeedbackId const feedback_id_; 106 }; 107 108 109 // Scoped class tracking context objects created by the visitor. Represents 110 // mutations of the context chain within the function body and allows to 111 // change the current {scope} and {context} during visitation. 112 class AstGraphBuilder::ContextScope BASE_EMBEDDED { 113 public: 114 ContextScope(AstGraphBuilder* builder, Scope* scope, Node* context) 115 : builder_(builder), 116 outer_(builder->execution_context()), 117 scope_(scope), 118 depth_(builder_->environment()->context_chain_length()) { 119 builder_->environment()->PushContext(context); // Push. 120 builder_->set_execution_context(this); 121 } 122 123 ~ContextScope() { 124 builder_->set_execution_context(outer_); // Pop. 125 builder_->environment()->PopContext(); 126 CHECK_EQ(depth_, builder_->environment()->context_chain_length()); 127 } 128 129 // Current scope during visitation. 130 Scope* scope() const { return scope_; } 131 132 private: 133 AstGraphBuilder* builder_; 134 ContextScope* outer_; 135 Scope* scope_; 136 int depth_; 137 }; 138 139 140 // Scoped class tracking control statements entered by the visitor. There are 141 // different types of statements participating in this stack to properly track 142 // local as well as non-local control flow: 143 // - IterationStatement : Allows proper 'break' and 'continue' behavior. 144 // - BreakableStatement : Allows 'break' from block and switch statements. 145 // - TryCatchStatement : Intercepts 'throw' and implicit exceptional edges. 146 // - TryFinallyStatement: Intercepts 'break', 'continue', 'throw' and 'return'. 147 class AstGraphBuilder::ControlScope BASE_EMBEDDED { 148 public: 149 explicit ControlScope(AstGraphBuilder* builder) 150 : builder_(builder), 151 outer_(builder->execution_control()), 152 context_length_(builder->environment()->context_chain_length()), 153 stack_height_(builder->environment()->stack_height()) { 154 builder_->set_execution_control(this); // Push. 155 } 156 157 virtual ~ControlScope() { 158 builder_->set_execution_control(outer_); // Pop. 159 } 160 161 // Either 'break' or 'continue' to the target statement. 162 void BreakTo(BreakableStatement* target); 163 void ContinueTo(BreakableStatement* target); 164 165 // Either 'return' or 'throw' the given value. 166 void ReturnValue(Node* return_value); 167 void ThrowValue(Node* exception_value); 168 169 class DeferredCommands; 170 171 protected: 172 enum Command { CMD_BREAK, CMD_CONTINUE, CMD_RETURN, CMD_THROW }; 173 174 // Performs one of the above commands on this stack of control scopes. This 175 // walks through the stack giving each scope a chance to execute or defer the 176 // given command by overriding the {Execute} method appropriately. Note that 177 // this also drops extra operands from the environment for each skipped scope. 178 void PerformCommand(Command cmd, Statement* target, Node* value); 179 180 // Interface to execute a given command in this scope. Returning {true} here 181 // indicates successful execution whereas {false} requests to skip scope. 182 virtual bool Execute(Command cmd, Statement* target, Node** value) { 183 // For function-level control. 184 switch (cmd) { 185 case CMD_THROW: 186 builder()->BuildThrow(*value); 187 return true; 188 case CMD_RETURN: 189 builder()->BuildReturn(*value); 190 return true; 191 case CMD_BREAK: 192 case CMD_CONTINUE: 193 break; 194 } 195 return false; 196 } 197 198 Environment* environment() { return builder_->environment(); } 199 AstGraphBuilder* builder() const { return builder_; } 200 int context_length() const { return context_length_; } 201 int stack_height() const { return stack_height_; } 202 203 private: 204 AstGraphBuilder* builder_; 205 ControlScope* outer_; 206 int context_length_; 207 int stack_height_; 208 }; 209 210 // Helper class for a try-finally control scope. It can record intercepted 211 // control-flow commands that cause entry into a finally-block, and re-apply 212 // them after again leaving that block. Special tokens are used to identify 213 // paths going through the finally-block to dispatch after leaving the block. 214 class AstGraphBuilder::ControlScope::DeferredCommands : public ZoneObject { 215 public: 216 explicit DeferredCommands(AstGraphBuilder* owner) 217 : owner_(owner), 218 deferred_(owner->local_zone()), 219 return_token_(nullptr), 220 throw_token_(nullptr) {} 221 222 // One recorded control-flow command. 223 struct Entry { 224 Command command; // The command type being applied on this path. 225 Statement* statement; // The target statement for the command or {nullptr}. 226 Node* token; // A token identifying this particular path. 227 }; 228 229 // Records a control-flow command while entering the finally-block. This also 230 // generates a new dispatch token that identifies one particular path. 231 Node* RecordCommand(Command cmd, Statement* stmt, Node* value) { 232 Node* token = nullptr; 233 switch (cmd) { 234 case CMD_BREAK: 235 case CMD_CONTINUE: 236 token = NewPathToken(dispenser_.GetBreakContinueToken()); 237 break; 238 case CMD_THROW: 239 if (throw_token_) return throw_token_; 240 token = NewPathToken(TokenDispenserForFinally::kThrowToken); 241 throw_token_ = token; 242 break; 243 case CMD_RETURN: 244 if (return_token_) return return_token_; 245 token = NewPathToken(TokenDispenserForFinally::kReturnToken); 246 return_token_ = token; 247 break; 248 } 249 DCHECK_NOT_NULL(token); 250 deferred_.push_back({cmd, stmt, token}); 251 return token; 252 } 253 254 // Returns the dispatch token to be used to identify the implicit fall-through 255 // path at the end of a try-block into the corresponding finally-block. 256 Node* GetFallThroughToken() { return NewPathTokenForImplicitFallThrough(); } 257 258 // Applies all recorded control-flow commands after the finally-block again. 259 // This generates a dynamic dispatch on the token from the entry point. 260 void ApplyDeferredCommands(Node* token, Node* value) { 261 SwitchBuilder dispatch(owner_, static_cast<int>(deferred_.size())); 262 dispatch.BeginSwitch(); 263 for (size_t i = 0; i < deferred_.size(); ++i) { 264 Node* condition = NewPathDispatchCondition(token, deferred_[i].token); 265 dispatch.BeginLabel(static_cast<int>(i), condition); 266 dispatch.EndLabel(); 267 } 268 for (size_t i = 0; i < deferred_.size(); ++i) { 269 dispatch.BeginCase(static_cast<int>(i)); 270 owner_->execution_control()->PerformCommand( 271 deferred_[i].command, deferred_[i].statement, value); 272 dispatch.EndCase(); 273 } 274 dispatch.EndSwitch(); 275 } 276 277 protected: 278 Node* NewPathToken(int token_id) { 279 return owner_->jsgraph()->Constant(token_id); 280 } 281 Node* NewPathTokenForImplicitFallThrough() { 282 return NewPathToken(TokenDispenserForFinally::kFallThroughToken); 283 } 284 Node* NewPathDispatchCondition(Node* t1, Node* t2) { 285 return owner_->NewNode( 286 owner_->javascript()->StrictEqual(CompareOperationHint::kAny), t1, t2); 287 } 288 289 private: 290 TokenDispenserForFinally dispenser_; 291 AstGraphBuilder* owner_; 292 ZoneVector<Entry> deferred_; 293 Node* return_token_; 294 Node* throw_token_; 295 }; 296 297 298 // Control scope implementation for a BreakableStatement. 299 class AstGraphBuilder::ControlScopeForBreakable : public ControlScope { 300 public: 301 ControlScopeForBreakable(AstGraphBuilder* owner, BreakableStatement* target, 302 ControlBuilder* control) 303 : ControlScope(owner), target_(target), control_(control) {} 304 305 protected: 306 bool Execute(Command cmd, Statement* target, Node** value) override { 307 if (target != target_) return false; // We are not the command target. 308 switch (cmd) { 309 case CMD_BREAK: 310 control_->Break(); 311 return true; 312 case CMD_CONTINUE: 313 case CMD_THROW: 314 case CMD_RETURN: 315 break; 316 } 317 return false; 318 } 319 320 private: 321 BreakableStatement* target_; 322 ControlBuilder* control_; 323 }; 324 325 326 // Control scope implementation for an IterationStatement. 327 class AstGraphBuilder::ControlScopeForIteration : public ControlScope { 328 public: 329 ControlScopeForIteration(AstGraphBuilder* owner, IterationStatement* target, 330 LoopBuilder* control) 331 : ControlScope(owner), target_(target), control_(control) {} 332 333 protected: 334 bool Execute(Command cmd, Statement* target, Node** value) override { 335 if (target != target_) { 336 control_->ExitLoop(value); 337 return false; 338 } 339 switch (cmd) { 340 case CMD_BREAK: 341 control_->Break(); 342 return true; 343 case CMD_CONTINUE: 344 control_->Continue(); 345 return true; 346 case CMD_THROW: 347 case CMD_RETURN: 348 break; 349 } 350 return false; 351 } 352 353 private: 354 BreakableStatement* target_; 355 LoopBuilder* control_; 356 }; 357 358 359 // Control scope implementation for a TryCatchStatement. 360 class AstGraphBuilder::ControlScopeForCatch : public ControlScope { 361 public: 362 ControlScopeForCatch(AstGraphBuilder* owner, TryCatchStatement* stmt, 363 TryCatchBuilder* control) 364 : ControlScope(owner), control_(control) { 365 builder()->try_nesting_level_++; // Increment nesting. 366 } 367 ~ControlScopeForCatch() { 368 builder()->try_nesting_level_--; // Decrement nesting. 369 } 370 371 protected: 372 bool Execute(Command cmd, Statement* target, Node** value) override { 373 switch (cmd) { 374 case CMD_THROW: 375 control_->Throw(*value); 376 return true; 377 case CMD_BREAK: 378 case CMD_CONTINUE: 379 case CMD_RETURN: 380 break; 381 } 382 return false; 383 } 384 385 private: 386 TryCatchBuilder* control_; 387 }; 388 389 390 // Control scope implementation for a TryFinallyStatement. 391 class AstGraphBuilder::ControlScopeForFinally : public ControlScope { 392 public: 393 ControlScopeForFinally(AstGraphBuilder* owner, TryFinallyStatement* stmt, 394 DeferredCommands* commands, TryFinallyBuilder* control) 395 : ControlScope(owner), commands_(commands), control_(control) { 396 builder()->try_nesting_level_++; // Increment nesting. 397 } 398 ~ControlScopeForFinally() { 399 builder()->try_nesting_level_--; // Decrement nesting. 400 } 401 402 protected: 403 bool Execute(Command cmd, Statement* target, Node** value) override { 404 Node* token = commands_->RecordCommand(cmd, target, *value); 405 control_->LeaveTry(token, *value); 406 return true; 407 } 408 409 private: 410 DeferredCommands* commands_; 411 TryFinallyBuilder* control_; 412 }; 413 414 AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info, 415 JSGraph* jsgraph, float invocation_frequency, 416 LoopAssignmentAnalysis* loop, 417 TypeHintAnalysis* type_hint_analysis) 418 : isolate_(info->isolate()), 419 local_zone_(local_zone), 420 info_(info), 421 jsgraph_(jsgraph), 422 invocation_frequency_(invocation_frequency), 423 environment_(nullptr), 424 ast_context_(nullptr), 425 globals_(0, local_zone), 426 execution_control_(nullptr), 427 execution_context_(nullptr), 428 try_nesting_level_(0), 429 input_buffer_size_(0), 430 input_buffer_(nullptr), 431 exit_controls_(local_zone), 432 loop_assignment_analysis_(loop), 433 type_hint_analysis_(type_hint_analysis), 434 state_values_cache_(jsgraph), 435 liveness_analyzer_(static_cast<size_t>(info->scope()->num_stack_slots()), 436 false, local_zone), 437 frame_state_function_info_(common()->CreateFrameStateFunctionInfo( 438 FrameStateType::kJavaScriptFunction, info->num_parameters() + 1, 439 info->scope()->num_stack_slots(), info->shared_info())) { 440 InitializeAstVisitor(info->isolate()); 441 } 442 443 444 Node* AstGraphBuilder::GetFunctionClosureForContext() { 445 DeclarationScope* closure_scope = current_scope()->GetClosureScope(); 446 if (closure_scope->is_script_scope() || 447 closure_scope->is_module_scope()) { 448 // Contexts nested in the native context have a canonical empty function as 449 // their closure, not the anonymous closure containing the global code. 450 return BuildLoadNativeContextField(Context::CLOSURE_INDEX); 451 } else if (closure_scope->is_eval_scope()) { 452 // Contexts nested inside eval code have the same closure as the context 453 // calling eval, not the anonymous closure containing the eval code. 454 const Operator* op = 455 javascript()->LoadContext(0, Context::CLOSURE_INDEX, false); 456 return NewNode(op, current_context()); 457 } else { 458 DCHECK(closure_scope->is_function_scope()); 459 return GetFunctionClosure(); 460 } 461 } 462 463 464 Node* AstGraphBuilder::GetFunctionClosure() { 465 if (!function_closure_.is_set()) { 466 int index = Linkage::kJSCallClosureParamIndex; 467 const Operator* op = common()->Parameter(index, "%closure"); 468 Node* node = NewNode(op, graph()->start()); 469 function_closure_.set(node); 470 } 471 return function_closure_.get(); 472 } 473 474 475 Node* AstGraphBuilder::GetFunctionContext() { 476 if (!function_context_.is_set()) { 477 int params = info()->num_parameters_including_this(); 478 int index = Linkage::GetJSCallContextParamIndex(params); 479 const Operator* op = common()->Parameter(index, "%context"); 480 Node* node = NewNode(op, graph()->start()); 481 function_context_.set(node); 482 } 483 return function_context_.get(); 484 } 485 486 487 Node* AstGraphBuilder::GetNewTarget() { 488 if (!new_target_.is_set()) { 489 int params = info()->num_parameters_including_this(); 490 int index = Linkage::GetJSCallNewTargetParamIndex(params); 491 const Operator* op = common()->Parameter(index, "%new.target"); 492 Node* node = NewNode(op, graph()->start()); 493 new_target_.set(node); 494 } 495 return new_target_.get(); 496 } 497 498 Node* AstGraphBuilder::GetEmptyFrameState() { 499 if (!empty_frame_state_.is_set()) { 500 const Operator* op = common()->FrameState( 501 BailoutId::None(), OutputFrameStateCombine::Ignore(), nullptr); 502 Node* node = graph()->NewNode( 503 op, jsgraph()->EmptyStateValues(), jsgraph()->EmptyStateValues(), 504 jsgraph()->EmptyStateValues(), jsgraph()->NoContextConstant(), 505 jsgraph()->UndefinedConstant(), graph()->start()); 506 empty_frame_state_.set(node); 507 } 508 return empty_frame_state_.get(); 509 } 510 511 bool AstGraphBuilder::CreateGraph(bool stack_check) { 512 DeclarationScope* scope = info()->scope(); 513 DCHECK_NOT_NULL(graph()); 514 515 // Set up the basic structure of the graph. Outputs for {Start} are the formal 516 // parameters (including the receiver) plus new target, number of arguments, 517 // context and closure. 518 int actual_parameter_count = info()->num_parameters_including_this() + 4; 519 graph()->SetStart(graph()->NewNode(common()->Start(actual_parameter_count))); 520 521 // Initialize the top-level environment. 522 Environment env(this, scope, graph()->start()); 523 set_environment(&env); 524 525 if (info()->is_osr()) { 526 // Use OSR normal entry as the start of the top-level environment. 527 // It will be replaced with {Dead} after typing and optimizations. 528 NewNode(common()->OsrNormalEntry()); 529 } 530 531 // Initialize the incoming context. 532 ContextScope incoming(this, scope, GetFunctionContext()); 533 534 // Initialize control scope. 535 ControlScope control(this); 536 537 // TODO(mstarzinger): For now we cannot assume that the {this} parameter is 538 // not {the_hole}, because for derived classes {this} has a TDZ and the 539 // JSConstructStubForDerived magically passes {the_hole} as a receiver. 540 if (scope->has_this_declaration() && scope->receiver()->mode() == CONST) { 541 env.RawParameterBind(0, jsgraph()->TheHoleConstant()); 542 } 543 544 if (scope->NeedsContext()) { 545 // Push a new inner context scope for the current activation. 546 Node* inner_context = BuildLocalActivationContext(GetFunctionContext()); 547 ContextScope top_context(this, scope, inner_context); 548 CreateGraphBody(stack_check); 549 } else { 550 // Simply use the outer function context in building the graph. 551 CreateGraphBody(stack_check); 552 } 553 554 // Finish the basic structure of the graph. 555 DCHECK_NE(0u, exit_controls_.size()); 556 int const input_count = static_cast<int>(exit_controls_.size()); 557 Node** const inputs = &exit_controls_.front(); 558 Node* end = graph()->NewNode(common()->End(input_count), input_count, inputs); 559 graph()->SetEnd(end); 560 561 // Compute local variable liveness information and use it to relax 562 // frame states. 563 ClearNonLiveSlotsInFrameStates(); 564 565 // Failures indicated by stack overflow. 566 return !HasStackOverflow(); 567 } 568 569 570 void AstGraphBuilder::CreateGraphBody(bool stack_check) { 571 DeclarationScope* scope = info()->scope(); 572 573 // Build the arguments object if it is used. 574 BuildArgumentsObject(scope->arguments()); 575 576 // Build rest arguments array if it is used. 577 Variable* rest_parameter = scope->rest_parameter(); 578 BuildRestArgumentsArray(rest_parameter); 579 580 // Build assignment to {.this_function} variable if it is used. 581 BuildThisFunctionVariable(scope->this_function_var()); 582 583 // Build assignment to {new.target} variable if it is used. 584 BuildNewTargetVariable(scope->new_target_var()); 585 586 // Emit tracing call if requested to do so. 587 if (FLAG_trace) { 588 NewNode(javascript()->CallRuntime(Runtime::kTraceEnter)); 589 } 590 591 // Visit declarations within the function scope. 592 VisitDeclarations(scope->declarations()); 593 594 // Build a stack-check before the body. 595 if (stack_check) { 596 Node* node = NewNode(javascript()->StackCheck()); 597 PrepareFrameState(node, BailoutId::FunctionEntry()); 598 } 599 600 // Visit statements in the function body. 601 VisitStatements(info()->literal()->body()); 602 603 // Return 'undefined' in case we can fall off the end. 604 BuildReturn(jsgraph()->UndefinedConstant()); 605 } 606 607 608 void AstGraphBuilder::ClearNonLiveSlotsInFrameStates() { 609 if (!FLAG_analyze_environment_liveness || 610 !info()->is_deoptimization_enabled()) { 611 return; 612 } 613 614 NonLiveFrameStateSlotReplacer replacer( 615 &state_values_cache_, jsgraph()->OptimizedOutConstant(), 616 liveness_analyzer()->local_count(), false, local_zone()); 617 Variable* arguments = info()->scope()->arguments(); 618 if (arguments != nullptr && arguments->IsStackAllocated()) { 619 replacer.MarkPermanentlyLive(arguments->index()); 620 } 621 liveness_analyzer()->Run(&replacer); 622 if (FLAG_trace_environment_liveness) { 623 OFStream os(stdout); 624 liveness_analyzer()->Print(os); 625 } 626 } 627 628 629 // Gets the bailout id just before reading a variable proxy, but only for 630 // unallocated variables. 631 static BailoutId BeforeId(VariableProxy* proxy) { 632 return proxy->var()->IsUnallocated() ? proxy->BeforeId() : BailoutId::None(); 633 } 634 635 static const char* GetDebugParameterName(Zone* zone, DeclarationScope* scope, 636 int index) { 637 #if DEBUG 638 const AstRawString* name = scope->parameter(index)->raw_name(); 639 if (name && name->length() > 0) { 640 char* data = zone->NewArray<char>(name->length() + 1); 641 data[name->length()] = 0; 642 memcpy(data, name->raw_data(), name->length()); 643 return data; 644 } 645 #endif 646 return nullptr; 647 } 648 649 AstGraphBuilder::Environment::Environment(AstGraphBuilder* builder, 650 DeclarationScope* scope, 651 Node* control_dependency) 652 : builder_(builder), 653 parameters_count_(scope->num_parameters() + 1), 654 locals_count_(scope->num_stack_slots()), 655 liveness_block_(IsLivenessAnalysisEnabled() 656 ? builder_->liveness_analyzer()->NewBlock() 657 : nullptr), 658 values_(builder_->local_zone()), 659 contexts_(builder_->local_zone()), 660 control_dependency_(control_dependency), 661 effect_dependency_(control_dependency), 662 parameters_node_(nullptr), 663 locals_node_(nullptr), 664 stack_node_(nullptr) { 665 DCHECK_EQ(scope->num_parameters() + 1, parameters_count()); 666 667 // Bind the receiver variable. 668 int param_num = 0; 669 if (builder->info()->is_this_defined()) { 670 const Operator* op = common()->Parameter(param_num++, "%this"); 671 Node* receiver = builder->graph()->NewNode(op, builder->graph()->start()); 672 values()->push_back(receiver); 673 } else { 674 values()->push_back(builder->jsgraph()->UndefinedConstant()); 675 } 676 677 // Bind all parameter variables. The parameter indices are shifted by 1 678 // (receiver is variable index -1 but {Parameter} node index 0 and located at 679 // index 0 in the environment). 680 for (int i = 0; i < scope->num_parameters(); ++i) { 681 const char* debug_name = GetDebugParameterName(graph()->zone(), scope, i); 682 const Operator* op = common()->Parameter(param_num++, debug_name); 683 Node* parameter = builder->graph()->NewNode(op, builder->graph()->start()); 684 values()->push_back(parameter); 685 } 686 687 // Bind all local variables to undefined. 688 Node* undefined_constant = builder->jsgraph()->UndefinedConstant(); 689 values()->insert(values()->end(), locals_count(), undefined_constant); 690 } 691 692 693 AstGraphBuilder::Environment::Environment(AstGraphBuilder::Environment* copy, 694 LivenessAnalyzerBlock* liveness_block) 695 : builder_(copy->builder_), 696 parameters_count_(copy->parameters_count_), 697 locals_count_(copy->locals_count_), 698 liveness_block_(liveness_block), 699 values_(copy->zone()), 700 contexts_(copy->zone()), 701 control_dependency_(copy->control_dependency_), 702 effect_dependency_(copy->effect_dependency_), 703 parameters_node_(copy->parameters_node_), 704 locals_node_(copy->locals_node_), 705 stack_node_(copy->stack_node_) { 706 const size_t kStackEstimate = 7; // optimum from experimentation! 707 values_.reserve(copy->values_.size() + kStackEstimate); 708 values_.insert(values_.begin(), copy->values_.begin(), copy->values_.end()); 709 contexts_.reserve(copy->contexts_.size()); 710 contexts_.insert(contexts_.begin(), copy->contexts_.begin(), 711 copy->contexts_.end()); 712 } 713 714 715 void AstGraphBuilder::Environment::Bind(Variable* variable, Node* node) { 716 DCHECK(variable->IsStackAllocated()); 717 if (variable->IsParameter()) { 718 // The parameter indices are shifted by 1 (receiver is variable 719 // index -1 but located at index 0 in the environment). 720 values()->at(variable->index() + 1) = node; 721 } else { 722 DCHECK(variable->IsStackLocal()); 723 values()->at(variable->index() + parameters_count_) = node; 724 DCHECK(IsLivenessBlockConsistent()); 725 if (liveness_block() != nullptr) { 726 liveness_block()->Bind(variable->index()); 727 } 728 } 729 } 730 731 732 Node* AstGraphBuilder::Environment::Lookup(Variable* variable) { 733 DCHECK(variable->IsStackAllocated()); 734 if (variable->IsParameter()) { 735 // The parameter indices are shifted by 1 (receiver is variable 736 // index -1 but located at index 0 in the environment). 737 return values()->at(variable->index() + 1); 738 } else { 739 DCHECK(variable->IsStackLocal()); 740 DCHECK(IsLivenessBlockConsistent()); 741 if (liveness_block() != nullptr) { 742 liveness_block()->Lookup(variable->index()); 743 } 744 return values()->at(variable->index() + parameters_count_); 745 } 746 } 747 748 749 void AstGraphBuilder::Environment::MarkAllLocalsLive() { 750 DCHECK(IsLivenessBlockConsistent()); 751 if (liveness_block() != nullptr) { 752 for (int i = 0; i < locals_count_; i++) { 753 liveness_block()->Lookup(i); 754 } 755 } 756 } 757 758 759 void AstGraphBuilder::Environment::RawParameterBind(int index, Node* node) { 760 DCHECK_LT(index, parameters_count()); 761 values()->at(index) = node; 762 } 763 764 765 Node* AstGraphBuilder::Environment::RawParameterLookup(int index) { 766 DCHECK_LT(index, parameters_count()); 767 return values()->at(index); 768 } 769 770 771 AstGraphBuilder::Environment* 772 AstGraphBuilder::Environment::CopyForConditional() { 773 LivenessAnalyzerBlock* copy_liveness_block = nullptr; 774 if (liveness_block() != nullptr) { 775 copy_liveness_block = 776 builder_->liveness_analyzer()->NewBlock(liveness_block()); 777 liveness_block_ = builder_->liveness_analyzer()->NewBlock(liveness_block()); 778 } 779 return new (zone()) Environment(this, copy_liveness_block); 780 } 781 782 783 AstGraphBuilder::Environment* 784 AstGraphBuilder::Environment::CopyAsUnreachable() { 785 Environment* env = new (zone()) Environment(this, nullptr); 786 env->MarkAsUnreachable(); 787 return env; 788 } 789 790 AstGraphBuilder::Environment* AstGraphBuilder::Environment::CopyForOsrEntry() { 791 LivenessAnalyzerBlock* copy_block = 792 liveness_block() == nullptr ? nullptr 793 : builder_->liveness_analyzer()->NewBlock(); 794 return new (zone()) Environment(this, copy_block); 795 } 796 797 AstGraphBuilder::Environment* 798 AstGraphBuilder::Environment::CopyAndShareLiveness() { 799 if (liveness_block() != nullptr) { 800 // Finish the current liveness block before copying. 801 liveness_block_ = builder_->liveness_analyzer()->NewBlock(liveness_block()); 802 } 803 Environment* env = new (zone()) Environment(this, liveness_block()); 804 return env; 805 } 806 807 808 AstGraphBuilder::Environment* AstGraphBuilder::Environment::CopyForLoop( 809 BitVector* assigned, bool is_osr) { 810 PrepareForLoop(assigned); 811 Environment* loop = CopyAndShareLiveness(); 812 if (is_osr) { 813 // Create and merge the OSR entry if necessary. 814 Environment* osr_env = CopyForOsrEntry(); 815 osr_env->PrepareForOsrEntry(); 816 loop->Merge(osr_env); 817 } 818 return loop; 819 } 820 821 822 void AstGraphBuilder::Environment::UpdateStateValues(Node** state_values, 823 int offset, int count) { 824 bool should_update = false; 825 Node** env_values = (count == 0) ? nullptr : &values()->at(offset); 826 if (*state_values == nullptr || (*state_values)->InputCount() != count) { 827 should_update = true; 828 } else { 829 DCHECK(static_cast<size_t>(offset + count) <= values()->size()); 830 for (int i = 0; i < count; i++) { 831 if ((*state_values)->InputAt(i) != env_values[i]) { 832 should_update = true; 833 break; 834 } 835 } 836 } 837 if (should_update) { 838 const Operator* op = common()->StateValues(count); 839 (*state_values) = graph()->NewNode(op, count, env_values); 840 } 841 } 842 843 844 Node* AstGraphBuilder::Environment::Checkpoint(BailoutId ast_id, 845 OutputFrameStateCombine combine, 846 bool owner_has_exception) { 847 if (!builder()->info()->is_deoptimization_enabled()) { 848 return builder()->GetEmptyFrameState(); 849 } 850 851 UpdateStateValues(¶meters_node_, 0, parameters_count()); 852 UpdateStateValues(&locals_node_, parameters_count(), locals_count()); 853 UpdateStateValues(&stack_node_, parameters_count() + locals_count(), 854 stack_height()); 855 856 const Operator* op = common()->FrameState( 857 ast_id, combine, builder()->frame_state_function_info()); 858 859 Node* result = graph()->NewNode(op, parameters_node_, locals_node_, 860 stack_node_, builder()->current_context(), 861 builder()->GetFunctionClosure(), 862 builder()->graph()->start()); 863 864 DCHECK(IsLivenessBlockConsistent()); 865 if (liveness_block() != nullptr) { 866 // If the owning node has an exception, register the checkpoint to the 867 // predecessor so that the checkpoint is used for both the normal and the 868 // exceptional paths. Yes, this is a terrible hack and we might want 869 // to use an explicit frame state for the exceptional path. 870 if (owner_has_exception) { 871 liveness_block()->GetPredecessor()->Checkpoint(result); 872 } else { 873 liveness_block()->Checkpoint(result); 874 } 875 } 876 return result; 877 } 878 879 void AstGraphBuilder::Environment::PrepareForLoopExit( 880 Node* loop, BitVector* assigned_variables) { 881 if (IsMarkedAsUnreachable()) return; 882 883 DCHECK_EQ(loop->opcode(), IrOpcode::kLoop); 884 885 Node* control = GetControlDependency(); 886 887 // Create the loop exit node. 888 Node* loop_exit = graph()->NewNode(common()->LoopExit(), control, loop); 889 UpdateControlDependency(loop_exit); 890 891 // Rename the environmnent values. 892 for (size_t i = 0; i < values()->size(); i++) { 893 if (assigned_variables == nullptr || 894 static_cast<int>(i) >= assigned_variables->length() || 895 assigned_variables->Contains(static_cast<int>(i))) { 896 Node* rename = graph()->NewNode(common()->LoopExitValue(), (*values())[i], 897 loop_exit); 898 (*values())[i] = rename; 899 } 900 } 901 902 // Rename the effect. 903 Node* effect_rename = graph()->NewNode(common()->LoopExitEffect(), 904 GetEffectDependency(), loop_exit); 905 UpdateEffectDependency(effect_rename); 906 } 907 908 bool AstGraphBuilder::Environment::IsLivenessAnalysisEnabled() { 909 return FLAG_analyze_environment_liveness && 910 builder()->info()->is_deoptimization_enabled(); 911 } 912 913 914 bool AstGraphBuilder::Environment::IsLivenessBlockConsistent() { 915 return (!IsLivenessAnalysisEnabled() || IsMarkedAsUnreachable()) == 916 (liveness_block() == nullptr); 917 } 918 919 920 AstGraphBuilder::AstContext::AstContext(AstGraphBuilder* own, 921 Expression::Context kind) 922 : kind_(kind), owner_(own), outer_(own->ast_context()) { 923 owner()->set_ast_context(this); // Push. 924 #ifdef DEBUG 925 original_height_ = environment()->stack_height(); 926 #endif 927 } 928 929 930 AstGraphBuilder::AstContext::~AstContext() { 931 owner()->set_ast_context(outer_); // Pop. 932 } 933 934 935 AstGraphBuilder::AstEffectContext::~AstEffectContext() { 936 DCHECK(environment()->stack_height() == original_height_); 937 } 938 939 940 AstGraphBuilder::AstValueContext::~AstValueContext() { 941 DCHECK(environment()->stack_height() == original_height_ + 1); 942 } 943 944 945 AstGraphBuilder::AstTestContext::~AstTestContext() { 946 DCHECK(environment()->stack_height() == original_height_ + 1); 947 } 948 949 void AstGraphBuilder::AstEffectContext::ProduceValue(Expression* expr, 950 Node* value) { 951 // The value is ignored. 952 owner()->PrepareEagerCheckpoint(expr->id()); 953 } 954 955 void AstGraphBuilder::AstValueContext::ProduceValue(Expression* expr, 956 Node* value) { 957 environment()->Push(value); 958 owner()->PrepareEagerCheckpoint(expr->id()); 959 } 960 961 void AstGraphBuilder::AstTestContext::ProduceValue(Expression* expr, 962 Node* value) { 963 environment()->Push(owner()->BuildToBoolean(value, feedback_id_)); 964 owner()->PrepareEagerCheckpoint(expr->id()); 965 } 966 967 968 Node* AstGraphBuilder::AstEffectContext::ConsumeValue() { return nullptr; } 969 970 971 Node* AstGraphBuilder::AstValueContext::ConsumeValue() { 972 return environment()->Pop(); 973 } 974 975 976 Node* AstGraphBuilder::AstTestContext::ConsumeValue() { 977 return environment()->Pop(); 978 } 979 980 981 Scope* AstGraphBuilder::current_scope() const { 982 return execution_context_->scope(); 983 } 984 985 986 Node* AstGraphBuilder::current_context() const { 987 return environment()->Context(); 988 } 989 990 991 void AstGraphBuilder::ControlScope::PerformCommand(Command command, 992 Statement* target, 993 Node* value) { 994 Environment* env = environment()->CopyAsUnreachable(); 995 ControlScope* current = this; 996 while (current != nullptr) { 997 environment()->TrimStack(current->stack_height()); 998 environment()->TrimContextChain(current->context_length()); 999 if (current->Execute(command, target, &value)) break; 1000 current = current->outer_; 1001 } 1002 builder()->set_environment(env); 1003 DCHECK_NOT_NULL(current); // Always handled (unless stack is malformed). 1004 } 1005 1006 1007 void AstGraphBuilder::ControlScope::BreakTo(BreakableStatement* stmt) { 1008 PerformCommand(CMD_BREAK, stmt, builder()->jsgraph()->TheHoleConstant()); 1009 } 1010 1011 1012 void AstGraphBuilder::ControlScope::ContinueTo(BreakableStatement* stmt) { 1013 PerformCommand(CMD_CONTINUE, stmt, builder()->jsgraph()->TheHoleConstant()); 1014 } 1015 1016 1017 void AstGraphBuilder::ControlScope::ReturnValue(Node* return_value) { 1018 PerformCommand(CMD_RETURN, nullptr, return_value); 1019 } 1020 1021 1022 void AstGraphBuilder::ControlScope::ThrowValue(Node* exception_value) { 1023 PerformCommand(CMD_THROW, nullptr, exception_value); 1024 } 1025 1026 1027 void AstGraphBuilder::VisitForValueOrNull(Expression* expr) { 1028 if (expr == nullptr) { 1029 return environment()->Push(jsgraph()->NullConstant()); 1030 } 1031 VisitForValue(expr); 1032 } 1033 1034 1035 void AstGraphBuilder::VisitForValueOrTheHole(Expression* expr) { 1036 if (expr == nullptr) { 1037 return environment()->Push(jsgraph()->TheHoleConstant()); 1038 } 1039 VisitForValue(expr); 1040 } 1041 1042 1043 void AstGraphBuilder::VisitForValues(ZoneList<Expression*>* exprs) { 1044 for (int i = 0; i < exprs->length(); ++i) { 1045 VisitForValue(exprs->at(i)); 1046 } 1047 } 1048 1049 1050 void AstGraphBuilder::VisitForValue(Expression* expr) { 1051 AstValueContext for_value(this); 1052 if (!CheckStackOverflow()) { 1053 VisitNoStackOverflowCheck(expr); 1054 } else { 1055 ast_context()->ProduceValue(expr, jsgraph()->UndefinedConstant()); 1056 } 1057 } 1058 1059 1060 void AstGraphBuilder::VisitForEffect(Expression* expr) { 1061 AstEffectContext for_effect(this); 1062 if (!CheckStackOverflow()) { 1063 VisitNoStackOverflowCheck(expr); 1064 } else { 1065 ast_context()->ProduceValue(expr, jsgraph()->UndefinedConstant()); 1066 } 1067 } 1068 1069 1070 void AstGraphBuilder::VisitForTest(Expression* expr) { 1071 AstTestContext for_condition(this, expr->test_id()); 1072 if (!CheckStackOverflow()) { 1073 VisitNoStackOverflowCheck(expr); 1074 } else { 1075 ast_context()->ProduceValue(expr, jsgraph()->UndefinedConstant()); 1076 } 1077 } 1078 1079 1080 void AstGraphBuilder::Visit(Expression* expr) { 1081 // Reuses enclosing AstContext. 1082 if (!CheckStackOverflow()) { 1083 VisitNoStackOverflowCheck(expr); 1084 } else { 1085 ast_context()->ProduceValue(expr, jsgraph()->UndefinedConstant()); 1086 } 1087 } 1088 1089 1090 void AstGraphBuilder::VisitVariableDeclaration(VariableDeclaration* decl) { 1091 Variable* variable = decl->proxy()->var(); 1092 switch (variable->location()) { 1093 case VariableLocation::UNALLOCATED: { 1094 DCHECK(!variable->binding_needs_init()); 1095 FeedbackVectorSlot slot = decl->proxy()->VariableFeedbackSlot(); 1096 DCHECK(!slot.IsInvalid()); 1097 globals()->push_back(handle(Smi::FromInt(slot.ToInt()), isolate())); 1098 globals()->push_back(isolate()->factory()->undefined_value()); 1099 break; 1100 } 1101 case VariableLocation::PARAMETER: 1102 case VariableLocation::LOCAL: 1103 if (variable->binding_needs_init()) { 1104 Node* value = jsgraph()->TheHoleConstant(); 1105 environment()->Bind(variable, value); 1106 } 1107 break; 1108 case VariableLocation::CONTEXT: 1109 if (variable->binding_needs_init()) { 1110 Node* value = jsgraph()->TheHoleConstant(); 1111 const Operator* op = javascript()->StoreContext(0, variable->index()); 1112 NewNode(op, current_context(), value); 1113 } 1114 break; 1115 case VariableLocation::LOOKUP: { 1116 DCHECK(!variable->binding_needs_init()); 1117 Node* name = jsgraph()->Constant(variable->name()); 1118 const Operator* op = javascript()->CallRuntime(Runtime::kDeclareEvalVar); 1119 Node* store = NewNode(op, name); 1120 PrepareFrameState(store, decl->proxy()->id()); 1121 break; 1122 } 1123 case VariableLocation::MODULE: 1124 UNREACHABLE(); 1125 } 1126 } 1127 1128 1129 void AstGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* decl) { 1130 Variable* variable = decl->proxy()->var(); 1131 switch (variable->location()) { 1132 case VariableLocation::UNALLOCATED: { 1133 Handle<SharedFunctionInfo> function = Compiler::GetSharedFunctionInfo( 1134 decl->fun(), info()->script(), info()); 1135 // Check for stack-overflow exception. 1136 if (function.is_null()) return SetStackOverflow(); 1137 FeedbackVectorSlot slot = decl->proxy()->VariableFeedbackSlot(); 1138 DCHECK(!slot.IsInvalid()); 1139 globals()->push_back(handle(Smi::FromInt(slot.ToInt()), isolate())); 1140 globals()->push_back(function); 1141 break; 1142 } 1143 case VariableLocation::PARAMETER: 1144 case VariableLocation::LOCAL: { 1145 VisitForValue(decl->fun()); 1146 Node* value = environment()->Pop(); 1147 environment()->Bind(variable, value); 1148 break; 1149 } 1150 case VariableLocation::CONTEXT: { 1151 VisitForValue(decl->fun()); 1152 Node* value = environment()->Pop(); 1153 const Operator* op = javascript()->StoreContext(0, variable->index()); 1154 NewNode(op, current_context(), value); 1155 break; 1156 } 1157 case VariableLocation::LOOKUP: { 1158 VisitForValue(decl->fun()); 1159 Node* value = environment()->Pop(); 1160 Node* name = jsgraph()->Constant(variable->name()); 1161 const Operator* op = 1162 javascript()->CallRuntime(Runtime::kDeclareEvalFunction); 1163 Node* store = NewNode(op, name, value); 1164 PrepareFrameState(store, decl->proxy()->id()); 1165 break; 1166 } 1167 case VariableLocation::MODULE: 1168 UNREACHABLE(); 1169 } 1170 } 1171 1172 1173 void AstGraphBuilder::VisitBlock(Block* stmt) { 1174 BlockBuilder block(this); 1175 ControlScopeForBreakable scope(this, stmt, &block); 1176 if (stmt->labels() != nullptr) block.BeginBlock(); 1177 if (stmt->scope() == nullptr) { 1178 // Visit statements in the same scope, no declarations. 1179 VisitStatements(stmt->statements()); 1180 } else { 1181 // Visit declarations and statements in a block scope. 1182 if (stmt->scope()->NeedsContext()) { 1183 Node* context = BuildLocalBlockContext(stmt->scope()); 1184 ContextScope scope(this, stmt->scope(), context); 1185 VisitDeclarations(stmt->scope()->declarations()); 1186 VisitStatements(stmt->statements()); 1187 } else { 1188 VisitDeclarations(stmt->scope()->declarations()); 1189 VisitStatements(stmt->statements()); 1190 } 1191 } 1192 if (stmt->labels() != nullptr) block.EndBlock(); 1193 } 1194 1195 1196 void AstGraphBuilder::VisitExpressionStatement(ExpressionStatement* stmt) { 1197 VisitForEffect(stmt->expression()); 1198 } 1199 1200 1201 void AstGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) { 1202 // Do nothing. 1203 } 1204 1205 1206 void AstGraphBuilder::VisitSloppyBlockFunctionStatement( 1207 SloppyBlockFunctionStatement* stmt) { 1208 Visit(stmt->statement()); 1209 } 1210 1211 1212 void AstGraphBuilder::VisitIfStatement(IfStatement* stmt) { 1213 IfBuilder compare_if(this); 1214 VisitForTest(stmt->condition()); 1215 Node* condition = environment()->Pop(); 1216 compare_if.If(condition); 1217 compare_if.Then(); 1218 Visit(stmt->then_statement()); 1219 compare_if.Else(); 1220 Visit(stmt->else_statement()); 1221 compare_if.End(); 1222 } 1223 1224 1225 void AstGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) { 1226 execution_control()->ContinueTo(stmt->target()); 1227 } 1228 1229 1230 void AstGraphBuilder::VisitBreakStatement(BreakStatement* stmt) { 1231 execution_control()->BreakTo(stmt->target()); 1232 } 1233 1234 1235 void AstGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { 1236 VisitForValue(stmt->expression()); 1237 Node* result = environment()->Pop(); 1238 execution_control()->ReturnValue(result); 1239 } 1240 1241 1242 void AstGraphBuilder::VisitWithStatement(WithStatement* stmt) { 1243 VisitForValue(stmt->expression()); 1244 Node* value = environment()->Pop(); 1245 Node* object = BuildToObject(value, stmt->ToObjectId()); 1246 Handle<ScopeInfo> scope_info = stmt->scope()->scope_info(); 1247 const Operator* op = javascript()->CreateWithContext(scope_info); 1248 Node* context = NewNode(op, object, GetFunctionClosureForContext()); 1249 PrepareFrameState(context, stmt->EntryId()); 1250 VisitInScope(stmt->statement(), stmt->scope(), context); 1251 } 1252 1253 1254 void AstGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { 1255 ZoneList<CaseClause*>* clauses = stmt->cases(); 1256 SwitchBuilder compare_switch(this, clauses->length()); 1257 ControlScopeForBreakable scope(this, stmt, &compare_switch); 1258 compare_switch.BeginSwitch(); 1259 int default_index = -1; 1260 1261 // Keep the switch value on the stack until a case matches. 1262 VisitForValue(stmt->tag()); 1263 1264 // Iterate over all cases and create nodes for label comparison. 1265 for (int i = 0; i < clauses->length(); i++) { 1266 CaseClause* clause = clauses->at(i); 1267 1268 // The default is not a test, remember index. 1269 if (clause->is_default()) { 1270 default_index = i; 1271 continue; 1272 } 1273 1274 // Create nodes to perform label comparison as if via '==='. The switch 1275 // value is still on the operand stack while the label is evaluated. 1276 VisitForValue(clause->label()); 1277 Node* label = environment()->Pop(); 1278 Node* tag = environment()->Top(); 1279 1280 CompareOperationHint hint; 1281 if (!type_hint_analysis_ || 1282 !type_hint_analysis_->GetCompareOperationHint(clause->CompareId(), 1283 &hint)) { 1284 hint = CompareOperationHint::kAny; 1285 } 1286 1287 const Operator* op = javascript()->StrictEqual(hint); 1288 Node* condition = NewNode(op, tag, label); 1289 compare_switch.BeginLabel(i, condition); 1290 1291 // Discard the switch value at label match. 1292 environment()->Pop(); 1293 compare_switch.EndLabel(); 1294 } 1295 1296 // Discard the switch value and mark the default case. 1297 environment()->Pop(); 1298 if (default_index >= 0) { 1299 compare_switch.DefaultAt(default_index); 1300 } 1301 1302 // Iterate over all cases and create nodes for case bodies. 1303 for (int i = 0; i < clauses->length(); i++) { 1304 CaseClause* clause = clauses->at(i); 1305 compare_switch.BeginCase(i); 1306 VisitStatements(clause->statements()); 1307 compare_switch.EndCase(); 1308 } 1309 1310 compare_switch.EndSwitch(); 1311 } 1312 1313 1314 void AstGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) { 1315 LoopBuilder while_loop(this); 1316 while_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt)); 1317 VisitIterationBody(stmt, &while_loop, stmt->StackCheckId()); 1318 while_loop.EndBody(); 1319 VisitForTest(stmt->cond()); 1320 Node* condition = environment()->Pop(); 1321 while_loop.BreakUnless(condition); 1322 while_loop.EndLoop(); 1323 } 1324 1325 1326 void AstGraphBuilder::VisitWhileStatement(WhileStatement* stmt) { 1327 LoopBuilder while_loop(this); 1328 while_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt)); 1329 VisitForTest(stmt->cond()); 1330 Node* condition = environment()->Pop(); 1331 while_loop.BreakUnless(condition); 1332 VisitIterationBody(stmt, &while_loop, stmt->StackCheckId()); 1333 while_loop.EndBody(); 1334 while_loop.EndLoop(); 1335 } 1336 1337 1338 void AstGraphBuilder::VisitForStatement(ForStatement* stmt) { 1339 LoopBuilder for_loop(this); 1340 VisitIfNotNull(stmt->init()); 1341 for_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt)); 1342 if (stmt->cond() != nullptr) { 1343 VisitForTest(stmt->cond()); 1344 Node* condition = environment()->Pop(); 1345 for_loop.BreakUnless(condition); 1346 } else { 1347 for_loop.BreakUnless(jsgraph()->TrueConstant()); 1348 } 1349 VisitIterationBody(stmt, &for_loop, stmt->StackCheckId()); 1350 for_loop.EndBody(); 1351 VisitIfNotNull(stmt->next()); 1352 for_loop.EndLoop(); 1353 } 1354 1355 1356 void AstGraphBuilder::VisitForInStatement(ForInStatement* stmt) { 1357 VisitForValue(stmt->subject()); 1358 Node* object = environment()->Pop(); 1359 BlockBuilder for_block(this); 1360 for_block.BeginBlock(); 1361 // Check for null or undefined before entering loop. 1362 Node* is_null_cond = 1363 NewNode(javascript()->StrictEqual(CompareOperationHint::kAny), object, 1364 jsgraph()->NullConstant()); 1365 for_block.BreakWhen(is_null_cond, BranchHint::kFalse); 1366 Node* is_undefined_cond = 1367 NewNode(javascript()->StrictEqual(CompareOperationHint::kAny), object, 1368 jsgraph()->UndefinedConstant()); 1369 for_block.BreakWhen(is_undefined_cond, BranchHint::kFalse); 1370 { 1371 // Convert object to jsobject. 1372 object = BuildToObject(object, stmt->ToObjectId()); 1373 environment()->Push(object); 1374 1375 // Prepare for-in cache. 1376 Node* prepare = NewNode(javascript()->ForInPrepare(), object); 1377 PrepareFrameState(prepare, stmt->PrepareId(), 1378 OutputFrameStateCombine::Push(3)); 1379 Node* cache_type = NewNode(common()->Projection(0), prepare); 1380 Node* cache_array = NewNode(common()->Projection(1), prepare); 1381 Node* cache_length = NewNode(common()->Projection(2), prepare); 1382 1383 // Construct the rest of the environment. 1384 environment()->Push(cache_type); 1385 environment()->Push(cache_array); 1386 environment()->Push(cache_length); 1387 environment()->Push(jsgraph()->ZeroConstant()); 1388 1389 // Build the actual loop body. 1390 LoopBuilder for_loop(this); 1391 for_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt)); 1392 { 1393 // These stack values are renamed in the case of OSR, so reload them 1394 // from the environment. 1395 Node* index = environment()->Peek(0); 1396 Node* cache_length = environment()->Peek(1); 1397 Node* cache_array = environment()->Peek(2); 1398 Node* cache_type = environment()->Peek(3); 1399 Node* object = environment()->Peek(4); 1400 1401 // Check loop termination condition (we know that the {index} is always 1402 // in Smi range, so we can just set the hint on the comparison below). 1403 PrepareEagerCheckpoint(stmt->EntryId()); 1404 Node* exit_cond = 1405 NewNode(javascript()->LessThan(CompareOperationHint::kSignedSmall), 1406 index, cache_length); 1407 PrepareFrameState(exit_cond, BailoutId::None()); 1408 for_loop.BreakUnless(exit_cond); 1409 1410 // Compute the next enumerated value. 1411 Node* value = NewNode(javascript()->ForInNext(), object, cache_array, 1412 cache_type, index); 1413 PrepareFrameState(value, stmt->FilterId(), 1414 OutputFrameStateCombine::Push()); 1415 IfBuilder test_value(this); 1416 Node* test_value_cond = 1417 NewNode(javascript()->StrictEqual(CompareOperationHint::kAny), value, 1418 jsgraph()->UndefinedConstant()); 1419 test_value.If(test_value_cond, BranchHint::kFalse); 1420 test_value.Then(); 1421 test_value.Else(); 1422 { 1423 environment()->Push(value); 1424 PrepareEagerCheckpoint(stmt->FilterId()); 1425 value = environment()->Pop(); 1426 // Bind value and do loop body. 1427 VectorSlotPair feedback = 1428 CreateVectorSlotPair(stmt->EachFeedbackSlot()); 1429 VisitForInAssignment(stmt->each(), value, feedback, 1430 stmt->AssignmentId()); 1431 VisitIterationBody(stmt, &for_loop, stmt->StackCheckId()); 1432 } 1433 test_value.End(); 1434 for_loop.EndBody(); 1435 1436 // Increment counter and continue (we know that the {index} is always 1437 // in Smi range, so we can just set the hint on the increment below). 1438 index = environment()->Peek(0); 1439 PrepareEagerCheckpoint(stmt->IncrementId()); 1440 index = NewNode(javascript()->Add(BinaryOperationHint::kSignedSmall), 1441 index, jsgraph()->OneConstant()); 1442 PrepareFrameState(index, BailoutId::None()); 1443 environment()->Poke(0, index); 1444 } 1445 for_loop.EndLoop(); 1446 environment()->Drop(5); 1447 } 1448 for_block.EndBlock(); 1449 } 1450 1451 1452 void AstGraphBuilder::VisitForOfStatement(ForOfStatement* stmt) { 1453 LoopBuilder for_loop(this); 1454 VisitForEffect(stmt->assign_iterator()); 1455 for_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt)); 1456 VisitForEffect(stmt->next_result()); 1457 VisitForTest(stmt->result_done()); 1458 Node* condition = environment()->Pop(); 1459 for_loop.BreakWhen(condition); 1460 VisitForEffect(stmt->assign_each()); 1461 VisitIterationBody(stmt, &for_loop, stmt->StackCheckId()); 1462 for_loop.EndBody(); 1463 for_loop.EndLoop(); 1464 } 1465 1466 1467 void AstGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) { 1468 TryCatchBuilder try_control(this); 1469 1470 // Evaluate the try-block inside a control scope. This simulates a handler 1471 // that is intercepting 'throw' control commands. 1472 try_control.BeginTry(); 1473 { 1474 ControlScopeForCatch scope(this, stmt, &try_control); 1475 STATIC_ASSERT(TryBlockConstant::kElementCount == 1); 1476 environment()->Push(current_context()); 1477 Visit(stmt->try_block()); 1478 environment()->Pop(); 1479 } 1480 try_control.EndTry(); 1481 1482 // If requested, clear message object as we enter the catch block. 1483 if (stmt->clear_pending_message()) { 1484 Node* the_hole = jsgraph()->TheHoleConstant(); 1485 NewNode(javascript()->StoreMessage(), the_hole); 1486 } 1487 1488 // Create a catch scope that binds the exception. 1489 Node* exception = try_control.GetExceptionNode(); 1490 Handle<String> name = stmt->variable()->name(); 1491 Handle<ScopeInfo> scope_info = stmt->scope()->scope_info(); 1492 const Operator* op = javascript()->CreateCatchContext(name, scope_info); 1493 Node* context = NewNode(op, exception, GetFunctionClosureForContext()); 1494 1495 // Evaluate the catch-block. 1496 VisitInScope(stmt->catch_block(), stmt->scope(), context); 1497 try_control.EndCatch(); 1498 } 1499 1500 1501 void AstGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) { 1502 TryFinallyBuilder try_control(this); 1503 1504 // We keep a record of all paths that enter the finally-block to be able to 1505 // dispatch to the correct continuation point after the statements in the 1506 // finally-block have been evaluated. 1507 // 1508 // The try-finally construct can enter the finally-block in three ways: 1509 // 1. By exiting the try-block normally, falling through at the end. 1510 // 2. By exiting the try-block with a function-local control flow transfer 1511 // (i.e. through break/continue/return statements). 1512 // 3. By exiting the try-block with a thrown exception. 1513 Node* fallthrough_result = jsgraph()->TheHoleConstant(); 1514 ControlScope::DeferredCommands* commands = 1515 new (local_zone()) ControlScope::DeferredCommands(this); 1516 1517 // Evaluate the try-block inside a control scope. This simulates a handler 1518 // that is intercepting all control commands. 1519 try_control.BeginTry(); 1520 { 1521 ControlScopeForFinally scope(this, stmt, commands, &try_control); 1522 STATIC_ASSERT(TryBlockConstant::kElementCount == 1); 1523 environment()->Push(current_context()); 1524 Visit(stmt->try_block()); 1525 environment()->Pop(); 1526 } 1527 try_control.EndTry(commands->GetFallThroughToken(), fallthrough_result); 1528 1529 // The result value semantics depend on how the block was entered: 1530 // - ReturnStatement: It represents the return value being returned. 1531 // - ThrowStatement: It represents the exception being thrown. 1532 // - BreakStatement/ContinueStatement: Filled with the hole. 1533 // - Falling through into finally-block: Filled with the hole. 1534 Node* result = try_control.GetResultValueNode(); 1535 Node* token = try_control.GetDispatchTokenNode(); 1536 1537 // The result value, dispatch token and message is expected on the operand 1538 // stack (this is in sync with FullCodeGenerator::EnterFinallyBlock). 1539 Node* message = NewNode(javascript()->LoadMessage()); 1540 environment()->Push(token); 1541 environment()->Push(result); 1542 environment()->Push(message); 1543 1544 // Clear message object as we enter the finally block. 1545 Node* the_hole = jsgraph()->TheHoleConstant(); 1546 NewNode(javascript()->StoreMessage(), the_hole); 1547 1548 // Evaluate the finally-block. 1549 Visit(stmt->finally_block()); 1550 try_control.EndFinally(); 1551 1552 // The result value, dispatch token and message is restored from the operand 1553 // stack (this is in sync with FullCodeGenerator::ExitFinallyBlock). 1554 message = environment()->Pop(); 1555 result = environment()->Pop(); 1556 token = environment()->Pop(); 1557 NewNode(javascript()->StoreMessage(), message); 1558 1559 // Dynamic dispatch after the finally-block. 1560 commands->ApplyDeferredCommands(token, result); 1561 } 1562 1563 1564 void AstGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) { 1565 Node* node = 1566 NewNode(javascript()->CallRuntime(Runtime::kHandleDebuggerStatement)); 1567 PrepareFrameState(node, stmt->DebugBreakId()); 1568 environment()->MarkAllLocalsLive(); 1569 } 1570 1571 1572 void AstGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { 1573 // Find or build a shared function info. 1574 Handle<SharedFunctionInfo> shared_info = 1575 Compiler::GetSharedFunctionInfo(expr, info()->script(), info()); 1576 CHECK(!shared_info.is_null()); // TODO(mstarzinger): Set stack overflow? 1577 1578 // Create node to instantiate a new closure. 1579 PretenureFlag pretenure = expr->pretenure() ? TENURED : NOT_TENURED; 1580 const Operator* op = javascript()->CreateClosure(shared_info, pretenure); 1581 Node* value = NewNode(op); 1582 ast_context()->ProduceValue(expr, value); 1583 } 1584 1585 1586 void AstGraphBuilder::VisitClassLiteral(ClassLiteral* expr) { 1587 VisitForValueOrTheHole(expr->extends()); 1588 VisitForValue(expr->constructor()); 1589 1590 // Create node to instantiate a new class. 1591 Node* constructor = environment()->Pop(); 1592 Node* extends = environment()->Pop(); 1593 Node* start = jsgraph()->Constant(expr->start_position()); 1594 Node* end = jsgraph()->Constant(expr->end_position()); 1595 const Operator* opc = javascript()->CallRuntime(Runtime::kDefineClass); 1596 Node* literal = NewNode(opc, extends, constructor, start, end); 1597 PrepareFrameState(literal, expr->CreateLiteralId(), 1598 OutputFrameStateCombine::Push()); 1599 environment()->Push(literal); 1600 1601 // Load the "prototype" from the constructor. 1602 PrepareEagerCheckpoint(expr->CreateLiteralId()); 1603 Handle<Name> name = isolate()->factory()->prototype_string(); 1604 VectorSlotPair pair = CreateVectorSlotPair(expr->PrototypeSlot()); 1605 Node* prototype = BuildNamedLoad(literal, name, pair); 1606 PrepareFrameState(prototype, expr->PrototypeId(), 1607 OutputFrameStateCombine::Push()); 1608 environment()->Push(prototype); 1609 1610 // Create nodes to store method values into the literal. 1611 for (int i = 0; i < expr->properties()->length(); i++) { 1612 ClassLiteral::Property* property = expr->properties()->at(i); 1613 environment()->Push(environment()->Peek(property->is_static() ? 1 : 0)); 1614 1615 VisitForValue(property->key()); 1616 Node* name = BuildToName(environment()->Pop(), expr->GetIdForProperty(i)); 1617 environment()->Push(name); 1618 1619 // The static prototype property is read only. We handle the non computed 1620 // property name case in the parser. Since this is the only case where we 1621 // need to check for an own read only property we special case this so we do 1622 // not need to do this for every property. 1623 if (property->is_static() && property->is_computed_name()) { 1624 Node* check = BuildThrowIfStaticPrototype(environment()->Pop(), 1625 expr->GetIdForProperty(i)); 1626 environment()->Push(check); 1627 } 1628 1629 VisitForValue(property->value()); 1630 Node* value = environment()->Pop(); 1631 Node* key = environment()->Pop(); 1632 Node* receiver = environment()->Pop(); 1633 1634 BuildSetHomeObject(value, receiver, property); 1635 1636 switch (property->kind()) { 1637 case ClassLiteral::Property::METHOD: { 1638 Node* attr = jsgraph()->Constant(DONT_ENUM); 1639 Node* set_function_name = 1640 jsgraph()->Constant(property->NeedsSetFunctionName()); 1641 const Operator* op = 1642 javascript()->CallRuntime(Runtime::kDefineDataPropertyInLiteral); 1643 Node* call = NewNode(op, receiver, key, value, attr, set_function_name); 1644 PrepareFrameState(call, BailoutId::None()); 1645 break; 1646 } 1647 case ClassLiteral::Property::GETTER: { 1648 Node* attr = jsgraph()->Constant(DONT_ENUM); 1649 const Operator* op = javascript()->CallRuntime( 1650 Runtime::kDefineGetterPropertyUnchecked, 4); 1651 NewNode(op, receiver, key, value, attr); 1652 break; 1653 } 1654 case ClassLiteral::Property::SETTER: { 1655 Node* attr = jsgraph()->Constant(DONT_ENUM); 1656 const Operator* op = javascript()->CallRuntime( 1657 Runtime::kDefineSetterPropertyUnchecked, 4); 1658 NewNode(op, receiver, key, value, attr); 1659 break; 1660 } 1661 case ClassLiteral::Property::FIELD: { 1662 UNREACHABLE(); 1663 break; 1664 } 1665 } 1666 } 1667 1668 // Set the constructor to have fast properties. 1669 prototype = environment()->Pop(); 1670 literal = environment()->Pop(); 1671 const Operator* op = javascript()->CallRuntime(Runtime::kToFastProperties); 1672 literal = NewNode(op, literal); 1673 1674 // Assign to class variable. 1675 if (expr->class_variable_proxy() != nullptr) { 1676 Variable* var = expr->class_variable_proxy()->var(); 1677 VectorSlotPair feedback = CreateVectorSlotPair( 1678 expr->NeedsProxySlot() ? expr->ProxySlot() 1679 : FeedbackVectorSlot::Invalid()); 1680 BuildVariableAssignment(var, literal, Token::INIT, feedback, 1681 BailoutId::None()); 1682 } 1683 ast_context()->ProduceValue(expr, literal); 1684 } 1685 1686 1687 void AstGraphBuilder::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) { 1688 UNREACHABLE(); 1689 } 1690 1691 1692 void AstGraphBuilder::VisitDoExpression(DoExpression* expr) { 1693 VisitBlock(expr->block()); 1694 VisitVariableProxy(expr->result()); 1695 ast_context()->ReplaceValue(expr); 1696 } 1697 1698 1699 void AstGraphBuilder::VisitConditional(Conditional* expr) { 1700 IfBuilder compare_if(this); 1701 VisitForTest(expr->condition()); 1702 Node* condition = environment()->Pop(); 1703 compare_if.If(condition); 1704 compare_if.Then(); 1705 Visit(expr->then_expression()); 1706 compare_if.Else(); 1707 Visit(expr->else_expression()); 1708 compare_if.End(); 1709 // Skip plugging AST evaluation contexts of the test kind. This is to stay in 1710 // sync with full codegen which doesn't prepare the proper bailout point (see 1711 // the implementation of FullCodeGenerator::VisitForControl). 1712 if (ast_context()->IsTest()) return; 1713 ast_context()->ReplaceValue(expr); 1714 } 1715 1716 1717 void AstGraphBuilder::VisitVariableProxy(VariableProxy* expr) { 1718 VectorSlotPair pair = CreateVectorSlotPair(expr->VariableFeedbackSlot()); 1719 PrepareEagerCheckpoint(BeforeId(expr)); 1720 Node* value = BuildVariableLoad(expr->var(), expr->id(), pair, 1721 ast_context()->GetStateCombine()); 1722 ast_context()->ProduceValue(expr, value); 1723 } 1724 1725 1726 void AstGraphBuilder::VisitLiteral(Literal* expr) { 1727 Node* value = jsgraph()->Constant(expr->value()); 1728 ast_context()->ProduceValue(expr, value); 1729 } 1730 1731 1732 void AstGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { 1733 Node* closure = GetFunctionClosure(); 1734 1735 // Create node to materialize a regular expression literal. 1736 const Operator* op = javascript()->CreateLiteralRegExp( 1737 expr->pattern(), expr->flags(), expr->literal_index()); 1738 Node* literal = NewNode(op, closure); 1739 PrepareFrameState(literal, expr->id(), ast_context()->GetStateCombine()); 1740 ast_context()->ProduceValue(expr, literal); 1741 } 1742 1743 1744 void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { 1745 Node* closure = GetFunctionClosure(); 1746 1747 // Create node to deep-copy the literal boilerplate. 1748 const Operator* op = javascript()->CreateLiteralObject( 1749 expr->constant_properties(), expr->ComputeFlags(true), 1750 expr->literal_index(), expr->properties_count()); 1751 Node* literal = NewNode(op, closure); 1752 PrepareFrameState(literal, expr->CreateLiteralId(), 1753 OutputFrameStateCombine::Push()); 1754 1755 // The object is expected on the operand stack during computation of the 1756 // property values and is the value of the entire expression. 1757 environment()->Push(literal); 1758 1759 // Create nodes to store computed values into the literal. 1760 int property_index = 0; 1761 AccessorTable accessor_table(local_zone()); 1762 for (; property_index < expr->properties()->length(); property_index++) { 1763 ObjectLiteral::Property* property = expr->properties()->at(property_index); 1764 if (property->is_computed_name()) break; 1765 if (property->IsCompileTimeValue()) continue; 1766 1767 Literal* key = property->key()->AsLiteral(); 1768 switch (property->kind()) { 1769 case ObjectLiteral::Property::CONSTANT: 1770 UNREACHABLE(); 1771 case ObjectLiteral::Property::MATERIALIZED_LITERAL: 1772 DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value())); 1773 // Fall through. 1774 case ObjectLiteral::Property::COMPUTED: { 1775 // It is safe to use [[Put]] here because the boilerplate already 1776 // contains computed properties with an uninitialized value. 1777 if (key->IsStringLiteral()) { 1778 DCHECK(key->IsPropertyName()); 1779 if (property->emit_store()) { 1780 VisitForValue(property->value()); 1781 Node* value = environment()->Pop(); 1782 Node* literal = environment()->Top(); 1783 Handle<Name> name = key->AsPropertyName(); 1784 VectorSlotPair feedback = 1785 CreateVectorSlotPair(property->GetSlot(0)); 1786 Node* store = BuildNamedStore(literal, name, value, feedback); 1787 PrepareFrameState(store, key->id(), 1788 OutputFrameStateCombine::Ignore()); 1789 BuildSetHomeObject(value, literal, property, 1); 1790 } else { 1791 VisitForEffect(property->value()); 1792 } 1793 break; 1794 } 1795 environment()->Push(environment()->Top()); // Duplicate receiver. 1796 VisitForValue(property->key()); 1797 VisitForValue(property->value()); 1798 Node* value = environment()->Pop(); 1799 Node* key = environment()->Pop(); 1800 Node* receiver = environment()->Pop(); 1801 if (property->emit_store()) { 1802 Node* language = jsgraph()->Constant(SLOPPY); 1803 const Operator* op = javascript()->CallRuntime(Runtime::kSetProperty); 1804 Node* set_property = NewNode(op, receiver, key, value, language); 1805 // SetProperty should not lazy deopt on an object literal. 1806 PrepareFrameState(set_property, BailoutId::None()); 1807 BuildSetHomeObject(value, receiver, property); 1808 } 1809 break; 1810 } 1811 case ObjectLiteral::Property::PROTOTYPE: { 1812 environment()->Push(environment()->Top()); // Duplicate receiver. 1813 VisitForValue(property->value()); 1814 Node* value = environment()->Pop(); 1815 Node* receiver = environment()->Pop(); 1816 DCHECK(property->emit_store()); 1817 const Operator* op = 1818 javascript()->CallRuntime(Runtime::kInternalSetPrototype); 1819 Node* set_prototype = NewNode(op, receiver, value); 1820 // SetPrototype should not lazy deopt on an object literal. 1821 PrepareFrameState(set_prototype, 1822 expr->GetIdForPropertySet(property_index)); 1823 break; 1824 } 1825 case ObjectLiteral::Property::GETTER: 1826 if (property->emit_store()) { 1827 AccessorTable::Iterator it = accessor_table.lookup(key); 1828 it->second->bailout_id = expr->GetIdForPropertySet(property_index); 1829 it->second->getter = property; 1830 } 1831 break; 1832 case ObjectLiteral::Property::SETTER: 1833 if (property->emit_store()) { 1834 AccessorTable::Iterator it = accessor_table.lookup(key); 1835 it->second->bailout_id = expr->GetIdForPropertySet(property_index); 1836 it->second->setter = property; 1837 } 1838 break; 1839 } 1840 } 1841 1842 // Create nodes to define accessors, using only a single call to the runtime 1843 // for each pair of corresponding getters and setters. 1844 literal = environment()->Top(); // Reload from operand stack. 1845 for (AccessorTable::Iterator it = accessor_table.begin(); 1846 it != accessor_table.end(); ++it) { 1847 VisitForValue(it->first); 1848 VisitObjectLiteralAccessor(literal, it->second->getter); 1849 VisitObjectLiteralAccessor(literal, it->second->setter); 1850 Node* setter = environment()->Pop(); 1851 Node* getter = environment()->Pop(); 1852 Node* name = environment()->Pop(); 1853 Node* attr = jsgraph()->Constant(NONE); 1854 const Operator* op = 1855 javascript()->CallRuntime(Runtime::kDefineAccessorPropertyUnchecked); 1856 Node* call = NewNode(op, literal, name, getter, setter, attr); 1857 PrepareFrameState(call, it->second->bailout_id); 1858 } 1859 1860 // Object literals have two parts. The "static" part on the left contains no 1861 // computed property names, and so we can compute its map ahead of time; see 1862 // Runtime_CreateObjectLiteralBoilerplate. The second "dynamic" part starts 1863 // with the first computed property name and continues with all properties to 1864 // its right. All the code from above initializes the static component of the 1865 // object literal, and arranges for the map of the result to reflect the 1866 // static order in which the keys appear. For the dynamic properties, we 1867 // compile them into a series of "SetOwnProperty" runtime calls. This will 1868 // preserve insertion order. 1869 for (; property_index < expr->properties()->length(); property_index++) { 1870 ObjectLiteral::Property* property = expr->properties()->at(property_index); 1871 1872 if (property->kind() == ObjectLiteral::Property::PROTOTYPE) { 1873 environment()->Push(environment()->Top()); // Duplicate receiver. 1874 VisitForValue(property->value()); 1875 Node* value = environment()->Pop(); 1876 Node* receiver = environment()->Pop(); 1877 const Operator* op = 1878 javascript()->CallRuntime(Runtime::kInternalSetPrototype); 1879 Node* call = NewNode(op, receiver, value); 1880 PrepareFrameState(call, expr->GetIdForPropertySet(property_index)); 1881 continue; 1882 } 1883 1884 environment()->Push(environment()->Top()); // Duplicate receiver. 1885 VisitForValue(property->key()); 1886 Node* name = BuildToName(environment()->Pop(), 1887 expr->GetIdForPropertyName(property_index)); 1888 environment()->Push(name); 1889 VisitForValue(property->value()); 1890 Node* value = environment()->Pop(); 1891 Node* key = environment()->Pop(); 1892 Node* receiver = environment()->Pop(); 1893 BuildSetHomeObject(value, receiver, property); 1894 switch (property->kind()) { 1895 case ObjectLiteral::Property::CONSTANT: 1896 case ObjectLiteral::Property::COMPUTED: 1897 case ObjectLiteral::Property::MATERIALIZED_LITERAL: { 1898 if (!property->emit_store()) continue; 1899 Node* attr = jsgraph()->Constant(NONE); 1900 Node* set_function_name = 1901 jsgraph()->Constant(property->NeedsSetFunctionName()); 1902 const Operator* op = 1903 javascript()->CallRuntime(Runtime::kDefineDataPropertyInLiteral); 1904 Node* call = NewNode(op, receiver, key, value, attr, set_function_name); 1905 PrepareFrameState(call, expr->GetIdForPropertySet(property_index)); 1906 break; 1907 } 1908 case ObjectLiteral::Property::PROTOTYPE: 1909 UNREACHABLE(); // Handled specially above. 1910 break; 1911 case ObjectLiteral::Property::GETTER: { 1912 Node* attr = jsgraph()->Constant(NONE); 1913 const Operator* op = javascript()->CallRuntime( 1914 Runtime::kDefineGetterPropertyUnchecked, 4); 1915 Node* call = NewNode(op, receiver, key, value, attr); 1916 PrepareFrameState(call, BailoutId::None()); 1917 break; 1918 } 1919 case ObjectLiteral::Property::SETTER: { 1920 Node* attr = jsgraph()->Constant(NONE); 1921 const Operator* op = javascript()->CallRuntime( 1922 Runtime::kDefineSetterPropertyUnchecked, 4); 1923 Node* call = NewNode(op, receiver, key, value, attr); 1924 PrepareFrameState(call, BailoutId::None()); 1925 break; 1926 } 1927 } 1928 } 1929 1930 ast_context()->ProduceValue(expr, environment()->Pop()); 1931 } 1932 1933 1934 void AstGraphBuilder::VisitObjectLiteralAccessor( 1935 Node* home_object, ObjectLiteralProperty* property) { 1936 if (property == nullptr) { 1937 VisitForValueOrNull(nullptr); 1938 } else { 1939 VisitForValue(property->value()); 1940 BuildSetHomeObject(environment()->Top(), home_object, property); 1941 } 1942 } 1943 1944 1945 void AstGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { 1946 Node* closure = GetFunctionClosure(); 1947 1948 // Create node to deep-copy the literal boilerplate. 1949 const Operator* op = javascript()->CreateLiteralArray( 1950 expr->constant_elements(), expr->ComputeFlags(true), 1951 expr->literal_index(), expr->values()->length()); 1952 Node* literal = NewNode(op, closure); 1953 PrepareFrameState(literal, expr->CreateLiteralId(), 1954 OutputFrameStateCombine::Push()); 1955 1956 // The array is expected on the operand stack during computation of the 1957 // element values. 1958 environment()->Push(literal); 1959 1960 // Create nodes to evaluate all the non-constant subexpressions and to store 1961 // them into the newly cloned array. 1962 for (int array_index = 0; array_index < expr->values()->length(); 1963 array_index++) { 1964 Expression* subexpr = expr->values()->at(array_index); 1965 DCHECK(!subexpr->IsSpread()); 1966 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; 1967 1968 VisitForValue(subexpr); 1969 VectorSlotPair pair = CreateVectorSlotPair(expr->LiteralFeedbackSlot()); 1970 Node* value = environment()->Pop(); 1971 Node* index = jsgraph()->Constant(array_index); 1972 Node* literal = environment()->Top(); 1973 Node* store = BuildKeyedStore(literal, index, value, pair); 1974 PrepareFrameState(store, expr->GetIdForElement(array_index), 1975 OutputFrameStateCombine::Ignore()); 1976 } 1977 1978 ast_context()->ProduceValue(expr, environment()->Pop()); 1979 } 1980 1981 void AstGraphBuilder::VisitForInAssignment(Expression* expr, Node* value, 1982 const VectorSlotPair& feedback, 1983 BailoutId bailout_id) { 1984 DCHECK(expr->IsValidReferenceExpressionOrThis()); 1985 1986 // Left-hand side can only be a property, a global or a variable slot. 1987 Property* property = expr->AsProperty(); 1988 LhsKind assign_type = Property::GetAssignType(property); 1989 1990 // Evaluate LHS expression and store the value. 1991 switch (assign_type) { 1992 case VARIABLE: { 1993 Variable* var = expr->AsVariableProxy()->var(); 1994 BuildVariableAssignment(var, value, Token::ASSIGN, feedback, bailout_id); 1995 break; 1996 } 1997 case NAMED_PROPERTY: { 1998 environment()->Push(value); 1999 VisitForValue(property->obj()); 2000 Node* object = environment()->Pop(); 2001 value = environment()->Pop(); 2002 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName(); 2003 Node* store = BuildNamedStore(object, name, value, feedback); 2004 PrepareFrameState(store, bailout_id, OutputFrameStateCombine::Ignore()); 2005 break; 2006 } 2007 case KEYED_PROPERTY: { 2008 environment()->Push(value); 2009 VisitForValue(property->obj()); 2010 VisitForValue(property->key()); 2011 Node* key = environment()->Pop(); 2012 Node* object = environment()->Pop(); 2013 value = environment()->Pop(); 2014 Node* store = BuildKeyedStore(object, key, value, feedback); 2015 PrepareFrameState(store, bailout_id, OutputFrameStateCombine::Ignore()); 2016 break; 2017 } 2018 case NAMED_SUPER_PROPERTY: { 2019 environment()->Push(value); 2020 VisitForValue(property->obj()->AsSuperPropertyReference()->this_var()); 2021 VisitForValue(property->obj()->AsSuperPropertyReference()->home_object()); 2022 Node* home_object = environment()->Pop(); 2023 Node* receiver = environment()->Pop(); 2024 value = environment()->Pop(); 2025 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName(); 2026 Node* store = BuildNamedSuperStore(receiver, home_object, name, value); 2027 PrepareFrameState(store, bailout_id, OutputFrameStateCombine::Ignore()); 2028 break; 2029 } 2030 case KEYED_SUPER_PROPERTY: { 2031 environment()->Push(value); 2032 VisitForValue(property->obj()->AsSuperPropertyReference()->this_var()); 2033 VisitForValue(property->obj()->AsSuperPropertyReference()->home_object()); 2034 VisitForValue(property->key()); 2035 Node* key = environment()->Pop(); 2036 Node* home_object = environment()->Pop(); 2037 Node* receiver = environment()->Pop(); 2038 value = environment()->Pop(); 2039 Node* store = BuildKeyedSuperStore(receiver, home_object, key, value); 2040 PrepareFrameState(store, bailout_id, OutputFrameStateCombine::Ignore()); 2041 break; 2042 } 2043 } 2044 } 2045 2046 2047 void AstGraphBuilder::VisitAssignment(Assignment* expr) { 2048 DCHECK(expr->target()->IsValidReferenceExpressionOrThis()); 2049 2050 // Left-hand side can only be a property, a global or a variable slot. 2051 Property* property = expr->target()->AsProperty(); 2052 LhsKind assign_type = Property::GetAssignType(property); 2053 bool needs_frame_state_before = true; 2054 2055 // Evaluate LHS expression. 2056 switch (assign_type) { 2057 case VARIABLE: { 2058 Variable* variable = expr->target()->AsVariableProxy()->var(); 2059 if (variable->location() == VariableLocation::PARAMETER || 2060 variable->location() == VariableLocation::LOCAL || 2061 variable->location() == VariableLocation::CONTEXT) { 2062 needs_frame_state_before = false; 2063 } 2064 break; 2065 } 2066 case NAMED_PROPERTY: 2067 VisitForValue(property->obj()); 2068 break; 2069 case KEYED_PROPERTY: 2070 VisitForValue(property->obj()); 2071 VisitForValue(property->key()); 2072 break; 2073 case NAMED_SUPER_PROPERTY: 2074 VisitForValue(property->obj()->AsSuperPropertyReference()->this_var()); 2075 VisitForValue(property->obj()->AsSuperPropertyReference()->home_object()); 2076 break; 2077 case KEYED_SUPER_PROPERTY: 2078 VisitForValue(property->obj()->AsSuperPropertyReference()->this_var()); 2079 VisitForValue(property->obj()->AsSuperPropertyReference()->home_object()); 2080 VisitForValue(property->key()); 2081 break; 2082 } 2083 2084 // Evaluate the value and potentially handle compound assignments by loading 2085 // the left-hand side value and performing a binary operation. 2086 if (expr->is_compound()) { 2087 Node* old_value = nullptr; 2088 switch (assign_type) { 2089 case VARIABLE: { 2090 VariableProxy* proxy = expr->target()->AsVariableProxy(); 2091 VectorSlotPair pair = 2092 CreateVectorSlotPair(proxy->VariableFeedbackSlot()); 2093 PrepareEagerCheckpoint(BeforeId(proxy)); 2094 old_value = BuildVariableLoad(proxy->var(), expr->target()->id(), pair, 2095 OutputFrameStateCombine::Push()); 2096 break; 2097 } 2098 case NAMED_PROPERTY: { 2099 Node* object = environment()->Top(); 2100 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName(); 2101 VectorSlotPair pair = 2102 CreateVectorSlotPair(property->PropertyFeedbackSlot()); 2103 old_value = BuildNamedLoad(object, name, pair); 2104 PrepareFrameState(old_value, property->LoadId(), 2105 OutputFrameStateCombine::Push()); 2106 break; 2107 } 2108 case KEYED_PROPERTY: { 2109 Node* key = environment()->Top(); 2110 Node* object = environment()->Peek(1); 2111 VectorSlotPair pair = 2112 CreateVectorSlotPair(property->PropertyFeedbackSlot()); 2113 old_value = BuildKeyedLoad(object, key, pair); 2114 PrepareFrameState(old_value, property->LoadId(), 2115 OutputFrameStateCombine::Push()); 2116 break; 2117 } 2118 case NAMED_SUPER_PROPERTY: { 2119 Node* home_object = environment()->Top(); 2120 Node* receiver = environment()->Peek(1); 2121 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName(); 2122 VectorSlotPair pair = 2123 CreateVectorSlotPair(property->PropertyFeedbackSlot()); 2124 old_value = BuildNamedSuperLoad(receiver, home_object, name, pair); 2125 PrepareFrameState(old_value, property->LoadId(), 2126 OutputFrameStateCombine::Push()); 2127 break; 2128 } 2129 case KEYED_SUPER_PROPERTY: { 2130 Node* key = environment()->Top(); 2131 Node* home_object = environment()->Peek(1); 2132 Node* receiver = environment()->Peek(2); 2133 VectorSlotPair pair = 2134 CreateVectorSlotPair(property->PropertyFeedbackSlot()); 2135 old_value = BuildKeyedSuperLoad(receiver, home_object, key, pair); 2136 PrepareFrameState(old_value, property->LoadId(), 2137 OutputFrameStateCombine::Push()); 2138 break; 2139 } 2140 } 2141 environment()->Push(old_value); 2142 VisitForValue(expr->value()); 2143 Node* right = environment()->Pop(); 2144 Node* left = environment()->Pop(); 2145 Node* value = 2146 BuildBinaryOp(left, right, expr->binary_op(), 2147 expr->binary_operation()->BinaryOperationFeedbackId()); 2148 PrepareFrameState(value, expr->binary_operation()->id(), 2149 OutputFrameStateCombine::Push()); 2150 environment()->Push(value); 2151 if (needs_frame_state_before) { 2152 PrepareEagerCheckpoint(expr->binary_operation()->id()); 2153 } 2154 } else { 2155 VisitForValue(expr->value()); 2156 } 2157 2158 // Store the value. 2159 Node* value = environment()->Pop(); 2160 VectorSlotPair feedback = CreateVectorSlotPair(expr->AssignmentSlot()); 2161 switch (assign_type) { 2162 case VARIABLE: { 2163 Variable* variable = expr->target()->AsVariableProxy()->var(); 2164 BuildVariableAssignment(variable, value, expr->op(), feedback, expr->id(), 2165 ast_context()->GetStateCombine()); 2166 break; 2167 } 2168 case NAMED_PROPERTY: { 2169 Node* object = environment()->Pop(); 2170 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName(); 2171 Node* store = BuildNamedStore(object, name, value, feedback); 2172 PrepareFrameState(store, expr->AssignmentId(), 2173 OutputFrameStateCombine::Push()); 2174 break; 2175 } 2176 case KEYED_PROPERTY: { 2177 Node* key = environment()->Pop(); 2178 Node* object = environment()->Pop(); 2179 Node* store = BuildKeyedStore(object, key, value, feedback); 2180 PrepareFrameState(store, expr->AssignmentId(), 2181 OutputFrameStateCombine::Push()); 2182 break; 2183 } 2184 case NAMED_SUPER_PROPERTY: { 2185 Node* home_object = environment()->Pop(); 2186 Node* receiver = environment()->Pop(); 2187 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName(); 2188 Node* store = BuildNamedSuperStore(receiver, home_object, name, value); 2189 PrepareFrameState(store, expr->id(), ast_context()->GetStateCombine()); 2190 break; 2191 } 2192 case KEYED_SUPER_PROPERTY: { 2193 Node* key = environment()->Pop(); 2194 Node* home_object = environment()->Pop(); 2195 Node* receiver = environment()->Pop(); 2196 Node* store = BuildKeyedSuperStore(receiver, home_object, key, value); 2197 PrepareFrameState(store, expr->id(), ast_context()->GetStateCombine()); 2198 break; 2199 } 2200 } 2201 2202 ast_context()->ProduceValue(expr, value); 2203 } 2204 2205 2206 void AstGraphBuilder::VisitYield(Yield* expr) { 2207 // Generator functions are supported only by going through Ignition first. 2208 SetStackOverflow(); 2209 ast_context()->ProduceValue(expr, jsgraph()->UndefinedConstant()); 2210 } 2211 2212 2213 void AstGraphBuilder::VisitThrow(Throw* expr) { 2214 VisitForValue(expr->exception()); 2215 Node* exception = environment()->Pop(); 2216 Node* value = BuildThrowError(exception, expr->id()); 2217 ast_context()->ProduceValue(expr, value); 2218 } 2219 2220 2221 void AstGraphBuilder::VisitProperty(Property* expr) { 2222 Node* value = nullptr; 2223 LhsKind property_kind = Property::GetAssignType(expr); 2224 VectorSlotPair pair = CreateVectorSlotPair(expr->PropertyFeedbackSlot()); 2225 switch (property_kind) { 2226 case VARIABLE: 2227 UNREACHABLE(); 2228 break; 2229 case NAMED_PROPERTY: { 2230 VisitForValue(expr->obj()); 2231 Node* object = environment()->Pop(); 2232 Handle<Name> name = expr->key()->AsLiteral()->AsPropertyName(); 2233 value = BuildNamedLoad(object, name, pair); 2234 PrepareFrameState(value, expr->LoadId(), OutputFrameStateCombine::Push()); 2235 break; 2236 } 2237 case KEYED_PROPERTY: { 2238 VisitForValue(expr->obj()); 2239 VisitForValue(expr->key()); 2240 Node* key = environment()->Pop(); 2241 Node* object = environment()->Pop(); 2242 value = BuildKeyedLoad(object, key, pair); 2243 PrepareFrameState(value, expr->LoadId(), OutputFrameStateCombine::Push()); 2244 break; 2245 } 2246 case NAMED_SUPER_PROPERTY: { 2247 VisitForValue(expr->obj()->AsSuperPropertyReference()->this_var()); 2248 VisitForValue(expr->obj()->AsSuperPropertyReference()->home_object()); 2249 Node* home_object = environment()->Pop(); 2250 Node* receiver = environment()->Pop(); 2251 Handle<Name> name = expr->key()->AsLiteral()->AsPropertyName(); 2252 value = BuildNamedSuperLoad(receiver, home_object, name, pair); 2253 PrepareFrameState(value, expr->LoadId(), OutputFrameStateCombine::Push()); 2254 break; 2255 } 2256 case KEYED_SUPER_PROPERTY: { 2257 VisitForValue(expr->obj()->AsSuperPropertyReference()->this_var()); 2258 VisitForValue(expr->obj()->AsSuperPropertyReference()->home_object()); 2259 VisitForValue(expr->key()); 2260 Node* key = environment()->Pop(); 2261 Node* home_object = environment()->Pop(); 2262 Node* receiver = environment()->Pop(); 2263 value = BuildKeyedSuperLoad(receiver, home_object, key, pair); 2264 PrepareFrameState(value, expr->LoadId(), OutputFrameStateCombine::Push()); 2265 break; 2266 } 2267 } 2268 ast_context()->ProduceValue(expr, value); 2269 } 2270 2271 2272 void AstGraphBuilder::VisitCall(Call* expr) { 2273 Expression* callee = expr->expression(); 2274 Call::CallType call_type = expr->GetCallType(); 2275 2276 // Prepare the callee and the receiver to the function call. This depends on 2277 // the semantics of the underlying call type. 2278 ConvertReceiverMode receiver_hint = ConvertReceiverMode::kAny; 2279 Node* receiver_value = nullptr; 2280 Node* callee_value = nullptr; 2281 if (expr->is_possibly_eval()) { 2282 if (callee->AsVariableProxy()->var()->IsLookupSlot()) { 2283 Variable* variable = callee->AsVariableProxy()->var(); 2284 Node* name = jsgraph()->Constant(variable->name()); 2285 const Operator* op = 2286 javascript()->CallRuntime(Runtime::kLoadLookupSlotForCall); 2287 Node* pair = NewNode(op, name); 2288 callee_value = NewNode(common()->Projection(0), pair); 2289 receiver_value = NewNode(common()->Projection(1), pair); 2290 PrepareFrameState(pair, expr->LookupId(), 2291 OutputFrameStateCombine::Push(2)); 2292 } else { 2293 VisitForValue(callee); 2294 callee_value = environment()->Pop(); 2295 receiver_hint = ConvertReceiverMode::kNullOrUndefined; 2296 receiver_value = jsgraph()->UndefinedConstant(); 2297 } 2298 } else { 2299 switch (call_type) { 2300 case Call::GLOBAL_CALL: { 2301 VariableProxy* proxy = callee->AsVariableProxy(); 2302 VectorSlotPair pair = 2303 CreateVectorSlotPair(proxy->VariableFeedbackSlot()); 2304 PrepareEagerCheckpoint(BeforeId(proxy)); 2305 callee_value = BuildVariableLoad(proxy->var(), expr->expression()->id(), 2306 pair, OutputFrameStateCombine::Push()); 2307 receiver_hint = ConvertReceiverMode::kNullOrUndefined; 2308 receiver_value = jsgraph()->UndefinedConstant(); 2309 break; 2310 } 2311 case Call::WITH_CALL: { 2312 Variable* variable = callee->AsVariableProxy()->var(); 2313 Node* name = jsgraph()->Constant(variable->name()); 2314 const Operator* op = 2315 javascript()->CallRuntime(Runtime::kLoadLookupSlotForCall); 2316 Node* pair = NewNode(op, name); 2317 callee_value = NewNode(common()->Projection(0), pair); 2318 receiver_value = NewNode(common()->Projection(1), pair); 2319 PrepareFrameState(pair, expr->LookupId(), 2320 OutputFrameStateCombine::Push(2)); 2321 break; 2322 } 2323 case Call::NAMED_PROPERTY_CALL: { 2324 Property* property = callee->AsProperty(); 2325 VectorSlotPair feedback = 2326 CreateVectorSlotPair(property->PropertyFeedbackSlot()); 2327 VisitForValue(property->obj()); 2328 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName(); 2329 Node* object = environment()->Top(); 2330 callee_value = BuildNamedLoad(object, name, feedback); 2331 PrepareFrameState(callee_value, property->LoadId(), 2332 OutputFrameStateCombine::Push()); 2333 // Note that a property call requires the receiver to be wrapped into 2334 // an object for sloppy callees. However the receiver is guaranteed 2335 // not to be null or undefined at this point. 2336 receiver_hint = ConvertReceiverMode::kNotNullOrUndefined; 2337 receiver_value = environment()->Pop(); 2338 break; 2339 } 2340 case Call::KEYED_PROPERTY_CALL: { 2341 Property* property = callee->AsProperty(); 2342 VectorSlotPair feedback = 2343 CreateVectorSlotPair(property->PropertyFeedbackSlot()); 2344 VisitForValue(property->obj()); 2345 VisitForValue(property->key()); 2346 Node* key = environment()->Pop(); 2347 Node* object = environment()->Top(); 2348 callee_value = BuildKeyedLoad(object, key, feedback); 2349 PrepareFrameState(callee_value, property->LoadId(), 2350 OutputFrameStateCombine::Push()); 2351 // Note that a property call requires the receiver to be wrapped into 2352 // an object for sloppy callees. However the receiver is guaranteed 2353 // not to be null or undefined at this point. 2354 receiver_hint = ConvertReceiverMode::kNotNullOrUndefined; 2355 receiver_value = environment()->Pop(); 2356 break; 2357 } 2358 case Call::NAMED_SUPER_PROPERTY_CALL: { 2359 Property* property = callee->AsProperty(); 2360 SuperPropertyReference* super_ref = 2361 property->obj()->AsSuperPropertyReference(); 2362 VisitForValue(super_ref->home_object()); 2363 VisitForValue(super_ref->this_var()); 2364 Node* home = environment()->Peek(1); 2365 Node* object = environment()->Top(); 2366 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName(); 2367 callee_value = 2368 BuildNamedSuperLoad(object, home, name, VectorSlotPair()); 2369 PrepareFrameState(callee_value, property->LoadId(), 2370 OutputFrameStateCombine::Push()); 2371 // Note that a property call requires the receiver to be wrapped into 2372 // an object for sloppy callees. Since the receiver is not the target of 2373 // the load, it could very well be null or undefined at this point. 2374 receiver_value = environment()->Pop(); 2375 environment()->Drop(1); 2376 break; 2377 } 2378 case Call::KEYED_SUPER_PROPERTY_CALL: { 2379 Property* property = callee->AsProperty(); 2380 SuperPropertyReference* super_ref = 2381 property->obj()->AsSuperPropertyReference(); 2382 VisitForValue(super_ref->home_object()); 2383 VisitForValue(super_ref->this_var()); 2384 environment()->Push(environment()->Top()); // Duplicate this_var. 2385 environment()->Push(environment()->Peek(2)); // Duplicate home_obj. 2386 VisitForValue(property->key()); 2387 Node* key = environment()->Pop(); 2388 Node* home = environment()->Pop(); 2389 Node* object = environment()->Pop(); 2390 callee_value = BuildKeyedSuperLoad(object, home, key, VectorSlotPair()); 2391 PrepareFrameState(callee_value, property->LoadId(), 2392 OutputFrameStateCombine::Push()); 2393 // Note that a property call requires the receiver to be wrapped into 2394 // an object for sloppy callees. Since the receiver is not the target of 2395 // the load, it could very well be null or undefined at this point. 2396 receiver_value = environment()->Pop(); 2397 environment()->Drop(1); 2398 break; 2399 } 2400 case Call::SUPER_CALL: 2401 return VisitCallSuper(expr); 2402 case Call::OTHER_CALL: 2403 VisitForValue(callee); 2404 callee_value = environment()->Pop(); 2405 receiver_hint = ConvertReceiverMode::kNullOrUndefined; 2406 receiver_value = jsgraph()->UndefinedConstant(); 2407 break; 2408 } 2409 } 2410 2411 // The callee and the receiver both have to be pushed onto the operand stack 2412 // before arguments are being evaluated. 2413 environment()->Push(callee_value); 2414 environment()->Push(receiver_value); 2415 2416 // Evaluate all arguments to the function call, 2417 ZoneList<Expression*>* args = expr->arguments(); 2418 VisitForValues(args); 2419 2420 // Resolve callee for a potential direct eval call. This block will mutate the 2421 // callee value pushed onto the environment. 2422 if (expr->is_possibly_eval() && args->length() > 0) { 2423 int arg_count = args->length(); 2424 2425 // Extract callee and source string from the environment. 2426 Node* callee = environment()->Peek(arg_count + 1); 2427 Node* source = environment()->Peek(arg_count - 1); 2428 2429 // Create node to ask for help resolving potential eval call. This will 2430 // provide a fully resolved callee to patch into the environment. 2431 Node* function = GetFunctionClosure(); 2432 Node* language = jsgraph()->Constant(language_mode()); 2433 Node* eval_scope_position = 2434 jsgraph()->Constant(current_scope()->start_position()); 2435 Node* eval_position = jsgraph()->Constant(expr->position()); 2436 const Operator* op = 2437 javascript()->CallRuntime(Runtime::kResolvePossiblyDirectEval); 2438 Node* new_callee = NewNode(op, callee, source, function, language, 2439 eval_scope_position, eval_position); 2440 PrepareFrameState(new_callee, expr->EvalId(), 2441 OutputFrameStateCombine::PokeAt(arg_count + 1)); 2442 2443 // Patch callee on the environment. 2444 environment()->Poke(arg_count + 1, new_callee); 2445 } 2446 2447 // Create node to perform the function call. 2448 float const frequency = ComputeCallFrequency(expr->CallFeedbackICSlot()); 2449 VectorSlotPair feedback = CreateVectorSlotPair(expr->CallFeedbackICSlot()); 2450 const Operator* call = 2451 javascript()->CallFunction(args->length() + 2, frequency, feedback, 2452 receiver_hint, expr->tail_call_mode()); 2453 PrepareEagerCheckpoint(expr->is_possibly_eval() ? expr->EvalId() 2454 : expr->CallId()); 2455 Node* value = ProcessArguments(call, args->length() + 2); 2456 // The callee passed to the call, we just need to push something here to 2457 // satisfy the bailout location contract. The fullcodegen code will not 2458 // ever look at this value, so we just push optimized_out here. 2459 environment()->Push(jsgraph()->OptimizedOutConstant()); 2460 PrepareFrameState(value, expr->ReturnId(), OutputFrameStateCombine::Push()); 2461 environment()->Drop(1); 2462 ast_context()->ProduceValue(expr, value); 2463 } 2464 2465 2466 void AstGraphBuilder::VisitCallSuper(Call* expr) { 2467 SuperCallReference* super = expr->expression()->AsSuperCallReference(); 2468 DCHECK_NOT_NULL(super); 2469 2470 // Prepare the callee to the super call. 2471 VisitForValue(super->this_function_var()); 2472 Node* this_function = environment()->Pop(); 2473 const Operator* op = 2474 javascript()->CallRuntime(Runtime::kInlineGetSuperConstructor, 1); 2475 Node* super_function = NewNode(op, this_function); 2476 environment()->Push(super_function); 2477 2478 // Evaluate all arguments to the super call. 2479 ZoneList<Expression*>* args = expr->arguments(); 2480 VisitForValues(args); 2481 2482 // The new target is loaded from the {new.target} variable. 2483 VisitForValue(super->new_target_var()); 2484 2485 // Create node to perform the super call. 2486 const Operator* call = 2487 javascript()->CallConstruct(args->length() + 2, 0.0f, VectorSlotPair()); 2488 Node* value = ProcessArguments(call, args->length() + 2); 2489 PrepareFrameState(value, expr->ReturnId(), OutputFrameStateCombine::Push()); 2490 ast_context()->ProduceValue(expr, value); 2491 } 2492 2493 2494 void AstGraphBuilder::VisitCallNew(CallNew* expr) { 2495 VisitForValue(expr->expression()); 2496 2497 // Evaluate all arguments to the construct call. 2498 ZoneList<Expression*>* args = expr->arguments(); 2499 VisitForValues(args); 2500 2501 // The new target is the same as the callee. 2502 environment()->Push(environment()->Peek(args->length())); 2503 2504 // Create node to perform the construct call. 2505 float const frequency = ComputeCallFrequency(expr->CallNewFeedbackSlot()); 2506 VectorSlotPair feedback = CreateVectorSlotPair(expr->CallNewFeedbackSlot()); 2507 const Operator* call = 2508 javascript()->CallConstruct(args->length() + 2, frequency, feedback); 2509 Node* value = ProcessArguments(call, args->length() + 2); 2510 PrepareFrameState(value, expr->ReturnId(), OutputFrameStateCombine::Push()); 2511 ast_context()->ProduceValue(expr, value); 2512 } 2513 2514 2515 void AstGraphBuilder::VisitCallJSRuntime(CallRuntime* expr) { 2516 // The callee and the receiver both have to be pushed onto the operand stack 2517 // before arguments are being evaluated. 2518 Node* callee_value = BuildLoadNativeContextField(expr->context_index()); 2519 Node* receiver_value = jsgraph()->UndefinedConstant(); 2520 2521 environment()->Push(callee_value); 2522 environment()->Push(receiver_value); 2523 2524 // Evaluate all arguments to the JS runtime call. 2525 ZoneList<Expression*>* args = expr->arguments(); 2526 VisitForValues(args); 2527 2528 // Create node to perform the JS runtime call. 2529 const Operator* call = javascript()->CallFunction(args->length() + 2); 2530 PrepareEagerCheckpoint(expr->CallId()); 2531 Node* value = ProcessArguments(call, args->length() + 2); 2532 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine()); 2533 ast_context()->ProduceValue(expr, value); 2534 } 2535 2536 2537 void AstGraphBuilder::VisitCallRuntime(CallRuntime* expr) { 2538 // Handle calls to runtime functions implemented in JavaScript separately as 2539 // the call follows JavaScript ABI and the callee is statically unknown. 2540 if (expr->is_jsruntime()) { 2541 return VisitCallJSRuntime(expr); 2542 } 2543 2544 // Evaluate all arguments to the runtime call. 2545 ZoneList<Expression*>* args = expr->arguments(); 2546 VisitForValues(args); 2547 2548 // Create node to perform the runtime call. 2549 Runtime::FunctionId functionId = expr->function()->function_id; 2550 const Operator* call = javascript()->CallRuntime(functionId, args->length()); 2551 if (expr->function()->intrinsic_type == Runtime::IntrinsicType::RUNTIME || 2552 expr->function()->function_id == Runtime::kInlineCall) { 2553 PrepareEagerCheckpoint(expr->CallId()); 2554 } 2555 Node* value = ProcessArguments(call, args->length()); 2556 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine()); 2557 ast_context()->ProduceValue(expr, value); 2558 } 2559 2560 2561 void AstGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { 2562 switch (expr->op()) { 2563 case Token::DELETE: 2564 return VisitDelete(expr); 2565 case Token::VOID: 2566 return VisitVoid(expr); 2567 case Token::TYPEOF: 2568 return VisitTypeof(expr); 2569 case Token::NOT: 2570 return VisitNot(expr); 2571 default: 2572 UNREACHABLE(); 2573 } 2574 } 2575 2576 2577 void AstGraphBuilder::VisitCountOperation(CountOperation* expr) { 2578 DCHECK(expr->expression()->IsValidReferenceExpressionOrThis()); 2579 2580 // Left-hand side can only be a property, a global or a variable slot. 2581 Property* property = expr->expression()->AsProperty(); 2582 LhsKind assign_type = Property::GetAssignType(property); 2583 2584 // Reserve space for result of postfix operation. 2585 bool is_postfix = expr->is_postfix() && !ast_context()->IsEffect(); 2586 if (is_postfix && assign_type != VARIABLE) { 2587 environment()->Push(jsgraph()->ZeroConstant()); 2588 } 2589 2590 // Evaluate LHS expression and get old value. 2591 Node* old_value = nullptr; 2592 int stack_depth = -1; 2593 switch (assign_type) { 2594 case VARIABLE: { 2595 VariableProxy* proxy = expr->expression()->AsVariableProxy(); 2596 VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot()); 2597 PrepareEagerCheckpoint(BeforeId(proxy)); 2598 old_value = BuildVariableLoad(proxy->var(), expr->expression()->id(), 2599 pair, OutputFrameStateCombine::Push()); 2600 stack_depth = 0; 2601 break; 2602 } 2603 case NAMED_PROPERTY: { 2604 VisitForValue(property->obj()); 2605 Node* object = environment()->Top(); 2606 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName(); 2607 VectorSlotPair pair = 2608 CreateVectorSlotPair(property->PropertyFeedbackSlot()); 2609 old_value = BuildNamedLoad(object, name, pair); 2610 PrepareFrameState(old_value, property->LoadId(), 2611 OutputFrameStateCombine::Push()); 2612 stack_depth = 1; 2613 break; 2614 } 2615 case KEYED_PROPERTY: { 2616 VisitForValue(property->obj()); 2617 VisitForValue(property->key()); 2618 Node* key = environment()->Top(); 2619 Node* object = environment()->Peek(1); 2620 VectorSlotPair pair = 2621 CreateVectorSlotPair(property->PropertyFeedbackSlot()); 2622 old_value = BuildKeyedLoad(object, key, pair); 2623 PrepareFrameState(old_value, property->LoadId(), 2624 OutputFrameStateCombine::Push()); 2625 stack_depth = 2; 2626 break; 2627 } 2628 case NAMED_SUPER_PROPERTY: { 2629 VisitForValue(property->obj()->AsSuperPropertyReference()->this_var()); 2630 VisitForValue(property->obj()->AsSuperPropertyReference()->home_object()); 2631 Node* home_object = environment()->Top(); 2632 Node* receiver = environment()->Peek(1); 2633 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName(); 2634 VectorSlotPair pair = 2635 CreateVectorSlotPair(property->PropertyFeedbackSlot()); 2636 old_value = BuildNamedSuperLoad(receiver, home_object, name, pair); 2637 PrepareFrameState(old_value, property->LoadId(), 2638 OutputFrameStateCombine::Push()); 2639 stack_depth = 2; 2640 break; 2641 } 2642 case KEYED_SUPER_PROPERTY: { 2643 VisitForValue(property->obj()->AsSuperPropertyReference()->this_var()); 2644 VisitForValue(property->obj()->AsSuperPropertyReference()->home_object()); 2645 VisitForValue(property->key()); 2646 Node* key = environment()->Top(); 2647 Node* home_object = environment()->Peek(1); 2648 Node* receiver = environment()->Peek(2); 2649 VectorSlotPair pair = 2650 CreateVectorSlotPair(property->PropertyFeedbackSlot()); 2651 old_value = BuildKeyedSuperLoad(receiver, home_object, key, pair); 2652 PrepareFrameState(old_value, property->LoadId(), 2653 OutputFrameStateCombine::Push()); 2654 stack_depth = 3; 2655 break; 2656 } 2657 } 2658 2659 // Convert old value into a number. 2660 old_value = NewNode(javascript()->ToNumber(), old_value); 2661 PrepareFrameState(old_value, expr->ToNumberId(), 2662 OutputFrameStateCombine::Push()); 2663 2664 // Create a proper eager frame state for the stores. 2665 environment()->Push(old_value); 2666 PrepareEagerCheckpoint(expr->ToNumberId()); 2667 old_value = environment()->Pop(); 2668 2669 // Save result for postfix expressions at correct stack depth. 2670 if (is_postfix) { 2671 if (assign_type != VARIABLE) { 2672 environment()->Poke(stack_depth, old_value); 2673 } else { 2674 environment()->Push(old_value); 2675 } 2676 } 2677 2678 // Create node to perform +1/-1 operation. 2679 Node* value = BuildBinaryOp(old_value, jsgraph()->OneConstant(), 2680 expr->binary_op(), expr->CountBinOpFeedbackId()); 2681 // This should never lazy deopt because we have converted to number before. 2682 PrepareFrameState(value, BailoutId::None()); 2683 2684 // Store the value. 2685 VectorSlotPair feedback = CreateVectorSlotPair(expr->CountSlot()); 2686 switch (assign_type) { 2687 case VARIABLE: { 2688 Variable* variable = expr->expression()->AsVariableProxy()->var(); 2689 environment()->Push(value); 2690 BuildVariableAssignment(variable, value, expr->op(), feedback, 2691 expr->AssignmentId()); 2692 environment()->Pop(); 2693 break; 2694 } 2695 case NAMED_PROPERTY: { 2696 Node* object = environment()->Pop(); 2697 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName(); 2698 Node* store = BuildNamedStore(object, name, value, feedback); 2699 PrepareFrameState(store, expr->AssignmentId(), 2700 OutputFrameStateCombine::Push()); 2701 break; 2702 } 2703 case KEYED_PROPERTY: { 2704 Node* key = environment()->Pop(); 2705 Node* object = environment()->Pop(); 2706 Node* store = BuildKeyedStore(object, key, value, feedback); 2707 PrepareFrameState(store, expr->AssignmentId(), 2708 OutputFrameStateCombine::Push()); 2709 break; 2710 } 2711 case NAMED_SUPER_PROPERTY: { 2712 Node* home_object = environment()->Pop(); 2713 Node* receiver = environment()->Pop(); 2714 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName(); 2715 Node* store = BuildNamedSuperStore(receiver, home_object, name, value); 2716 PrepareFrameState(store, expr->AssignmentId(), 2717 OutputFrameStateCombine::Push()); 2718 break; 2719 } 2720 case KEYED_SUPER_PROPERTY: { 2721 Node* key = environment()->Pop(); 2722 Node* home_object = environment()->Pop(); 2723 Node* receiver = environment()->Pop(); 2724 Node* store = BuildKeyedSuperStore(receiver, home_object, key, value); 2725 PrepareFrameState(store, expr->AssignmentId(), 2726 OutputFrameStateCombine::Push()); 2727 break; 2728 } 2729 } 2730 2731 // Restore old value for postfix expressions. 2732 if (is_postfix) value = environment()->Pop(); 2733 2734 ast_context()->ProduceValue(expr, value); 2735 } 2736 2737 2738 void AstGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { 2739 switch (expr->op()) { 2740 case Token::COMMA: 2741 return VisitComma(expr); 2742 case Token::OR: 2743 case Token::AND: 2744 return VisitLogicalExpression(expr); 2745 default: { 2746 VisitForValue(expr->left()); 2747 VisitForValue(expr->right()); 2748 Node* right = environment()->Pop(); 2749 Node* left = environment()->Pop(); 2750 Node* value = BuildBinaryOp(left, right, expr->op(), 2751 expr->BinaryOperationFeedbackId()); 2752 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine()); 2753 ast_context()->ProduceValue(expr, value); 2754 } 2755 } 2756 } 2757 2758 void AstGraphBuilder::VisitLiteralCompareNil(CompareOperation* expr, 2759 Expression* sub_expr, 2760 Node* nil_value) { 2761 const Operator* op = nullptr; 2762 switch (expr->op()) { 2763 case Token::EQ: 2764 op = javascript()->Equal(CompareOperationHint::kAny); 2765 break; 2766 case Token::EQ_STRICT: 2767 op = javascript()->StrictEqual(CompareOperationHint::kAny); 2768 break; 2769 default: 2770 UNREACHABLE(); 2771 } 2772 VisitForValue(sub_expr); 2773 Node* value_to_compare = environment()->Pop(); 2774 Node* value = NewNode(op, value_to_compare, nil_value); 2775 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine()); 2776 return ast_context()->ProduceValue(expr, value); 2777 } 2778 2779 void AstGraphBuilder::VisitLiteralCompareTypeof(CompareOperation* expr, 2780 Expression* sub_expr, 2781 Handle<String> check) { 2782 VisitTypeofExpression(sub_expr); 2783 Node* typeof_arg = NewNode(javascript()->TypeOf(), environment()->Pop()); 2784 Node* value = NewNode(javascript()->StrictEqual(CompareOperationHint::kAny), 2785 typeof_arg, jsgraph()->Constant(check)); 2786 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine()); 2787 return ast_context()->ProduceValue(expr, value); 2788 } 2789 2790 void AstGraphBuilder::VisitCompareOperation(CompareOperation* expr) { 2791 // Check for a few fast cases. The AST visiting behavior must be in sync 2792 // with the full codegen: We don't push both left and right values onto 2793 // the expression stack when one side is a special-case literal. 2794 Expression* sub_expr = nullptr; 2795 Handle<String> check; 2796 if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) { 2797 return VisitLiteralCompareTypeof(expr, sub_expr, check); 2798 } 2799 if (expr->IsLiteralCompareUndefined(&sub_expr)) { 2800 return VisitLiteralCompareNil(expr, sub_expr, 2801 jsgraph()->UndefinedConstant()); 2802 } 2803 if (expr->IsLiteralCompareNull(&sub_expr)) { 2804 return VisitLiteralCompareNil(expr, sub_expr, jsgraph()->NullConstant()); 2805 } 2806 2807 CompareOperationHint hint; 2808 if (!type_hint_analysis_ || 2809 !type_hint_analysis_->GetCompareOperationHint( 2810 expr->CompareOperationFeedbackId(), &hint)) { 2811 hint = CompareOperationHint::kAny; 2812 } 2813 2814 const Operator* op; 2815 switch (expr->op()) { 2816 case Token::EQ: 2817 op = javascript()->Equal(hint); 2818 break; 2819 case Token::NE: 2820 op = javascript()->NotEqual(hint); 2821 break; 2822 case Token::EQ_STRICT: 2823 op = javascript()->StrictEqual(hint); 2824 break; 2825 case Token::NE_STRICT: 2826 op = javascript()->StrictNotEqual(hint); 2827 break; 2828 case Token::LT: 2829 op = javascript()->LessThan(hint); 2830 break; 2831 case Token::GT: 2832 op = javascript()->GreaterThan(hint); 2833 break; 2834 case Token::LTE: 2835 op = javascript()->LessThanOrEqual(hint); 2836 break; 2837 case Token::GTE: 2838 op = javascript()->GreaterThanOrEqual(hint); 2839 break; 2840 case Token::INSTANCEOF: 2841 op = javascript()->InstanceOf(); 2842 break; 2843 case Token::IN: 2844 op = javascript()->HasProperty(); 2845 break; 2846 default: 2847 op = nullptr; 2848 UNREACHABLE(); 2849 } 2850 VisitForValue(expr->left()); 2851 VisitForValue(expr->right()); 2852 Node* right = environment()->Pop(); 2853 Node* left = environment()->Pop(); 2854 Node* value = NewNode(op, left, right); 2855 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine()); 2856 ast_context()->ProduceValue(expr, value); 2857 } 2858 2859 2860 void AstGraphBuilder::VisitSpread(Spread* expr) { 2861 // Handled entirely by the parser itself. 2862 UNREACHABLE(); 2863 } 2864 2865 2866 void AstGraphBuilder::VisitEmptyParentheses(EmptyParentheses* expr) { 2867 // Handled entirely by the parser itself. 2868 UNREACHABLE(); 2869 } 2870 2871 2872 void AstGraphBuilder::VisitThisFunction(ThisFunction* expr) { 2873 Node* value = GetFunctionClosure(); 2874 ast_context()->ProduceValue(expr, value); 2875 } 2876 2877 2878 void AstGraphBuilder::VisitSuperPropertyReference( 2879 SuperPropertyReference* expr) { 2880 Node* value = BuildThrowUnsupportedSuperError(expr->id()); 2881 ast_context()->ProduceValue(expr, value); 2882 } 2883 2884 2885 void AstGraphBuilder::VisitSuperCallReference(SuperCallReference* expr) { 2886 // Handled by VisitCall 2887 UNREACHABLE(); 2888 } 2889 2890 2891 void AstGraphBuilder::VisitCaseClause(CaseClause* expr) { 2892 // Handled entirely in VisitSwitch. 2893 UNREACHABLE(); 2894 } 2895 2896 void AstGraphBuilder::VisitDeclarations(Declaration::List* declarations) { 2897 DCHECK(globals()->empty()); 2898 AstVisitor<AstGraphBuilder>::VisitDeclarations(declarations); 2899 if (globals()->empty()) return; 2900 int array_index = 0; 2901 Handle<TypeFeedbackVector> feedback_vector( 2902 info()->closure()->feedback_vector()); 2903 Handle<FixedArray> data = isolate()->factory()->NewFixedArray( 2904 static_cast<int>(globals()->size()), TENURED); 2905 for (Handle<Object> obj : *globals()) data->set(array_index++, *obj); 2906 int encoded_flags = info()->GetDeclareGlobalsFlags(); 2907 Node* flags = jsgraph()->Constant(encoded_flags); 2908 Node* pairs = jsgraph()->Constant(data); 2909 Node* vector = jsgraph()->Constant(feedback_vector); 2910 const Operator* op = javascript()->CallRuntime(Runtime::kDeclareGlobals); 2911 Node* call = NewNode(op, pairs, flags, vector); 2912 PrepareFrameState(call, BailoutId::Declarations()); 2913 globals()->clear(); 2914 } 2915 2916 2917 void AstGraphBuilder::VisitIfNotNull(Statement* stmt) { 2918 if (stmt == nullptr) return; 2919 Visit(stmt); 2920 } 2921 2922 2923 void AstGraphBuilder::VisitInScope(Statement* stmt, Scope* s, Node* context) { 2924 ContextScope scope(this, s, context); 2925 DCHECK(s->declarations()->is_empty()); 2926 Visit(stmt); 2927 } 2928 2929 void AstGraphBuilder::VisitIterationBody(IterationStatement* stmt, 2930 LoopBuilder* loop, 2931 BailoutId stack_check_id) { 2932 ControlScopeForIteration scope(this, stmt, loop); 2933 if (FLAG_turbo_loop_stackcheck || !info()->shared_info()->asm_function()) { 2934 Node* node = NewNode(javascript()->StackCheck()); 2935 PrepareFrameState(node, stack_check_id); 2936 } 2937 Visit(stmt->body()); 2938 } 2939 2940 2941 void AstGraphBuilder::VisitDelete(UnaryOperation* expr) { 2942 Node* value; 2943 if (expr->expression()->IsVariableProxy()) { 2944 // Delete of an unqualified identifier is disallowed in strict mode but 2945 // "delete this" is allowed. 2946 Variable* variable = expr->expression()->AsVariableProxy()->var(); 2947 DCHECK(is_sloppy(language_mode()) || variable->is_this()); 2948 value = BuildVariableDelete(variable, expr->id(), 2949 ast_context()->GetStateCombine()); 2950 } else if (expr->expression()->IsProperty()) { 2951 Property* property = expr->expression()->AsProperty(); 2952 VisitForValue(property->obj()); 2953 VisitForValue(property->key()); 2954 Node* key = environment()->Pop(); 2955 Node* object = environment()->Pop(); 2956 value = NewNode(javascript()->DeleteProperty(language_mode()), object, key); 2957 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine()); 2958 } else { 2959 VisitForEffect(expr->expression()); 2960 value = jsgraph()->TrueConstant(); 2961 } 2962 ast_context()->ProduceValue(expr, value); 2963 } 2964 2965 2966 void AstGraphBuilder::VisitVoid(UnaryOperation* expr) { 2967 VisitForEffect(expr->expression()); 2968 Node* value = jsgraph()->UndefinedConstant(); 2969 ast_context()->ProduceValue(expr, value); 2970 } 2971 2972 void AstGraphBuilder::VisitTypeofExpression(Expression* expr) { 2973 if (expr->IsVariableProxy()) { 2974 // Typeof does not throw a reference error on global variables, hence we 2975 // perform a non-contextual load in case the operand is a variable proxy. 2976 VariableProxy* proxy = expr->AsVariableProxy(); 2977 VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot()); 2978 PrepareEagerCheckpoint(BeforeId(proxy)); 2979 Node* load = 2980 BuildVariableLoad(proxy->var(), expr->id(), pair, 2981 OutputFrameStateCombine::Push(), INSIDE_TYPEOF); 2982 environment()->Push(load); 2983 } else { 2984 VisitForValue(expr); 2985 } 2986 } 2987 2988 void AstGraphBuilder::VisitTypeof(UnaryOperation* expr) { 2989 VisitTypeofExpression(expr->expression()); 2990 Node* value = NewNode(javascript()->TypeOf(), environment()->Pop()); 2991 ast_context()->ProduceValue(expr, value); 2992 } 2993 2994 2995 void AstGraphBuilder::VisitNot(UnaryOperation* expr) { 2996 VisitForTest(expr->expression()); 2997 Node* input = environment()->Pop(); 2998 Node* value = NewNode(common()->Select(MachineRepresentation::kTagged), input, 2999 jsgraph()->FalseConstant(), jsgraph()->TrueConstant()); 3000 // Skip plugging AST evaluation contexts of the test kind. This is to stay in 3001 // sync with full codegen which doesn't prepare the proper bailout point (see 3002 // the implementation of FullCodeGenerator::VisitForControl). 3003 if (ast_context()->IsTest()) return environment()->Push(value); 3004 ast_context()->ProduceValue(expr, value); 3005 } 3006 3007 3008 void AstGraphBuilder::VisitComma(BinaryOperation* expr) { 3009 VisitForEffect(expr->left()); 3010 Visit(expr->right()); 3011 // Skip plugging AST evaluation contexts of the test kind. This is to stay in 3012 // sync with full codegen which doesn't prepare the proper bailout point (see 3013 // the implementation of FullCodeGenerator::VisitForControl). 3014 if (ast_context()->IsTest()) return; 3015 ast_context()->ReplaceValue(expr); 3016 } 3017 3018 3019 void AstGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) { 3020 bool is_logical_and = expr->op() == Token::AND; 3021 IfBuilder compare_if(this); 3022 // Only use an AST evaluation context of the value kind when this expression 3023 // is evaluated as value as well. Otherwise stick to a test context which is 3024 // in sync with full codegen (see FullCodeGenerator::VisitLogicalExpression). 3025 Node* condition = nullptr; 3026 if (ast_context()->IsValue()) { 3027 VisitForValue(expr->left()); 3028 Node* left = environment()->Top(); 3029 condition = BuildToBoolean(left, expr->left()->test_id()); 3030 } else { 3031 VisitForTest(expr->left()); 3032 condition = environment()->Top(); 3033 } 3034 compare_if.If(condition); 3035 compare_if.Then(); 3036 if (is_logical_and) { 3037 environment()->Pop(); 3038 Visit(expr->right()); 3039 } else if (ast_context()->IsEffect()) { 3040 environment()->Pop(); 3041 } else if (ast_context()->IsTest()) { 3042 environment()->Poke(0, jsgraph()->TrueConstant()); 3043 } 3044 compare_if.Else(); 3045 if (!is_logical_and) { 3046 environment()->Pop(); 3047 Visit(expr->right()); 3048 } else if (ast_context()->IsEffect()) { 3049 environment()->Pop(); 3050 } else if (ast_context()->IsTest()) { 3051 environment()->Poke(0, jsgraph()->FalseConstant()); 3052 } 3053 compare_if.End(); 3054 // Skip plugging AST evaluation contexts of the test kind. This is to stay in 3055 // sync with full codegen which doesn't prepare the proper bailout point (see 3056 // the implementation of FullCodeGenerator::VisitForControl). 3057 if (ast_context()->IsTest()) return; 3058 ast_context()->ReplaceValue(expr); 3059 } 3060 3061 3062 LanguageMode AstGraphBuilder::language_mode() const { 3063 return current_scope()->language_mode(); 3064 } 3065 3066 3067 VectorSlotPair AstGraphBuilder::CreateVectorSlotPair( 3068 FeedbackVectorSlot slot) const { 3069 return VectorSlotPair(handle(info()->closure()->feedback_vector()), slot); 3070 } 3071 3072 3073 void AstGraphBuilder::VisitRewritableExpression(RewritableExpression* node) { 3074 Visit(node->expression()); 3075 } 3076 3077 3078 namespace { 3079 3080 // Limit of context chain length to which inline check is possible. 3081 const int kMaxCheckDepth = 30; 3082 3083 // Sentinel for {TryLoadDynamicVariable} disabling inline checks. 3084 const uint32_t kFullCheckRequired = -1; 3085 3086 } // namespace 3087 3088 3089 uint32_t AstGraphBuilder::ComputeBitsetForDynamicGlobal(Variable* variable) { 3090 DCHECK_EQ(DYNAMIC_GLOBAL, variable->mode()); 3091 uint32_t check_depths = 0; 3092 for (Scope* s = current_scope(); s != nullptr; s = s->outer_scope()) { 3093 if (!s->NeedsContext()) continue; 3094 if (!s->calls_sloppy_eval()) continue; 3095 int depth = current_scope()->ContextChainLength(s); 3096 if (depth > kMaxCheckDepth) return kFullCheckRequired; 3097 check_depths |= 1 << depth; 3098 } 3099 return check_depths; 3100 } 3101 3102 3103 uint32_t AstGraphBuilder::ComputeBitsetForDynamicContext(Variable* variable) { 3104 DCHECK_EQ(DYNAMIC_LOCAL, variable->mode()); 3105 uint32_t check_depths = 0; 3106 for (Scope* s = current_scope(); s != nullptr; s = s->outer_scope()) { 3107 if (!s->NeedsContext()) continue; 3108 if (!s->calls_sloppy_eval() && s != variable->scope()) continue; 3109 int depth = current_scope()->ContextChainLength(s); 3110 if (depth > kMaxCheckDepth) return kFullCheckRequired; 3111 check_depths |= 1 << depth; 3112 if (s == variable->scope()) break; 3113 } 3114 return check_depths; 3115 } 3116 3117 float AstGraphBuilder::ComputeCallFrequency(FeedbackVectorSlot slot) const { 3118 if (slot.IsInvalid()) return 0.0f; 3119 Handle<TypeFeedbackVector> feedback_vector( 3120 info()->closure()->feedback_vector(), isolate()); 3121 CallICNexus nexus(feedback_vector, slot); 3122 return nexus.ComputeCallFrequency() * invocation_frequency_; 3123 } 3124 3125 Node* AstGraphBuilder::ProcessArguments(const Operator* op, int arity) { 3126 DCHECK(environment()->stack_height() >= arity); 3127 Node** all = info()->zone()->NewArray<Node*>(arity); 3128 for (int i = arity - 1; i >= 0; --i) { 3129 all[i] = environment()->Pop(); 3130 } 3131 Node* value = NewNode(op, arity, all); 3132 return value; 3133 } 3134 3135 3136 Node* AstGraphBuilder::BuildLocalActivationContext(Node* context) { 3137 DeclarationScope* scope = info()->scope(); 3138 3139 // Allocate a new local context. 3140 Node* local_context = scope->is_script_scope() 3141 ? BuildLocalScriptContext(scope) 3142 : BuildLocalFunctionContext(scope); 3143 3144 if (scope->has_this_declaration() && scope->receiver()->IsContextSlot()) { 3145 Node* receiver = environment()->RawParameterLookup(0); 3146 // Context variable (at bottom of the context chain). 3147 Variable* variable = scope->receiver(); 3148 DCHECK_EQ(0, scope->ContextChainLength(variable->scope())); 3149 const Operator* op = javascript()->StoreContext(0, variable->index()); 3150 NewNode(op, local_context, receiver); 3151 } 3152 3153 // Copy parameters into context if necessary. 3154 int num_parameters = scope->num_parameters(); 3155 for (int i = 0; i < num_parameters; i++) { 3156 Variable* variable = scope->parameter(i); 3157 if (!variable->IsContextSlot()) continue; 3158 Node* parameter = environment()->RawParameterLookup(i + 1); 3159 // Context variable (at bottom of the context chain). 3160 DCHECK_EQ(0, scope->ContextChainLength(variable->scope())); 3161 const Operator* op = javascript()->StoreContext(0, variable->index()); 3162 NewNode(op, local_context, parameter); 3163 } 3164 3165 return local_context; 3166 } 3167 3168 3169 Node* AstGraphBuilder::BuildLocalFunctionContext(Scope* scope) { 3170 DCHECK(scope->is_function_scope() || scope->is_eval_scope()); 3171 3172 // Allocate a new local context. 3173 int slot_count = scope->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; 3174 const Operator* op = javascript()->CreateFunctionContext(slot_count); 3175 Node* local_context = NewNode(op, GetFunctionClosure()); 3176 3177 return local_context; 3178 } 3179 3180 3181 Node* AstGraphBuilder::BuildLocalScriptContext(Scope* scope) { 3182 DCHECK(scope->is_script_scope()); 3183 3184 // Allocate a new local context. 3185 Handle<ScopeInfo> scope_info = scope->scope_info(); 3186 const Operator* op = javascript()->CreateScriptContext(scope_info); 3187 Node* local_context = NewNode(op, GetFunctionClosure()); 3188 PrepareFrameState(local_context, BailoutId::ScriptContext(), 3189 OutputFrameStateCombine::Push()); 3190 3191 return local_context; 3192 } 3193 3194 3195 Node* AstGraphBuilder::BuildLocalBlockContext(Scope* scope) { 3196 DCHECK(scope->is_block_scope()); 3197 3198 // Allocate a new local context. 3199 Handle<ScopeInfo> scope_info = scope->scope_info(); 3200 const Operator* op = javascript()->CreateBlockContext(scope_info); 3201 Node* local_context = NewNode(op, GetFunctionClosureForContext()); 3202 3203 return local_context; 3204 } 3205 3206 3207 Node* AstGraphBuilder::BuildArgumentsObject(Variable* arguments) { 3208 if (arguments == nullptr) return nullptr; 3209 3210 // Allocate and initialize a new arguments object. 3211 CreateArgumentsType type = 3212 is_strict(language_mode()) || !info()->has_simple_parameters() 3213 ? CreateArgumentsType::kUnmappedArguments 3214 : CreateArgumentsType::kMappedArguments; 3215 const Operator* op = javascript()->CreateArguments(type); 3216 Node* object = NewNode(op, GetFunctionClosure()); 3217 PrepareFrameState(object, BailoutId::None()); 3218 3219 // Assign the object to the {arguments} variable. This should never lazy 3220 // deopt, so it is fine to send invalid bailout id. 3221 DCHECK(arguments->IsContextSlot() || arguments->IsStackAllocated()); 3222 BuildVariableAssignment(arguments, object, Token::ASSIGN, VectorSlotPair(), 3223 BailoutId::None()); 3224 return object; 3225 } 3226 3227 Node* AstGraphBuilder::BuildRestArgumentsArray(Variable* rest) { 3228 if (rest == nullptr) return nullptr; 3229 3230 // Allocate and initialize a new arguments object. 3231 CreateArgumentsType type = CreateArgumentsType::kRestParameter; 3232 const Operator* op = javascript()->CreateArguments(type); 3233 Node* object = NewNode(op, GetFunctionClosure()); 3234 PrepareFrameState(object, BailoutId::None()); 3235 3236 // Assign the object to the {rest} variable. This should never lazy 3237 // deopt, so it is fine to send invalid bailout id. 3238 DCHECK(rest->IsContextSlot() || rest->IsStackAllocated()); 3239 BuildVariableAssignment(rest, object, Token::ASSIGN, VectorSlotPair(), 3240 BailoutId::None()); 3241 return object; 3242 } 3243 3244 3245 Node* AstGraphBuilder::BuildThisFunctionVariable(Variable* this_function_var) { 3246 if (this_function_var == nullptr) return nullptr; 3247 3248 // Retrieve the closure we were called with. 3249 Node* this_function = GetFunctionClosure(); 3250 3251 // Assign the object to the {.this_function} variable. This should never lazy 3252 // deopt, so it is fine to send invalid bailout id. 3253 BuildVariableAssignment(this_function_var, this_function, Token::INIT, 3254 VectorSlotPair(), BailoutId::None()); 3255 return this_function; 3256 } 3257 3258 3259 Node* AstGraphBuilder::BuildNewTargetVariable(Variable* new_target_var) { 3260 if (new_target_var == nullptr) return nullptr; 3261 3262 // Retrieve the new target we were called with. 3263 Node* object = GetNewTarget(); 3264 3265 // Assign the object to the {new.target} variable. This should never lazy 3266 // deopt, so it is fine to send invalid bailout id. 3267 BuildVariableAssignment(new_target_var, object, Token::INIT, VectorSlotPair(), 3268 BailoutId::None()); 3269 return object; 3270 } 3271 3272 3273 Node* AstGraphBuilder::BuildHoleCheckThenThrow(Node* value, Variable* variable, 3274 Node* not_hole, 3275 BailoutId bailout_id) { 3276 IfBuilder hole_check(this); 3277 Node* the_hole = jsgraph()->TheHoleConstant(); 3278 Node* check = NewNode(javascript()->StrictEqual(CompareOperationHint::kAny), 3279 value, the_hole); 3280 hole_check.If(check); 3281 hole_check.Then(); 3282 Node* error = BuildThrowReferenceError(variable, bailout_id); 3283 environment()->Push(error); 3284 hole_check.Else(); 3285 environment()->Push(not_hole); 3286 hole_check.End(); 3287 return environment()->Pop(); 3288 } 3289 3290 3291 Node* AstGraphBuilder::BuildHoleCheckElseThrow(Node* value, Variable* variable, 3292 Node* for_hole, 3293 BailoutId bailout_id) { 3294 IfBuilder hole_check(this); 3295 Node* the_hole = jsgraph()->TheHoleConstant(); 3296 Node* check = NewNode(javascript()->StrictEqual(CompareOperationHint::kAny), 3297 value, the_hole); 3298 hole_check.If(check); 3299 hole_check.Then(); 3300 environment()->Push(for_hole); 3301 hole_check.Else(); 3302 Node* error = BuildThrowReferenceError(variable, bailout_id); 3303 environment()->Push(error); 3304 hole_check.End(); 3305 return environment()->Pop(); 3306 } 3307 3308 3309 Node* AstGraphBuilder::BuildThrowIfStaticPrototype(Node* name, 3310 BailoutId bailout_id) { 3311 IfBuilder prototype_check(this); 3312 Node* prototype_string = 3313 jsgraph()->Constant(isolate()->factory()->prototype_string()); 3314 Node* check = NewNode(javascript()->StrictEqual(CompareOperationHint::kAny), 3315 name, prototype_string); 3316 prototype_check.If(check); 3317 prototype_check.Then(); 3318 Node* error = BuildThrowStaticPrototypeError(bailout_id); 3319 environment()->Push(error); 3320 prototype_check.Else(); 3321 environment()->Push(name); 3322 prototype_check.End(); 3323 return environment()->Pop(); 3324 } 3325 3326 3327 Node* AstGraphBuilder::BuildVariableLoad(Variable* variable, 3328 BailoutId bailout_id, 3329 const VectorSlotPair& feedback, 3330 OutputFrameStateCombine combine, 3331 TypeofMode typeof_mode) { 3332 Node* the_hole = jsgraph()->TheHoleConstant(); 3333 switch (variable->location()) { 3334 case VariableLocation::UNALLOCATED: { 3335 // Global var, const, or let variable. 3336 Handle<Name> name = variable->name(); 3337 if (Node* node = TryLoadGlobalConstant(name)) return node; 3338 Node* value = BuildGlobalLoad(name, feedback, typeof_mode); 3339 PrepareFrameState(value, bailout_id, combine); 3340 return value; 3341 } 3342 case VariableLocation::PARAMETER: 3343 case VariableLocation::LOCAL: { 3344 // Local var, const, or let variable. 3345 Node* value = environment()->Lookup(variable); 3346 if (variable->binding_needs_init()) { 3347 // Perform check for uninitialized let/const variables. 3348 if (value->op() == the_hole->op()) { 3349 value = BuildThrowReferenceError(variable, bailout_id); 3350 } else if (value->opcode() == IrOpcode::kPhi) { 3351 value = BuildHoleCheckThenThrow(value, variable, value, bailout_id); 3352 } 3353 } 3354 return value; 3355 } 3356 case VariableLocation::CONTEXT: { 3357 // Context variable (potentially up the context chain). 3358 int depth = current_scope()->ContextChainLength(variable->scope()); 3359 // TODO(mstarzinger): The {maybe_assigned} flag computed during variable 3360 // resolution is highly inaccurate and cannot be trusted. We are only 3361 // taking this information into account when asm.js compilation is used. 3362 bool immutable = variable->maybe_assigned() == kNotAssigned && 3363 info()->is_function_context_specializing(); 3364 const Operator* op = 3365 javascript()->LoadContext(depth, variable->index(), immutable); 3366 Node* value = NewNode(op, current_context()); 3367 // TODO(titzer): initialization checks are redundant for already 3368 // initialized immutable context loads, but only specialization knows. 3369 // Maybe specializer should be a parameter to the graph builder? 3370 if (variable->binding_needs_init()) { 3371 // Perform check for uninitialized let/const variables. 3372 value = BuildHoleCheckThenThrow(value, variable, value, bailout_id); 3373 } 3374 return value; 3375 } 3376 case VariableLocation::LOOKUP: { 3377 // Dynamic lookup of context variable (anywhere in the chain). 3378 Handle<String> name = variable->name(); 3379 if (Node* node = TryLoadDynamicVariable(variable, name, bailout_id, 3380 feedback, combine, typeof_mode)) { 3381 return node; 3382 } 3383 Node* value = BuildDynamicLoad(name, typeof_mode); 3384 PrepareFrameState(value, bailout_id, combine); 3385 return value; 3386 } 3387 case VariableLocation::MODULE: 3388 UNREACHABLE(); 3389 } 3390 UNREACHABLE(); 3391 return nullptr; 3392 } 3393 3394 3395 Node* AstGraphBuilder::BuildVariableDelete(Variable* variable, 3396 BailoutId bailout_id, 3397 OutputFrameStateCombine combine) { 3398 switch (variable->location()) { 3399 case VariableLocation::UNALLOCATED: { 3400 // Global var, const, or let variable. 3401 Node* global = BuildLoadGlobalObject(); 3402 Node* name = jsgraph()->Constant(variable->name()); 3403 const Operator* op = javascript()->DeleteProperty(language_mode()); 3404 Node* result = NewNode(op, global, name); 3405 PrepareFrameState(result, bailout_id, combine); 3406 return result; 3407 } 3408 case VariableLocation::PARAMETER: 3409 case VariableLocation::LOCAL: 3410 case VariableLocation::CONTEXT: { 3411 // Local var, const, or let variable or context variable. 3412 return jsgraph()->BooleanConstant(variable->is_this()); 3413 } 3414 case VariableLocation::LOOKUP: { 3415 // Dynamic lookup of context variable (anywhere in the chain). 3416 Node* name = jsgraph()->Constant(variable->name()); 3417 const Operator* op = 3418 javascript()->CallRuntime(Runtime::kDeleteLookupSlot); 3419 Node* result = NewNode(op, name); 3420 PrepareFrameState(result, bailout_id, combine); 3421 return result; 3422 } 3423 case VariableLocation::MODULE: 3424 UNREACHABLE(); 3425 } 3426 UNREACHABLE(); 3427 return nullptr; 3428 } 3429 3430 Node* AstGraphBuilder::BuildVariableAssignment( 3431 Variable* variable, Node* value, Token::Value op, 3432 const VectorSlotPair& feedback, BailoutId bailout_id, 3433 OutputFrameStateCombine combine) { 3434 Node* the_hole = jsgraph()->TheHoleConstant(); 3435 VariableMode mode = variable->mode(); 3436 switch (variable->location()) { 3437 case VariableLocation::UNALLOCATED: { 3438 // Global var, const, or let variable. 3439 Handle<Name> name = variable->name(); 3440 Node* store = BuildGlobalStore(name, value, feedback); 3441 PrepareFrameState(store, bailout_id, combine); 3442 return store; 3443 } 3444 case VariableLocation::PARAMETER: 3445 case VariableLocation::LOCAL: 3446 // Local var, const, or let variable. 3447 if (mode == LET && op == Token::INIT) { 3448 // No initialization check needed because scoping guarantees it. Note 3449 // that we still perform a lookup to keep the variable live, because 3450 // baseline code might contain debug code that inspects the variable. 3451 Node* current = environment()->Lookup(variable); 3452 CHECK_NOT_NULL(current); 3453 } else if (mode == LET && op != Token::INIT && 3454 variable->binding_needs_init()) { 3455 // Perform an initialization check for let declared variables. 3456 Node* current = environment()->Lookup(variable); 3457 if (current->op() == the_hole->op()) { 3458 return BuildThrowReferenceError(variable, bailout_id); 3459 } else if (current->opcode() == IrOpcode::kPhi) { 3460 BuildHoleCheckThenThrow(current, variable, value, bailout_id); 3461 } 3462 } else if (mode == CONST && op == Token::INIT) { 3463 // Perform an initialization check for const {this} variables. 3464 // Note that the {this} variable is the only const variable being able 3465 // to trigger bind operations outside the TDZ, via {super} calls. 3466 Node* current = environment()->Lookup(variable); 3467 if (current->op() != the_hole->op() && variable->is_this()) { 3468 value = BuildHoleCheckElseThrow(current, variable, value, bailout_id); 3469 } 3470 } else if (mode == CONST && op != Token::INIT && 3471 variable->is_sloppy_function_name()) { 3472 // Non-initializing assignment to sloppy function names is 3473 // - exception in strict mode. 3474 // - ignored in sloppy mode. 3475 DCHECK(!variable->binding_needs_init()); 3476 if (variable->throw_on_const_assignment(language_mode())) { 3477 return BuildThrowConstAssignError(bailout_id); 3478 } 3479 return value; 3480 } else if (mode == CONST && op != Token::INIT) { 3481 if (variable->binding_needs_init()) { 3482 Node* current = environment()->Lookup(variable); 3483 if (current->op() == the_hole->op()) { 3484 return BuildThrowReferenceError(variable, bailout_id); 3485 } else if (current->opcode() == IrOpcode::kPhi) { 3486 BuildHoleCheckThenThrow(current, variable, value, bailout_id); 3487 } 3488 } 3489 // Assignment to const is exception in all modes. 3490 return BuildThrowConstAssignError(bailout_id); 3491 } 3492 environment()->Bind(variable, value); 3493 return value; 3494 case VariableLocation::CONTEXT: { 3495 // Context variable (potentially up the context chain). 3496 int depth = current_scope()->ContextChainLength(variable->scope()); 3497 if (mode == LET && op != Token::INIT && variable->binding_needs_init()) { 3498 // Perform an initialization check for let declared variables. 3499 const Operator* op = 3500 javascript()->LoadContext(depth, variable->index(), false); 3501 Node* current = NewNode(op, current_context()); 3502 value = BuildHoleCheckThenThrow(current, variable, value, bailout_id); 3503 } else if (mode == CONST && op == Token::INIT) { 3504 // Perform an initialization check for const {this} variables. 3505 // Note that the {this} variable is the only const variable being able 3506 // to trigger bind operations outside the TDZ, via {super} calls. 3507 if (variable->is_this()) { 3508 const Operator* op = 3509 javascript()->LoadContext(depth, variable->index(), false); 3510 Node* current = NewNode(op, current_context()); 3511 value = BuildHoleCheckElseThrow(current, variable, value, bailout_id); 3512 } 3513 } else if (mode == CONST && op != Token::INIT && 3514 variable->is_sloppy_function_name()) { 3515 // Non-initializing assignment to sloppy function names is 3516 // - exception in strict mode. 3517 // - ignored in sloppy mode. 3518 DCHECK(!variable->binding_needs_init()); 3519 if (variable->throw_on_const_assignment(language_mode())) { 3520 return BuildThrowConstAssignError(bailout_id); 3521 } 3522 return value; 3523 } else if (mode == CONST && op != Token::INIT) { 3524 if (variable->binding_needs_init()) { 3525 const Operator* op = 3526 javascript()->LoadContext(depth, variable->index(), false); 3527 Node* current = NewNode(op, current_context()); 3528 BuildHoleCheckThenThrow(current, variable, value, bailout_id); 3529 } 3530 // Assignment to const is exception in all modes. 3531 return BuildThrowConstAssignError(bailout_id); 3532 } 3533 const Operator* op = javascript()->StoreContext(depth, variable->index()); 3534 return NewNode(op, current_context(), value); 3535 } 3536 case VariableLocation::LOOKUP: { 3537 // Dynamic lookup of context variable (anywhere in the chain). 3538 Handle<Name> name = variable->name(); 3539 Node* store = BuildDynamicStore(name, value); 3540 PrepareFrameState(store, bailout_id, combine); 3541 return store; 3542 } 3543 case VariableLocation::MODULE: 3544 UNREACHABLE(); 3545 } 3546 UNREACHABLE(); 3547 return nullptr; 3548 } 3549 3550 3551 Node* AstGraphBuilder::BuildKeyedLoad(Node* object, Node* key, 3552 const VectorSlotPair& feedback) { 3553 const Operator* op = javascript()->LoadProperty(feedback); 3554 Node* node = NewNode(op, object, key, GetFunctionClosure()); 3555 return node; 3556 } 3557 3558 3559 Node* AstGraphBuilder::BuildNamedLoad(Node* object, Handle<Name> name, 3560 const VectorSlotPair& feedback) { 3561 const Operator* op = javascript()->LoadNamed(name, feedback); 3562 Node* node = NewNode(op, object, GetFunctionClosure()); 3563 return node; 3564 } 3565 3566 3567 Node* AstGraphBuilder::BuildKeyedStore(Node* object, Node* key, Node* value, 3568 const VectorSlotPair& feedback) { 3569 const Operator* op = javascript()->StoreProperty(language_mode(), feedback); 3570 Node* node = NewNode(op, object, key, value, GetFunctionClosure()); 3571 return node; 3572 } 3573 3574 3575 Node* AstGraphBuilder::BuildNamedStore(Node* object, Handle<Name> name, 3576 Node* value, 3577 const VectorSlotPair& feedback) { 3578 const Operator* op = 3579 javascript()->StoreNamed(language_mode(), name, feedback); 3580 Node* node = NewNode(op, object, value, GetFunctionClosure()); 3581 return node; 3582 } 3583 3584 3585 Node* AstGraphBuilder::BuildNamedSuperLoad(Node* receiver, Node* home_object, 3586 Handle<Name> name, 3587 const VectorSlotPair& feedback) { 3588 Node* name_node = jsgraph()->Constant(name); 3589 const Operator* op = javascript()->CallRuntime(Runtime::kLoadFromSuper); 3590 Node* node = NewNode(op, receiver, home_object, name_node); 3591 return node; 3592 } 3593 3594 3595 Node* AstGraphBuilder::BuildKeyedSuperLoad(Node* receiver, Node* home_object, 3596 Node* key, 3597 const VectorSlotPair& feedback) { 3598 const Operator* op = javascript()->CallRuntime(Runtime::kLoadKeyedFromSuper); 3599 Node* node = NewNode(op, receiver, home_object, key); 3600 return node; 3601 } 3602 3603 3604 Node* AstGraphBuilder::BuildKeyedSuperStore(Node* receiver, Node* home_object, 3605 Node* key, Node* value) { 3606 Runtime::FunctionId function_id = is_strict(language_mode()) 3607 ? Runtime::kStoreKeyedToSuper_Strict 3608 : Runtime::kStoreKeyedToSuper_Sloppy; 3609 const Operator* op = javascript()->CallRuntime(function_id, 4); 3610 Node* node = NewNode(op, receiver, home_object, key, value); 3611 return node; 3612 } 3613 3614 3615 Node* AstGraphBuilder::BuildNamedSuperStore(Node* receiver, Node* home_object, 3616 Handle<Name> name, Node* value) { 3617 Node* name_node = jsgraph()->Constant(name); 3618 Runtime::FunctionId function_id = is_strict(language_mode()) 3619 ? Runtime::kStoreToSuper_Strict 3620 : Runtime::kStoreToSuper_Sloppy; 3621 const Operator* op = javascript()->CallRuntime(function_id, 4); 3622 Node* node = NewNode(op, receiver, home_object, name_node, value); 3623 return node; 3624 } 3625 3626 3627 Node* AstGraphBuilder::BuildGlobalLoad(Handle<Name> name, 3628 const VectorSlotPair& feedback, 3629 TypeofMode typeof_mode) { 3630 const Operator* op = javascript()->LoadGlobal(name, feedback, typeof_mode); 3631 Node* node = NewNode(op, GetFunctionClosure()); 3632 return node; 3633 } 3634 3635 3636 Node* AstGraphBuilder::BuildGlobalStore(Handle<Name> name, Node* value, 3637 const VectorSlotPair& feedback) { 3638 const Operator* op = 3639 javascript()->StoreGlobal(language_mode(), name, feedback); 3640 Node* node = NewNode(op, value, GetFunctionClosure()); 3641 return node; 3642 } 3643 3644 3645 Node* AstGraphBuilder::BuildDynamicLoad(Handle<Name> name, 3646 TypeofMode typeof_mode) { 3647 Node* name_node = jsgraph()->Constant(name); 3648 const Operator* op = 3649 javascript()->CallRuntime(typeof_mode == TypeofMode::NOT_INSIDE_TYPEOF 3650 ? Runtime::kLoadLookupSlot 3651 : Runtime::kLoadLookupSlotInsideTypeof); 3652 Node* node = NewNode(op, name_node); 3653 return node; 3654 } 3655 3656 3657 Node* AstGraphBuilder::BuildDynamicStore(Handle<Name> name, Node* value) { 3658 Node* name_node = jsgraph()->Constant(name); 3659 const Operator* op = javascript()->CallRuntime( 3660 is_strict(language_mode()) ? Runtime::kStoreLookupSlot_Strict 3661 : Runtime::kStoreLookupSlot_Sloppy); 3662 Node* node = NewNode(op, name_node, value); 3663 return node; 3664 } 3665 3666 3667 Node* AstGraphBuilder::BuildLoadGlobalObject() { 3668 return BuildLoadNativeContextField(Context::EXTENSION_INDEX); 3669 } 3670 3671 3672 Node* AstGraphBuilder::BuildLoadNativeContextField(int index) { 3673 const Operator* op = 3674 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true); 3675 Node* native_context = NewNode(op, current_context()); 3676 return NewNode(javascript()->LoadContext(0, index, true), native_context); 3677 } 3678 3679 3680 Node* AstGraphBuilder::BuildToBoolean(Node* input, TypeFeedbackId feedback_id) { 3681 if (Node* node = TryFastToBoolean(input)) return node; 3682 ToBooleanHints hints; 3683 if (!type_hint_analysis_ || 3684 !type_hint_analysis_->GetToBooleanHints(feedback_id, &hints)) { 3685 hints = ToBooleanHint::kAny; 3686 } 3687 return NewNode(javascript()->ToBoolean(hints), input); 3688 } 3689 3690 3691 Node* AstGraphBuilder::BuildToName(Node* input, BailoutId bailout_id) { 3692 if (Node* node = TryFastToName(input)) return node; 3693 Node* name = NewNode(javascript()->ToName(), input); 3694 PrepareFrameState(name, bailout_id, OutputFrameStateCombine::Push()); 3695 return name; 3696 } 3697 3698 3699 Node* AstGraphBuilder::BuildToObject(Node* input, BailoutId bailout_id) { 3700 Node* object = NewNode(javascript()->ToObject(), input); 3701 PrepareFrameState(object, bailout_id, OutputFrameStateCombine::Push()); 3702 return object; 3703 } 3704 3705 Node* AstGraphBuilder::BuildSetHomeObject(Node* value, Node* home_object, 3706 LiteralProperty* property, 3707 int slot_number) { 3708 Expression* expr = property->value(); 3709 if (!FunctionLiteral::NeedsHomeObject(expr)) return value; 3710 Handle<Name> name = isolate()->factory()->home_object_symbol(); 3711 VectorSlotPair feedback = 3712 CreateVectorSlotPair(property->GetSlot(slot_number)); 3713 Node* store = BuildNamedStore(value, name, home_object, feedback); 3714 PrepareFrameState(store, BailoutId::None(), 3715 OutputFrameStateCombine::Ignore()); 3716 return store; 3717 } 3718 3719 3720 Node* AstGraphBuilder::BuildThrowError(Node* exception, BailoutId bailout_id) { 3721 const Operator* op = javascript()->CallRuntime(Runtime::kThrow); 3722 Node* call = NewNode(op, exception); 3723 PrepareFrameState(call, bailout_id); 3724 Node* control = NewNode(common()->Throw(), call); 3725 UpdateControlDependencyToLeaveFunction(control); 3726 return call; 3727 } 3728 3729 3730 Node* AstGraphBuilder::BuildThrowReferenceError(Variable* variable, 3731 BailoutId bailout_id) { 3732 Node* variable_name = jsgraph()->Constant(variable->name()); 3733 const Operator* op = javascript()->CallRuntime(Runtime::kThrowReferenceError); 3734 Node* call = NewNode(op, variable_name); 3735 PrepareFrameState(call, bailout_id); 3736 Node* control = NewNode(common()->Throw(), call); 3737 UpdateControlDependencyToLeaveFunction(control); 3738 return call; 3739 } 3740 3741 3742 Node* AstGraphBuilder::BuildThrowConstAssignError(BailoutId bailout_id) { 3743 const Operator* op = 3744 javascript()->CallRuntime(Runtime::kThrowConstAssignError); 3745 Node* call = NewNode(op); 3746 PrepareFrameState(call, bailout_id); 3747 Node* control = NewNode(common()->Throw(), call); 3748 UpdateControlDependencyToLeaveFunction(control); 3749 return call; 3750 } 3751 3752 3753 Node* AstGraphBuilder::BuildThrowStaticPrototypeError(BailoutId bailout_id) { 3754 const Operator* op = 3755 javascript()->CallRuntime(Runtime::kThrowStaticPrototypeError); 3756 Node* call = NewNode(op); 3757 PrepareFrameState(call, bailout_id); 3758 Node* control = NewNode(common()->Throw(), call); 3759 UpdateControlDependencyToLeaveFunction(control); 3760 return call; 3761 } 3762 3763 3764 Node* AstGraphBuilder::BuildThrowUnsupportedSuperError(BailoutId bailout_id) { 3765 const Operator* op = 3766 javascript()->CallRuntime(Runtime::kThrowUnsupportedSuperError); 3767 Node* call = NewNode(op); 3768 PrepareFrameState(call, bailout_id); 3769 Node* control = NewNode(common()->Throw(), call); 3770 UpdateControlDependencyToLeaveFunction(control); 3771 return call; 3772 } 3773 3774 3775 Node* AstGraphBuilder::BuildReturn(Node* return_value) { 3776 // Emit tracing call if requested to do so. 3777 if (FLAG_trace) { 3778 return_value = 3779 NewNode(javascript()->CallRuntime(Runtime::kTraceExit), return_value); 3780 } 3781 Node* pop_node = jsgraph()->ZeroConstant(); 3782 Node* control = NewNode(common()->Return(), pop_node, return_value); 3783 UpdateControlDependencyToLeaveFunction(control); 3784 return control; 3785 } 3786 3787 3788 Node* AstGraphBuilder::BuildThrow(Node* exception_value) { 3789 NewNode(javascript()->CallRuntime(Runtime::kReThrow), exception_value); 3790 Node* control = NewNode(common()->Throw(), exception_value); 3791 UpdateControlDependencyToLeaveFunction(control); 3792 return control; 3793 } 3794 3795 3796 Node* AstGraphBuilder::BuildBinaryOp(Node* left, Node* right, Token::Value op, 3797 TypeFeedbackId feedback_id) { 3798 const Operator* js_op; 3799 BinaryOperationHint hint; 3800 if (!type_hint_analysis_ || 3801 !type_hint_analysis_->GetBinaryOperationHint(feedback_id, &hint)) { 3802 hint = BinaryOperationHint::kAny; 3803 } 3804 switch (op) { 3805 case Token::BIT_OR: 3806 js_op = javascript()->BitwiseOr(hint); 3807 break; 3808 case Token::BIT_AND: 3809 js_op = javascript()->BitwiseAnd(hint); 3810 break; 3811 case Token::BIT_XOR: 3812 js_op = javascript()->BitwiseXor(hint); 3813 break; 3814 case Token::SHL: 3815 js_op = javascript()->ShiftLeft(hint); 3816 break; 3817 case Token::SAR: 3818 js_op = javascript()->ShiftRight(hint); 3819 break; 3820 case Token::SHR: 3821 js_op = javascript()->ShiftRightLogical(hint); 3822 break; 3823 case Token::ADD: 3824 js_op = javascript()->Add(hint); 3825 break; 3826 case Token::SUB: 3827 js_op = javascript()->Subtract(hint); 3828 break; 3829 case Token::MUL: 3830 js_op = javascript()->Multiply(hint); 3831 break; 3832 case Token::DIV: 3833 js_op = javascript()->Divide(hint); 3834 break; 3835 case Token::MOD: 3836 js_op = javascript()->Modulus(hint); 3837 break; 3838 default: 3839 UNREACHABLE(); 3840 js_op = nullptr; 3841 } 3842 return NewNode(js_op, left, right); 3843 } 3844 3845 3846 Node* AstGraphBuilder::TryLoadGlobalConstant(Handle<Name> name) { 3847 // Optimize global constants like "undefined", "Infinity", and "NaN". 3848 Handle<Object> constant_value = isolate()->factory()->GlobalConstantFor(name); 3849 if (!constant_value.is_null()) return jsgraph()->Constant(constant_value); 3850 return nullptr; 3851 } 3852 3853 Node* AstGraphBuilder::TryLoadDynamicVariable(Variable* variable, 3854 Handle<String> name, 3855 BailoutId bailout_id, 3856 const VectorSlotPair& feedback, 3857 OutputFrameStateCombine combine, 3858 TypeofMode typeof_mode) { 3859 VariableMode mode = variable->mode(); 3860 3861 if (mode == DYNAMIC_GLOBAL) { 3862 uint32_t bitset = ComputeBitsetForDynamicGlobal(variable); 3863 if (bitset == kFullCheckRequired) return nullptr; 3864 3865 // We are using two blocks to model fast and slow cases. 3866 BlockBuilder fast_block(this); 3867 BlockBuilder slow_block(this); 3868 environment()->Push(jsgraph()->TheHoleConstant()); 3869 slow_block.BeginBlock(); 3870 environment()->Pop(); 3871 fast_block.BeginBlock(); 3872 3873 // Perform checks whether the fast mode applies, by looking for any 3874 // extension object which might shadow the optimistic declaration. 3875 for (int depth = 0; bitset != 0; bitset >>= 1, depth++) { 3876 if ((bitset & 1) == 0) continue; 3877 Node* load = NewNode( 3878 javascript()->LoadContext(depth, Context::EXTENSION_INDEX, false), 3879 current_context()); 3880 Node* check = 3881 NewNode(javascript()->StrictEqual(CompareOperationHint::kAny), load, 3882 jsgraph()->TheHoleConstant()); 3883 fast_block.BreakUnless(check, BranchHint::kTrue); 3884 } 3885 3886 // Fast case, because variable is not shadowed. 3887 if (Node* constant = TryLoadGlobalConstant(name)) { 3888 environment()->Push(constant); 3889 } else { 3890 // Perform global slot load. 3891 Node* fast = BuildGlobalLoad(name, feedback, typeof_mode); 3892 PrepareFrameState(fast, bailout_id, combine); 3893 environment()->Push(fast); 3894 } 3895 slow_block.Break(); 3896 environment()->Pop(); 3897 fast_block.EndBlock(); 3898 3899 // Slow case, because variable potentially shadowed. Perform dynamic lookup. 3900 Node* slow = BuildDynamicLoad(name, typeof_mode); 3901 PrepareFrameState(slow, bailout_id, combine); 3902 environment()->Push(slow); 3903 slow_block.EndBlock(); 3904 3905 return environment()->Pop(); 3906 } 3907 3908 if (mode == DYNAMIC_LOCAL) { 3909 uint32_t bitset = ComputeBitsetForDynamicContext(variable); 3910 if (bitset == kFullCheckRequired) return nullptr; 3911 3912 // We are using two blocks to model fast and slow cases. 3913 BlockBuilder fast_block(this); 3914 BlockBuilder slow_block(this); 3915 environment()->Push(jsgraph()->TheHoleConstant()); 3916 slow_block.BeginBlock(); 3917 environment()->Pop(); 3918 fast_block.BeginBlock(); 3919 3920 // Perform checks whether the fast mode applies, by looking for any 3921 // extension object which might shadow the optimistic declaration. 3922 for (int depth = 0; bitset != 0; bitset >>= 1, depth++) { 3923 if ((bitset & 1) == 0) continue; 3924 Node* load = NewNode( 3925 javascript()->LoadContext(depth, Context::EXTENSION_INDEX, false), 3926 current_context()); 3927 Node* check = 3928 NewNode(javascript()->StrictEqual(CompareOperationHint::kAny), load, 3929 jsgraph()->TheHoleConstant()); 3930 fast_block.BreakUnless(check, BranchHint::kTrue); 3931 } 3932 3933 // Fast case, because variable is not shadowed. Perform context slot load. 3934 Variable* local = variable->local_if_not_shadowed(); 3935 DCHECK(local->location() == VariableLocation::CONTEXT); // Must be context. 3936 Node* fast = 3937 BuildVariableLoad(local, bailout_id, feedback, combine, typeof_mode); 3938 environment()->Push(fast); 3939 slow_block.Break(); 3940 environment()->Pop(); 3941 fast_block.EndBlock(); 3942 3943 // Slow case, because variable potentially shadowed. Perform dynamic lookup. 3944 Node* slow = BuildDynamicLoad(name, typeof_mode); 3945 PrepareFrameState(slow, bailout_id, combine); 3946 environment()->Push(slow); 3947 slow_block.EndBlock(); 3948 3949 return environment()->Pop(); 3950 } 3951 3952 return nullptr; 3953 } 3954 3955 3956 Node* AstGraphBuilder::TryFastToBoolean(Node* input) { 3957 switch (input->opcode()) { 3958 case IrOpcode::kNumberConstant: { 3959 NumberMatcher m(input); 3960 return jsgraph_->BooleanConstant(!m.Is(0) && !m.IsNaN()); 3961 } 3962 case IrOpcode::kHeapConstant: { 3963 Handle<HeapObject> object = HeapObjectMatcher(input).Value(); 3964 return jsgraph_->BooleanConstant(object->BooleanValue()); 3965 } 3966 case IrOpcode::kJSEqual: 3967 case IrOpcode::kJSNotEqual: 3968 case IrOpcode::kJSStrictEqual: 3969 case IrOpcode::kJSStrictNotEqual: 3970 case IrOpcode::kJSLessThan: 3971 case IrOpcode::kJSLessThanOrEqual: 3972 case IrOpcode::kJSGreaterThan: 3973 case IrOpcode::kJSGreaterThanOrEqual: 3974 case IrOpcode::kJSToBoolean: 3975 case IrOpcode::kJSDeleteProperty: 3976 case IrOpcode::kJSHasProperty: 3977 case IrOpcode::kJSInstanceOf: 3978 return input; 3979 default: 3980 break; 3981 } 3982 return nullptr; 3983 } 3984 3985 3986 Node* AstGraphBuilder::TryFastToName(Node* input) { 3987 switch (input->opcode()) { 3988 case IrOpcode::kHeapConstant: { 3989 Handle<HeapObject> object = HeapObjectMatcher(input).Value(); 3990 if (object->IsName()) return input; 3991 break; 3992 } 3993 case IrOpcode::kJSToString: 3994 case IrOpcode::kJSToName: 3995 case IrOpcode::kJSTypeOf: 3996 return input; 3997 default: 3998 break; 3999 } 4000 return nullptr; 4001 } 4002 4003 4004 bool AstGraphBuilder::CheckOsrEntry(IterationStatement* stmt) { 4005 if (info()->osr_ast_id() == stmt->OsrEntryId()) { 4006 DCHECK_EQ(-1, info()->osr_expr_stack_height()); 4007 info()->set_osr_expr_stack_height(environment()->stack_height()); 4008 return true; 4009 } 4010 return false; 4011 } 4012 4013 4014 void AstGraphBuilder::PrepareFrameState(Node* node, BailoutId ast_id, 4015 OutputFrameStateCombine combine) { 4016 if (OperatorProperties::HasFrameStateInput(node->op())) { 4017 DCHECK(ast_id.IsNone() || info()->shared_info()->VerifyBailoutId(ast_id)); 4018 DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op())); 4019 DCHECK_EQ(IrOpcode::kDead, 4020 NodeProperties::GetFrameStateInput(node)->opcode()); 4021 bool has_exception = NodeProperties::IsExceptionalCall(node); 4022 Node* state = environment()->Checkpoint(ast_id, combine, has_exception); 4023 NodeProperties::ReplaceFrameStateInput(node, state); 4024 } 4025 } 4026 4027 void AstGraphBuilder::PrepareEagerCheckpoint(BailoutId ast_id) { 4028 if (environment()->GetEffectDependency()->opcode() == IrOpcode::kCheckpoint) { 4029 // We skip preparing a checkpoint if there already is one the current effect 4030 // dependency. This is just an optimization and not need for correctness. 4031 return; 4032 } 4033 if (ast_id != BailoutId::None()) { 4034 DCHECK(info()->shared_info()->VerifyBailoutId(ast_id)); 4035 Node* node = NewNode(common()->Checkpoint()); 4036 DCHECK_EQ(IrOpcode::kDead, 4037 NodeProperties::GetFrameStateInput(node)->opcode()); 4038 Node* state = environment()->Checkpoint(ast_id); 4039 NodeProperties::ReplaceFrameStateInput(node, state); 4040 } 4041 } 4042 4043 BitVector* AstGraphBuilder::GetVariablesAssignedInLoop( 4044 IterationStatement* stmt) { 4045 if (loop_assignment_analysis_ == nullptr) return nullptr; 4046 return loop_assignment_analysis_->GetVariablesAssignedInLoop(stmt); 4047 } 4048 4049 4050 Node** AstGraphBuilder::EnsureInputBufferSize(int size) { 4051 if (size > input_buffer_size_) { 4052 size = size + kInputBufferSizeIncrement + input_buffer_size_; 4053 input_buffer_ = local_zone()->NewArray<Node*>(size); 4054 input_buffer_size_ = size; 4055 } 4056 return input_buffer_; 4057 } 4058 4059 4060 Node* AstGraphBuilder::MakeNode(const Operator* op, int value_input_count, 4061 Node** value_inputs, bool incomplete) { 4062 DCHECK_EQ(op->ValueInputCount(), value_input_count); 4063 4064 bool has_context = OperatorProperties::HasContextInput(op); 4065 bool has_frame_state = OperatorProperties::HasFrameStateInput(op); 4066 bool has_control = op->ControlInputCount() == 1; 4067 bool has_effect = op->EffectInputCount() == 1; 4068 4069 DCHECK(op->ControlInputCount() < 2); 4070 DCHECK(op->EffectInputCount() < 2); 4071 4072 Node* result = nullptr; 4073 if (!has_context && !has_frame_state && !has_control && !has_effect) { 4074 result = graph()->NewNode(op, value_input_count, value_inputs, incomplete); 4075 } else { 4076 bool inside_try_scope = try_nesting_level_ > 0; 4077 int input_count_with_deps = value_input_count; 4078 if (has_context) ++input_count_with_deps; 4079 if (has_frame_state) ++input_count_with_deps; 4080 if (has_control) ++input_count_with_deps; 4081 if (has_effect) ++input_count_with_deps; 4082 Node** buffer = EnsureInputBufferSize(input_count_with_deps); 4083 memcpy(buffer, value_inputs, kPointerSize * value_input_count); 4084 Node** current_input = buffer + value_input_count; 4085 if (has_context) { 4086 *current_input++ = current_context(); 4087 } 4088 if (has_frame_state) { 4089 // The frame state will be inserted later. Here we misuse 4090 // the {Dead} node as a sentinel to be later overwritten 4091 // with the real frame state. 4092 *current_input++ = jsgraph()->Dead(); 4093 } 4094 if (has_effect) { 4095 *current_input++ = environment_->GetEffectDependency(); 4096 } 4097 if (has_control) { 4098 *current_input++ = environment_->GetControlDependency(); 4099 } 4100 result = graph()->NewNode(op, input_count_with_deps, buffer, incomplete); 4101 if (!environment()->IsMarkedAsUnreachable()) { 4102 // Update the current control dependency for control-producing nodes. 4103 if (NodeProperties::IsControl(result)) { 4104 environment_->UpdateControlDependency(result); 4105 } 4106 // Update the current effect dependency for effect-producing nodes. 4107 if (result->op()->EffectOutputCount() > 0) { 4108 environment_->UpdateEffectDependency(result); 4109 } 4110 // Add implicit exception continuation for throwing nodes. 4111 if (!result->op()->HasProperty(Operator::kNoThrow) && inside_try_scope) { 4112 // Copy the environment for the success continuation. 4113 Environment* success_env = environment()->CopyForConditional(); 4114 const Operator* op = common()->IfException(); 4115 Node* effect = environment()->GetEffectDependency(); 4116 Node* on_exception = graph()->NewNode(op, effect, result); 4117 environment_->UpdateControlDependency(on_exception); 4118 environment_->UpdateEffectDependency(on_exception); 4119 execution_control()->ThrowValue(on_exception); 4120 set_environment(success_env); 4121 } 4122 // Add implicit success continuation for throwing nodes. 4123 if (!result->op()->HasProperty(Operator::kNoThrow)) { 4124 const Operator* op = common()->IfSuccess(); 4125 Node* on_success = graph()->NewNode(op, result); 4126 environment_->UpdateControlDependency(on_success); 4127 } 4128 } 4129 } 4130 4131 return result; 4132 } 4133 4134 4135 void AstGraphBuilder::UpdateControlDependencyToLeaveFunction(Node* exit) { 4136 if (environment()->IsMarkedAsUnreachable()) return; 4137 environment()->MarkAsUnreachable(); 4138 exit_controls_.push_back(exit); 4139 } 4140 4141 4142 void AstGraphBuilder::Environment::Merge(Environment* other) { 4143 DCHECK(values_.size() == other->values_.size()); 4144 DCHECK(contexts_.size() == other->contexts_.size()); 4145 4146 // Nothing to do if the other environment is dead. 4147 if (other->IsMarkedAsUnreachable()) return; 4148 4149 // Resurrect a dead environment by copying the contents of the other one and 4150 // placing a singleton merge as the new control dependency. 4151 if (this->IsMarkedAsUnreachable()) { 4152 Node* other_control = other->control_dependency_; 4153 Node* inputs[] = {other_control}; 4154 control_dependency_ = 4155 graph()->NewNode(common()->Merge(1), arraysize(inputs), inputs, true); 4156 effect_dependency_ = other->effect_dependency_; 4157 values_ = other->values_; 4158 contexts_ = other->contexts_; 4159 if (IsLivenessAnalysisEnabled()) { 4160 liveness_block_ = 4161 builder_->liveness_analyzer()->NewBlock(other->liveness_block()); 4162 } 4163 return; 4164 } 4165 4166 // Record the merge for the local variable liveness calculation. 4167 // For loops, we are connecting a back edge into the existing block; 4168 // for merges, we create a new merged block. 4169 if (IsLivenessAnalysisEnabled()) { 4170 if (GetControlDependency()->opcode() != IrOpcode::kLoop) { 4171 liveness_block_ = 4172 builder_->liveness_analyzer()->NewBlock(liveness_block()); 4173 } 4174 liveness_block()->AddPredecessor(other->liveness_block()); 4175 } 4176 4177 // Create a merge of the control dependencies of both environments and update 4178 // the current environment's control dependency accordingly. 4179 Node* control = builder_->MergeControl(this->GetControlDependency(), 4180 other->GetControlDependency()); 4181 UpdateControlDependency(control); 4182 4183 // Create a merge of the effect dependencies of both environments and update 4184 // the current environment's effect dependency accordingly. 4185 Node* effect = builder_->MergeEffect(this->GetEffectDependency(), 4186 other->GetEffectDependency(), control); 4187 UpdateEffectDependency(effect); 4188 4189 // Introduce Phi nodes for values that have differing input at merge points, 4190 // potentially extending an existing Phi node if possible. 4191 for (int i = 0; i < static_cast<int>(values_.size()); ++i) { 4192 values_[i] = builder_->MergeValue(values_[i], other->values_[i], control); 4193 } 4194 for (int i = 0; i < static_cast<int>(contexts_.size()); ++i) { 4195 contexts_[i] = 4196 builder_->MergeValue(contexts_[i], other->contexts_[i], control); 4197 } 4198 } 4199 4200 void AstGraphBuilder::Environment::PrepareForOsrEntry() { 4201 int size = static_cast<int>(values()->size()); 4202 Graph* graph = builder_->graph(); 4203 4204 // Set the control and effect to the OSR loop entry. 4205 Node* osr_loop_entry = graph->NewNode(builder_->common()->OsrLoopEntry(), 4206 graph->start(), graph->start()); 4207 UpdateControlDependency(osr_loop_entry); 4208 UpdateEffectDependency(osr_loop_entry); 4209 4210 // Set OSR values. 4211 for (int i = 0; i < size; ++i) { 4212 values()->at(i) = 4213 graph->NewNode(builder_->common()->OsrValue(i), osr_loop_entry); 4214 } 4215 4216 // Set the innermost context. 4217 const Operator* op_inner = 4218 builder_->common()->OsrValue(Linkage::kOsrContextSpillSlotIndex); 4219 contexts()->back() = graph->NewNode(op_inner, osr_loop_entry); 4220 4221 // Create a checkpoint. 4222 Node* frame_state = Checkpoint(builder_->info()->osr_ast_id()); 4223 Node* checkpoint = graph->NewNode(common()->Checkpoint(), frame_state, 4224 osr_loop_entry, osr_loop_entry); 4225 UpdateEffectDependency(checkpoint); 4226 4227 // Create the OSR guard nodes. 4228 const Operator* guard_op = 4229 builder_->info()->is_deoptimization_enabled() 4230 ? builder_->common()->OsrGuard(OsrGuardType::kUninitialized) 4231 : builder_->common()->OsrGuard(OsrGuardType::kAny); 4232 Node* effect = checkpoint; 4233 for (int i = 0; i < size; ++i) { 4234 values()->at(i) = effect = 4235 graph->NewNode(guard_op, values()->at(i), effect, osr_loop_entry); 4236 } 4237 contexts()->back() = effect = 4238 graph->NewNode(guard_op, contexts()->back(), effect, osr_loop_entry); 4239 4240 // The innermost context is the OSR value, and the outer contexts are 4241 // reconstructed by dynamically walking up the context chain. 4242 const Operator* load_op = 4243 builder_->javascript()->LoadContext(0, Context::PREVIOUS_INDEX, true); 4244 Node* osr_context = effect = contexts()->back(); 4245 int last = static_cast<int>(contexts()->size() - 1); 4246 for (int i = last - 1; i >= 0; i--) { 4247 osr_context = effect = 4248 graph->NewNode(load_op, osr_context, osr_context, effect); 4249 contexts()->at(i) = osr_context; 4250 } 4251 UpdateEffectDependency(effect); 4252 } 4253 4254 void AstGraphBuilder::Environment::PrepareForLoop(BitVector* assigned) { 4255 int size = static_cast<int>(values()->size()); 4256 4257 Node* control = builder_->NewLoop(); 4258 if (assigned == nullptr) { 4259 // Assume that everything is updated in the loop. 4260 for (int i = 0; i < size; ++i) { 4261 values()->at(i) = builder_->NewPhi(1, values()->at(i), control); 4262 } 4263 } else { 4264 // Only build phis for those locals assigned in this loop. 4265 for (int i = 0; i < size; ++i) { 4266 if (i < assigned->length() && !assigned->Contains(i)) continue; 4267 Node* phi = builder_->NewPhi(1, values()->at(i), control); 4268 values()->at(i) = phi; 4269 } 4270 } 4271 Node* effect = builder_->NewEffectPhi(1, GetEffectDependency(), control); 4272 UpdateEffectDependency(effect); 4273 4274 // Connect the loop to end via Terminate if it's not marked as unreachable. 4275 if (!IsMarkedAsUnreachable()) { 4276 // Connect the Loop node to end via a Terminate node. 4277 Node* terminate = builder_->graph()->NewNode( 4278 builder_->common()->Terminate(), effect, control); 4279 builder_->exit_controls_.push_back(terminate); 4280 } 4281 4282 if (builder_->info()->is_osr()) { 4283 // Introduce phis for all context values in the case of an OSR graph. 4284 for (size_t i = 0; i < contexts()->size(); ++i) { 4285 Node* context = contexts()->at(i); 4286 contexts()->at(i) = builder_->NewPhi(1, context, control); 4287 } 4288 } 4289 } 4290 4291 4292 Node* AstGraphBuilder::NewPhi(int count, Node* input, Node* control) { 4293 const Operator* phi_op = common()->Phi(MachineRepresentation::kTagged, count); 4294 Node** buffer = EnsureInputBufferSize(count + 1); 4295 MemsetPointer(buffer, input, count); 4296 buffer[count] = control; 4297 return graph()->NewNode(phi_op, count + 1, buffer, true); 4298 } 4299 4300 4301 Node* AstGraphBuilder::NewEffectPhi(int count, Node* input, Node* control) { 4302 const Operator* phi_op = common()->EffectPhi(count); 4303 Node** buffer = EnsureInputBufferSize(count + 1); 4304 MemsetPointer(buffer, input, count); 4305 buffer[count] = control; 4306 return graph()->NewNode(phi_op, count + 1, buffer, true); 4307 } 4308 4309 4310 Node* AstGraphBuilder::MergeControl(Node* control, Node* other) { 4311 int inputs = control->op()->ControlInputCount() + 1; 4312 if (control->opcode() == IrOpcode::kLoop) { 4313 // Control node for loop exists, add input. 4314 const Operator* op = common()->Loop(inputs); 4315 control->AppendInput(graph_zone(), other); 4316 NodeProperties::ChangeOp(control, op); 4317 } else if (control->opcode() == IrOpcode::kMerge) { 4318 // Control node for merge exists, add input. 4319 const Operator* op = common()->Merge(inputs); 4320 control->AppendInput(graph_zone(), other); 4321 NodeProperties::ChangeOp(control, op); 4322 } else { 4323 // Control node is a singleton, introduce a merge. 4324 const Operator* op = common()->Merge(inputs); 4325 Node* inputs[] = {control, other}; 4326 control = graph()->NewNode(op, arraysize(inputs), inputs, true); 4327 } 4328 return control; 4329 } 4330 4331 4332 Node* AstGraphBuilder::MergeEffect(Node* value, Node* other, Node* control) { 4333 int inputs = control->op()->ControlInputCount(); 4334 if (value->opcode() == IrOpcode::kEffectPhi && 4335 NodeProperties::GetControlInput(value) == control) { 4336 // Phi already exists, add input. 4337 value->InsertInput(graph_zone(), inputs - 1, other); 4338 NodeProperties::ChangeOp(value, common()->EffectPhi(inputs)); 4339 } else if (value != other) { 4340 // Phi does not exist yet, introduce one. 4341 value = NewEffectPhi(inputs, value, control); 4342 value->ReplaceInput(inputs - 1, other); 4343 } 4344 return value; 4345 } 4346 4347 4348 Node* AstGraphBuilder::MergeValue(Node* value, Node* other, Node* control) { 4349 int inputs = control->op()->ControlInputCount(); 4350 if (value->opcode() == IrOpcode::kPhi && 4351 NodeProperties::GetControlInput(value) == control) { 4352 // Phi already exists, add input. 4353 value->InsertInput(graph_zone(), inputs - 1, other); 4354 NodeProperties::ChangeOp( 4355 value, common()->Phi(MachineRepresentation::kTagged, inputs)); 4356 } else if (value != other) { 4357 // Phi does not exist yet, introduce one. 4358 value = NewPhi(inputs, value, control); 4359 value->ReplaceInput(inputs - 1, other); 4360 } 4361 return value; 4362 } 4363 4364 AstGraphBuilderWithPositions::AstGraphBuilderWithPositions( 4365 Zone* local_zone, CompilationInfo* info, JSGraph* jsgraph, 4366 float invocation_frequency, LoopAssignmentAnalysis* loop_assignment, 4367 TypeHintAnalysis* type_hint_analysis, SourcePositionTable* source_positions, 4368 int inlining_id) 4369 : AstGraphBuilder(local_zone, info, jsgraph, invocation_frequency, 4370 loop_assignment, type_hint_analysis), 4371 source_positions_(source_positions), 4372 start_position_(info->shared_info()->start_position(), inlining_id) {} 4373 4374 } // namespace compiler 4375 } // namespace internal 4376 } // namespace v8 4377