1// Copyright 2014 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "src/compiler/ast-graph-builder.h" 6 7#include "src/ast/compile-time-value.h" 8#include "src/ast/scopes.h" 9#include "src/compilation-info.h" 10#include "src/compiler.h" 11#include "src/compiler/ast-loop-assignment-analyzer.h" 12#include "src/compiler/control-builders.h" 13#include "src/compiler/linkage.h" 14#include "src/compiler/liveness-analyzer.h" 15#include "src/compiler/machine-operator.h" 16#include "src/compiler/node-matchers.h" 17#include "src/compiler/node-properties.h" 18#include "src/compiler/operator-properties.h" 19#include "src/compiler/state-values-utils.h" 20#include "src/feedback-vector.h" 21#include "src/objects-inl.h" 22#include "src/objects/literal-objects.h" 23 24namespace v8 { 25namespace internal { 26namespace compiler { 27 28 29// Each expression in the AST is evaluated in a specific context. This context 30// decides how the evaluation result is passed up the visitor. 31class AstGraphBuilder::AstContext BASE_EMBEDDED { 32 public: 33 bool IsEffect() const { return kind_ == Expression::kEffect; } 34 bool IsValue() const { return kind_ == Expression::kValue; } 35 bool IsTest() const { return kind_ == Expression::kTest; } 36 37 // Determines how to combine the frame state with the value 38 // that is about to be plugged into this AstContext. 39 OutputFrameStateCombine GetStateCombine() { 40 return IsEffect() ? OutputFrameStateCombine::Ignore() 41 : OutputFrameStateCombine::Push(); 42 } 43 44 // Plug a node into this expression context. Call this function in tail 45 // position in the Visit functions for expressions. 46 virtual void ProduceValue(Expression* expr, Node* value) = 0; 47 48 // Unplugs a node from this expression context. Call this to retrieve the 49 // result of another Visit function that already plugged the context. 50 virtual Node* ConsumeValue() = 0; 51 52 // Shortcut for "context->ProduceValue(context->ConsumeValue())". 53 void ReplaceValue(Expression* expr) { ProduceValue(expr, ConsumeValue()); } 54 55 protected: 56 AstContext(AstGraphBuilder* owner, Expression::Context kind); 57 virtual ~AstContext(); 58 59 AstGraphBuilder* owner() const { return owner_; } 60 Environment* environment() const { return owner_->environment(); } 61 62// We want to be able to assert, in a context-specific way, that the stack 63// height makes sense when the context is filled. 64#ifdef DEBUG 65 int original_height_; 66#endif 67 68 private: 69 Expression::Context kind_; 70 AstGraphBuilder* owner_; 71 AstContext* outer_; 72}; 73 74 75// Context to evaluate expression for its side effects only. 76class AstGraphBuilder::AstEffectContext final : public AstContext { 77 public: 78 explicit AstEffectContext(AstGraphBuilder* owner) 79 : AstContext(owner, Expression::kEffect) {} 80 ~AstEffectContext() final; 81 void ProduceValue(Expression* expr, Node* value) final; 82 Node* ConsumeValue() final; 83}; 84 85 86// Context to evaluate expression for its value (and side effects). 87class AstGraphBuilder::AstValueContext final : public AstContext { 88 public: 89 explicit AstValueContext(AstGraphBuilder* owner) 90 : AstContext(owner, Expression::kValue) {} 91 ~AstValueContext() final; 92 void ProduceValue(Expression* expr, Node* value) final; 93 Node* ConsumeValue() final; 94}; 95 96 97// Context to evaluate expression for a condition value (and side effects). 98class AstGraphBuilder::AstTestContext final : public AstContext { 99 public: 100 AstTestContext(AstGraphBuilder* owner, TypeFeedbackId feedback_id) 101 : AstContext(owner, Expression::kTest), feedback_id_(feedback_id) {} 102 ~AstTestContext() final; 103 void ProduceValue(Expression* expr, Node* value) final; 104 Node* ConsumeValue() final; 105 106 private: 107 TypeFeedbackId const feedback_id_; 108}; 109 110 111// Scoped class tracking context objects created by the visitor. Represents 112// mutations of the context chain within the function body and allows to 113// change the current {scope} and {context} during visitation. 114class AstGraphBuilder::ContextScope BASE_EMBEDDED { 115 public: 116 ContextScope(AstGraphBuilder* builder, Scope* scope, Node* context) 117 : builder_(builder), 118 outer_(builder->execution_context()), 119 scope_(scope), 120 depth_(builder_->environment()->context_chain_length()) { 121 builder_->environment()->PushContext(context); // Push. 122 builder_->set_execution_context(this); 123 } 124 125 ~ContextScope() { 126 builder_->set_execution_context(outer_); // Pop. 127 builder_->environment()->PopContext(); 128 CHECK_EQ(depth_, builder_->environment()->context_chain_length()); 129 } 130 131 // Current scope during visitation. 132 Scope* scope() const { return scope_; } 133 134 private: 135 AstGraphBuilder* builder_; 136 ContextScope* outer_; 137 Scope* scope_; 138 int depth_; 139}; 140 141 142// Scoped class tracking control statements entered by the visitor. There are 143// different types of statements participating in this stack to properly track 144// local as well as non-local control flow: 145// - IterationStatement : Allows proper 'break' and 'continue' behavior. 146// - BreakableStatement : Allows 'break' from block and switch statements. 147// - TryCatchStatement : Intercepts 'throw' and implicit exceptional edges. 148// - TryFinallyStatement: Intercepts 'break', 'continue', 'throw' and 'return'. 149class AstGraphBuilder::ControlScope BASE_EMBEDDED { 150 public: 151 explicit ControlScope(AstGraphBuilder* builder) 152 : builder_(builder), 153 outer_(builder->execution_control()), 154 context_length_(builder->environment()->context_chain_length()), 155 stack_height_(builder->environment()->stack_height()) { 156 builder_->set_execution_control(this); // Push. 157 } 158 159 virtual ~ControlScope() { 160 builder_->set_execution_control(outer_); // Pop. 161 } 162 163 // Either 'break' or 'continue' to the target statement. 164 void BreakTo(BreakableStatement* target); 165 void ContinueTo(BreakableStatement* target); 166 167 // Either 'return' or 'throw' the given value. 168 void ReturnValue(Node* return_value); 169 void ThrowValue(Node* exception_value); 170 171 protected: 172 enum Command { CMD_BREAK, CMD_CONTINUE, CMD_RETURN, CMD_THROW }; 173 174 // Performs one of the above commands on this stack of control scopes. This 175 // walks through the stack giving each scope a chance to execute or defer the 176 // given command by overriding the {Execute} method appropriately. Note that 177 // this also drops extra operands from the environment for each skipped scope. 178 void PerformCommand(Command cmd, Statement* target, Node* value); 179 180 // Interface to execute a given command in this scope. Returning {true} here 181 // indicates successful execution whereas {false} requests to skip scope. 182 virtual bool Execute(Command cmd, Statement* target, Node** value) { 183 // For function-level control. 184 switch (cmd) { 185 case CMD_THROW: 186 builder()->BuildThrow(*value); 187 return true; 188 case CMD_RETURN: 189 builder()->BuildReturn(*value); 190 return true; 191 case CMD_BREAK: 192 case CMD_CONTINUE: 193 break; 194 } 195 return false; 196 } 197 198 Environment* environment() { return builder_->environment(); } 199 AstGraphBuilder* builder() const { return builder_; } 200 int context_length() const { return context_length_; } 201 int stack_height() const { return stack_height_; } 202 203 private: 204 AstGraphBuilder* builder_; 205 ControlScope* outer_; 206 int context_length_; 207 int stack_height_; 208}; 209 210 211// Control scope implementation for a BreakableStatement. 212class AstGraphBuilder::ControlScopeForBreakable : public ControlScope { 213 public: 214 ControlScopeForBreakable(AstGraphBuilder* owner, BreakableStatement* target, 215 ControlBuilder* control) 216 : ControlScope(owner), target_(target), control_(control) {} 217 218 protected: 219 bool Execute(Command cmd, Statement* target, Node** value) override { 220 if (target != target_) return false; // We are not the command target. 221 switch (cmd) { 222 case CMD_BREAK: 223 control_->Break(); 224 return true; 225 case CMD_CONTINUE: 226 case CMD_THROW: 227 case CMD_RETURN: 228 break; 229 } 230 return false; 231 } 232 233 private: 234 BreakableStatement* target_; 235 ControlBuilder* control_; 236}; 237 238 239// Control scope implementation for an IterationStatement. 240class AstGraphBuilder::ControlScopeForIteration : public ControlScope { 241 public: 242 ControlScopeForIteration(AstGraphBuilder* owner, IterationStatement* target, 243 LoopBuilder* control) 244 : ControlScope(owner), target_(target), control_(control) {} 245 246 protected: 247 bool Execute(Command cmd, Statement* target, Node** value) override { 248 if (target != target_) { 249 control_->ExitLoop(value); 250 return false; 251 } 252 switch (cmd) { 253 case CMD_BREAK: 254 control_->Break(); 255 return true; 256 case CMD_CONTINUE: 257 control_->Continue(); 258 return true; 259 case CMD_THROW: 260 case CMD_RETURN: 261 break; 262 } 263 return false; 264 } 265 266 private: 267 BreakableStatement* target_; 268 LoopBuilder* control_; 269}; 270 271 272AstGraphBuilder::AstGraphBuilder(Zone* local_zone, CompilationInfo* info, 273 JSGraph* jsgraph, float invocation_frequency, 274 LoopAssignmentAnalysis* loop) 275 : isolate_(info->isolate()), 276 local_zone_(local_zone), 277 info_(info), 278 jsgraph_(jsgraph), 279 invocation_frequency_(invocation_frequency), 280 environment_(nullptr), 281 ast_context_(nullptr), 282 globals_(0, local_zone), 283 execution_control_(nullptr), 284 execution_context_(nullptr), 285 input_buffer_size_(0), 286 input_buffer_(nullptr), 287 exit_controls_(local_zone), 288 loop_assignment_analysis_(loop), 289 state_values_cache_(jsgraph), 290 liveness_analyzer_(static_cast<size_t>(info->scope()->num_stack_slots()), 291 false, local_zone), 292 frame_state_function_info_(common()->CreateFrameStateFunctionInfo( 293 FrameStateType::kJavaScriptFunction, info->num_parameters() + 1, 294 info->scope()->num_stack_slots(), info->shared_info())) { 295 InitializeAstVisitor(info->isolate()); 296} 297 298 299Node* AstGraphBuilder::GetFunctionClosureForContext() { 300 DeclarationScope* closure_scope = current_scope()->GetClosureScope(); 301 if (closure_scope->is_script_scope() || 302 closure_scope->is_module_scope()) { 303 // Contexts nested in the native context have a canonical empty function as 304 // their closure, not the anonymous closure containing the global code. 305 return BuildLoadNativeContextField(Context::CLOSURE_INDEX); 306 } else if (closure_scope->is_eval_scope()) { 307 // Contexts nested inside eval code have the same closure as the context 308 // calling eval, not the anonymous closure containing the eval code. 309 const Operator* op = 310 javascript()->LoadContext(0, Context::CLOSURE_INDEX, false); 311 return NewNode(op); 312 } else { 313 DCHECK(closure_scope->is_function_scope()); 314 return GetFunctionClosure(); 315 } 316} 317 318 319Node* AstGraphBuilder::GetFunctionClosure() { 320 if (!function_closure_.is_set()) { 321 int index = Linkage::kJSCallClosureParamIndex; 322 const Operator* op = common()->Parameter(index, "%closure"); 323 Node* node = NewNode(op, graph()->start()); 324 function_closure_.set(node); 325 } 326 return function_closure_.get(); 327} 328 329 330Node* AstGraphBuilder::GetFunctionContext() { 331 if (!function_context_.is_set()) { 332 int params = info()->num_parameters_including_this(); 333 int index = Linkage::GetJSCallContextParamIndex(params); 334 const Operator* op = common()->Parameter(index, "%context"); 335 Node* node = NewNode(op, graph()->start()); 336 function_context_.set(node); 337 } 338 return function_context_.get(); 339} 340 341Node* AstGraphBuilder::GetEmptyFrameState() { 342 if (!empty_frame_state_.is_set()) { 343 const Operator* op = common()->FrameState( 344 BailoutId::None(), OutputFrameStateCombine::Ignore(), nullptr); 345 Node* node = graph()->NewNode( 346 op, jsgraph()->EmptyStateValues(), jsgraph()->EmptyStateValues(), 347 jsgraph()->EmptyStateValues(), jsgraph()->NoContextConstant(), 348 jsgraph()->UndefinedConstant(), graph()->start()); 349 empty_frame_state_.set(node); 350 } 351 return empty_frame_state_.get(); 352} 353 354bool AstGraphBuilder::CreateGraph(bool stack_check) { 355 DeclarationScope* scope = info()->scope(); 356 DCHECK_NOT_NULL(graph()); 357 358 // Set up the basic structure of the graph. Outputs for {Start} are the formal 359 // parameters (including the receiver) plus new target, number of arguments, 360 // context and closure. 361 int actual_parameter_count = info()->num_parameters_including_this() + 4; 362 graph()->SetStart(graph()->NewNode(common()->Start(actual_parameter_count))); 363 364 // Initialize the top-level environment. 365 Environment env(this, scope, graph()->start()); 366 set_environment(&env); 367 368 if (info()->is_osr()) { 369 // Use OSR normal entry as the start of the top-level environment. 370 // It will be replaced with {Dead} after typing and optimizations. 371 NewNode(common()->OsrNormalEntry()); 372 } 373 374 // Initialize the incoming context. 375 ContextScope incoming(this, scope, GetFunctionContext()); 376 377 // Initialize control scope. 378 ControlScope control(this); 379 380 // TODO(mstarzinger): For now we cannot assume that the {this} parameter is 381 // not {the_hole}, because for derived classes {this} has a TDZ and the 382 // JSConstructStubForDerived magically passes {the_hole} as a receiver. 383 if (scope->has_this_declaration() && scope->receiver()->mode() == CONST) { 384 env.RawParameterBind(0, jsgraph()->TheHoleConstant()); 385 } 386 387 if (scope->NeedsContext()) { 388 // Push a new inner context scope for the current activation. 389 Node* inner_context = BuildLocalActivationContext(GetFunctionContext()); 390 ContextScope top_context(this, scope, inner_context); 391 CreateGraphBody(stack_check); 392 } else { 393 // Simply use the outer function context in building the graph. 394 CreateGraphBody(stack_check); 395 } 396 397 // Finish the basic structure of the graph. 398 DCHECK_NE(0u, exit_controls_.size()); 399 int const input_count = static_cast<int>(exit_controls_.size()); 400 Node** const inputs = &exit_controls_.front(); 401 Node* end = graph()->NewNode(common()->End(input_count), input_count, inputs); 402 graph()->SetEnd(end); 403 404 // Compute local variable liveness information and use it to relax 405 // frame states. 406 ClearNonLiveSlotsInFrameStates(); 407 408 // Failures indicated by stack overflow. 409 return !HasStackOverflow(); 410} 411 412 413void AstGraphBuilder::CreateGraphBody(bool stack_check) { 414 DeclarationScope* scope = info()->scope(); 415 416 // Build the arguments object if it is used. 417 BuildArgumentsObject(scope->arguments()); 418 419 // We don't support new.target and rest parameters here. 420 DCHECK_NULL(scope->new_target_var()); 421 DCHECK_NULL(scope->rest_parameter()); 422 DCHECK_NULL(scope->this_function_var()); 423 424 // Emit tracing call if requested to do so. 425 if (FLAG_trace) { 426 NewNode(javascript()->CallRuntime(Runtime::kTraceEnter)); 427 } 428 429 // Visit declarations within the function scope. 430 VisitDeclarations(scope->declarations()); 431 432 // Build a stack-check before the body. 433 if (stack_check) { 434 Node* node = NewNode(javascript()->StackCheck()); 435 PrepareFrameState(node, BailoutId::FunctionEntry()); 436 } 437 438 // Visit statements in the function body. 439 VisitStatements(info()->literal()->body()); 440 441 // Return 'undefined' in case we can fall off the end. 442 BuildReturn(jsgraph()->UndefinedConstant()); 443} 444 445 446void AstGraphBuilder::ClearNonLiveSlotsInFrameStates() { 447 if (!FLAG_analyze_environment_liveness || 448 !info()->is_deoptimization_enabled()) { 449 return; 450 } 451 452 NonLiveFrameStateSlotReplacer replacer( 453 &state_values_cache_, jsgraph()->OptimizedOutConstant(), 454 liveness_analyzer()->local_count(), false, local_zone()); 455 Variable* arguments = info()->scope()->arguments(); 456 if (arguments != nullptr && arguments->IsStackAllocated()) { 457 replacer.MarkPermanentlyLive(arguments->index()); 458 } 459 liveness_analyzer()->Run(&replacer); 460 if (FLAG_trace_environment_liveness) { 461 OFStream os(stdout); 462 liveness_analyzer()->Print(os); 463 } 464} 465 466 467// Gets the bailout id just before reading a variable proxy, but only for 468// unallocated variables. 469static BailoutId BeforeId(VariableProxy* proxy) { 470 return proxy->var()->IsUnallocated() ? proxy->BeforeId() : BailoutId::None(); 471} 472 473static const char* GetDebugParameterName(Zone* zone, DeclarationScope* scope, 474 int index) { 475#if DEBUG 476 const AstRawString* name = scope->parameter(index)->raw_name(); 477 if (name && name->length() > 0) { 478 char* data = zone->NewArray<char>(name->length() + 1); 479 data[name->length()] = 0; 480 memcpy(data, name->raw_data(), name->length()); 481 return data; 482 } 483#endif 484 return nullptr; 485} 486 487AstGraphBuilder::Environment::Environment(AstGraphBuilder* builder, 488 DeclarationScope* scope, 489 Node* control_dependency) 490 : builder_(builder), 491 parameters_count_(scope->num_parameters() + 1), 492 locals_count_(scope->num_stack_slots()), 493 liveness_block_(IsLivenessAnalysisEnabled() 494 ? builder_->liveness_analyzer()->NewBlock() 495 : nullptr), 496 values_(builder_->local_zone()), 497 contexts_(builder_->local_zone()), 498 control_dependency_(control_dependency), 499 effect_dependency_(control_dependency), 500 parameters_node_(nullptr), 501 locals_node_(nullptr), 502 stack_node_(nullptr) { 503 DCHECK_EQ(scope->num_parameters() + 1, parameters_count()); 504 505 // Bind the receiver variable. 506 int param_num = 0; 507 if (builder->info()->is_this_defined()) { 508 const Operator* op = common()->Parameter(param_num++, "%this"); 509 Node* receiver = builder->graph()->NewNode(op, builder->graph()->start()); 510 values()->push_back(receiver); 511 } else { 512 values()->push_back(builder->jsgraph()->UndefinedConstant()); 513 } 514 515 // Bind all parameter variables. The parameter indices are shifted by 1 516 // (receiver is variable index -1 but {Parameter} node index 0 and located at 517 // index 0 in the environment). 518 for (int i = 0; i < scope->num_parameters(); ++i) { 519 const char* debug_name = GetDebugParameterName(graph()->zone(), scope, i); 520 const Operator* op = common()->Parameter(param_num++, debug_name); 521 Node* parameter = builder->graph()->NewNode(op, builder->graph()->start()); 522 values()->push_back(parameter); 523 } 524 525 // Bind all local variables to undefined. 526 Node* undefined_constant = builder->jsgraph()->UndefinedConstant(); 527 values()->insert(values()->end(), locals_count(), undefined_constant); 528} 529 530 531AstGraphBuilder::Environment::Environment(AstGraphBuilder::Environment* copy, 532 LivenessAnalyzerBlock* liveness_block) 533 : builder_(copy->builder_), 534 parameters_count_(copy->parameters_count_), 535 locals_count_(copy->locals_count_), 536 liveness_block_(liveness_block), 537 values_(copy->zone()), 538 contexts_(copy->zone()), 539 control_dependency_(copy->control_dependency_), 540 effect_dependency_(copy->effect_dependency_), 541 parameters_node_(copy->parameters_node_), 542 locals_node_(copy->locals_node_), 543 stack_node_(copy->stack_node_) { 544 const size_t kStackEstimate = 7; // optimum from experimentation! 545 values_.reserve(copy->values_.size() + kStackEstimate); 546 values_.insert(values_.begin(), copy->values_.begin(), copy->values_.end()); 547 contexts_.reserve(copy->contexts_.size()); 548 contexts_.insert(contexts_.begin(), copy->contexts_.begin(), 549 copy->contexts_.end()); 550} 551 552 553void AstGraphBuilder::Environment::Bind(Variable* variable, Node* node) { 554 DCHECK(variable->IsStackAllocated()); 555 if (variable->IsParameter()) { 556 // The parameter indices are shifted by 1 (receiver is variable 557 // index -1 but located at index 0 in the environment). 558 values()->at(variable->index() + 1) = node; 559 } else { 560 DCHECK(variable->IsStackLocal()); 561 values()->at(variable->index() + parameters_count_) = node; 562 DCHECK(IsLivenessBlockConsistent()); 563 if (liveness_block() != nullptr) { 564 liveness_block()->Bind(variable->index()); 565 } 566 } 567} 568 569 570Node* AstGraphBuilder::Environment::Lookup(Variable* variable) { 571 DCHECK(variable->IsStackAllocated()); 572 if (variable->IsParameter()) { 573 // The parameter indices are shifted by 1 (receiver is variable 574 // index -1 but located at index 0 in the environment). 575 return values()->at(variable->index() + 1); 576 } else { 577 DCHECK(variable->IsStackLocal()); 578 DCHECK(IsLivenessBlockConsistent()); 579 if (liveness_block() != nullptr) { 580 liveness_block()->Lookup(variable->index()); 581 } 582 return values()->at(variable->index() + parameters_count_); 583 } 584} 585 586 587void AstGraphBuilder::Environment::MarkAllLocalsLive() { 588 DCHECK(IsLivenessBlockConsistent()); 589 if (liveness_block() != nullptr) { 590 for (int i = 0; i < locals_count_; i++) { 591 liveness_block()->Lookup(i); 592 } 593 } 594} 595 596 597void AstGraphBuilder::Environment::RawParameterBind(int index, Node* node) { 598 DCHECK_LT(index, parameters_count()); 599 values()->at(index) = node; 600} 601 602 603Node* AstGraphBuilder::Environment::RawParameterLookup(int index) { 604 DCHECK_LT(index, parameters_count()); 605 return values()->at(index); 606} 607 608 609AstGraphBuilder::Environment* 610AstGraphBuilder::Environment::CopyForConditional() { 611 LivenessAnalyzerBlock* copy_liveness_block = nullptr; 612 if (liveness_block() != nullptr) { 613 copy_liveness_block = 614 builder_->liveness_analyzer()->NewBlock(liveness_block()); 615 liveness_block_ = builder_->liveness_analyzer()->NewBlock(liveness_block()); 616 } 617 return new (zone()) Environment(this, copy_liveness_block); 618} 619 620 621AstGraphBuilder::Environment* 622AstGraphBuilder::Environment::CopyAsUnreachable() { 623 Environment* env = new (zone()) Environment(this, nullptr); 624 env->MarkAsUnreachable(); 625 return env; 626} 627 628AstGraphBuilder::Environment* AstGraphBuilder::Environment::CopyForOsrEntry() { 629 LivenessAnalyzerBlock* copy_block = 630 liveness_block() == nullptr ? nullptr 631 : builder_->liveness_analyzer()->NewBlock(); 632 return new (zone()) Environment(this, copy_block); 633} 634 635AstGraphBuilder::Environment* 636AstGraphBuilder::Environment::CopyAndShareLiveness() { 637 if (liveness_block() != nullptr) { 638 // Finish the current liveness block before copying. 639 liveness_block_ = builder_->liveness_analyzer()->NewBlock(liveness_block()); 640 } 641 Environment* env = new (zone()) Environment(this, liveness_block()); 642 return env; 643} 644 645 646AstGraphBuilder::Environment* AstGraphBuilder::Environment::CopyForLoop( 647 BitVector* assigned, bool is_osr) { 648 PrepareForLoop(assigned); 649 Environment* loop = CopyAndShareLiveness(); 650 if (is_osr) { 651 // Create and merge the OSR entry if necessary. 652 Environment* osr_env = CopyForOsrEntry(); 653 osr_env->PrepareForOsrEntry(); 654 loop->Merge(osr_env); 655 } 656 return loop; 657} 658 659 660void AstGraphBuilder::Environment::UpdateStateValues(Node** state_values, 661 int offset, int count) { 662 bool should_update = false; 663 Node** env_values = (count == 0) ? nullptr : &values()->at(offset); 664 if (*state_values == nullptr || (*state_values)->InputCount() != count) { 665 should_update = true; 666 } else { 667 DCHECK(static_cast<size_t>(offset + count) <= values()->size()); 668 for (int i = 0; i < count; i++) { 669 if ((*state_values)->InputAt(i) != env_values[i]) { 670 should_update = true; 671 break; 672 } 673 } 674 } 675 if (should_update) { 676 const Operator* op = common()->StateValues(count, SparseInputMask::Dense()); 677 (*state_values) = graph()->NewNode(op, count, env_values); 678 } 679} 680 681 682Node* AstGraphBuilder::Environment::Checkpoint(BailoutId ast_id, 683 OutputFrameStateCombine combine, 684 bool owner_has_exception) { 685 if (!builder()->info()->is_deoptimization_enabled()) { 686 return builder()->GetEmptyFrameState(); 687 } 688 689 UpdateStateValues(¶meters_node_, 0, parameters_count()); 690 UpdateStateValues(&locals_node_, parameters_count(), locals_count()); 691 UpdateStateValues(&stack_node_, parameters_count() + locals_count(), 692 stack_height()); 693 694 const Operator* op = common()->FrameState( 695 ast_id, combine, builder()->frame_state_function_info()); 696 697 Node* result = graph()->NewNode(op, parameters_node_, locals_node_, 698 stack_node_, builder()->current_context(), 699 builder()->GetFunctionClosure(), 700 builder()->graph()->start()); 701 702 DCHECK(IsLivenessBlockConsistent()); 703 if (liveness_block() != nullptr) { 704 // If the owning node has an exception, register the checkpoint to the 705 // predecessor so that the checkpoint is used for both the normal and the 706 // exceptional paths. Yes, this is a terrible hack and we might want 707 // to use an explicit frame state for the exceptional path. 708 if (owner_has_exception) { 709 liveness_block()->GetPredecessor()->Checkpoint(result); 710 } else { 711 liveness_block()->Checkpoint(result); 712 } 713 } 714 return result; 715} 716 717void AstGraphBuilder::Environment::PrepareForLoopExit( 718 Node* loop, BitVector* assigned_variables) { 719 if (IsMarkedAsUnreachable()) return; 720 721 DCHECK_EQ(loop->opcode(), IrOpcode::kLoop); 722 723 Node* control = GetControlDependency(); 724 725 // Create the loop exit node. 726 Node* loop_exit = graph()->NewNode(common()->LoopExit(), control, loop); 727 UpdateControlDependency(loop_exit); 728 729 // Rename the environmnent values. 730 for (size_t i = 0; i < values()->size(); i++) { 731 if (assigned_variables == nullptr || 732 static_cast<int>(i) >= assigned_variables->length() || 733 assigned_variables->Contains(static_cast<int>(i))) { 734 Node* rename = graph()->NewNode(common()->LoopExitValue(), (*values())[i], 735 loop_exit); 736 (*values())[i] = rename; 737 } 738 } 739 740 // Rename the effect. 741 Node* effect_rename = graph()->NewNode(common()->LoopExitEffect(), 742 GetEffectDependency(), loop_exit); 743 UpdateEffectDependency(effect_rename); 744} 745 746bool AstGraphBuilder::Environment::IsLivenessAnalysisEnabled() { 747 return FLAG_analyze_environment_liveness && 748 builder()->info()->is_deoptimization_enabled(); 749} 750 751 752bool AstGraphBuilder::Environment::IsLivenessBlockConsistent() { 753 return (!IsLivenessAnalysisEnabled() || IsMarkedAsUnreachable()) == 754 (liveness_block() == nullptr); 755} 756 757 758AstGraphBuilder::AstContext::AstContext(AstGraphBuilder* own, 759 Expression::Context kind) 760 : kind_(kind), owner_(own), outer_(own->ast_context()) { 761 owner()->set_ast_context(this); // Push. 762#ifdef DEBUG 763 original_height_ = environment()->stack_height(); 764#endif 765} 766 767 768AstGraphBuilder::AstContext::~AstContext() { 769 owner()->set_ast_context(outer_); // Pop. 770} 771 772 773AstGraphBuilder::AstEffectContext::~AstEffectContext() { 774 DCHECK(environment()->stack_height() == original_height_); 775} 776 777 778AstGraphBuilder::AstValueContext::~AstValueContext() { 779 DCHECK(environment()->stack_height() == original_height_ + 1); 780} 781 782 783AstGraphBuilder::AstTestContext::~AstTestContext() { 784 DCHECK(environment()->stack_height() == original_height_ + 1); 785} 786 787void AstGraphBuilder::AstEffectContext::ProduceValue(Expression* expr, 788 Node* value) { 789 // The value is ignored. 790 owner()->PrepareEagerCheckpoint(expr->id()); 791} 792 793void AstGraphBuilder::AstValueContext::ProduceValue(Expression* expr, 794 Node* value) { 795 environment()->Push(value); 796 owner()->PrepareEagerCheckpoint(expr->id()); 797} 798 799void AstGraphBuilder::AstTestContext::ProduceValue(Expression* expr, 800 Node* value) { 801 environment()->Push(owner()->BuildToBoolean(value, feedback_id_)); 802 owner()->PrepareEagerCheckpoint(expr->id()); 803} 804 805 806Node* AstGraphBuilder::AstEffectContext::ConsumeValue() { return nullptr; } 807 808 809Node* AstGraphBuilder::AstValueContext::ConsumeValue() { 810 return environment()->Pop(); 811} 812 813 814Node* AstGraphBuilder::AstTestContext::ConsumeValue() { 815 return environment()->Pop(); 816} 817 818 819Scope* AstGraphBuilder::current_scope() const { 820 return execution_context_->scope(); 821} 822 823 824Node* AstGraphBuilder::current_context() const { 825 return environment()->Context(); 826} 827 828 829void AstGraphBuilder::ControlScope::PerformCommand(Command command, 830 Statement* target, 831 Node* value) { 832 Environment* env = environment()->CopyAsUnreachable(); 833 ControlScope* current = this; 834 while (current != nullptr) { 835 environment()->TrimStack(current->stack_height()); 836 environment()->TrimContextChain(current->context_length()); 837 if (current->Execute(command, target, &value)) break; 838 current = current->outer_; 839 } 840 builder()->set_environment(env); 841 DCHECK_NOT_NULL(current); // Always handled (unless stack is malformed). 842} 843 844 845void AstGraphBuilder::ControlScope::BreakTo(BreakableStatement* stmt) { 846 PerformCommand(CMD_BREAK, stmt, builder()->jsgraph()->TheHoleConstant()); 847} 848 849 850void AstGraphBuilder::ControlScope::ContinueTo(BreakableStatement* stmt) { 851 PerformCommand(CMD_CONTINUE, stmt, builder()->jsgraph()->TheHoleConstant()); 852} 853 854 855void AstGraphBuilder::ControlScope::ReturnValue(Node* return_value) { 856 PerformCommand(CMD_RETURN, nullptr, return_value); 857} 858 859 860void AstGraphBuilder::ControlScope::ThrowValue(Node* exception_value) { 861 PerformCommand(CMD_THROW, nullptr, exception_value); 862} 863 864 865void AstGraphBuilder::VisitForValueOrNull(Expression* expr) { 866 if (expr == nullptr) { 867 return environment()->Push(jsgraph()->NullConstant()); 868 } 869 VisitForValue(expr); 870} 871 872 873void AstGraphBuilder::VisitForValueOrTheHole(Expression* expr) { 874 if (expr == nullptr) { 875 return environment()->Push(jsgraph()->TheHoleConstant()); 876 } 877 VisitForValue(expr); 878} 879 880 881void AstGraphBuilder::VisitForValues(ZoneList<Expression*>* exprs) { 882 for (int i = 0; i < exprs->length(); ++i) { 883 VisitForValue(exprs->at(i)); 884 } 885} 886 887 888void AstGraphBuilder::VisitForValue(Expression* expr) { 889 AstValueContext for_value(this); 890 if (!CheckStackOverflow()) { 891 VisitNoStackOverflowCheck(expr); 892 } else { 893 ast_context()->ProduceValue(expr, jsgraph()->UndefinedConstant()); 894 } 895} 896 897 898void AstGraphBuilder::VisitForEffect(Expression* expr) { 899 AstEffectContext for_effect(this); 900 if (!CheckStackOverflow()) { 901 VisitNoStackOverflowCheck(expr); 902 } else { 903 ast_context()->ProduceValue(expr, jsgraph()->UndefinedConstant()); 904 } 905} 906 907 908void AstGraphBuilder::VisitForTest(Expression* expr) { 909 AstTestContext for_condition(this, expr->test_id()); 910 if (!CheckStackOverflow()) { 911 VisitNoStackOverflowCheck(expr); 912 } else { 913 ast_context()->ProduceValue(expr, jsgraph()->UndefinedConstant()); 914 } 915} 916 917 918void AstGraphBuilder::Visit(Expression* expr) { 919 // Reuses enclosing AstContext. 920 if (!CheckStackOverflow()) { 921 VisitNoStackOverflowCheck(expr); 922 } else { 923 ast_context()->ProduceValue(expr, jsgraph()->UndefinedConstant()); 924 } 925} 926 927 928void AstGraphBuilder::VisitVariableDeclaration(VariableDeclaration* decl) { 929 Variable* variable = decl->proxy()->var(); 930 switch (variable->location()) { 931 case VariableLocation::UNALLOCATED: { 932 DCHECK(!variable->binding_needs_init()); 933 globals()->push_back(variable->name()); 934 FeedbackSlot slot = decl->proxy()->VariableFeedbackSlot(); 935 DCHECK(!slot.IsInvalid()); 936 globals()->push_back(handle(Smi::FromInt(slot.ToInt()), isolate())); 937 globals()->push_back(isolate()->factory()->undefined_value()); 938 globals()->push_back(isolate()->factory()->undefined_value()); 939 break; 940 } 941 case VariableLocation::PARAMETER: 942 case VariableLocation::LOCAL: 943 if (variable->binding_needs_init()) { 944 Node* value = jsgraph()->TheHoleConstant(); 945 environment()->Bind(variable, value); 946 } 947 break; 948 case VariableLocation::CONTEXT: 949 if (variable->binding_needs_init()) { 950 Node* value = jsgraph()->TheHoleConstant(); 951 const Operator* op = javascript()->StoreContext(0, variable->index()); 952 NewNode(op, value); 953 } 954 break; 955 case VariableLocation::LOOKUP: 956 case VariableLocation::MODULE: 957 UNREACHABLE(); 958 } 959} 960 961 962void AstGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* decl) { 963 Variable* variable = decl->proxy()->var(); 964 switch (variable->location()) { 965 case VariableLocation::UNALLOCATED: { 966 Handle<SharedFunctionInfo> function = Compiler::GetSharedFunctionInfo( 967 decl->fun(), info()->script(), info()); 968 // Check for stack-overflow exception. 969 if (function.is_null()) return SetStackOverflow(); 970 globals()->push_back(variable->name()); 971 FeedbackSlot slot = decl->proxy()->VariableFeedbackSlot(); 972 DCHECK(!slot.IsInvalid()); 973 globals()->push_back(handle(Smi::FromInt(slot.ToInt()), isolate())); 974 975 // We need the slot where the literals array lives, too. 976 slot = decl->fun()->LiteralFeedbackSlot(); 977 DCHECK(!slot.IsInvalid()); 978 globals()->push_back(handle(Smi::FromInt(slot.ToInt()), isolate())); 979 980 globals()->push_back(function); 981 break; 982 } 983 case VariableLocation::PARAMETER: 984 case VariableLocation::LOCAL: { 985 VisitForValue(decl->fun()); 986 Node* value = environment()->Pop(); 987 environment()->Bind(variable, value); 988 break; 989 } 990 case VariableLocation::CONTEXT: { 991 VisitForValue(decl->fun()); 992 Node* value = environment()->Pop(); 993 const Operator* op = javascript()->StoreContext(0, variable->index()); 994 NewNode(op, value); 995 break; 996 } 997 case VariableLocation::LOOKUP: 998 case VariableLocation::MODULE: 999 UNREACHABLE(); 1000 } 1001} 1002 1003 1004void AstGraphBuilder::VisitBlock(Block* stmt) { 1005 BlockBuilder block(this); 1006 ControlScopeForBreakable scope(this, stmt, &block); 1007 if (stmt->labels() != nullptr) block.BeginBlock(); 1008 if (stmt->scope() == nullptr) { 1009 // Visit statements in the same scope, no declarations. 1010 VisitStatements(stmt->statements()); 1011 } else { 1012 // Visit declarations and statements in a block scope. 1013 if (stmt->scope()->NeedsContext()) { 1014 Node* context = BuildLocalBlockContext(stmt->scope()); 1015 ContextScope scope(this, stmt->scope(), context); 1016 VisitDeclarations(stmt->scope()->declarations()); 1017 VisitStatements(stmt->statements()); 1018 } else { 1019 VisitDeclarations(stmt->scope()->declarations()); 1020 VisitStatements(stmt->statements()); 1021 } 1022 } 1023 if (stmt->labels() != nullptr) block.EndBlock(); 1024} 1025 1026 1027void AstGraphBuilder::VisitExpressionStatement(ExpressionStatement* stmt) { 1028 VisitForEffect(stmt->expression()); 1029} 1030 1031 1032void AstGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) { 1033 // Do nothing. 1034} 1035 1036 1037void AstGraphBuilder::VisitSloppyBlockFunctionStatement( 1038 SloppyBlockFunctionStatement* stmt) { 1039 Visit(stmt->statement()); 1040} 1041 1042 1043void AstGraphBuilder::VisitIfStatement(IfStatement* stmt) { 1044 IfBuilder compare_if(this); 1045 VisitForTest(stmt->condition()); 1046 Node* condition = environment()->Pop(); 1047 compare_if.If(condition); 1048 compare_if.Then(); 1049 Visit(stmt->then_statement()); 1050 compare_if.Else(); 1051 Visit(stmt->else_statement()); 1052 compare_if.End(); 1053} 1054 1055 1056void AstGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) { 1057 execution_control()->ContinueTo(stmt->target()); 1058} 1059 1060 1061void AstGraphBuilder::VisitBreakStatement(BreakStatement* stmt) { 1062 execution_control()->BreakTo(stmt->target()); 1063} 1064 1065 1066void AstGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { 1067 VisitForValue(stmt->expression()); 1068 Node* result = environment()->Pop(); 1069 execution_control()->ReturnValue(result); 1070} 1071 1072 1073void AstGraphBuilder::VisitWithStatement(WithStatement* stmt) { 1074 // Dynamic scoping is supported only by going through Ignition first. 1075 UNREACHABLE(); 1076} 1077 1078 1079void AstGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { 1080 ZoneList<CaseClause*>* clauses = stmt->cases(); 1081 SwitchBuilder compare_switch(this, clauses->length()); 1082 ControlScopeForBreakable scope(this, stmt, &compare_switch); 1083 compare_switch.BeginSwitch(); 1084 int default_index = -1; 1085 1086 // Keep the switch value on the stack until a case matches. 1087 VisitForValue(stmt->tag()); 1088 1089 // Iterate over all cases and create nodes for label comparison. 1090 for (int i = 0; i < clauses->length(); i++) { 1091 CaseClause* clause = clauses->at(i); 1092 1093 // The default is not a test, remember index. 1094 if (clause->is_default()) { 1095 default_index = i; 1096 continue; 1097 } 1098 1099 // Create nodes to perform label comparison as if via '==='. The switch 1100 // value is still on the operand stack while the label is evaluated. 1101 VisitForValue(clause->label()); 1102 Node* label = environment()->Pop(); 1103 Node* tag = environment()->Top(); 1104 1105 CompareOperationHint hint = CompareOperationHint::kAny; 1106 const Operator* op = javascript()->StrictEqual(hint); 1107 Node* condition = NewNode(op, tag, label); 1108 compare_switch.BeginLabel(i, condition); 1109 1110 // Discard the switch value at label match. 1111 environment()->Pop(); 1112 compare_switch.EndLabel(); 1113 } 1114 1115 // Discard the switch value and mark the default case. 1116 environment()->Pop(); 1117 if (default_index >= 0) { 1118 compare_switch.DefaultAt(default_index); 1119 } 1120 1121 // Iterate over all cases and create nodes for case bodies. 1122 for (int i = 0; i < clauses->length(); i++) { 1123 CaseClause* clause = clauses->at(i); 1124 compare_switch.BeginCase(i); 1125 VisitStatements(clause->statements()); 1126 compare_switch.EndCase(); 1127 } 1128 1129 compare_switch.EndSwitch(); 1130} 1131 1132 1133void AstGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) { 1134 LoopBuilder while_loop(this); 1135 while_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt)); 1136 VisitIterationBody(stmt, &while_loop, stmt->StackCheckId()); 1137 while_loop.EndBody(); 1138 VisitForTest(stmt->cond()); 1139 Node* condition = environment()->Pop(); 1140 while_loop.BreakUnless(condition); 1141 while_loop.EndLoop(); 1142} 1143 1144 1145void AstGraphBuilder::VisitWhileStatement(WhileStatement* stmt) { 1146 LoopBuilder while_loop(this); 1147 while_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt)); 1148 VisitForTest(stmt->cond()); 1149 Node* condition = environment()->Pop(); 1150 while_loop.BreakUnless(condition); 1151 VisitIterationBody(stmt, &while_loop, stmt->StackCheckId()); 1152 while_loop.EndBody(); 1153 while_loop.EndLoop(); 1154} 1155 1156 1157void AstGraphBuilder::VisitForStatement(ForStatement* stmt) { 1158 LoopBuilder for_loop(this); 1159 VisitIfNotNull(stmt->init()); 1160 for_loop.BeginLoop(GetVariablesAssignedInLoop(stmt), CheckOsrEntry(stmt)); 1161 if (stmt->cond() != nullptr) { 1162 VisitForTest(stmt->cond()); 1163 Node* condition = environment()->Pop(); 1164 for_loop.BreakUnless(condition); 1165 } else { 1166 for_loop.BreakUnless(jsgraph()->TrueConstant()); 1167 } 1168 VisitIterationBody(stmt, &for_loop, stmt->StackCheckId()); 1169 for_loop.EndBody(); 1170 VisitIfNotNull(stmt->next()); 1171 for_loop.EndLoop(); 1172} 1173 1174 1175void AstGraphBuilder::VisitForInStatement(ForInStatement* stmt) { 1176 // Only the BytecodeGraphBuilder supports for-in. 1177 return SetStackOverflow(); 1178} 1179 1180 1181void AstGraphBuilder::VisitForOfStatement(ForOfStatement* stmt) { 1182 // Iterator looping is supported only by going through Ignition first. 1183 UNREACHABLE(); 1184} 1185 1186 1187void AstGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) { 1188 // Exception handling is supported only by going through Ignition first. 1189 UNREACHABLE(); 1190} 1191 1192 1193void AstGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) { 1194 // Exception handling is supported only by going through Ignition first. 1195 UNREACHABLE(); 1196} 1197 1198 1199void AstGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) { 1200 // Debugger statement is supported only by going through Ignition first. 1201 UNREACHABLE(); 1202} 1203 1204 1205void AstGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { 1206 // Find or build a shared function info. 1207 Handle<SharedFunctionInfo> shared_info = 1208 Compiler::GetSharedFunctionInfo(expr, info()->script(), info()); 1209 CHECK(!shared_info.is_null()); // TODO(mstarzinger): Set stack overflow? 1210 1211 // Create node to instantiate a new closure. 1212 PretenureFlag pretenure = expr->pretenure() ? TENURED : NOT_TENURED; 1213 VectorSlotPair pair = CreateVectorSlotPair(expr->LiteralFeedbackSlot()); 1214 const Operator* op = 1215 javascript()->CreateClosure(shared_info, pair, pretenure); 1216 Node* value = NewNode(op); 1217 ast_context()->ProduceValue(expr, value); 1218} 1219 1220void AstGraphBuilder::VisitClassLiteral(ClassLiteral* expr) { UNREACHABLE(); } 1221 1222void AstGraphBuilder::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) { 1223 UNREACHABLE(); 1224} 1225 1226 1227void AstGraphBuilder::VisitDoExpression(DoExpression* expr) { 1228 VisitBlock(expr->block()); 1229 VisitVariableProxy(expr->result()); 1230 ast_context()->ReplaceValue(expr); 1231} 1232 1233 1234void AstGraphBuilder::VisitConditional(Conditional* expr) { 1235 IfBuilder compare_if(this); 1236 VisitForTest(expr->condition()); 1237 Node* condition = environment()->Pop(); 1238 compare_if.If(condition); 1239 compare_if.Then(); 1240 Visit(expr->then_expression()); 1241 compare_if.Else(); 1242 Visit(expr->else_expression()); 1243 compare_if.End(); 1244 // Skip plugging AST evaluation contexts of the test kind. This is to stay in 1245 // sync with full codegen which doesn't prepare the proper bailout point (see 1246 // the implementation of FullCodeGenerator::VisitForControl). 1247 if (ast_context()->IsTest()) return; 1248 ast_context()->ReplaceValue(expr); 1249} 1250 1251 1252void AstGraphBuilder::VisitVariableProxy(VariableProxy* expr) { 1253 VectorSlotPair pair = CreateVectorSlotPair(expr->VariableFeedbackSlot()); 1254 PrepareEagerCheckpoint(BeforeId(expr)); 1255 Node* value = BuildVariableLoad(expr->var(), expr->id(), pair, 1256 ast_context()->GetStateCombine()); 1257 ast_context()->ProduceValue(expr, value); 1258} 1259 1260 1261void AstGraphBuilder::VisitLiteral(Literal* expr) { 1262 Node* value = jsgraph()->Constant(expr->value()); 1263 ast_context()->ProduceValue(expr, value); 1264} 1265 1266 1267void AstGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { 1268 Node* closure = GetFunctionClosure(); 1269 1270 // Create node to materialize a regular expression literal. 1271 const Operator* op = javascript()->CreateLiteralRegExp( 1272 expr->pattern(), expr->flags(), 1273 FeedbackVector::GetIndex(expr->literal_slot())); 1274 Node* literal = NewNode(op, closure); 1275 PrepareFrameState(literal, expr->id(), ast_context()->GetStateCombine()); 1276 ast_context()->ProduceValue(expr, literal); 1277} 1278 1279 1280void AstGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { 1281 Node* closure = GetFunctionClosure(); 1282 1283 // Create node to deep-copy the literal boilerplate. 1284 const Operator* op = javascript()->CreateLiteralObject( 1285 expr->GetOrBuildConstantProperties(isolate()), expr->ComputeFlags(true), 1286 FeedbackVector::GetIndex(expr->literal_slot()), expr->properties_count()); 1287 Node* literal = NewNode(op, closure); 1288 PrepareFrameState(literal, expr->CreateLiteralId(), 1289 OutputFrameStateCombine::Push()); 1290 1291 // The object is expected on the operand stack during computation of the 1292 // property values and is the value of the entire expression. 1293 environment()->Push(literal); 1294 1295 // Create nodes to store computed values into the literal. 1296 AccessorTable accessor_table(local_zone()); 1297 for (int i = 0; i < expr->properties()->length(); i++) { 1298 ObjectLiteral::Property* property = expr->properties()->at(i); 1299 DCHECK(!property->is_computed_name()); 1300 if (property->IsCompileTimeValue()) continue; 1301 1302 Literal* key = property->key()->AsLiteral(); 1303 switch (property->kind()) { 1304 case ObjectLiteral::Property::SPREAD: 1305 case ObjectLiteral::Property::CONSTANT: 1306 UNREACHABLE(); 1307 case ObjectLiteral::Property::MATERIALIZED_LITERAL: 1308 DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value())); 1309 // Fall through. 1310 case ObjectLiteral::Property::COMPUTED: { 1311 // It is safe to use [[Put]] here because the boilerplate already 1312 // contains computed properties with an uninitialized value. 1313 if (key->IsStringLiteral()) { 1314 DCHECK(key->IsPropertyName()); 1315 if (property->emit_store()) { 1316 VisitForValue(property->value()); 1317 Node* value = environment()->Pop(); 1318 Node* literal = environment()->Top(); 1319 Handle<Name> name = key->AsPropertyName(); 1320 VectorSlotPair feedback = 1321 CreateVectorSlotPair(property->GetSlot(0)); 1322 Node* store = BuildNamedStoreOwn(literal, name, value, feedback); 1323 PrepareFrameState(store, key->id(), 1324 OutputFrameStateCombine::Ignore()); 1325 BuildSetHomeObject(value, literal, property, 1); 1326 } else { 1327 VisitForEffect(property->value()); 1328 } 1329 break; 1330 } 1331 environment()->Push(environment()->Top()); // Duplicate receiver. 1332 VisitForValue(property->key()); 1333 VisitForValue(property->value()); 1334 Node* value = environment()->Pop(); 1335 Node* key = environment()->Pop(); 1336 Node* receiver = environment()->Pop(); 1337 if (property->emit_store()) { 1338 Node* language = jsgraph()->Constant(SLOPPY); 1339 const Operator* op = javascript()->CallRuntime(Runtime::kSetProperty); 1340 Node* set_property = NewNode(op, receiver, key, value, language); 1341 // SetProperty should not lazy deopt on an object literal. 1342 PrepareFrameState(set_property, BailoutId::None()); 1343 BuildSetHomeObject(value, receiver, property); 1344 } 1345 break; 1346 } 1347 case ObjectLiteral::Property::PROTOTYPE: { 1348 environment()->Push(environment()->Top()); // Duplicate receiver. 1349 VisitForValue(property->value()); 1350 Node* value = environment()->Pop(); 1351 Node* receiver = environment()->Pop(); 1352 DCHECK(property->emit_store()); 1353 const Operator* op = 1354 javascript()->CallRuntime(Runtime::kInternalSetPrototype); 1355 Node* set_prototype = NewNode(op, receiver, value); 1356 // SetPrototype should not lazy deopt on an object literal. 1357 PrepareFrameState(set_prototype, expr->GetIdForPropertySet(i)); 1358 break; 1359 } 1360 case ObjectLiteral::Property::GETTER: 1361 if (property->emit_store()) { 1362 AccessorTable::Iterator it = accessor_table.lookup(key); 1363 it->second->bailout_id = expr->GetIdForPropertySet(i); 1364 it->second->getter = property; 1365 } 1366 break; 1367 case ObjectLiteral::Property::SETTER: 1368 if (property->emit_store()) { 1369 AccessorTable::Iterator it = accessor_table.lookup(key); 1370 it->second->bailout_id = expr->GetIdForPropertySet(i); 1371 it->second->setter = property; 1372 } 1373 break; 1374 } 1375 } 1376 1377 // Create nodes to define accessors, using only a single call to the runtime 1378 // for each pair of corresponding getters and setters. 1379 literal = environment()->Top(); // Reload from operand stack. 1380 for (AccessorTable::Iterator it = accessor_table.begin(); 1381 it != accessor_table.end(); ++it) { 1382 VisitForValue(it->first); 1383 VisitObjectLiteralAccessor(literal, it->second->getter); 1384 VisitObjectLiteralAccessor(literal, it->second->setter); 1385 Node* setter = environment()->Pop(); 1386 Node* getter = environment()->Pop(); 1387 Node* name = environment()->Pop(); 1388 Node* attr = jsgraph()->Constant(NONE); 1389 const Operator* op = 1390 javascript()->CallRuntime(Runtime::kDefineAccessorPropertyUnchecked); 1391 Node* call = NewNode(op, literal, name, getter, setter, attr); 1392 PrepareFrameState(call, it->second->bailout_id); 1393 } 1394 ast_context()->ProduceValue(expr, environment()->Pop()); 1395} 1396 1397 1398void AstGraphBuilder::VisitObjectLiteralAccessor( 1399 Node* home_object, ObjectLiteralProperty* property) { 1400 if (property == nullptr) { 1401 VisitForValueOrNull(nullptr); 1402 } else { 1403 VisitForValue(property->value()); 1404 BuildSetHomeObject(environment()->Top(), home_object, property); 1405 } 1406} 1407 1408 1409void AstGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { 1410 Node* closure = GetFunctionClosure(); 1411 1412 // Create node to deep-copy the literal boilerplate. 1413 const Operator* op = javascript()->CreateLiteralArray( 1414 expr->GetOrBuildConstantElements(isolate()), expr->ComputeFlags(true), 1415 FeedbackVector::GetIndex(expr->literal_slot()), expr->values()->length()); 1416 Node* literal = NewNode(op, closure); 1417 PrepareFrameState(literal, expr->CreateLiteralId(), 1418 OutputFrameStateCombine::Push()); 1419 1420 // The array is expected on the operand stack during computation of the 1421 // element values. 1422 environment()->Push(literal); 1423 1424 // Create nodes to evaluate all the non-constant subexpressions and to store 1425 // them into the newly cloned array. 1426 for (int array_index = 0; array_index < expr->values()->length(); 1427 array_index++) { 1428 Expression* subexpr = expr->values()->at(array_index); 1429 DCHECK(!subexpr->IsSpread()); 1430 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; 1431 1432 VisitForValue(subexpr); 1433 VectorSlotPair pair = CreateVectorSlotPair(expr->LiteralFeedbackSlot()); 1434 Node* value = environment()->Pop(); 1435 Node* index = jsgraph()->Constant(array_index); 1436 Node* literal = environment()->Top(); 1437 Node* store = BuildKeyedStore(literal, index, value, pair); 1438 PrepareFrameState(store, expr->GetIdForElement(array_index), 1439 OutputFrameStateCombine::Ignore()); 1440 } 1441 1442 ast_context()->ProduceValue(expr, environment()->Pop()); 1443} 1444 1445void AstGraphBuilder::VisitAssignment(Assignment* expr) { 1446 DCHECK(expr->target()->IsValidReferenceExpressionOrThis()); 1447 1448 // Left-hand side can only be a property, a global or a variable slot. 1449 Property* property = expr->target()->AsProperty(); 1450 LhsKind assign_type = Property::GetAssignType(property); 1451 bool needs_frame_state_before = true; 1452 1453 // Evaluate LHS expression. 1454 switch (assign_type) { 1455 case VARIABLE: { 1456 Variable* variable = expr->target()->AsVariableProxy()->var(); 1457 if (variable->location() == VariableLocation::PARAMETER || 1458 variable->location() == VariableLocation::LOCAL || 1459 variable->location() == VariableLocation::CONTEXT) { 1460 needs_frame_state_before = false; 1461 } 1462 break; 1463 } 1464 case NAMED_PROPERTY: 1465 VisitForValue(property->obj()); 1466 break; 1467 case KEYED_PROPERTY: 1468 VisitForValue(property->obj()); 1469 VisitForValue(property->key()); 1470 break; 1471 case NAMED_SUPER_PROPERTY: 1472 case KEYED_SUPER_PROPERTY: 1473 UNREACHABLE(); 1474 break; 1475 } 1476 1477 // Evaluate the value and potentially handle compound assignments by loading 1478 // the left-hand side value and performing a binary operation. 1479 if (expr->is_compound()) { 1480 Node* old_value = nullptr; 1481 switch (assign_type) { 1482 case VARIABLE: { 1483 VariableProxy* proxy = expr->target()->AsVariableProxy(); 1484 VectorSlotPair pair = 1485 CreateVectorSlotPair(proxy->VariableFeedbackSlot()); 1486 PrepareEagerCheckpoint(BeforeId(proxy)); 1487 old_value = BuildVariableLoad(proxy->var(), expr->target()->id(), pair, 1488 OutputFrameStateCombine::Push()); 1489 break; 1490 } 1491 case NAMED_PROPERTY: { 1492 Node* object = environment()->Top(); 1493 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName(); 1494 VectorSlotPair pair = 1495 CreateVectorSlotPair(property->PropertyFeedbackSlot()); 1496 old_value = BuildNamedLoad(object, name, pair); 1497 PrepareFrameState(old_value, property->LoadId(), 1498 OutputFrameStateCombine::Push()); 1499 break; 1500 } 1501 case KEYED_PROPERTY: { 1502 Node* key = environment()->Top(); 1503 Node* object = environment()->Peek(1); 1504 VectorSlotPair pair = 1505 CreateVectorSlotPair(property->PropertyFeedbackSlot()); 1506 old_value = BuildKeyedLoad(object, key, pair); 1507 PrepareFrameState(old_value, property->LoadId(), 1508 OutputFrameStateCombine::Push()); 1509 break; 1510 } 1511 case NAMED_SUPER_PROPERTY: 1512 case KEYED_SUPER_PROPERTY: 1513 UNREACHABLE(); 1514 break; 1515 } 1516 environment()->Push(old_value); 1517 VisitForValue(expr->value()); 1518 Node* right = environment()->Pop(); 1519 Node* left = environment()->Pop(); 1520 Node* value = 1521 BuildBinaryOp(left, right, expr->binary_op(), 1522 expr->binary_operation()->BinaryOperationFeedbackId()); 1523 PrepareFrameState(value, expr->binary_operation()->id(), 1524 OutputFrameStateCombine::Push()); 1525 environment()->Push(value); 1526 if (needs_frame_state_before) { 1527 PrepareEagerCheckpoint(expr->binary_operation()->id()); 1528 } 1529 } else { 1530 VisitForValue(expr->value()); 1531 } 1532 1533 // Store the value. 1534 Node* value = environment()->Pop(); 1535 VectorSlotPair feedback = CreateVectorSlotPair(expr->AssignmentSlot()); 1536 switch (assign_type) { 1537 case VARIABLE: { 1538 Variable* variable = expr->target()->AsVariableProxy()->var(); 1539 BuildVariableAssignment(variable, value, expr->op(), feedback, expr->id(), 1540 ast_context()->GetStateCombine()); 1541 break; 1542 } 1543 case NAMED_PROPERTY: { 1544 Node* object = environment()->Pop(); 1545 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName(); 1546 Node* store = BuildNamedStore(object, name, value, feedback); 1547 PrepareFrameState(store, expr->AssignmentId(), 1548 OutputFrameStateCombine::Push()); 1549 break; 1550 } 1551 case KEYED_PROPERTY: { 1552 Node* key = environment()->Pop(); 1553 Node* object = environment()->Pop(); 1554 Node* store = BuildKeyedStore(object, key, value, feedback); 1555 PrepareFrameState(store, expr->AssignmentId(), 1556 OutputFrameStateCombine::Push()); 1557 break; 1558 } 1559 case NAMED_SUPER_PROPERTY: 1560 case KEYED_SUPER_PROPERTY: 1561 UNREACHABLE(); 1562 break; 1563 } 1564 1565 ast_context()->ProduceValue(expr, value); 1566} 1567 1568 1569void AstGraphBuilder::VisitYield(Yield* expr) { 1570 // Generator functions are supported only by going through Ignition first. 1571 UNREACHABLE(); 1572} 1573 1574 1575void AstGraphBuilder::VisitThrow(Throw* expr) { 1576 VisitForValue(expr->exception()); 1577 Node* exception = environment()->Pop(); 1578 Node* value = BuildThrowError(exception, expr->id()); 1579 ast_context()->ProduceValue(expr, value); 1580} 1581 1582 1583void AstGraphBuilder::VisitProperty(Property* expr) { 1584 Node* value = nullptr; 1585 LhsKind property_kind = Property::GetAssignType(expr); 1586 VectorSlotPair pair = CreateVectorSlotPair(expr->PropertyFeedbackSlot()); 1587 switch (property_kind) { 1588 case VARIABLE: 1589 UNREACHABLE(); 1590 break; 1591 case NAMED_PROPERTY: { 1592 VisitForValue(expr->obj()); 1593 Node* object = environment()->Pop(); 1594 Handle<Name> name = expr->key()->AsLiteral()->AsPropertyName(); 1595 value = BuildNamedLoad(object, name, pair); 1596 PrepareFrameState(value, expr->LoadId(), OutputFrameStateCombine::Push()); 1597 break; 1598 } 1599 case KEYED_PROPERTY: { 1600 VisitForValue(expr->obj()); 1601 VisitForValue(expr->key()); 1602 Node* key = environment()->Pop(); 1603 Node* object = environment()->Pop(); 1604 value = BuildKeyedLoad(object, key, pair); 1605 PrepareFrameState(value, expr->LoadId(), OutputFrameStateCombine::Push()); 1606 break; 1607 } 1608 case NAMED_SUPER_PROPERTY: 1609 case KEYED_SUPER_PROPERTY: 1610 UNREACHABLE(); 1611 break; 1612 } 1613 ast_context()->ProduceValue(expr, value); 1614} 1615 1616 1617void AstGraphBuilder::VisitCall(Call* expr) { 1618 Expression* callee = expr->expression(); 1619 Call::CallType call_type = expr->GetCallType(); 1620 CHECK(!expr->is_possibly_eval()); 1621 1622 // Prepare the callee and the receiver to the function call. This depends on 1623 // the semantics of the underlying call type. 1624 ConvertReceiverMode receiver_hint = ConvertReceiverMode::kAny; 1625 Node* receiver_value = nullptr; 1626 Node* callee_value = nullptr; 1627 switch (call_type) { 1628 case Call::GLOBAL_CALL: { 1629 VariableProxy* proxy = callee->AsVariableProxy(); 1630 VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot()); 1631 PrepareEagerCheckpoint(BeforeId(proxy)); 1632 callee_value = BuildVariableLoad(proxy->var(), expr->expression()->id(), 1633 pair, OutputFrameStateCombine::Push()); 1634 receiver_hint = ConvertReceiverMode::kNullOrUndefined; 1635 receiver_value = jsgraph()->UndefinedConstant(); 1636 break; 1637 } 1638 case Call::NAMED_PROPERTY_CALL: { 1639 Property* property = callee->AsProperty(); 1640 VectorSlotPair feedback = 1641 CreateVectorSlotPair(property->PropertyFeedbackSlot()); 1642 VisitForValue(property->obj()); 1643 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName(); 1644 Node* object = environment()->Top(); 1645 callee_value = BuildNamedLoad(object, name, feedback); 1646 PrepareFrameState(callee_value, property->LoadId(), 1647 OutputFrameStateCombine::Push()); 1648 // Note that a property call requires the receiver to be wrapped into 1649 // an object for sloppy callees. However the receiver is guaranteed 1650 // not to be null or undefined at this point. 1651 receiver_hint = ConvertReceiverMode::kNotNullOrUndefined; 1652 receiver_value = environment()->Pop(); 1653 break; 1654 } 1655 case Call::KEYED_PROPERTY_CALL: { 1656 Property* property = callee->AsProperty(); 1657 VectorSlotPair feedback = 1658 CreateVectorSlotPair(property->PropertyFeedbackSlot()); 1659 VisitForValue(property->obj()); 1660 VisitForValue(property->key()); 1661 Node* key = environment()->Pop(); 1662 Node* object = environment()->Top(); 1663 callee_value = BuildKeyedLoad(object, key, feedback); 1664 PrepareFrameState(callee_value, property->LoadId(), 1665 OutputFrameStateCombine::Push()); 1666 // Note that a property call requires the receiver to be wrapped into 1667 // an object for sloppy callees. However the receiver is guaranteed 1668 // not to be null or undefined at this point. 1669 receiver_hint = ConvertReceiverMode::kNotNullOrUndefined; 1670 receiver_value = environment()->Pop(); 1671 break; 1672 } 1673 case Call::OTHER_CALL: 1674 VisitForValue(callee); 1675 callee_value = environment()->Pop(); 1676 receiver_hint = ConvertReceiverMode::kNullOrUndefined; 1677 receiver_value = jsgraph()->UndefinedConstant(); 1678 break; 1679 case Call::NAMED_SUPER_PROPERTY_CALL: 1680 case Call::KEYED_SUPER_PROPERTY_CALL: 1681 case Call::SUPER_CALL: 1682 case Call::WITH_CALL: 1683 UNREACHABLE(); 1684 } 1685 1686 // The callee and the receiver both have to be pushed onto the operand stack 1687 // before arguments are being evaluated. 1688 environment()->Push(callee_value); 1689 environment()->Push(receiver_value); 1690 1691 // Evaluate all arguments to the function call, 1692 ZoneList<Expression*>* args = expr->arguments(); 1693 VisitForValues(args); 1694 1695 // Create node to perform the function call. 1696 float const frequency = ComputeCallFrequency(expr->CallFeedbackICSlot()); 1697 VectorSlotPair feedback = CreateVectorSlotPair(expr->CallFeedbackICSlot()); 1698 const Operator* call = 1699 javascript()->Call(args->length() + 2, frequency, feedback, receiver_hint, 1700 expr->tail_call_mode()); 1701 PrepareEagerCheckpoint(expr->CallId()); 1702 Node* value = ProcessArguments(call, args->length() + 2); 1703 // The callee passed to the call, we just need to push something here to 1704 // satisfy the bailout location contract. The fullcodegen code will not 1705 // ever look at this value, so we just push optimized_out here. 1706 environment()->Push(jsgraph()->OptimizedOutConstant()); 1707 PrepareFrameState(value, expr->ReturnId(), OutputFrameStateCombine::Push()); 1708 environment()->Drop(1); 1709 ast_context()->ProduceValue(expr, value); 1710} 1711 1712 1713void AstGraphBuilder::VisitCallNew(CallNew* expr) { 1714 VisitForValue(expr->expression()); 1715 1716 // Evaluate all arguments to the construct call. 1717 ZoneList<Expression*>* args = expr->arguments(); 1718 VisitForValues(args); 1719 1720 // The new target is the same as the callee. 1721 environment()->Push(environment()->Peek(args->length())); 1722 1723 // Create node to perform the construct call. 1724 float const frequency = ComputeCallFrequency(expr->CallNewFeedbackSlot()); 1725 VectorSlotPair feedback = CreateVectorSlotPair(expr->CallNewFeedbackSlot()); 1726 const Operator* call = 1727 javascript()->Construct(args->length() + 2, frequency, feedback); 1728 Node* value = ProcessArguments(call, args->length() + 2); 1729 PrepareFrameState(value, expr->ReturnId(), OutputFrameStateCombine::Push()); 1730 ast_context()->ProduceValue(expr, value); 1731} 1732 1733 1734void AstGraphBuilder::VisitCallJSRuntime(CallRuntime* expr) { 1735 // The callee and the receiver both have to be pushed onto the operand stack 1736 // before arguments are being evaluated. 1737 Node* callee_value = BuildLoadNativeContextField(expr->context_index()); 1738 Node* receiver_value = jsgraph()->UndefinedConstant(); 1739 1740 environment()->Push(callee_value); 1741 environment()->Push(receiver_value); 1742 1743 // Evaluate all arguments to the JS runtime call. 1744 ZoneList<Expression*>* args = expr->arguments(); 1745 VisitForValues(args); 1746 1747 // Create node to perform the JS runtime call. 1748 const Operator* call = javascript()->Call(args->length() + 2); 1749 PrepareEagerCheckpoint(expr->CallId()); 1750 Node* value = ProcessArguments(call, args->length() + 2); 1751 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine()); 1752 ast_context()->ProduceValue(expr, value); 1753} 1754 1755 1756void AstGraphBuilder::VisitCallRuntime(CallRuntime* expr) { 1757 // Handle calls to runtime functions implemented in JavaScript separately as 1758 // the call follows JavaScript ABI and the callee is statically unknown. 1759 if (expr->is_jsruntime()) { 1760 return VisitCallJSRuntime(expr); 1761 } 1762 1763 // Evaluate all arguments to the runtime call. 1764 ZoneList<Expression*>* args = expr->arguments(); 1765 VisitForValues(args); 1766 1767 // Create node to perform the runtime call. 1768 Runtime::FunctionId functionId = expr->function()->function_id; 1769 const Operator* call = javascript()->CallRuntime(functionId, args->length()); 1770 if (expr->function()->intrinsic_type == Runtime::IntrinsicType::RUNTIME || 1771 expr->function()->function_id == Runtime::kInlineCall) { 1772 PrepareEagerCheckpoint(expr->CallId()); 1773 } 1774 Node* value = ProcessArguments(call, args->length()); 1775 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine()); 1776 ast_context()->ProduceValue(expr, value); 1777} 1778 1779 1780void AstGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { 1781 switch (expr->op()) { 1782 case Token::DELETE: 1783 return VisitDelete(expr); 1784 case Token::VOID: 1785 return VisitVoid(expr); 1786 case Token::TYPEOF: 1787 return VisitTypeof(expr); 1788 case Token::NOT: 1789 return VisitNot(expr); 1790 default: 1791 UNREACHABLE(); 1792 } 1793} 1794 1795 1796void AstGraphBuilder::VisitCountOperation(CountOperation* expr) { 1797 DCHECK(expr->expression()->IsValidReferenceExpressionOrThis()); 1798 1799 // Left-hand side can only be a property, a global or a variable slot. 1800 Property* property = expr->expression()->AsProperty(); 1801 LhsKind assign_type = Property::GetAssignType(property); 1802 1803 // Reserve space for result of postfix operation. 1804 bool is_postfix = expr->is_postfix() && !ast_context()->IsEffect(); 1805 if (is_postfix && assign_type != VARIABLE) { 1806 environment()->Push(jsgraph()->ZeroConstant()); 1807 } 1808 1809 // Evaluate LHS expression and get old value. 1810 Node* old_value = nullptr; 1811 int stack_depth = -1; 1812 switch (assign_type) { 1813 case VARIABLE: { 1814 VariableProxy* proxy = expr->expression()->AsVariableProxy(); 1815 VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot()); 1816 PrepareEagerCheckpoint(BeforeId(proxy)); 1817 old_value = BuildVariableLoad(proxy->var(), expr->expression()->id(), 1818 pair, OutputFrameStateCombine::Push()); 1819 stack_depth = 0; 1820 break; 1821 } 1822 case NAMED_PROPERTY: { 1823 VisitForValue(property->obj()); 1824 Node* object = environment()->Top(); 1825 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName(); 1826 VectorSlotPair pair = 1827 CreateVectorSlotPair(property->PropertyFeedbackSlot()); 1828 old_value = BuildNamedLoad(object, name, pair); 1829 PrepareFrameState(old_value, property->LoadId(), 1830 OutputFrameStateCombine::Push()); 1831 stack_depth = 1; 1832 break; 1833 } 1834 case KEYED_PROPERTY: { 1835 VisitForValue(property->obj()); 1836 VisitForValue(property->key()); 1837 Node* key = environment()->Top(); 1838 Node* object = environment()->Peek(1); 1839 VectorSlotPair pair = 1840 CreateVectorSlotPair(property->PropertyFeedbackSlot()); 1841 old_value = BuildKeyedLoad(object, key, pair); 1842 PrepareFrameState(old_value, property->LoadId(), 1843 OutputFrameStateCombine::Push()); 1844 stack_depth = 2; 1845 break; 1846 } 1847 case NAMED_SUPER_PROPERTY: 1848 case KEYED_SUPER_PROPERTY: 1849 UNREACHABLE(); 1850 break; 1851 } 1852 1853 // Convert old value into a number. 1854 old_value = NewNode(javascript()->ToNumber(), old_value); 1855 PrepareFrameState(old_value, expr->ToNumberId(), 1856 OutputFrameStateCombine::Push()); 1857 1858 // Create a proper eager frame state for the stores. 1859 environment()->Push(old_value); 1860 PrepareEagerCheckpoint(expr->ToNumberId()); 1861 old_value = environment()->Pop(); 1862 1863 // Save result for postfix expressions at correct stack depth. 1864 if (is_postfix) { 1865 if (assign_type != VARIABLE) { 1866 environment()->Poke(stack_depth, old_value); 1867 } else { 1868 environment()->Push(old_value); 1869 } 1870 } 1871 1872 // Create node to perform +1/-1 operation. 1873 Node* value = BuildBinaryOp(old_value, jsgraph()->OneConstant(), 1874 expr->binary_op(), expr->CountBinOpFeedbackId()); 1875 // This should never lazy deopt because we have converted to number before. 1876 PrepareFrameState(value, BailoutId::None()); 1877 1878 // Store the value. 1879 VectorSlotPair feedback = CreateVectorSlotPair(expr->CountSlot()); 1880 switch (assign_type) { 1881 case VARIABLE: { 1882 Variable* variable = expr->expression()->AsVariableProxy()->var(); 1883 environment()->Push(value); 1884 BuildVariableAssignment(variable, value, expr->op(), feedback, 1885 expr->AssignmentId()); 1886 environment()->Pop(); 1887 break; 1888 } 1889 case NAMED_PROPERTY: { 1890 Node* object = environment()->Pop(); 1891 Handle<Name> name = property->key()->AsLiteral()->AsPropertyName(); 1892 Node* store = BuildNamedStore(object, name, value, feedback); 1893 PrepareFrameState(store, expr->AssignmentId(), 1894 OutputFrameStateCombine::Push()); 1895 break; 1896 } 1897 case KEYED_PROPERTY: { 1898 Node* key = environment()->Pop(); 1899 Node* object = environment()->Pop(); 1900 Node* store = BuildKeyedStore(object, key, value, feedback); 1901 PrepareFrameState(store, expr->AssignmentId(), 1902 OutputFrameStateCombine::Push()); 1903 break; 1904 } 1905 case NAMED_SUPER_PROPERTY: 1906 case KEYED_SUPER_PROPERTY: 1907 UNREACHABLE(); 1908 break; 1909 } 1910 1911 // Restore old value for postfix expressions. 1912 if (is_postfix) value = environment()->Pop(); 1913 1914 ast_context()->ProduceValue(expr, value); 1915} 1916 1917 1918void AstGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { 1919 switch (expr->op()) { 1920 case Token::COMMA: 1921 return VisitComma(expr); 1922 case Token::OR: 1923 case Token::AND: 1924 return VisitLogicalExpression(expr); 1925 default: { 1926 VisitForValue(expr->left()); 1927 VisitForValue(expr->right()); 1928 Node* right = environment()->Pop(); 1929 Node* left = environment()->Pop(); 1930 Node* value = BuildBinaryOp(left, right, expr->op(), 1931 expr->BinaryOperationFeedbackId()); 1932 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine()); 1933 ast_context()->ProduceValue(expr, value); 1934 } 1935 } 1936} 1937 1938void AstGraphBuilder::VisitLiteralCompareNil(CompareOperation* expr, 1939 Expression* sub_expr, 1940 Node* nil_value) { 1941 const Operator* op = nullptr; 1942 switch (expr->op()) { 1943 case Token::EQ: 1944 op = javascript()->Equal(CompareOperationHint::kAny); 1945 break; 1946 case Token::EQ_STRICT: 1947 op = javascript()->StrictEqual(CompareOperationHint::kAny); 1948 break; 1949 default: 1950 UNREACHABLE(); 1951 } 1952 VisitForValue(sub_expr); 1953 Node* value_to_compare = environment()->Pop(); 1954 Node* value = NewNode(op, value_to_compare, nil_value); 1955 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine()); 1956 return ast_context()->ProduceValue(expr, value); 1957} 1958 1959void AstGraphBuilder::VisitLiteralCompareTypeof(CompareOperation* expr, 1960 Expression* sub_expr, 1961 Handle<String> check) { 1962 VisitTypeofExpression(sub_expr); 1963 Node* typeof_arg = NewNode(javascript()->TypeOf(), environment()->Pop()); 1964 Node* value = NewNode(javascript()->StrictEqual(CompareOperationHint::kAny), 1965 typeof_arg, jsgraph()->Constant(check)); 1966 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine()); 1967 return ast_context()->ProduceValue(expr, value); 1968} 1969 1970void AstGraphBuilder::VisitCompareOperation(CompareOperation* expr) { 1971 // Check for a few fast cases. The AST visiting behavior must be in sync 1972 // with the full codegen: We don't push both left and right values onto 1973 // the expression stack when one side is a special-case literal. 1974 Expression* sub_expr = nullptr; 1975 Handle<String> check; 1976 if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) { 1977 return VisitLiteralCompareTypeof(expr, sub_expr, check); 1978 } 1979 if (expr->IsLiteralCompareUndefined(&sub_expr)) { 1980 return VisitLiteralCompareNil(expr, sub_expr, 1981 jsgraph()->UndefinedConstant()); 1982 } 1983 if (expr->IsLiteralCompareNull(&sub_expr)) { 1984 return VisitLiteralCompareNil(expr, sub_expr, jsgraph()->NullConstant()); 1985 } 1986 1987 CompareOperationHint hint = CompareOperationHint::kAny; 1988 const Operator* op; 1989 switch (expr->op()) { 1990 case Token::EQ: 1991 op = javascript()->Equal(hint); 1992 break; 1993 case Token::NE: 1994 op = javascript()->NotEqual(hint); 1995 break; 1996 case Token::EQ_STRICT: 1997 op = javascript()->StrictEqual(hint); 1998 break; 1999 case Token::NE_STRICT: 2000 op = javascript()->StrictNotEqual(hint); 2001 break; 2002 case Token::LT: 2003 op = javascript()->LessThan(hint); 2004 break; 2005 case Token::GT: 2006 op = javascript()->GreaterThan(hint); 2007 break; 2008 case Token::LTE: 2009 op = javascript()->LessThanOrEqual(hint); 2010 break; 2011 case Token::GTE: 2012 op = javascript()->GreaterThanOrEqual(hint); 2013 break; 2014 case Token::INSTANCEOF: 2015 op = javascript()->InstanceOf(); 2016 break; 2017 case Token::IN: 2018 op = javascript()->HasProperty(); 2019 break; 2020 default: 2021 op = nullptr; 2022 UNREACHABLE(); 2023 } 2024 VisitForValue(expr->left()); 2025 VisitForValue(expr->right()); 2026 Node* right = environment()->Pop(); 2027 Node* left = environment()->Pop(); 2028 Node* value = NewNode(op, left, right); 2029 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine()); 2030 ast_context()->ProduceValue(expr, value); 2031} 2032 2033 2034void AstGraphBuilder::VisitSpread(Spread* expr) { 2035 // Handled entirely by the parser itself. 2036 UNREACHABLE(); 2037} 2038 2039 2040void AstGraphBuilder::VisitEmptyParentheses(EmptyParentheses* expr) { 2041 // Handled entirely by the parser itself. 2042 UNREACHABLE(); 2043} 2044 2045void AstGraphBuilder::VisitGetIterator(GetIterator* expr) { 2046 // GetIterator is supported only by going through Ignition first. 2047 UNREACHABLE(); 2048} 2049 2050void AstGraphBuilder::VisitThisFunction(ThisFunction* expr) { 2051 Node* value = GetFunctionClosure(); 2052 ast_context()->ProduceValue(expr, value); 2053} 2054 2055 2056void AstGraphBuilder::VisitSuperPropertyReference( 2057 SuperPropertyReference* expr) { 2058 UNREACHABLE(); 2059} 2060 2061 2062void AstGraphBuilder::VisitSuperCallReference(SuperCallReference* expr) { 2063 // Handled by VisitCall 2064 UNREACHABLE(); 2065} 2066 2067 2068void AstGraphBuilder::VisitCaseClause(CaseClause* expr) { 2069 // Handled entirely in VisitSwitch. 2070 UNREACHABLE(); 2071} 2072 2073void AstGraphBuilder::VisitDeclarations(Declaration::List* declarations) { 2074 DCHECK(globals()->empty()); 2075 AstVisitor<AstGraphBuilder>::VisitDeclarations(declarations); 2076 if (globals()->empty()) return; 2077 int array_index = 0; 2078 Handle<FeedbackVector> feedback_vector(info()->closure()->feedback_vector()); 2079 Handle<FixedArray> data = isolate()->factory()->NewFixedArray( 2080 static_cast<int>(globals()->size()), TENURED); 2081 for (Handle<Object> obj : *globals()) data->set(array_index++, *obj); 2082 int encoded_flags = info()->GetDeclareGlobalsFlags(); 2083 Node* flags = jsgraph()->Constant(encoded_flags); 2084 Node* decls = jsgraph()->Constant(data); 2085 Node* vector = jsgraph()->Constant(feedback_vector); 2086 const Operator* op = javascript()->CallRuntime(Runtime::kDeclareGlobals); 2087 Node* call = NewNode(op, decls, flags, vector); 2088 PrepareFrameState(call, BailoutId::Declarations()); 2089 globals()->clear(); 2090} 2091 2092 2093void AstGraphBuilder::VisitIfNotNull(Statement* stmt) { 2094 if (stmt == nullptr) return; 2095 Visit(stmt); 2096} 2097 2098 2099void AstGraphBuilder::VisitIterationBody(IterationStatement* stmt, 2100 LoopBuilder* loop, 2101 BailoutId stack_check_id) { 2102 ControlScopeForIteration scope(this, stmt, loop); 2103 Node* node = NewNode(javascript()->StackCheck()); 2104 PrepareFrameState(node, stack_check_id); 2105 Visit(stmt->body()); 2106} 2107 2108 2109void AstGraphBuilder::VisitDelete(UnaryOperation* expr) { 2110 Node* value; 2111 if (expr->expression()->IsVariableProxy()) { 2112 // Delete of an unqualified identifier is disallowed in strict mode but 2113 // "delete this" is allowed. 2114 Variable* variable = expr->expression()->AsVariableProxy()->var(); 2115 DCHECK(is_sloppy(language_mode()) || variable->is_this()); 2116 value = BuildVariableDelete(variable, expr->id(), 2117 ast_context()->GetStateCombine()); 2118 } else if (expr->expression()->IsProperty()) { 2119 Property* property = expr->expression()->AsProperty(); 2120 VisitForValue(property->obj()); 2121 VisitForValue(property->key()); 2122 Node* key = environment()->Pop(); 2123 Node* object = environment()->Pop(); 2124 value = NewNode(javascript()->DeleteProperty(language_mode()), object, key); 2125 PrepareFrameState(value, expr->id(), ast_context()->GetStateCombine()); 2126 } else { 2127 VisitForEffect(expr->expression()); 2128 value = jsgraph()->TrueConstant(); 2129 } 2130 ast_context()->ProduceValue(expr, value); 2131} 2132 2133 2134void AstGraphBuilder::VisitVoid(UnaryOperation* expr) { 2135 VisitForEffect(expr->expression()); 2136 Node* value = jsgraph()->UndefinedConstant(); 2137 ast_context()->ProduceValue(expr, value); 2138} 2139 2140void AstGraphBuilder::VisitTypeofExpression(Expression* expr) { 2141 if (expr->IsVariableProxy()) { 2142 // Typeof does not throw a reference error on global variables, hence we 2143 // perform a non-contextual load in case the operand is a variable proxy. 2144 VariableProxy* proxy = expr->AsVariableProxy(); 2145 VectorSlotPair pair = CreateVectorSlotPair(proxy->VariableFeedbackSlot()); 2146 PrepareEagerCheckpoint(BeforeId(proxy)); 2147 Node* load = 2148 BuildVariableLoad(proxy->var(), expr->id(), pair, 2149 OutputFrameStateCombine::Push(), INSIDE_TYPEOF); 2150 environment()->Push(load); 2151 } else { 2152 VisitForValue(expr); 2153 } 2154} 2155 2156void AstGraphBuilder::VisitTypeof(UnaryOperation* expr) { 2157 VisitTypeofExpression(expr->expression()); 2158 Node* value = NewNode(javascript()->TypeOf(), environment()->Pop()); 2159 ast_context()->ProduceValue(expr, value); 2160} 2161 2162 2163void AstGraphBuilder::VisitNot(UnaryOperation* expr) { 2164 VisitForTest(expr->expression()); 2165 Node* input = environment()->Pop(); 2166 Node* value = NewNode(common()->Select(MachineRepresentation::kTagged), input, 2167 jsgraph()->FalseConstant(), jsgraph()->TrueConstant()); 2168 // Skip plugging AST evaluation contexts of the test kind. This is to stay in 2169 // sync with full codegen which doesn't prepare the proper bailout point (see 2170 // the implementation of FullCodeGenerator::VisitForControl). 2171 if (ast_context()->IsTest()) return environment()->Push(value); 2172 ast_context()->ProduceValue(expr, value); 2173} 2174 2175 2176void AstGraphBuilder::VisitComma(BinaryOperation* expr) { 2177 VisitForEffect(expr->left()); 2178 Visit(expr->right()); 2179 // Skip plugging AST evaluation contexts of the test kind. This is to stay in 2180 // sync with full codegen which doesn't prepare the proper bailout point (see 2181 // the implementation of FullCodeGenerator::VisitForControl). 2182 if (ast_context()->IsTest()) return; 2183 ast_context()->ReplaceValue(expr); 2184} 2185 2186 2187void AstGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) { 2188 bool is_logical_and = expr->op() == Token::AND; 2189 IfBuilder compare_if(this); 2190 // Only use an AST evaluation context of the value kind when this expression 2191 // is evaluated as value as well. Otherwise stick to a test context which is 2192 // in sync with full codegen (see FullCodeGenerator::VisitLogicalExpression). 2193 Node* condition = nullptr; 2194 if (ast_context()->IsValue()) { 2195 VisitForValue(expr->left()); 2196 Node* left = environment()->Top(); 2197 condition = BuildToBoolean(left, expr->left()->test_id()); 2198 } else { 2199 VisitForTest(expr->left()); 2200 condition = environment()->Top(); 2201 } 2202 compare_if.If(condition); 2203 compare_if.Then(); 2204 if (is_logical_and) { 2205 environment()->Pop(); 2206 Visit(expr->right()); 2207 } else if (ast_context()->IsEffect()) { 2208 environment()->Pop(); 2209 } else if (ast_context()->IsTest()) { 2210 environment()->Poke(0, jsgraph()->TrueConstant()); 2211 } 2212 compare_if.Else(); 2213 if (!is_logical_and) { 2214 environment()->Pop(); 2215 Visit(expr->right()); 2216 } else if (ast_context()->IsEffect()) { 2217 environment()->Pop(); 2218 } else if (ast_context()->IsTest()) { 2219 environment()->Poke(0, jsgraph()->FalseConstant()); 2220 } 2221 compare_if.End(); 2222 // Skip plugging AST evaluation contexts of the test kind. This is to stay in 2223 // sync with full codegen which doesn't prepare the proper bailout point (see 2224 // the implementation of FullCodeGenerator::VisitForControl). 2225 if (ast_context()->IsTest()) return; 2226 ast_context()->ReplaceValue(expr); 2227} 2228 2229 2230LanguageMode AstGraphBuilder::language_mode() const { 2231 return current_scope()->language_mode(); 2232} 2233 2234VectorSlotPair AstGraphBuilder::CreateVectorSlotPair(FeedbackSlot slot) const { 2235 return VectorSlotPair(handle(info()->closure()->feedback_vector()), slot); 2236} 2237 2238 2239void AstGraphBuilder::VisitRewritableExpression(RewritableExpression* node) { 2240 Visit(node->expression()); 2241} 2242 2243float AstGraphBuilder::ComputeCallFrequency(FeedbackSlot slot) const { 2244 if (slot.IsInvalid()) return 0.0f; 2245 Handle<FeedbackVector> feedback_vector(info()->closure()->feedback_vector(), 2246 isolate()); 2247 CallICNexus nexus(feedback_vector, slot); 2248 return nexus.ComputeCallFrequency() * invocation_frequency_; 2249} 2250 2251Node* AstGraphBuilder::ProcessArguments(const Operator* op, int arity) { 2252 DCHECK(environment()->stack_height() >= arity); 2253 Node** all = info()->zone()->NewArray<Node*>(arity); 2254 for (int i = arity - 1; i >= 0; --i) { 2255 all[i] = environment()->Pop(); 2256 } 2257 Node* value = NewNode(op, arity, all); 2258 return value; 2259} 2260 2261 2262Node* AstGraphBuilder::BuildLocalActivationContext(Node* context) { 2263 DeclarationScope* scope = info()->scope(); 2264 2265 // Allocate a new local context. 2266 Node* local_context = scope->is_script_scope() 2267 ? BuildLocalScriptContext(scope) 2268 : BuildLocalFunctionContext(scope); 2269 2270 if (scope->has_this_declaration() && scope->receiver()->IsContextSlot()) { 2271 Node* receiver = environment()->RawParameterLookup(0); 2272 // Context variable (at bottom of the context chain). 2273 Variable* variable = scope->receiver(); 2274 DCHECK_EQ(0, scope->ContextChainLength(variable->scope())); 2275 const Operator* op = javascript()->StoreContext(0, variable->index()); 2276 Node* node = NewNode(op, receiver); 2277 NodeProperties::ReplaceContextInput(node, local_context); 2278 } 2279 2280 // Copy parameters into context if necessary. 2281 int num_parameters = scope->num_parameters(); 2282 for (int i = 0; i < num_parameters; i++) { 2283 Variable* variable = scope->parameter(i); 2284 if (!variable->IsContextSlot()) continue; 2285 Node* parameter = environment()->RawParameterLookup(i + 1); 2286 // Context variable (at bottom of the context chain). 2287 DCHECK_EQ(0, scope->ContextChainLength(variable->scope())); 2288 const Operator* op = javascript()->StoreContext(0, variable->index()); 2289 Node* node = NewNode(op, parameter); 2290 NodeProperties::ReplaceContextInput(node, local_context); 2291 } 2292 2293 return local_context; 2294} 2295 2296 2297Node* AstGraphBuilder::BuildLocalFunctionContext(Scope* scope) { 2298 DCHECK(scope->is_function_scope() || scope->is_eval_scope()); 2299 2300 // Allocate a new local context. 2301 int slot_count = scope->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; 2302 const Operator* op = 2303 javascript()->CreateFunctionContext(slot_count, scope->scope_type()); 2304 Node* local_context = NewNode(op, GetFunctionClosure()); 2305 2306 return local_context; 2307} 2308 2309 2310Node* AstGraphBuilder::BuildLocalScriptContext(Scope* scope) { 2311 DCHECK(scope->is_script_scope()); 2312 2313 // Allocate a new local context. 2314 Handle<ScopeInfo> scope_info = scope->scope_info(); 2315 const Operator* op = javascript()->CreateScriptContext(scope_info); 2316 Node* local_context = NewNode(op, GetFunctionClosure()); 2317 PrepareFrameState(local_context, BailoutId::ScriptContext(), 2318 OutputFrameStateCombine::Push()); 2319 2320 return local_context; 2321} 2322 2323 2324Node* AstGraphBuilder::BuildLocalBlockContext(Scope* scope) { 2325 DCHECK(scope->is_block_scope()); 2326 2327 // Allocate a new local context. 2328 Handle<ScopeInfo> scope_info = scope->scope_info(); 2329 const Operator* op = javascript()->CreateBlockContext(scope_info); 2330 Node* local_context = NewNode(op, GetFunctionClosureForContext()); 2331 2332 return local_context; 2333} 2334 2335 2336Node* AstGraphBuilder::BuildArgumentsObject(Variable* arguments) { 2337 if (arguments == nullptr) return nullptr; 2338 2339 // Allocate and initialize a new arguments object. 2340 CreateArgumentsType type = 2341 is_strict(language_mode()) || !info()->has_simple_parameters() 2342 ? CreateArgumentsType::kUnmappedArguments 2343 : CreateArgumentsType::kMappedArguments; 2344 const Operator* op = javascript()->CreateArguments(type); 2345 Node* object = NewNode(op, GetFunctionClosure()); 2346 PrepareFrameState(object, BailoutId::None()); 2347 2348 // Assign the object to the {arguments} variable. This should never lazy 2349 // deopt, so it is fine to send invalid bailout id. 2350 DCHECK(arguments->IsContextSlot() || arguments->IsStackAllocated()); 2351 BuildVariableAssignment(arguments, object, Token::ASSIGN, VectorSlotPair(), 2352 BailoutId::None()); 2353 return object; 2354} 2355 2356Node* AstGraphBuilder::BuildHoleCheckThenThrow(Node* value, Variable* variable, 2357 Node* not_hole, 2358 BailoutId bailout_id) { 2359 IfBuilder hole_check(this); 2360 Node* the_hole = jsgraph()->TheHoleConstant(); 2361 Node* check = NewNode(javascript()->StrictEqual(CompareOperationHint::kAny), 2362 value, the_hole); 2363 hole_check.If(check); 2364 hole_check.Then(); 2365 Node* error = BuildThrowReferenceError(variable, bailout_id); 2366 environment()->Push(error); 2367 hole_check.Else(); 2368 environment()->Push(not_hole); 2369 hole_check.End(); 2370 return environment()->Pop(); 2371} 2372 2373 2374Node* AstGraphBuilder::BuildHoleCheckElseThrow(Node* value, Variable* variable, 2375 Node* for_hole, 2376 BailoutId bailout_id) { 2377 IfBuilder hole_check(this); 2378 Node* the_hole = jsgraph()->TheHoleConstant(); 2379 Node* check = NewNode(javascript()->StrictEqual(CompareOperationHint::kAny), 2380 value, the_hole); 2381 hole_check.If(check); 2382 hole_check.Then(); 2383 environment()->Push(for_hole); 2384 hole_check.Else(); 2385 Node* error = BuildThrowReferenceError(variable, bailout_id); 2386 environment()->Push(error); 2387 hole_check.End(); 2388 return environment()->Pop(); 2389} 2390 2391Node* AstGraphBuilder::BuildVariableLoad(Variable* variable, 2392 BailoutId bailout_id, 2393 const VectorSlotPair& feedback, 2394 OutputFrameStateCombine combine, 2395 TypeofMode typeof_mode) { 2396 Node* the_hole = jsgraph()->TheHoleConstant(); 2397 switch (variable->location()) { 2398 case VariableLocation::UNALLOCATED: { 2399 // Global var, const, or let variable. 2400 Handle<Name> name = variable->name(); 2401 if (Node* node = TryLoadGlobalConstant(name)) return node; 2402 Node* value = BuildGlobalLoad(name, feedback, typeof_mode); 2403 PrepareFrameState(value, bailout_id, combine); 2404 return value; 2405 } 2406 case VariableLocation::PARAMETER: 2407 case VariableLocation::LOCAL: { 2408 // Local var, const, or let variable. 2409 Node* value = environment()->Lookup(variable); 2410 if (variable->binding_needs_init()) { 2411 // Perform check for uninitialized let/const variables. 2412 if (value->op() == the_hole->op()) { 2413 value = BuildThrowReferenceError(variable, bailout_id); 2414 } else if (value->opcode() == IrOpcode::kPhi) { 2415 value = BuildHoleCheckThenThrow(value, variable, value, bailout_id); 2416 } 2417 } 2418 return value; 2419 } 2420 case VariableLocation::CONTEXT: { 2421 // Context variable (potentially up the context chain). 2422 int depth = current_scope()->ContextChainLength(variable->scope()); 2423 // TODO(mstarzinger): The {maybe_assigned} flag computed during variable 2424 // resolution is highly inaccurate and cannot be trusted. We are only 2425 // taking this information into account when asm.js compilation is used. 2426 bool immutable = variable->maybe_assigned() == kNotAssigned && 2427 info()->is_function_context_specializing(); 2428 const Operator* op = 2429 javascript()->LoadContext(depth, variable->index(), immutable); 2430 Node* value = NewNode(op); 2431 // TODO(titzer): initialization checks are redundant for already 2432 // initialized immutable context loads, but only specialization knows. 2433 // Maybe specializer should be a parameter to the graph builder? 2434 if (variable->binding_needs_init()) { 2435 // Perform check for uninitialized let/const variables. 2436 value = BuildHoleCheckThenThrow(value, variable, value, bailout_id); 2437 } 2438 return value; 2439 } 2440 case VariableLocation::LOOKUP: 2441 case VariableLocation::MODULE: 2442 UNREACHABLE(); 2443 } 2444 UNREACHABLE(); 2445 return nullptr; 2446} 2447 2448 2449Node* AstGraphBuilder::BuildVariableDelete(Variable* variable, 2450 BailoutId bailout_id, 2451 OutputFrameStateCombine combine) { 2452 switch (variable->location()) { 2453 case VariableLocation::UNALLOCATED: { 2454 // Global var, const, or let variable. 2455 Node* global = BuildLoadGlobalObject(); 2456 Node* name = jsgraph()->Constant(variable->name()); 2457 const Operator* op = javascript()->DeleteProperty(language_mode()); 2458 Node* result = NewNode(op, global, name); 2459 PrepareFrameState(result, bailout_id, combine); 2460 return result; 2461 } 2462 case VariableLocation::PARAMETER: 2463 case VariableLocation::LOCAL: 2464 case VariableLocation::CONTEXT: { 2465 // Local var, const, or let variable or context variable. 2466 return jsgraph()->BooleanConstant(variable->is_this()); 2467 } 2468 case VariableLocation::LOOKUP: 2469 case VariableLocation::MODULE: 2470 UNREACHABLE(); 2471 } 2472 UNREACHABLE(); 2473 return nullptr; 2474} 2475 2476Node* AstGraphBuilder::BuildVariableAssignment( 2477 Variable* variable, Node* value, Token::Value op, 2478 const VectorSlotPair& feedback, BailoutId bailout_id, 2479 OutputFrameStateCombine combine) { 2480 Node* the_hole = jsgraph()->TheHoleConstant(); 2481 VariableMode mode = variable->mode(); 2482 switch (variable->location()) { 2483 case VariableLocation::UNALLOCATED: { 2484 // Global var, const, or let variable. 2485 Handle<Name> name = variable->name(); 2486 Node* store = BuildGlobalStore(name, value, feedback); 2487 PrepareFrameState(store, bailout_id, combine); 2488 return store; 2489 } 2490 case VariableLocation::PARAMETER: 2491 case VariableLocation::LOCAL: 2492 // Local var, const, or let variable. 2493 if (mode == LET && op == Token::INIT) { 2494 // No initialization check needed because scoping guarantees it. Note 2495 // that we still perform a lookup to keep the variable live, because 2496 // baseline code might contain debug code that inspects the variable. 2497 Node* current = environment()->Lookup(variable); 2498 CHECK_NOT_NULL(current); 2499 } else if (mode == LET && op != Token::INIT && 2500 variable->binding_needs_init()) { 2501 // Perform an initialization check for let declared variables. 2502 Node* current = environment()->Lookup(variable); 2503 if (current->op() == the_hole->op()) { 2504 return BuildThrowReferenceError(variable, bailout_id); 2505 } else if (current->opcode() == IrOpcode::kPhi) { 2506 BuildHoleCheckThenThrow(current, variable, value, bailout_id); 2507 } 2508 } else if (mode == CONST && op == Token::INIT) { 2509 // Perform an initialization check for const {this} variables. 2510 // Note that the {this} variable is the only const variable being able 2511 // to trigger bind operations outside the TDZ, via {super} calls. 2512 Node* current = environment()->Lookup(variable); 2513 if (current->op() != the_hole->op() && variable->is_this()) { 2514 value = BuildHoleCheckElseThrow(current, variable, value, bailout_id); 2515 } 2516 } else if (mode == CONST && op != Token::INIT && 2517 variable->is_sloppy_function_name()) { 2518 // Non-initializing assignment to sloppy function names is 2519 // - exception in strict mode. 2520 // - ignored in sloppy mode. 2521 DCHECK(!variable->binding_needs_init()); 2522 if (variable->throw_on_const_assignment(language_mode())) { 2523 return BuildThrowConstAssignError(bailout_id); 2524 } 2525 return value; 2526 } else if (mode == CONST && op != Token::INIT) { 2527 if (variable->binding_needs_init()) { 2528 Node* current = environment()->Lookup(variable); 2529 if (current->op() == the_hole->op()) { 2530 return BuildThrowReferenceError(variable, bailout_id); 2531 } else if (current->opcode() == IrOpcode::kPhi) { 2532 BuildHoleCheckThenThrow(current, variable, value, bailout_id); 2533 } 2534 } 2535 // Assignment to const is exception in all modes. 2536 return BuildThrowConstAssignError(bailout_id); 2537 } 2538 environment()->Bind(variable, value); 2539 return value; 2540 case VariableLocation::CONTEXT: { 2541 // Context variable (potentially up the context chain). 2542 int depth = current_scope()->ContextChainLength(variable->scope()); 2543 if (mode == LET && op != Token::INIT && variable->binding_needs_init()) { 2544 // Perform an initialization check for let declared variables. 2545 const Operator* op = 2546 javascript()->LoadContext(depth, variable->index(), false); 2547 Node* current = NewNode(op); 2548 value = BuildHoleCheckThenThrow(current, variable, value, bailout_id); 2549 } else if (mode == CONST && op == Token::INIT) { 2550 // Perform an initialization check for const {this} variables. 2551 // Note that the {this} variable is the only const variable being able 2552 // to trigger bind operations outside the TDZ, via {super} calls. 2553 if (variable->is_this()) { 2554 const Operator* op = 2555 javascript()->LoadContext(depth, variable->index(), false); 2556 Node* current = NewNode(op); 2557 value = BuildHoleCheckElseThrow(current, variable, value, bailout_id); 2558 } 2559 } else if (mode == CONST && op != Token::INIT && 2560 variable->is_sloppy_function_name()) { 2561 // Non-initializing assignment to sloppy function names is 2562 // - exception in strict mode. 2563 // - ignored in sloppy mode. 2564 DCHECK(!variable->binding_needs_init()); 2565 if (variable->throw_on_const_assignment(language_mode())) { 2566 return BuildThrowConstAssignError(bailout_id); 2567 } 2568 return value; 2569 } else if (mode == CONST && op != Token::INIT) { 2570 if (variable->binding_needs_init()) { 2571 const Operator* op = 2572 javascript()->LoadContext(depth, variable->index(), false); 2573 Node* current = NewNode(op); 2574 BuildHoleCheckThenThrow(current, variable, value, bailout_id); 2575 } 2576 // Assignment to const is exception in all modes. 2577 return BuildThrowConstAssignError(bailout_id); 2578 } 2579 const Operator* op = javascript()->StoreContext(depth, variable->index()); 2580 return NewNode(op, value); 2581 } 2582 case VariableLocation::LOOKUP: 2583 case VariableLocation::MODULE: 2584 UNREACHABLE(); 2585 } 2586 UNREACHABLE(); 2587 return nullptr; 2588} 2589 2590 2591Node* AstGraphBuilder::BuildKeyedLoad(Node* object, Node* key, 2592 const VectorSlotPair& feedback) { 2593 const Operator* op = javascript()->LoadProperty(feedback); 2594 Node* node = NewNode(op, object, key); 2595 return node; 2596} 2597 2598 2599Node* AstGraphBuilder::BuildNamedLoad(Node* object, Handle<Name> name, 2600 const VectorSlotPair& feedback) { 2601 const Operator* op = javascript()->LoadNamed(name, feedback); 2602 Node* node = NewNode(op, object); 2603 return node; 2604} 2605 2606 2607Node* AstGraphBuilder::BuildKeyedStore(Node* object, Node* key, Node* value, 2608 const VectorSlotPair& feedback) { 2609 DCHECK_EQ(feedback.vector()->GetLanguageMode(feedback.slot()), 2610 language_mode()); 2611 const Operator* op = javascript()->StoreProperty(language_mode(), feedback); 2612 Node* node = NewNode(op, object, key, value); 2613 return node; 2614} 2615 2616 2617Node* AstGraphBuilder::BuildNamedStore(Node* object, Handle<Name> name, 2618 Node* value, 2619 const VectorSlotPair& feedback) { 2620 DCHECK_EQ(feedback.vector()->GetLanguageMode(feedback.slot()), 2621 language_mode()); 2622 const Operator* op = 2623 javascript()->StoreNamed(language_mode(), name, feedback); 2624 Node* node = NewNode(op, object, value); 2625 return node; 2626} 2627 2628Node* AstGraphBuilder::BuildNamedStoreOwn(Node* object, Handle<Name> name, 2629 Node* value, 2630 const VectorSlotPair& feedback) { 2631 DCHECK_EQ(FeedbackSlotKind::kStoreOwnNamed, 2632 feedback.vector()->GetKind(feedback.slot())); 2633 const Operator* op = javascript()->StoreNamedOwn(name, feedback); 2634 Node* node = NewNode(op, object, value); 2635 return node; 2636} 2637 2638Node* AstGraphBuilder::BuildGlobalLoad(Handle<Name> name, 2639 const VectorSlotPair& feedback, 2640 TypeofMode typeof_mode) { 2641 DCHECK_EQ(feedback.vector()->GetTypeofMode(feedback.slot()), typeof_mode); 2642 const Operator* op = javascript()->LoadGlobal(name, feedback, typeof_mode); 2643 Node* node = NewNode(op); 2644 return node; 2645} 2646 2647 2648Node* AstGraphBuilder::BuildGlobalStore(Handle<Name> name, Node* value, 2649 const VectorSlotPair& feedback) { 2650 const Operator* op = 2651 javascript()->StoreGlobal(language_mode(), name, feedback); 2652 Node* node = NewNode(op, value); 2653 return node; 2654} 2655 2656Node* AstGraphBuilder::BuildLoadGlobalObject() { 2657 return BuildLoadNativeContextField(Context::EXTENSION_INDEX); 2658} 2659 2660 2661Node* AstGraphBuilder::BuildLoadNativeContextField(int index) { 2662 const Operator* op = 2663 javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true); 2664 Node* native_context = NewNode(op); 2665 Node* result = NewNode(javascript()->LoadContext(0, index, true)); 2666 NodeProperties::ReplaceContextInput(result, native_context); 2667 return result; 2668} 2669 2670 2671Node* AstGraphBuilder::BuildToBoolean(Node* input, TypeFeedbackId feedback_id) { 2672 if (Node* node = TryFastToBoolean(input)) return node; 2673 ToBooleanHints hints = ToBooleanHint::kAny; 2674 return NewNode(javascript()->ToBoolean(hints), input); 2675} 2676 2677 2678Node* AstGraphBuilder::BuildToObject(Node* input, BailoutId bailout_id) { 2679 Node* object = NewNode(javascript()->ToObject(), input); 2680 PrepareFrameState(object, bailout_id, OutputFrameStateCombine::Push()); 2681 return object; 2682} 2683 2684Node* AstGraphBuilder::BuildSetHomeObject(Node* value, Node* home_object, 2685 LiteralProperty* property, 2686 int slot_number) { 2687 Expression* expr = property->value(); 2688 if (!FunctionLiteral::NeedsHomeObject(expr)) return value; 2689 Handle<Name> name = isolate()->factory()->home_object_symbol(); 2690 VectorSlotPair feedback = 2691 CreateVectorSlotPair(property->GetSlot(slot_number)); 2692 Node* store = BuildNamedStore(value, name, home_object, feedback); 2693 PrepareFrameState(store, BailoutId::None(), 2694 OutputFrameStateCombine::Ignore()); 2695 return store; 2696} 2697 2698 2699Node* AstGraphBuilder::BuildThrowError(Node* exception, BailoutId bailout_id) { 2700 const Operator* op = javascript()->CallRuntime(Runtime::kThrow); 2701 Node* call = NewNode(op, exception); 2702 PrepareFrameState(call, bailout_id); 2703 Node* control = NewNode(common()->Throw(), call); 2704 UpdateControlDependencyToLeaveFunction(control); 2705 return call; 2706} 2707 2708 2709Node* AstGraphBuilder::BuildThrowReferenceError(Variable* variable, 2710 BailoutId bailout_id) { 2711 Node* variable_name = jsgraph()->Constant(variable->name()); 2712 const Operator* op = javascript()->CallRuntime(Runtime::kThrowReferenceError); 2713 Node* call = NewNode(op, variable_name); 2714 PrepareFrameState(call, bailout_id); 2715 Node* control = NewNode(common()->Throw(), call); 2716 UpdateControlDependencyToLeaveFunction(control); 2717 return call; 2718} 2719 2720 2721Node* AstGraphBuilder::BuildThrowConstAssignError(BailoutId bailout_id) { 2722 const Operator* op = 2723 javascript()->CallRuntime(Runtime::kThrowConstAssignError); 2724 Node* call = NewNode(op); 2725 PrepareFrameState(call, bailout_id); 2726 Node* control = NewNode(common()->Throw(), call); 2727 UpdateControlDependencyToLeaveFunction(control); 2728 return call; 2729} 2730 2731 2732Node* AstGraphBuilder::BuildReturn(Node* return_value) { 2733 // Emit tracing call if requested to do so. 2734 if (FLAG_trace) { 2735 return_value = 2736 NewNode(javascript()->CallRuntime(Runtime::kTraceExit), return_value); 2737 } 2738 Node* pop_node = jsgraph()->ZeroConstant(); 2739 Node* control = NewNode(common()->Return(), pop_node, return_value); 2740 UpdateControlDependencyToLeaveFunction(control); 2741 return control; 2742} 2743 2744 2745Node* AstGraphBuilder::BuildThrow(Node* exception_value) { 2746 NewNode(javascript()->CallRuntime(Runtime::kReThrow), exception_value); 2747 Node* control = NewNode(common()->Throw(), exception_value); 2748 UpdateControlDependencyToLeaveFunction(control); 2749 return control; 2750} 2751 2752 2753Node* AstGraphBuilder::BuildBinaryOp(Node* left, Node* right, Token::Value op, 2754 TypeFeedbackId feedback_id) { 2755 const Operator* js_op; 2756 BinaryOperationHint hint = BinaryOperationHint::kAny; 2757 switch (op) { 2758 case Token::BIT_OR: 2759 js_op = javascript()->BitwiseOr(); 2760 break; 2761 case Token::BIT_AND: 2762 js_op = javascript()->BitwiseAnd(); 2763 break; 2764 case Token::BIT_XOR: 2765 js_op = javascript()->BitwiseXor(); 2766 break; 2767 case Token::SHL: 2768 js_op = javascript()->ShiftLeft(); 2769 break; 2770 case Token::SAR: 2771 js_op = javascript()->ShiftRight(); 2772 break; 2773 case Token::SHR: 2774 js_op = javascript()->ShiftRightLogical(); 2775 break; 2776 case Token::ADD: 2777 js_op = javascript()->Add(hint); 2778 break; 2779 case Token::SUB: 2780 js_op = javascript()->Subtract(); 2781 break; 2782 case Token::MUL: 2783 js_op = javascript()->Multiply(); 2784 break; 2785 case Token::DIV: 2786 js_op = javascript()->Divide(); 2787 break; 2788 case Token::MOD: 2789 js_op = javascript()->Modulus(); 2790 break; 2791 default: 2792 UNREACHABLE(); 2793 js_op = nullptr; 2794 } 2795 return NewNode(js_op, left, right); 2796} 2797 2798 2799Node* AstGraphBuilder::TryLoadGlobalConstant(Handle<Name> name) { 2800 // Optimize global constants like "undefined", "Infinity", and "NaN". 2801 Handle<Object> constant_value = isolate()->factory()->GlobalConstantFor(name); 2802 if (!constant_value.is_null()) return jsgraph()->Constant(constant_value); 2803 return nullptr; 2804} 2805 2806Node* AstGraphBuilder::TryFastToBoolean(Node* input) { 2807 switch (input->opcode()) { 2808 case IrOpcode::kNumberConstant: { 2809 NumberMatcher m(input); 2810 return jsgraph_->BooleanConstant(!m.Is(0) && !m.IsNaN()); 2811 } 2812 case IrOpcode::kHeapConstant: { 2813 Handle<HeapObject> object = HeapObjectMatcher(input).Value(); 2814 return jsgraph_->BooleanConstant(object->BooleanValue()); 2815 } 2816 case IrOpcode::kJSEqual: 2817 case IrOpcode::kJSNotEqual: 2818 case IrOpcode::kJSStrictEqual: 2819 case IrOpcode::kJSStrictNotEqual: 2820 case IrOpcode::kJSLessThan: 2821 case IrOpcode::kJSLessThanOrEqual: 2822 case IrOpcode::kJSGreaterThan: 2823 case IrOpcode::kJSGreaterThanOrEqual: 2824 case IrOpcode::kJSToBoolean: 2825 case IrOpcode::kJSDeleteProperty: 2826 case IrOpcode::kJSHasProperty: 2827 case IrOpcode::kJSInstanceOf: 2828 return input; 2829 default: 2830 break; 2831 } 2832 return nullptr; 2833} 2834 2835 2836bool AstGraphBuilder::CheckOsrEntry(IterationStatement* stmt) { 2837 if (info()->osr_ast_id() == stmt->OsrEntryId()) { 2838 DCHECK_EQ(-1, info()->osr_expr_stack_height()); 2839 info()->set_osr_expr_stack_height(environment()->stack_height()); 2840 return true; 2841 } 2842 return false; 2843} 2844 2845 2846void AstGraphBuilder::PrepareFrameState(Node* node, BailoutId ast_id, 2847 OutputFrameStateCombine combine) { 2848 if (OperatorProperties::HasFrameStateInput(node->op())) { 2849 DCHECK(ast_id.IsNone() || info()->shared_info()->VerifyBailoutId(ast_id)); 2850 DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op())); 2851 DCHECK_EQ(IrOpcode::kDead, 2852 NodeProperties::GetFrameStateInput(node)->opcode()); 2853 bool has_exception = NodeProperties::IsExceptionalCall(node); 2854 Node* state = environment()->Checkpoint(ast_id, combine, has_exception); 2855 NodeProperties::ReplaceFrameStateInput(node, state); 2856 } 2857} 2858 2859void AstGraphBuilder::PrepareEagerCheckpoint(BailoutId ast_id) { 2860 if (environment()->GetEffectDependency()->opcode() == IrOpcode::kCheckpoint) { 2861 // We skip preparing a checkpoint if there already is one the current effect 2862 // dependency. This is just an optimization and not need for correctness. 2863 return; 2864 } 2865 if (ast_id != BailoutId::None()) { 2866 DCHECK(info()->shared_info()->VerifyBailoutId(ast_id)); 2867 Node* node = NewNode(common()->Checkpoint()); 2868 DCHECK_EQ(IrOpcode::kDead, 2869 NodeProperties::GetFrameStateInput(node)->opcode()); 2870 Node* state = environment()->Checkpoint(ast_id); 2871 NodeProperties::ReplaceFrameStateInput(node, state); 2872 } 2873} 2874 2875BitVector* AstGraphBuilder::GetVariablesAssignedInLoop( 2876 IterationStatement* stmt) { 2877 if (loop_assignment_analysis_ == nullptr) return nullptr; 2878 return loop_assignment_analysis_->GetVariablesAssignedInLoop(stmt); 2879} 2880 2881 2882Node** AstGraphBuilder::EnsureInputBufferSize(int size) { 2883 if (size > input_buffer_size_) { 2884 size = size + kInputBufferSizeIncrement + input_buffer_size_; 2885 input_buffer_ = local_zone()->NewArray<Node*>(size); 2886 input_buffer_size_ = size; 2887 } 2888 return input_buffer_; 2889} 2890 2891 2892Node* AstGraphBuilder::MakeNode(const Operator* op, int value_input_count, 2893 Node** value_inputs, bool incomplete) { 2894 DCHECK_EQ(op->ValueInputCount(), value_input_count); 2895 2896 bool has_context = OperatorProperties::HasContextInput(op); 2897 bool has_frame_state = OperatorProperties::HasFrameStateInput(op); 2898 bool has_control = op->ControlInputCount() == 1; 2899 bool has_effect = op->EffectInputCount() == 1; 2900 2901 DCHECK(op->ControlInputCount() < 2); 2902 DCHECK(op->EffectInputCount() < 2); 2903 2904 Node* result = nullptr; 2905 if (!has_context && !has_frame_state && !has_control && !has_effect) { 2906 result = graph()->NewNode(op, value_input_count, value_inputs, incomplete); 2907 } else { 2908 int input_count_with_deps = value_input_count; 2909 if (has_context) ++input_count_with_deps; 2910 if (has_frame_state) ++input_count_with_deps; 2911 if (has_control) ++input_count_with_deps; 2912 if (has_effect) ++input_count_with_deps; 2913 Node** buffer = EnsureInputBufferSize(input_count_with_deps); 2914 memcpy(buffer, value_inputs, kPointerSize * value_input_count); 2915 Node** current_input = buffer + value_input_count; 2916 if (has_context) { 2917 *current_input++ = current_context(); 2918 } 2919 if (has_frame_state) { 2920 // The frame state will be inserted later. Here we misuse 2921 // the {Dead} node as a sentinel to be later overwritten 2922 // with the real frame state. 2923 *current_input++ = jsgraph()->Dead(); 2924 } 2925 if (has_effect) { 2926 *current_input++ = environment_->GetEffectDependency(); 2927 } 2928 if (has_control) { 2929 *current_input++ = environment_->GetControlDependency(); 2930 } 2931 result = graph()->NewNode(op, input_count_with_deps, buffer, incomplete); 2932 if (!environment()->IsMarkedAsUnreachable()) { 2933 // Update the current control dependency for control-producing nodes. 2934 if (NodeProperties::IsControl(result)) { 2935 environment_->UpdateControlDependency(result); 2936 } 2937 // Update the current effect dependency for effect-producing nodes. 2938 if (result->op()->EffectOutputCount() > 0) { 2939 environment_->UpdateEffectDependency(result); 2940 } 2941 // Add implicit success continuation for throwing nodes. 2942 if (!result->op()->HasProperty(Operator::kNoThrow)) { 2943 const Operator* op = common()->IfSuccess(); 2944 Node* on_success = graph()->NewNode(op, result); 2945 environment_->UpdateControlDependency(on_success); 2946 } 2947 } 2948 } 2949 2950 return result; 2951} 2952 2953 2954void AstGraphBuilder::UpdateControlDependencyToLeaveFunction(Node* exit) { 2955 if (environment()->IsMarkedAsUnreachable()) return; 2956 environment()->MarkAsUnreachable(); 2957 exit_controls_.push_back(exit); 2958} 2959 2960 2961void AstGraphBuilder::Environment::Merge(Environment* other) { 2962 DCHECK(values_.size() == other->values_.size()); 2963 DCHECK(contexts_.size() == other->contexts_.size()); 2964 2965 // Nothing to do if the other environment is dead. 2966 if (other->IsMarkedAsUnreachable()) return; 2967 2968 // Resurrect a dead environment by copying the contents of the other one and 2969 // placing a singleton merge as the new control dependency. 2970 if (this->IsMarkedAsUnreachable()) { 2971 Node* other_control = other->control_dependency_; 2972 Node* inputs[] = {other_control}; 2973 control_dependency_ = 2974 graph()->NewNode(common()->Merge(1), arraysize(inputs), inputs, true); 2975 effect_dependency_ = other->effect_dependency_; 2976 values_ = other->values_; 2977 contexts_ = other->contexts_; 2978 if (IsLivenessAnalysisEnabled()) { 2979 liveness_block_ = 2980 builder_->liveness_analyzer()->NewBlock(other->liveness_block()); 2981 } 2982 return; 2983 } 2984 2985 // Record the merge for the local variable liveness calculation. 2986 // For loops, we are connecting a back edge into the existing block; 2987 // for merges, we create a new merged block. 2988 if (IsLivenessAnalysisEnabled()) { 2989 if (GetControlDependency()->opcode() != IrOpcode::kLoop) { 2990 liveness_block_ = 2991 builder_->liveness_analyzer()->NewBlock(liveness_block()); 2992 } 2993 liveness_block()->AddPredecessor(other->liveness_block()); 2994 } 2995 2996 // Create a merge of the control dependencies of both environments and update 2997 // the current environment's control dependency accordingly. 2998 Node* control = builder_->MergeControl(this->GetControlDependency(), 2999 other->GetControlDependency()); 3000 UpdateControlDependency(control); 3001 3002 // Create a merge of the effect dependencies of both environments and update 3003 // the current environment's effect dependency accordingly. 3004 Node* effect = builder_->MergeEffect(this->GetEffectDependency(), 3005 other->GetEffectDependency(), control); 3006 UpdateEffectDependency(effect); 3007 3008 // Introduce Phi nodes for values that have differing input at merge points, 3009 // potentially extending an existing Phi node if possible. 3010 for (int i = 0; i < static_cast<int>(values_.size()); ++i) { 3011 values_[i] = builder_->MergeValue(values_[i], other->values_[i], control); 3012 } 3013 for (int i = 0; i < static_cast<int>(contexts_.size()); ++i) { 3014 contexts_[i] = 3015 builder_->MergeValue(contexts_[i], other->contexts_[i], control); 3016 } 3017} 3018 3019void AstGraphBuilder::Environment::PrepareForOsrEntry() { 3020 int size = static_cast<int>(values()->size()); 3021 Graph* graph = builder_->graph(); 3022 3023 // Set the control and effect to the OSR loop entry. 3024 Node* osr_loop_entry = graph->NewNode(builder_->common()->OsrLoopEntry(), 3025 graph->start(), graph->start()); 3026 UpdateControlDependency(osr_loop_entry); 3027 UpdateEffectDependency(osr_loop_entry); 3028 3029 // Set OSR values. 3030 for (int i = 0; i < size; ++i) { 3031 values()->at(i) = 3032 graph->NewNode(builder_->common()->OsrValue(i), osr_loop_entry); 3033 } 3034 3035 // Set the innermost context. 3036 const Operator* op_inner = 3037 builder_->common()->OsrValue(Linkage::kOsrContextSpillSlotIndex); 3038 contexts()->back() = graph->NewNode(op_inner, osr_loop_entry); 3039 3040 // Create a checkpoint. 3041 Node* frame_state = Checkpoint(builder_->info()->osr_ast_id()); 3042 Node* checkpoint = graph->NewNode(common()->Checkpoint(), frame_state, 3043 osr_loop_entry, osr_loop_entry); 3044 UpdateEffectDependency(checkpoint); 3045 3046 // Create the OSR guard nodes. 3047 const Operator* guard_op = 3048 builder_->info()->is_deoptimization_enabled() 3049 ? builder_->common()->OsrGuard(OsrGuardType::kUninitialized) 3050 : builder_->common()->OsrGuard(OsrGuardType::kAny); 3051 Node* effect = checkpoint; 3052 for (int i = 0; i < size; ++i) { 3053 values()->at(i) = effect = 3054 graph->NewNode(guard_op, values()->at(i), effect, osr_loop_entry); 3055 } 3056 contexts()->back() = effect = 3057 graph->NewNode(guard_op, contexts()->back(), effect, osr_loop_entry); 3058 3059 // The innermost context is the OSR value, and the outer contexts are 3060 // reconstructed by dynamically walking up the context chain. 3061 const Operator* load_op = 3062 builder_->javascript()->LoadContext(0, Context::PREVIOUS_INDEX, true); 3063 Node* osr_context = effect = contexts()->back(); 3064 int last = static_cast<int>(contexts()->size() - 1); 3065 for (int i = last - 1; i >= 0; i--) { 3066 osr_context = effect = graph->NewNode(load_op, osr_context, effect); 3067 contexts()->at(i) = osr_context; 3068 } 3069 UpdateEffectDependency(effect); 3070} 3071 3072void AstGraphBuilder::Environment::PrepareForLoop(BitVector* assigned) { 3073 int size = static_cast<int>(values()->size()); 3074 3075 Node* control = builder_->NewLoop(); 3076 if (assigned == nullptr) { 3077 // Assume that everything is updated in the loop. 3078 for (int i = 0; i < size; ++i) { 3079 values()->at(i) = builder_->NewPhi(1, values()->at(i), control); 3080 } 3081 } else { 3082 // Only build phis for those locals assigned in this loop. 3083 for (int i = 0; i < size; ++i) { 3084 if (i < assigned->length() && !assigned->Contains(i)) continue; 3085 Node* phi = builder_->NewPhi(1, values()->at(i), control); 3086 values()->at(i) = phi; 3087 } 3088 } 3089 Node* effect = builder_->NewEffectPhi(1, GetEffectDependency(), control); 3090 UpdateEffectDependency(effect); 3091 3092 // Connect the loop to end via Terminate if it's not marked as unreachable. 3093 if (!IsMarkedAsUnreachable()) { 3094 // Connect the Loop node to end via a Terminate node. 3095 Node* terminate = builder_->graph()->NewNode( 3096 builder_->common()->Terminate(), effect, control); 3097 builder_->exit_controls_.push_back(terminate); 3098 } 3099 3100 if (builder_->info()->is_osr()) { 3101 // Introduce phis for all context values in the case of an OSR graph. 3102 for (size_t i = 0; i < contexts()->size(); ++i) { 3103 Node* context = contexts()->at(i); 3104 contexts()->at(i) = builder_->NewPhi(1, context, control); 3105 } 3106 } 3107} 3108 3109 3110Node* AstGraphBuilder::NewPhi(int count, Node* input, Node* control) { 3111 const Operator* phi_op = common()->Phi(MachineRepresentation::kTagged, count); 3112 Node** buffer = EnsureInputBufferSize(count + 1); 3113 MemsetPointer(buffer, input, count); 3114 buffer[count] = control; 3115 return graph()->NewNode(phi_op, count + 1, buffer, true); 3116} 3117 3118 3119Node* AstGraphBuilder::NewEffectPhi(int count, Node* input, Node* control) { 3120 const Operator* phi_op = common()->EffectPhi(count); 3121 Node** buffer = EnsureInputBufferSize(count + 1); 3122 MemsetPointer(buffer, input, count); 3123 buffer[count] = control; 3124 return graph()->NewNode(phi_op, count + 1, buffer, true); 3125} 3126 3127 3128Node* AstGraphBuilder::MergeControl(Node* control, Node* other) { 3129 int inputs = control->op()->ControlInputCount() + 1; 3130 if (control->opcode() == IrOpcode::kLoop) { 3131 // Control node for loop exists, add input. 3132 const Operator* op = common()->Loop(inputs); 3133 control->AppendInput(graph_zone(), other); 3134 NodeProperties::ChangeOp(control, op); 3135 } else if (control->opcode() == IrOpcode::kMerge) { 3136 // Control node for merge exists, add input. 3137 const Operator* op = common()->Merge(inputs); 3138 control->AppendInput(graph_zone(), other); 3139 NodeProperties::ChangeOp(control, op); 3140 } else { 3141 // Control node is a singleton, introduce a merge. 3142 const Operator* op = common()->Merge(inputs); 3143 Node* inputs[] = {control, other}; 3144 control = graph()->NewNode(op, arraysize(inputs), inputs, true); 3145 } 3146 return control; 3147} 3148 3149 3150Node* AstGraphBuilder::MergeEffect(Node* value, Node* other, Node* control) { 3151 int inputs = control->op()->ControlInputCount(); 3152 if (value->opcode() == IrOpcode::kEffectPhi && 3153 NodeProperties::GetControlInput(value) == control) { 3154 // Phi already exists, add input. 3155 value->InsertInput(graph_zone(), inputs - 1, other); 3156 NodeProperties::ChangeOp(value, common()->EffectPhi(inputs)); 3157 } else if (value != other) { 3158 // Phi does not exist yet, introduce one. 3159 value = NewEffectPhi(inputs, value, control); 3160 value->ReplaceInput(inputs - 1, other); 3161 } 3162 return value; 3163} 3164 3165 3166Node* AstGraphBuilder::MergeValue(Node* value, Node* other, Node* control) { 3167 int inputs = control->op()->ControlInputCount(); 3168 if (value->opcode() == IrOpcode::kPhi && 3169 NodeProperties::GetControlInput(value) == control) { 3170 // Phi already exists, add input. 3171 value->InsertInput(graph_zone(), inputs - 1, other); 3172 NodeProperties::ChangeOp( 3173 value, common()->Phi(MachineRepresentation::kTagged, inputs)); 3174 } else if (value != other) { 3175 // Phi does not exist yet, introduce one. 3176 value = NewPhi(inputs, value, control); 3177 value->ReplaceInput(inputs - 1, other); 3178 } 3179 return value; 3180} 3181 3182AstGraphBuilderWithPositions::AstGraphBuilderWithPositions( 3183 Zone* local_zone, CompilationInfo* info, JSGraph* jsgraph, 3184 float invocation_frequency, LoopAssignmentAnalysis* loop_assignment, 3185 SourcePositionTable* source_positions, int inlining_id) 3186 : AstGraphBuilder(local_zone, info, jsgraph, invocation_frequency, 3187 loop_assignment), 3188 source_positions_(source_positions), 3189 start_position_(info->shared_info()->start_position(), inlining_id) {} 3190 3191} // namespace compiler 3192} // namespace internal 3193} // namespace v8 3194