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