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