1 // Copyright 2013 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/crankshaft/hydrogen.h" 6 7 #include <memory> 8 #include <sstream> 9 10 #include "src/allocation-site-scopes.h" 11 #include "src/ast/ast-numbering.h" 12 #include "src/ast/compile-time-value.h" 13 #include "src/ast/scopes.h" 14 #include "src/code-factory.h" 15 #include "src/crankshaft/hydrogen-bce.h" 16 #include "src/crankshaft/hydrogen-canonicalize.h" 17 #include "src/crankshaft/hydrogen-check-elimination.h" 18 #include "src/crankshaft/hydrogen-dce.h" 19 #include "src/crankshaft/hydrogen-dehoist.h" 20 #include "src/crankshaft/hydrogen-environment-liveness.h" 21 #include "src/crankshaft/hydrogen-escape-analysis.h" 22 #include "src/crankshaft/hydrogen-gvn.h" 23 #include "src/crankshaft/hydrogen-infer-representation.h" 24 #include "src/crankshaft/hydrogen-infer-types.h" 25 #include "src/crankshaft/hydrogen-load-elimination.h" 26 #include "src/crankshaft/hydrogen-mark-unreachable.h" 27 #include "src/crankshaft/hydrogen-osr.h" 28 #include "src/crankshaft/hydrogen-range-analysis.h" 29 #include "src/crankshaft/hydrogen-redundant-phi.h" 30 #include "src/crankshaft/hydrogen-removable-simulates.h" 31 #include "src/crankshaft/hydrogen-representation-changes.h" 32 #include "src/crankshaft/hydrogen-sce.h" 33 #include "src/crankshaft/hydrogen-store-elimination.h" 34 #include "src/crankshaft/hydrogen-uint32-analysis.h" 35 #include "src/crankshaft/lithium-allocator.h" 36 #include "src/crankshaft/typing.h" 37 #include "src/field-type.h" 38 #include "src/full-codegen/full-codegen.h" 39 #include "src/globals.h" 40 #include "src/ic/call-optimization.h" 41 #include "src/ic/ic.h" 42 // GetRootConstructor 43 #include "src/ic/ic-inl.h" 44 #include "src/isolate-inl.h" 45 #include "src/runtime/runtime.h" 46 47 #if V8_TARGET_ARCH_IA32 48 #include "src/crankshaft/ia32/lithium-codegen-ia32.h" // NOLINT 49 #elif V8_TARGET_ARCH_X64 50 #include "src/crankshaft/x64/lithium-codegen-x64.h" // NOLINT 51 #elif V8_TARGET_ARCH_ARM64 52 #include "src/crankshaft/arm64/lithium-codegen-arm64.h" // NOLINT 53 #elif V8_TARGET_ARCH_ARM 54 #include "src/crankshaft/arm/lithium-codegen-arm.h" // NOLINT 55 #elif V8_TARGET_ARCH_PPC 56 #include "src/crankshaft/ppc/lithium-codegen-ppc.h" // NOLINT 57 #elif V8_TARGET_ARCH_MIPS 58 #include "src/crankshaft/mips/lithium-codegen-mips.h" // NOLINT 59 #elif V8_TARGET_ARCH_MIPS64 60 #include "src/crankshaft/mips64/lithium-codegen-mips64.h" // NOLINT 61 #elif V8_TARGET_ARCH_S390 62 #include "src/crankshaft/s390/lithium-codegen-s390.h" // NOLINT 63 #elif V8_TARGET_ARCH_X87 64 #include "src/crankshaft/x87/lithium-codegen-x87.h" // NOLINT 65 #else 66 #error Unsupported target architecture. 67 #endif 68 69 namespace v8 { 70 namespace internal { 71 72 const auto GetRegConfig = RegisterConfiguration::Crankshaft; 73 74 class HOptimizedGraphBuilderWithPositions : public HOptimizedGraphBuilder { 75 public: 76 explicit HOptimizedGraphBuilderWithPositions(CompilationInfo* info) 77 : HOptimizedGraphBuilder(info, true) { 78 SetSourcePosition(info->shared_info()->start_position()); 79 } 80 81 #define DEF_VISIT(type) \ 82 void Visit##type(type* node) override { \ 83 SourcePosition old_position = SourcePosition::Unknown(); \ 84 if (node->position() != kNoSourcePosition) { \ 85 old_position = source_position(); \ 86 SetSourcePosition(node->position()); \ 87 } \ 88 HOptimizedGraphBuilder::Visit##type(node); \ 89 if (old_position.IsKnown()) { \ 90 set_source_position(old_position); \ 91 } \ 92 } 93 EXPRESSION_NODE_LIST(DEF_VISIT) 94 #undef DEF_VISIT 95 96 #define DEF_VISIT(type) \ 97 void Visit##type(type* node) override { \ 98 SourcePosition old_position = SourcePosition::Unknown(); \ 99 if (node->position() != kNoSourcePosition) { \ 100 old_position = source_position(); \ 101 SetSourcePosition(node->position()); \ 102 } \ 103 HOptimizedGraphBuilder::Visit##type(node); \ 104 if (old_position.IsKnown()) { \ 105 set_source_position(old_position); \ 106 } \ 107 } 108 STATEMENT_NODE_LIST(DEF_VISIT) 109 #undef DEF_VISIT 110 111 #define DEF_VISIT(type) \ 112 void Visit##type(type* node) override { \ 113 HOptimizedGraphBuilder::Visit##type(node); \ 114 } 115 DECLARATION_NODE_LIST(DEF_VISIT) 116 #undef DEF_VISIT 117 }; 118 119 HCompilationJob::Status HCompilationJob::PrepareJobImpl() { 120 if (!isolate()->use_crankshaft() || 121 info()->shared_info()->dont_crankshaft()) { 122 // Crankshaft is entirely disabled. 123 return FAILED; 124 } 125 126 // Optimization requires a version of fullcode with deoptimization support. 127 // Recompile the unoptimized version of the code if the current version 128 // doesn't have deoptimization support already. 129 // Otherwise, if we are gathering compilation time and space statistics 130 // for hydrogen, gather baseline statistics for a fullcode compilation. 131 bool should_recompile = !info()->shared_info()->has_deoptimization_support(); 132 if (should_recompile || FLAG_hydrogen_stats) { 133 base::ElapsedTimer timer; 134 if (FLAG_hydrogen_stats) { 135 timer.Start(); 136 } 137 if (!Compiler::EnsureDeoptimizationSupport(info())) { 138 return FAILED; 139 } 140 if (FLAG_hydrogen_stats) { 141 isolate()->GetHStatistics()->IncrementFullCodeGen(timer.Elapsed()); 142 } 143 } 144 DCHECK(info()->shared_info()->has_deoptimization_support()); 145 DCHECK(!info()->shared_info()->never_compiled()); 146 147 // Check the whitelist for Crankshaft. 148 if (!info()->shared_info()->PassesFilter(FLAG_hydrogen_filter)) { 149 return AbortOptimization(kHydrogenFilter); 150 } 151 152 Scope* scope = info()->scope(); 153 if (LUnallocated::TooManyParameters(scope->num_parameters())) { 154 // Crankshaft would require too many Lithium operands. 155 return AbortOptimization(kTooManyParameters); 156 } 157 158 if (info()->is_osr() && 159 LUnallocated::TooManyParametersOrStackSlots(scope->num_parameters(), 160 scope->num_stack_slots())) { 161 // Crankshaft would require too many Lithium operands. 162 return AbortOptimization(kTooManyParametersLocals); 163 } 164 165 if (IsGeneratorFunction(info()->shared_info()->kind())) { 166 // Crankshaft does not support generators. 167 return AbortOptimization(kGenerator); 168 } 169 170 if (FLAG_trace_hydrogen) { 171 isolate()->GetHTracer()->TraceCompilation(info()); 172 } 173 174 // Optimization could have been disabled by the parser. Note that this check 175 // is only needed because the Hydrogen graph builder is missing some bailouts. 176 if (info()->shared_info()->optimization_disabled()) { 177 return AbortOptimization( 178 info()->shared_info()->disable_optimization_reason()); 179 } 180 181 HOptimizedGraphBuilder* graph_builder = 182 (FLAG_hydrogen_track_positions || isolate()->is_profiling() || 183 FLAG_trace_ic) 184 ? new (info()->zone()) HOptimizedGraphBuilderWithPositions(info()) 185 : new (info()->zone()) HOptimizedGraphBuilder(info(), false); 186 187 // Type-check the function. 188 AstTyper(info()->isolate(), info()->zone(), info()->closure(), 189 info()->scope(), info()->osr_ast_id(), info()->literal(), 190 graph_builder->bounds()) 191 .Run(); 192 193 graph_ = graph_builder->CreateGraph(); 194 195 if (isolate()->has_pending_exception()) { 196 return FAILED; 197 } 198 199 if (graph_ == NULL) return FAILED; 200 201 if (info()->dependencies()->HasAborted()) { 202 // Dependency has changed during graph creation. Let's try again later. 203 return RetryOptimization(kBailedOutDueToDependencyChange); 204 } 205 206 return SUCCEEDED; 207 } 208 209 HCompilationJob::Status HCompilationJob::ExecuteJobImpl() { 210 DCHECK(graph_ != NULL); 211 BailoutReason bailout_reason = kNoReason; 212 213 if (graph_->Optimize(&bailout_reason)) { 214 chunk_ = LChunk::NewChunk(graph_); 215 if (chunk_ != NULL) return SUCCEEDED; 216 } else if (bailout_reason != kNoReason) { 217 info()->AbortOptimization(bailout_reason); 218 } 219 220 return FAILED; 221 } 222 223 HCompilationJob::Status HCompilationJob::FinalizeJobImpl() { 224 DCHECK(chunk_ != NULL); 225 DCHECK(graph_ != NULL); 226 { 227 // Deferred handles reference objects that were accessible during 228 // graph creation. To make sure that we don't encounter inconsistencies 229 // between graph creation and code generation, we disallow accessing 230 // objects through deferred handles during the latter, with exceptions. 231 DisallowDeferredHandleDereference no_deferred_handle_deref; 232 Handle<Code> optimized_code = chunk_->Codegen(); 233 if (optimized_code.is_null()) { 234 if (info()->bailout_reason() == kNoReason) { 235 return AbortOptimization(kCodeGenerationFailed); 236 } 237 return FAILED; 238 } 239 RegisterWeakObjectsInOptimizedCode(optimized_code); 240 info()->SetCode(optimized_code); 241 } 242 // Add to the weak list of optimized code objects. 243 info()->context()->native_context()->AddOptimizedCode(*info()->code()); 244 return SUCCEEDED; 245 } 246 247 HBasicBlock::HBasicBlock(HGraph* graph) 248 : block_id_(graph->GetNextBlockID()), 249 graph_(graph), 250 phis_(4, graph->zone()), 251 first_(NULL), 252 last_(NULL), 253 end_(NULL), 254 loop_information_(NULL), 255 predecessors_(2, graph->zone()), 256 dominator_(NULL), 257 dominated_blocks_(4, graph->zone()), 258 last_environment_(NULL), 259 argument_count_(-1), 260 first_instruction_index_(-1), 261 last_instruction_index_(-1), 262 deleted_phis_(4, graph->zone()), 263 parent_loop_header_(NULL), 264 inlined_entry_block_(NULL), 265 is_inline_return_target_(false), 266 is_reachable_(true), 267 dominates_loop_successors_(false), 268 is_osr_entry_(false), 269 is_ordered_(false) { } 270 271 272 Isolate* HBasicBlock::isolate() const { 273 return graph_->isolate(); 274 } 275 276 277 void HBasicBlock::MarkUnreachable() { 278 is_reachable_ = false; 279 } 280 281 282 void HBasicBlock::AttachLoopInformation() { 283 DCHECK(!IsLoopHeader()); 284 loop_information_ = new(zone()) HLoopInformation(this, zone()); 285 } 286 287 288 void HBasicBlock::DetachLoopInformation() { 289 DCHECK(IsLoopHeader()); 290 loop_information_ = NULL; 291 } 292 293 294 void HBasicBlock::AddPhi(HPhi* phi) { 295 DCHECK(!IsStartBlock()); 296 phis_.Add(phi, zone()); 297 phi->SetBlock(this); 298 } 299 300 301 void HBasicBlock::RemovePhi(HPhi* phi) { 302 DCHECK(phi->block() == this); 303 DCHECK(phis_.Contains(phi)); 304 phi->Kill(); 305 phis_.RemoveElement(phi); 306 phi->SetBlock(NULL); 307 } 308 309 310 void HBasicBlock::AddInstruction(HInstruction* instr, SourcePosition position) { 311 DCHECK(!IsStartBlock() || !IsFinished()); 312 DCHECK(!instr->IsLinked()); 313 DCHECK(!IsFinished()); 314 315 if (position.IsKnown()) { 316 instr->set_position(position); 317 } 318 if (first_ == NULL) { 319 DCHECK(last_environment() != NULL); 320 DCHECK(!last_environment()->ast_id().IsNone()); 321 HBlockEntry* entry = new(zone()) HBlockEntry(); 322 entry->InitializeAsFirst(this); 323 if (position.IsKnown()) { 324 entry->set_position(position); 325 } else { 326 DCHECK(!FLAG_hydrogen_track_positions || 327 !graph()->info()->IsOptimizing() || instr->IsAbnormalExit()); 328 } 329 first_ = last_ = entry; 330 } 331 instr->InsertAfter(last_); 332 } 333 334 335 HPhi* HBasicBlock::AddNewPhi(int merged_index) { 336 if (graph()->IsInsideNoSideEffectsScope()) { 337 merged_index = HPhi::kInvalidMergedIndex; 338 } 339 HPhi* phi = new(zone()) HPhi(merged_index, zone()); 340 AddPhi(phi); 341 return phi; 342 } 343 344 345 HSimulate* HBasicBlock::CreateSimulate(BailoutId ast_id, 346 RemovableSimulate removable) { 347 DCHECK(HasEnvironment()); 348 HEnvironment* environment = last_environment(); 349 DCHECK(ast_id.IsNone() || 350 ast_id == BailoutId::StubEntry() || 351 environment->closure()->shared()->VerifyBailoutId(ast_id)); 352 353 int push_count = environment->push_count(); 354 int pop_count = environment->pop_count(); 355 356 HSimulate* instr = 357 new(zone()) HSimulate(ast_id, pop_count, zone(), removable); 358 #ifdef DEBUG 359 instr->set_closure(environment->closure()); 360 #endif 361 // Order of pushed values: newest (top of stack) first. This allows 362 // HSimulate::MergeWith() to easily append additional pushed values 363 // that are older (from further down the stack). 364 for (int i = 0; i < push_count; ++i) { 365 instr->AddPushedValue(environment->ExpressionStackAt(i)); 366 } 367 for (GrowableBitVector::Iterator it(environment->assigned_variables(), 368 zone()); 369 !it.Done(); 370 it.Advance()) { 371 int index = it.Current(); 372 instr->AddAssignedValue(index, environment->Lookup(index)); 373 } 374 environment->ClearHistory(); 375 return instr; 376 } 377 378 379 void HBasicBlock::Finish(HControlInstruction* end, SourcePosition position) { 380 DCHECK(!IsFinished()); 381 AddInstruction(end, position); 382 end_ = end; 383 for (HSuccessorIterator it(end); !it.Done(); it.Advance()) { 384 it.Current()->RegisterPredecessor(this); 385 } 386 } 387 388 389 void HBasicBlock::Goto(HBasicBlock* block, SourcePosition position, 390 FunctionState* state, bool add_simulate) { 391 bool drop_extra = state != NULL && 392 state->inlining_kind() == NORMAL_RETURN; 393 394 if (block->IsInlineReturnTarget()) { 395 HEnvironment* env = last_environment(); 396 int argument_count = env->arguments_environment()->parameter_count(); 397 AddInstruction(new(zone()) 398 HLeaveInlined(state->entry(), argument_count), 399 position); 400 UpdateEnvironment(last_environment()->DiscardInlined(drop_extra)); 401 } 402 403 if (add_simulate) AddNewSimulate(BailoutId::None(), position); 404 HGoto* instr = new(zone()) HGoto(block); 405 Finish(instr, position); 406 } 407 408 409 void HBasicBlock::AddLeaveInlined(HValue* return_value, FunctionState* state, 410 SourcePosition position) { 411 HBasicBlock* target = state->function_return(); 412 bool drop_extra = state->inlining_kind() == NORMAL_RETURN; 413 414 DCHECK(target->IsInlineReturnTarget()); 415 DCHECK(return_value != NULL); 416 HEnvironment* env = last_environment(); 417 int argument_count = env->arguments_environment()->parameter_count(); 418 AddInstruction(new(zone()) HLeaveInlined(state->entry(), argument_count), 419 position); 420 UpdateEnvironment(last_environment()->DiscardInlined(drop_extra)); 421 last_environment()->Push(return_value); 422 AddNewSimulate(BailoutId::None(), position); 423 HGoto* instr = new(zone()) HGoto(target); 424 Finish(instr, position); 425 } 426 427 428 void HBasicBlock::SetInitialEnvironment(HEnvironment* env) { 429 DCHECK(!HasEnvironment()); 430 DCHECK(first() == NULL); 431 UpdateEnvironment(env); 432 } 433 434 435 void HBasicBlock::UpdateEnvironment(HEnvironment* env) { 436 last_environment_ = env; 437 graph()->update_maximum_environment_size(env->first_expression_index()); 438 } 439 440 441 void HBasicBlock::SetJoinId(BailoutId ast_id) { 442 int length = predecessors_.length(); 443 DCHECK(length > 0); 444 for (int i = 0; i < length; i++) { 445 HBasicBlock* predecessor = predecessors_[i]; 446 DCHECK(predecessor->end()->IsGoto()); 447 HSimulate* simulate = HSimulate::cast(predecessor->end()->previous()); 448 DCHECK(i != 0 || 449 (predecessor->last_environment()->closure().is_null() || 450 predecessor->last_environment()->closure()->shared() 451 ->VerifyBailoutId(ast_id))); 452 simulate->set_ast_id(ast_id); 453 predecessor->last_environment()->set_ast_id(ast_id); 454 } 455 } 456 457 458 bool HBasicBlock::Dominates(HBasicBlock* other) const { 459 HBasicBlock* current = other->dominator(); 460 while (current != NULL) { 461 if (current == this) return true; 462 current = current->dominator(); 463 } 464 return false; 465 } 466 467 468 bool HBasicBlock::EqualToOrDominates(HBasicBlock* other) const { 469 if (this == other) return true; 470 return Dominates(other); 471 } 472 473 474 int HBasicBlock::LoopNestingDepth() const { 475 const HBasicBlock* current = this; 476 int result = (current->IsLoopHeader()) ? 1 : 0; 477 while (current->parent_loop_header() != NULL) { 478 current = current->parent_loop_header(); 479 result++; 480 } 481 return result; 482 } 483 484 485 void HBasicBlock::PostProcessLoopHeader(IterationStatement* stmt) { 486 DCHECK(IsLoopHeader()); 487 488 SetJoinId(stmt->EntryId()); 489 if (predecessors()->length() == 1) { 490 // This is a degenerated loop. 491 DetachLoopInformation(); 492 return; 493 } 494 495 // Only the first entry into the loop is from outside the loop. All other 496 // entries must be back edges. 497 for (int i = 1; i < predecessors()->length(); ++i) { 498 loop_information()->RegisterBackEdge(predecessors()->at(i)); 499 } 500 } 501 502 503 void HBasicBlock::MarkSuccEdgeUnreachable(int succ) { 504 DCHECK(IsFinished()); 505 HBasicBlock* succ_block = end()->SuccessorAt(succ); 506 507 DCHECK(succ_block->predecessors()->length() == 1); 508 succ_block->MarkUnreachable(); 509 } 510 511 512 void HBasicBlock::RegisterPredecessor(HBasicBlock* pred) { 513 if (HasPredecessor()) { 514 // Only loop header blocks can have a predecessor added after 515 // instructions have been added to the block (they have phis for all 516 // values in the environment, these phis may be eliminated later). 517 DCHECK(IsLoopHeader() || first_ == NULL); 518 HEnvironment* incoming_env = pred->last_environment(); 519 if (IsLoopHeader()) { 520 DCHECK_EQ(phis()->length(), incoming_env->length()); 521 for (int i = 0; i < phis_.length(); ++i) { 522 phis_[i]->AddInput(incoming_env->values()->at(i)); 523 } 524 } else { 525 last_environment()->AddIncomingEdge(this, pred->last_environment()); 526 } 527 } else if (!HasEnvironment() && !IsFinished()) { 528 DCHECK(!IsLoopHeader()); 529 SetInitialEnvironment(pred->last_environment()->Copy()); 530 } 531 532 predecessors_.Add(pred, zone()); 533 } 534 535 536 void HBasicBlock::AddDominatedBlock(HBasicBlock* block) { 537 DCHECK(!dominated_blocks_.Contains(block)); 538 // Keep the list of dominated blocks sorted such that if there is two 539 // succeeding block in this list, the predecessor is before the successor. 540 int index = 0; 541 while (index < dominated_blocks_.length() && 542 dominated_blocks_[index]->block_id() < block->block_id()) { 543 ++index; 544 } 545 dominated_blocks_.InsertAt(index, block, zone()); 546 } 547 548 549 void HBasicBlock::AssignCommonDominator(HBasicBlock* other) { 550 if (dominator_ == NULL) { 551 dominator_ = other; 552 other->AddDominatedBlock(this); 553 } else if (other->dominator() != NULL) { 554 HBasicBlock* first = dominator_; 555 HBasicBlock* second = other; 556 557 while (first != second) { 558 if (first->block_id() > second->block_id()) { 559 first = first->dominator(); 560 } else { 561 second = second->dominator(); 562 } 563 DCHECK(first != NULL && second != NULL); 564 } 565 566 if (dominator_ != first) { 567 DCHECK(dominator_->dominated_blocks_.Contains(this)); 568 dominator_->dominated_blocks_.RemoveElement(this); 569 dominator_ = first; 570 first->AddDominatedBlock(this); 571 } 572 } 573 } 574 575 576 void HBasicBlock::AssignLoopSuccessorDominators() { 577 // Mark blocks that dominate all subsequent reachable blocks inside their 578 // loop. Exploit the fact that blocks are sorted in reverse post order. When 579 // the loop is visited in increasing block id order, if the number of 580 // non-loop-exiting successor edges at the dominator_candidate block doesn't 581 // exceed the number of previously encountered predecessor edges, there is no 582 // path from the loop header to any block with higher id that doesn't go 583 // through the dominator_candidate block. In this case, the 584 // dominator_candidate block is guaranteed to dominate all blocks reachable 585 // from it with higher ids. 586 HBasicBlock* last = loop_information()->GetLastBackEdge(); 587 int outstanding_successors = 1; // one edge from the pre-header 588 // Header always dominates everything. 589 MarkAsLoopSuccessorDominator(); 590 for (int j = block_id(); j <= last->block_id(); ++j) { 591 HBasicBlock* dominator_candidate = graph_->blocks()->at(j); 592 for (HPredecessorIterator it(dominator_candidate); !it.Done(); 593 it.Advance()) { 594 HBasicBlock* predecessor = it.Current(); 595 // Don't count back edges. 596 if (predecessor->block_id() < dominator_candidate->block_id()) { 597 outstanding_successors--; 598 } 599 } 600 601 // If more successors than predecessors have been seen in the loop up to 602 // now, it's not possible to guarantee that the current block dominates 603 // all of the blocks with higher IDs. In this case, assume conservatively 604 // that those paths through loop that don't go through the current block 605 // contain all of the loop's dependencies. Also be careful to record 606 // dominator information about the current loop that's being processed, 607 // and not nested loops, which will be processed when 608 // AssignLoopSuccessorDominators gets called on their header. 609 DCHECK(outstanding_successors >= 0); 610 HBasicBlock* parent_loop_header = dominator_candidate->parent_loop_header(); 611 if (outstanding_successors == 0 && 612 (parent_loop_header == this && !dominator_candidate->IsLoopHeader())) { 613 dominator_candidate->MarkAsLoopSuccessorDominator(); 614 } 615 HControlInstruction* end = dominator_candidate->end(); 616 for (HSuccessorIterator it(end); !it.Done(); it.Advance()) { 617 HBasicBlock* successor = it.Current(); 618 // Only count successors that remain inside the loop and don't loop back 619 // to a loop header. 620 if (successor->block_id() > dominator_candidate->block_id() && 621 successor->block_id() <= last->block_id()) { 622 // Backwards edges must land on loop headers. 623 DCHECK(successor->block_id() > dominator_candidate->block_id() || 624 successor->IsLoopHeader()); 625 outstanding_successors++; 626 } 627 } 628 } 629 } 630 631 632 int HBasicBlock::PredecessorIndexOf(HBasicBlock* predecessor) const { 633 for (int i = 0; i < predecessors_.length(); ++i) { 634 if (predecessors_[i] == predecessor) return i; 635 } 636 UNREACHABLE(); 637 return -1; 638 } 639 640 641 #ifdef DEBUG 642 void HBasicBlock::Verify() { 643 // Check that every block is finished. 644 DCHECK(IsFinished()); 645 DCHECK(block_id() >= 0); 646 647 // Check that the incoming edges are in edge split form. 648 if (predecessors_.length() > 1) { 649 for (int i = 0; i < predecessors_.length(); ++i) { 650 DCHECK(predecessors_[i]->end()->SecondSuccessor() == NULL); 651 } 652 } 653 } 654 #endif 655 656 657 void HLoopInformation::RegisterBackEdge(HBasicBlock* block) { 658 this->back_edges_.Add(block, block->zone()); 659 AddBlock(block); 660 } 661 662 663 HBasicBlock* HLoopInformation::GetLastBackEdge() const { 664 int max_id = -1; 665 HBasicBlock* result = NULL; 666 for (int i = 0; i < back_edges_.length(); ++i) { 667 HBasicBlock* cur = back_edges_[i]; 668 if (cur->block_id() > max_id) { 669 max_id = cur->block_id(); 670 result = cur; 671 } 672 } 673 return result; 674 } 675 676 677 void HLoopInformation::AddBlock(HBasicBlock* block) { 678 if (block == loop_header()) return; 679 if (block->parent_loop_header() == loop_header()) return; 680 if (block->parent_loop_header() != NULL) { 681 AddBlock(block->parent_loop_header()); 682 } else { 683 block->set_parent_loop_header(loop_header()); 684 blocks_.Add(block, block->zone()); 685 for (int i = 0; i < block->predecessors()->length(); ++i) { 686 AddBlock(block->predecessors()->at(i)); 687 } 688 } 689 } 690 691 692 #ifdef DEBUG 693 694 // Checks reachability of the blocks in this graph and stores a bit in 695 // the BitVector "reachable()" for every block that can be reached 696 // from the start block of the graph. If "dont_visit" is non-null, the given 697 // block is treated as if it would not be part of the graph. "visited_count()" 698 // returns the number of reachable blocks. 699 class ReachabilityAnalyzer BASE_EMBEDDED { 700 public: 701 ReachabilityAnalyzer(HBasicBlock* entry_block, 702 int block_count, 703 HBasicBlock* dont_visit) 704 : visited_count_(0), 705 stack_(16, entry_block->zone()), 706 reachable_(block_count, entry_block->zone()), 707 dont_visit_(dont_visit) { 708 PushBlock(entry_block); 709 Analyze(); 710 } 711 712 int visited_count() const { return visited_count_; } 713 const BitVector* reachable() const { return &reachable_; } 714 715 private: 716 void PushBlock(HBasicBlock* block) { 717 if (block != NULL && block != dont_visit_ && 718 !reachable_.Contains(block->block_id())) { 719 reachable_.Add(block->block_id()); 720 stack_.Add(block, block->zone()); 721 visited_count_++; 722 } 723 } 724 725 void Analyze() { 726 while (!stack_.is_empty()) { 727 HControlInstruction* end = stack_.RemoveLast()->end(); 728 for (HSuccessorIterator it(end); !it.Done(); it.Advance()) { 729 PushBlock(it.Current()); 730 } 731 } 732 } 733 734 int visited_count_; 735 ZoneList<HBasicBlock*> stack_; 736 BitVector reachable_; 737 HBasicBlock* dont_visit_; 738 }; 739 740 741 void HGraph::Verify(bool do_full_verify) const { 742 Heap::RelocationLock relocation_lock(isolate()->heap()); 743 AllowHandleDereference allow_deref; 744 AllowDeferredHandleDereference allow_deferred_deref; 745 for (int i = 0; i < blocks_.length(); i++) { 746 HBasicBlock* block = blocks_.at(i); 747 748 block->Verify(); 749 750 // Check that every block contains at least one node and that only the last 751 // node is a control instruction. 752 HInstruction* current = block->first(); 753 DCHECK(current != NULL && current->IsBlockEntry()); 754 while (current != NULL) { 755 DCHECK((current->next() == NULL) == current->IsControlInstruction()); 756 DCHECK(current->block() == block); 757 current->Verify(); 758 current = current->next(); 759 } 760 761 // Check that successors are correctly set. 762 HBasicBlock* first = block->end()->FirstSuccessor(); 763 HBasicBlock* second = block->end()->SecondSuccessor(); 764 DCHECK(second == NULL || first != NULL); 765 766 // Check that the predecessor array is correct. 767 if (first != NULL) { 768 DCHECK(first->predecessors()->Contains(block)); 769 if (second != NULL) { 770 DCHECK(second->predecessors()->Contains(block)); 771 } 772 } 773 774 // Check that phis have correct arguments. 775 for (int j = 0; j < block->phis()->length(); j++) { 776 HPhi* phi = block->phis()->at(j); 777 phi->Verify(); 778 } 779 780 // Check that all join blocks have predecessors that end with an 781 // unconditional goto and agree on their environment node id. 782 if (block->predecessors()->length() >= 2) { 783 BailoutId id = 784 block->predecessors()->first()->last_environment()->ast_id(); 785 for (int k = 0; k < block->predecessors()->length(); k++) { 786 HBasicBlock* predecessor = block->predecessors()->at(k); 787 DCHECK(predecessor->end()->IsGoto() || 788 predecessor->end()->IsDeoptimize()); 789 DCHECK(predecessor->last_environment()->ast_id() == id); 790 } 791 } 792 } 793 794 // Check special property of first block to have no predecessors. 795 DCHECK(blocks_.at(0)->predecessors()->is_empty()); 796 797 if (do_full_verify) { 798 // Check that the graph is fully connected. 799 ReachabilityAnalyzer analyzer(entry_block_, blocks_.length(), NULL); 800 DCHECK(analyzer.visited_count() == blocks_.length()); 801 802 // Check that entry block dominator is NULL. 803 DCHECK(entry_block_->dominator() == NULL); 804 805 // Check dominators. 806 for (int i = 0; i < blocks_.length(); ++i) { 807 HBasicBlock* block = blocks_.at(i); 808 if (block->dominator() == NULL) { 809 // Only start block may have no dominator assigned to. 810 DCHECK(i == 0); 811 } else { 812 // Assert that block is unreachable if dominator must not be visited. 813 ReachabilityAnalyzer dominator_analyzer(entry_block_, 814 blocks_.length(), 815 block->dominator()); 816 DCHECK(!dominator_analyzer.reachable()->Contains(block->block_id())); 817 } 818 } 819 } 820 } 821 822 #endif 823 824 825 HConstant* HGraph::GetConstant(SetOncePointer<HConstant>* pointer, 826 int32_t value) { 827 if (!pointer->is_set()) { 828 // Can't pass GetInvalidContext() to HConstant::New, because that will 829 // recursively call GetConstant 830 HConstant* constant = HConstant::New(isolate(), zone(), NULL, value); 831 constant->InsertAfter(entry_block()->first()); 832 pointer->set(constant); 833 return constant; 834 } 835 return ReinsertConstantIfNecessary(pointer->get()); 836 } 837 838 839 HConstant* HGraph::ReinsertConstantIfNecessary(HConstant* constant) { 840 if (!constant->IsLinked()) { 841 // The constant was removed from the graph. Reinsert. 842 constant->ClearFlag(HValue::kIsDead); 843 constant->InsertAfter(entry_block()->first()); 844 } 845 return constant; 846 } 847 848 849 HConstant* HGraph::GetConstant0() { 850 return GetConstant(&constant_0_, 0); 851 } 852 853 854 HConstant* HGraph::GetConstant1() { 855 return GetConstant(&constant_1_, 1); 856 } 857 858 859 HConstant* HGraph::GetConstantMinus1() { 860 return GetConstant(&constant_minus1_, -1); 861 } 862 863 864 HConstant* HGraph::GetConstantBool(bool value) { 865 return value ? GetConstantTrue() : GetConstantFalse(); 866 } 867 868 #define DEFINE_GET_CONSTANT(Name, name, constant, type, htype, boolean_value, \ 869 undetectable) \ 870 HConstant* HGraph::GetConstant##Name() { \ 871 if (!constant_##name##_.is_set()) { \ 872 HConstant* constant = new (zone()) HConstant( \ 873 Unique<Object>::CreateImmovable(isolate()->factory()->constant()), \ 874 Unique<Map>::CreateImmovable(isolate()->factory()->type##_map()), \ 875 false, Representation::Tagged(), htype, true, boolean_value, \ 876 undetectable, ODDBALL_TYPE); \ 877 constant->InsertAfter(entry_block()->first()); \ 878 constant_##name##_.set(constant); \ 879 } \ 880 return ReinsertConstantIfNecessary(constant_##name##_.get()); \ 881 } 882 883 DEFINE_GET_CONSTANT(Undefined, undefined, undefined_value, undefined, 884 HType::Undefined(), false, true) 885 DEFINE_GET_CONSTANT(True, true, true_value, boolean, HType::Boolean(), true, 886 false) 887 DEFINE_GET_CONSTANT(False, false, false_value, boolean, HType::Boolean(), false, 888 false) 889 DEFINE_GET_CONSTANT(Hole, the_hole, the_hole_value, the_hole, HType::None(), 890 false, false) 891 DEFINE_GET_CONSTANT(Null, null, null_value, null, HType::Null(), false, true) 892 DEFINE_GET_CONSTANT(OptimizedOut, optimized_out, optimized_out, optimized_out, 893 HType::None(), false, false) 894 895 #undef DEFINE_GET_CONSTANT 896 897 #define DEFINE_IS_CONSTANT(Name, name) \ 898 bool HGraph::IsConstant##Name(HConstant* constant) { \ 899 return constant_##name##_.is_set() && constant == constant_##name##_.get(); \ 900 } 901 DEFINE_IS_CONSTANT(Undefined, undefined) 902 DEFINE_IS_CONSTANT(0, 0) 903 DEFINE_IS_CONSTANT(1, 1) 904 DEFINE_IS_CONSTANT(Minus1, minus1) 905 DEFINE_IS_CONSTANT(True, true) 906 DEFINE_IS_CONSTANT(False, false) 907 DEFINE_IS_CONSTANT(Hole, the_hole) 908 DEFINE_IS_CONSTANT(Null, null) 909 910 #undef DEFINE_IS_CONSTANT 911 912 913 HConstant* HGraph::GetInvalidContext() { 914 return GetConstant(&constant_invalid_context_, 0xFFFFC0C7); 915 } 916 917 918 bool HGraph::IsStandardConstant(HConstant* constant) { 919 if (IsConstantUndefined(constant)) return true; 920 if (IsConstant0(constant)) return true; 921 if (IsConstant1(constant)) return true; 922 if (IsConstantMinus1(constant)) return true; 923 if (IsConstantTrue(constant)) return true; 924 if (IsConstantFalse(constant)) return true; 925 if (IsConstantHole(constant)) return true; 926 if (IsConstantNull(constant)) return true; 927 return false; 928 } 929 930 931 HGraphBuilder::IfBuilder::IfBuilder() : builder_(NULL), needs_compare_(true) {} 932 933 934 HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder) 935 : needs_compare_(true) { 936 Initialize(builder); 937 } 938 939 940 HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder, 941 HIfContinuation* continuation) 942 : needs_compare_(false), first_true_block_(NULL), first_false_block_(NULL) { 943 InitializeDontCreateBlocks(builder); 944 continuation->Continue(&first_true_block_, &first_false_block_); 945 } 946 947 948 void HGraphBuilder::IfBuilder::InitializeDontCreateBlocks( 949 HGraphBuilder* builder) { 950 builder_ = builder; 951 finished_ = false; 952 did_then_ = false; 953 did_else_ = false; 954 did_else_if_ = false; 955 did_and_ = false; 956 did_or_ = false; 957 captured_ = false; 958 pending_merge_block_ = false; 959 split_edge_merge_block_ = NULL; 960 merge_at_join_blocks_ = NULL; 961 normal_merge_at_join_block_count_ = 0; 962 deopt_merge_at_join_block_count_ = 0; 963 } 964 965 966 void HGraphBuilder::IfBuilder::Initialize(HGraphBuilder* builder) { 967 InitializeDontCreateBlocks(builder); 968 HEnvironment* env = builder->environment(); 969 first_true_block_ = builder->CreateBasicBlock(env->Copy()); 970 first_false_block_ = builder->CreateBasicBlock(env->Copy()); 971 } 972 973 974 HControlInstruction* HGraphBuilder::IfBuilder::AddCompare( 975 HControlInstruction* compare) { 976 DCHECK(did_then_ == did_else_); 977 if (did_else_) { 978 // Handle if-then-elseif 979 did_else_if_ = true; 980 did_else_ = false; 981 did_then_ = false; 982 did_and_ = false; 983 did_or_ = false; 984 pending_merge_block_ = false; 985 split_edge_merge_block_ = NULL; 986 HEnvironment* env = builder()->environment(); 987 first_true_block_ = builder()->CreateBasicBlock(env->Copy()); 988 first_false_block_ = builder()->CreateBasicBlock(env->Copy()); 989 } 990 if (split_edge_merge_block_ != NULL) { 991 HEnvironment* env = first_false_block_->last_environment(); 992 HBasicBlock* split_edge = builder()->CreateBasicBlock(env->Copy()); 993 if (did_or_) { 994 compare->SetSuccessorAt(0, split_edge); 995 compare->SetSuccessorAt(1, first_false_block_); 996 } else { 997 compare->SetSuccessorAt(0, first_true_block_); 998 compare->SetSuccessorAt(1, split_edge); 999 } 1000 builder()->GotoNoSimulate(split_edge, split_edge_merge_block_); 1001 } else { 1002 compare->SetSuccessorAt(0, first_true_block_); 1003 compare->SetSuccessorAt(1, first_false_block_); 1004 } 1005 builder()->FinishCurrentBlock(compare); 1006 needs_compare_ = false; 1007 return compare; 1008 } 1009 1010 1011 void HGraphBuilder::IfBuilder::Or() { 1012 DCHECK(!needs_compare_); 1013 DCHECK(!did_and_); 1014 did_or_ = true; 1015 HEnvironment* env = first_false_block_->last_environment(); 1016 if (split_edge_merge_block_ == NULL) { 1017 split_edge_merge_block_ = builder()->CreateBasicBlock(env->Copy()); 1018 builder()->GotoNoSimulate(first_true_block_, split_edge_merge_block_); 1019 first_true_block_ = split_edge_merge_block_; 1020 } 1021 builder()->set_current_block(first_false_block_); 1022 first_false_block_ = builder()->CreateBasicBlock(env->Copy()); 1023 } 1024 1025 1026 void HGraphBuilder::IfBuilder::And() { 1027 DCHECK(!needs_compare_); 1028 DCHECK(!did_or_); 1029 did_and_ = true; 1030 HEnvironment* env = first_false_block_->last_environment(); 1031 if (split_edge_merge_block_ == NULL) { 1032 split_edge_merge_block_ = builder()->CreateBasicBlock(env->Copy()); 1033 builder()->GotoNoSimulate(first_false_block_, split_edge_merge_block_); 1034 first_false_block_ = split_edge_merge_block_; 1035 } 1036 builder()->set_current_block(first_true_block_); 1037 first_true_block_ = builder()->CreateBasicBlock(env->Copy()); 1038 } 1039 1040 1041 void HGraphBuilder::IfBuilder::CaptureContinuation( 1042 HIfContinuation* continuation) { 1043 DCHECK(!did_else_if_); 1044 DCHECK(!finished_); 1045 DCHECK(!captured_); 1046 1047 HBasicBlock* true_block = NULL; 1048 HBasicBlock* false_block = NULL; 1049 Finish(&true_block, &false_block); 1050 DCHECK(true_block != NULL); 1051 DCHECK(false_block != NULL); 1052 continuation->Capture(true_block, false_block); 1053 captured_ = true; 1054 builder()->set_current_block(NULL); 1055 End(); 1056 } 1057 1058 1059 void HGraphBuilder::IfBuilder::JoinContinuation(HIfContinuation* continuation) { 1060 DCHECK(!did_else_if_); 1061 DCHECK(!finished_); 1062 DCHECK(!captured_); 1063 HBasicBlock* true_block = NULL; 1064 HBasicBlock* false_block = NULL; 1065 Finish(&true_block, &false_block); 1066 merge_at_join_blocks_ = NULL; 1067 if (true_block != NULL && !true_block->IsFinished()) { 1068 DCHECK(continuation->IsTrueReachable()); 1069 builder()->GotoNoSimulate(true_block, continuation->true_branch()); 1070 } 1071 if (false_block != NULL && !false_block->IsFinished()) { 1072 DCHECK(continuation->IsFalseReachable()); 1073 builder()->GotoNoSimulate(false_block, continuation->false_branch()); 1074 } 1075 captured_ = true; 1076 End(); 1077 } 1078 1079 1080 void HGraphBuilder::IfBuilder::Then() { 1081 DCHECK(!captured_); 1082 DCHECK(!finished_); 1083 did_then_ = true; 1084 if (needs_compare_) { 1085 // Handle if's without any expressions, they jump directly to the "else" 1086 // branch. However, we must pretend that the "then" branch is reachable, 1087 // so that the graph builder visits it and sees any live range extending 1088 // constructs within it. 1089 HConstant* constant_false = builder()->graph()->GetConstantFalse(); 1090 ToBooleanHints boolean_type = ToBooleanHint::kBoolean; 1091 HBranch* branch = builder()->New<HBranch>( 1092 constant_false, boolean_type, first_true_block_, first_false_block_); 1093 builder()->FinishCurrentBlock(branch); 1094 } 1095 builder()->set_current_block(first_true_block_); 1096 pending_merge_block_ = true; 1097 } 1098 1099 1100 void HGraphBuilder::IfBuilder::Else() { 1101 DCHECK(did_then_); 1102 DCHECK(!captured_); 1103 DCHECK(!finished_); 1104 AddMergeAtJoinBlock(false); 1105 builder()->set_current_block(first_false_block_); 1106 pending_merge_block_ = true; 1107 did_else_ = true; 1108 } 1109 1110 void HGraphBuilder::IfBuilder::Deopt(DeoptimizeReason reason) { 1111 DCHECK(did_then_); 1112 builder()->Add<HDeoptimize>(reason, Deoptimizer::EAGER); 1113 AddMergeAtJoinBlock(true); 1114 } 1115 1116 1117 void HGraphBuilder::IfBuilder::Return(HValue* value) { 1118 HValue* parameter_count = builder()->graph()->GetConstantMinus1(); 1119 builder()->FinishExitCurrentBlock( 1120 builder()->New<HReturn>(value, parameter_count)); 1121 AddMergeAtJoinBlock(false); 1122 } 1123 1124 1125 void HGraphBuilder::IfBuilder::AddMergeAtJoinBlock(bool deopt) { 1126 if (!pending_merge_block_) return; 1127 HBasicBlock* block = builder()->current_block(); 1128 DCHECK(block == NULL || !block->IsFinished()); 1129 MergeAtJoinBlock* record = new (builder()->zone()) 1130 MergeAtJoinBlock(block, deopt, merge_at_join_blocks_); 1131 merge_at_join_blocks_ = record; 1132 if (block != NULL) { 1133 DCHECK(block->end() == NULL); 1134 if (deopt) { 1135 normal_merge_at_join_block_count_++; 1136 } else { 1137 deopt_merge_at_join_block_count_++; 1138 } 1139 } 1140 builder()->set_current_block(NULL); 1141 pending_merge_block_ = false; 1142 } 1143 1144 1145 void HGraphBuilder::IfBuilder::Finish() { 1146 DCHECK(!finished_); 1147 if (!did_then_) { 1148 Then(); 1149 } 1150 AddMergeAtJoinBlock(false); 1151 if (!did_else_) { 1152 Else(); 1153 AddMergeAtJoinBlock(false); 1154 } 1155 finished_ = true; 1156 } 1157 1158 1159 void HGraphBuilder::IfBuilder::Finish(HBasicBlock** then_continuation, 1160 HBasicBlock** else_continuation) { 1161 Finish(); 1162 1163 MergeAtJoinBlock* else_record = merge_at_join_blocks_; 1164 if (else_continuation != NULL) { 1165 *else_continuation = else_record->block_; 1166 } 1167 MergeAtJoinBlock* then_record = else_record->next_; 1168 if (then_continuation != NULL) { 1169 *then_continuation = then_record->block_; 1170 } 1171 DCHECK(then_record->next_ == NULL); 1172 } 1173 1174 1175 void HGraphBuilder::IfBuilder::EndUnreachable() { 1176 if (captured_) return; 1177 Finish(); 1178 builder()->set_current_block(nullptr); 1179 } 1180 1181 1182 void HGraphBuilder::IfBuilder::End() { 1183 if (captured_) return; 1184 Finish(); 1185 1186 int total_merged_blocks = normal_merge_at_join_block_count_ + 1187 deopt_merge_at_join_block_count_; 1188 DCHECK(total_merged_blocks >= 1); 1189 HBasicBlock* merge_block = 1190 total_merged_blocks == 1 ? NULL : builder()->graph()->CreateBasicBlock(); 1191 1192 // Merge non-deopt blocks first to ensure environment has right size for 1193 // padding. 1194 MergeAtJoinBlock* current = merge_at_join_blocks_; 1195 while (current != NULL) { 1196 if (!current->deopt_ && current->block_ != NULL) { 1197 // If there is only one block that makes it through to the end of the 1198 // if, then just set it as the current block and continue rather then 1199 // creating an unnecessary merge block. 1200 if (total_merged_blocks == 1) { 1201 builder()->set_current_block(current->block_); 1202 return; 1203 } 1204 builder()->GotoNoSimulate(current->block_, merge_block); 1205 } 1206 current = current->next_; 1207 } 1208 1209 // Merge deopt blocks, padding when necessary. 1210 current = merge_at_join_blocks_; 1211 while (current != NULL) { 1212 if (current->deopt_ && current->block_ != NULL) { 1213 current->block_->FinishExit( 1214 HAbnormalExit::New(builder()->isolate(), builder()->zone(), NULL), 1215 SourcePosition::Unknown()); 1216 } 1217 current = current->next_; 1218 } 1219 builder()->set_current_block(merge_block); 1220 } 1221 1222 1223 HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder) { 1224 Initialize(builder, NULL, kWhileTrue, NULL); 1225 } 1226 1227 1228 HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder, HValue* context, 1229 LoopBuilder::Direction direction) { 1230 Initialize(builder, context, direction, builder->graph()->GetConstant1()); 1231 } 1232 1233 1234 HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder, HValue* context, 1235 LoopBuilder::Direction direction, 1236 HValue* increment_amount) { 1237 Initialize(builder, context, direction, increment_amount); 1238 increment_amount_ = increment_amount; 1239 } 1240 1241 1242 void HGraphBuilder::LoopBuilder::Initialize(HGraphBuilder* builder, 1243 HValue* context, 1244 Direction direction, 1245 HValue* increment_amount) { 1246 builder_ = builder; 1247 context_ = context; 1248 direction_ = direction; 1249 increment_amount_ = increment_amount; 1250 1251 finished_ = false; 1252 header_block_ = builder->CreateLoopHeaderBlock(); 1253 body_block_ = NULL; 1254 exit_block_ = NULL; 1255 exit_trampoline_block_ = NULL; 1256 } 1257 1258 1259 HValue* HGraphBuilder::LoopBuilder::BeginBody( 1260 HValue* initial, 1261 HValue* terminating, 1262 Token::Value token) { 1263 DCHECK(direction_ != kWhileTrue); 1264 HEnvironment* env = builder_->environment(); 1265 phi_ = header_block_->AddNewPhi(env->values()->length()); 1266 phi_->AddInput(initial); 1267 env->Push(initial); 1268 builder_->GotoNoSimulate(header_block_); 1269 1270 HEnvironment* body_env = env->Copy(); 1271 HEnvironment* exit_env = env->Copy(); 1272 // Remove the phi from the expression stack 1273 body_env->Pop(); 1274 exit_env->Pop(); 1275 body_block_ = builder_->CreateBasicBlock(body_env); 1276 exit_block_ = builder_->CreateBasicBlock(exit_env); 1277 1278 builder_->set_current_block(header_block_); 1279 env->Pop(); 1280 builder_->FinishCurrentBlock(builder_->New<HCompareNumericAndBranch>( 1281 phi_, terminating, token, body_block_, exit_block_)); 1282 1283 builder_->set_current_block(body_block_); 1284 if (direction_ == kPreIncrement || direction_ == kPreDecrement) { 1285 Isolate* isolate = builder_->isolate(); 1286 HValue* one = builder_->graph()->GetConstant1(); 1287 if (direction_ == kPreIncrement) { 1288 increment_ = HAdd::New(isolate, zone(), context_, phi_, one); 1289 } else { 1290 increment_ = HSub::New(isolate, zone(), context_, phi_, one); 1291 } 1292 increment_->ClearFlag(HValue::kCanOverflow); 1293 builder_->AddInstruction(increment_); 1294 return increment_; 1295 } else { 1296 return phi_; 1297 } 1298 } 1299 1300 1301 void HGraphBuilder::LoopBuilder::BeginBody(int drop_count) { 1302 DCHECK(direction_ == kWhileTrue); 1303 HEnvironment* env = builder_->environment(); 1304 builder_->GotoNoSimulate(header_block_); 1305 builder_->set_current_block(header_block_); 1306 env->Drop(drop_count); 1307 } 1308 1309 1310 void HGraphBuilder::LoopBuilder::Break() { 1311 if (exit_trampoline_block_ == NULL) { 1312 // Its the first time we saw a break. 1313 if (direction_ == kWhileTrue) { 1314 HEnvironment* env = builder_->environment()->Copy(); 1315 exit_trampoline_block_ = builder_->CreateBasicBlock(env); 1316 } else { 1317 HEnvironment* env = exit_block_->last_environment()->Copy(); 1318 exit_trampoline_block_ = builder_->CreateBasicBlock(env); 1319 builder_->GotoNoSimulate(exit_block_, exit_trampoline_block_); 1320 } 1321 } 1322 1323 builder_->GotoNoSimulate(exit_trampoline_block_); 1324 builder_->set_current_block(NULL); 1325 } 1326 1327 1328 void HGraphBuilder::LoopBuilder::EndBody() { 1329 DCHECK(!finished_); 1330 1331 if (direction_ == kPostIncrement || direction_ == kPostDecrement) { 1332 Isolate* isolate = builder_->isolate(); 1333 if (direction_ == kPostIncrement) { 1334 increment_ = 1335 HAdd::New(isolate, zone(), context_, phi_, increment_amount_); 1336 } else { 1337 increment_ = 1338 HSub::New(isolate, zone(), context_, phi_, increment_amount_); 1339 } 1340 increment_->ClearFlag(HValue::kCanOverflow); 1341 builder_->AddInstruction(increment_); 1342 } 1343 1344 if (direction_ != kWhileTrue) { 1345 // Push the new increment value on the expression stack to merge into 1346 // the phi. 1347 builder_->environment()->Push(increment_); 1348 } 1349 HBasicBlock* last_block = builder_->current_block(); 1350 builder_->GotoNoSimulate(last_block, header_block_); 1351 header_block_->loop_information()->RegisterBackEdge(last_block); 1352 1353 if (exit_trampoline_block_ != NULL) { 1354 builder_->set_current_block(exit_trampoline_block_); 1355 } else { 1356 builder_->set_current_block(exit_block_); 1357 } 1358 finished_ = true; 1359 } 1360 1361 1362 HGraph* HGraphBuilder::CreateGraph() { 1363 DCHECK(!FLAG_minimal); 1364 graph_ = new (zone()) HGraph(info_, descriptor_); 1365 if (FLAG_hydrogen_stats) isolate()->GetHStatistics()->Initialize(info_); 1366 if (!info_->IsStub() && is_tracking_positions()) { 1367 TraceInlinedFunction(info_->shared_info(), SourcePosition::Unknown(), 1368 SourcePosition::kNotInlined); 1369 } 1370 CompilationPhase phase("H_Block building", info_); 1371 set_current_block(graph()->entry_block()); 1372 if (!BuildGraph()) return NULL; 1373 graph()->FinalizeUniqueness(); 1374 return graph_; 1375 } 1376 1377 void HGraphBuilder::TraceInlinedFunction(Handle<SharedFunctionInfo> shared, 1378 SourcePosition position, 1379 int inlining_id) { 1380 DCHECK(is_tracking_positions()); 1381 1382 if (!shared->script()->IsUndefined(isolate())) { 1383 Handle<Script> script(Script::cast(shared->script()), isolate()); 1384 1385 if (FLAG_hydrogen_track_positions && 1386 !script->source()->IsUndefined(isolate())) { 1387 CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer()); 1388 Object* source_name = script->name(); 1389 OFStream os(tracing_scope.file()); 1390 os << "--- FUNCTION SOURCE ("; 1391 if (source_name->IsString()) { 1392 os << String::cast(source_name)->ToCString().get() << ":"; 1393 } 1394 os << shared->DebugName()->ToCString().get() << ") id{"; 1395 os << info_->optimization_id() << "," << inlining_id << "} ---\n"; 1396 { 1397 DisallowHeapAllocation no_allocation; 1398 int start = shared->start_position(); 1399 int len = shared->end_position() - start; 1400 String::SubStringRange source(String::cast(script->source()), start, 1401 len); 1402 for (const auto& c : source) { 1403 os << AsReversiblyEscapedUC16(c); 1404 } 1405 } 1406 1407 os << "\n--- END ---\n"; 1408 } 1409 } 1410 1411 if (FLAG_hydrogen_track_positions && 1412 inlining_id != SourcePosition::kNotInlined) { 1413 CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer()); 1414 OFStream os(tracing_scope.file()); 1415 os << "INLINE (" << shared->DebugName()->ToCString().get() << ") id{" 1416 << info_->optimization_id() << "," << inlining_id << "} AS " 1417 << inlining_id << " AT " << position.ScriptOffset() << std::endl; 1418 } 1419 } 1420 1421 HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) { 1422 DCHECK(current_block() != NULL); 1423 DCHECK(!FLAG_hydrogen_track_positions || position_.IsKnown() || 1424 !info_->IsOptimizing()); 1425 current_block()->AddInstruction(instr, source_position()); 1426 if (graph()->IsInsideNoSideEffectsScope()) { 1427 instr->SetFlag(HValue::kHasNoObservableSideEffects); 1428 } 1429 return instr; 1430 } 1431 1432 1433 void HGraphBuilder::FinishCurrentBlock(HControlInstruction* last) { 1434 DCHECK(!FLAG_hydrogen_track_positions || !info_->IsOptimizing() || 1435 position_.IsKnown()); 1436 current_block()->Finish(last, source_position()); 1437 if (last->IsReturn() || last->IsAbnormalExit()) { 1438 set_current_block(NULL); 1439 } 1440 } 1441 1442 1443 void HGraphBuilder::FinishExitCurrentBlock(HControlInstruction* instruction) { 1444 DCHECK(!FLAG_hydrogen_track_positions || !info_->IsOptimizing() || 1445 position_.IsKnown()); 1446 current_block()->FinishExit(instruction, source_position()); 1447 if (instruction->IsReturn() || instruction->IsAbnormalExit()) { 1448 set_current_block(NULL); 1449 } 1450 } 1451 1452 1453 void HGraphBuilder::AddIncrementCounter(StatsCounter* counter) { 1454 if (FLAG_native_code_counters && counter->Enabled()) { 1455 HValue* reference = Add<HConstant>(ExternalReference(counter)); 1456 HValue* old_value = 1457 Add<HLoadNamedField>(reference, nullptr, HObjectAccess::ForCounter()); 1458 HValue* new_value = AddUncasted<HAdd>(old_value, graph()->GetConstant1()); 1459 new_value->ClearFlag(HValue::kCanOverflow); // Ignore counter overflow 1460 Add<HStoreNamedField>(reference, HObjectAccess::ForCounter(), 1461 new_value, STORE_TO_INITIALIZED_ENTRY); 1462 } 1463 } 1464 1465 1466 void HGraphBuilder::AddSimulate(BailoutId id, 1467 RemovableSimulate removable) { 1468 DCHECK(current_block() != NULL); 1469 DCHECK(!graph()->IsInsideNoSideEffectsScope()); 1470 current_block()->AddNewSimulate(id, source_position(), removable); 1471 } 1472 1473 1474 HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) { 1475 HBasicBlock* b = graph()->CreateBasicBlock(); 1476 b->SetInitialEnvironment(env); 1477 return b; 1478 } 1479 1480 1481 HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() { 1482 HBasicBlock* header = graph()->CreateBasicBlock(); 1483 HEnvironment* entry_env = environment()->CopyAsLoopHeader(header); 1484 header->SetInitialEnvironment(entry_env); 1485 header->AttachLoopInformation(); 1486 return header; 1487 } 1488 1489 1490 HValue* HGraphBuilder::BuildGetElementsKind(HValue* object) { 1491 HValue* map = Add<HLoadNamedField>(object, nullptr, HObjectAccess::ForMap()); 1492 1493 HValue* bit_field2 = 1494 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField2()); 1495 return BuildDecodeField<Map::ElementsKindBits>(bit_field2); 1496 } 1497 1498 1499 HValue* HGraphBuilder::BuildEnumLength(HValue* map) { 1500 NoObservableSideEffectsScope scope(this); 1501 HValue* bit_field3 = 1502 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField3()); 1503 return BuildDecodeField<Map::EnumLengthBits>(bit_field3); 1504 } 1505 1506 1507 HValue* HGraphBuilder::BuildCheckHeapObject(HValue* obj) { 1508 if (obj->type().IsHeapObject()) return obj; 1509 return Add<HCheckHeapObject>(obj); 1510 } 1511 1512 void HGraphBuilder::FinishExitWithHardDeoptimization(DeoptimizeReason reason) { 1513 Add<HDeoptimize>(reason, Deoptimizer::EAGER); 1514 FinishExitCurrentBlock(New<HAbnormalExit>()); 1515 } 1516 1517 1518 HValue* HGraphBuilder::BuildCheckString(HValue* string) { 1519 if (!string->type().IsString()) { 1520 DCHECK(!string->IsConstant() || 1521 !HConstant::cast(string)->HasStringValue()); 1522 BuildCheckHeapObject(string); 1523 return Add<HCheckInstanceType>(string, HCheckInstanceType::IS_STRING); 1524 } 1525 return string; 1526 } 1527 1528 HValue* HGraphBuilder::BuildWrapReceiver(HValue* object, HValue* checked) { 1529 if (object->type().IsJSObject()) return object; 1530 HValue* function = checked->ActualValue(); 1531 if (function->IsConstant() && 1532 HConstant::cast(function)->handle(isolate())->IsJSFunction()) { 1533 Handle<JSFunction> f = Handle<JSFunction>::cast( 1534 HConstant::cast(function)->handle(isolate())); 1535 SharedFunctionInfo* shared = f->shared(); 1536 if (is_strict(shared->language_mode()) || shared->native()) return object; 1537 } 1538 return Add<HWrapReceiver>(object, checked); 1539 } 1540 1541 1542 HValue* HGraphBuilder::BuildCheckAndGrowElementsCapacity( 1543 HValue* object, HValue* elements, ElementsKind kind, HValue* length, 1544 HValue* capacity, HValue* key) { 1545 HValue* max_gap = Add<HConstant>(static_cast<int32_t>(JSObject::kMaxGap)); 1546 HValue* max_capacity = AddUncasted<HAdd>(capacity, max_gap); 1547 Add<HBoundsCheck>(key, max_capacity); 1548 1549 HValue* new_capacity = BuildNewElementsCapacity(key); 1550 HValue* new_elements = BuildGrowElementsCapacity(object, elements, kind, kind, 1551 length, new_capacity); 1552 return new_elements; 1553 } 1554 1555 1556 HValue* HGraphBuilder::BuildCheckForCapacityGrow( 1557 HValue* object, 1558 HValue* elements, 1559 ElementsKind kind, 1560 HValue* length, 1561 HValue* key, 1562 bool is_js_array, 1563 PropertyAccessType access_type) { 1564 IfBuilder length_checker(this); 1565 1566 Token::Value token = IsHoleyElementsKind(kind) ? Token::GTE : Token::EQ; 1567 length_checker.If<HCompareNumericAndBranch>(key, length, token); 1568 1569 length_checker.Then(); 1570 1571 HValue* current_capacity = AddLoadFixedArrayLength(elements); 1572 1573 if (top_info()->IsStub()) { 1574 IfBuilder capacity_checker(this); 1575 capacity_checker.If<HCompareNumericAndBranch>(key, current_capacity, 1576 Token::GTE); 1577 capacity_checker.Then(); 1578 HValue* new_elements = BuildCheckAndGrowElementsCapacity( 1579 object, elements, kind, length, current_capacity, key); 1580 environment()->Push(new_elements); 1581 capacity_checker.Else(); 1582 environment()->Push(elements); 1583 capacity_checker.End(); 1584 } else { 1585 HValue* result = Add<HMaybeGrowElements>( 1586 object, elements, key, current_capacity, is_js_array, kind); 1587 environment()->Push(result); 1588 } 1589 1590 if (is_js_array) { 1591 HValue* new_length = AddUncasted<HAdd>(key, graph_->GetConstant1()); 1592 new_length->ClearFlag(HValue::kCanOverflow); 1593 1594 Add<HStoreNamedField>(object, HObjectAccess::ForArrayLength(kind), 1595 new_length); 1596 } 1597 1598 if (access_type == STORE && kind == FAST_SMI_ELEMENTS) { 1599 HValue* checked_elements = environment()->Top(); 1600 1601 // Write zero to ensure that the new element is initialized with some smi. 1602 Add<HStoreKeyed>(checked_elements, key, graph()->GetConstant0(), nullptr, 1603 kind); 1604 } 1605 1606 length_checker.Else(); 1607 Add<HBoundsCheck>(key, length); 1608 1609 environment()->Push(elements); 1610 length_checker.End(); 1611 1612 return environment()->Pop(); 1613 } 1614 1615 1616 HValue* HGraphBuilder::BuildCopyElementsOnWrite(HValue* object, 1617 HValue* elements, 1618 ElementsKind kind, 1619 HValue* length) { 1620 Factory* factory = isolate()->factory(); 1621 1622 IfBuilder cow_checker(this); 1623 1624 cow_checker.If<HCompareMap>(elements, factory->fixed_cow_array_map()); 1625 cow_checker.Then(); 1626 1627 HValue* capacity = AddLoadFixedArrayLength(elements); 1628 1629 HValue* new_elements = BuildGrowElementsCapacity(object, elements, kind, 1630 kind, length, capacity); 1631 1632 environment()->Push(new_elements); 1633 1634 cow_checker.Else(); 1635 1636 environment()->Push(elements); 1637 1638 cow_checker.End(); 1639 1640 return environment()->Pop(); 1641 } 1642 1643 HValue* HGraphBuilder::BuildElementIndexHash(HValue* index) { 1644 int32_t seed_value = static_cast<uint32_t>(isolate()->heap()->HashSeed()); 1645 HValue* seed = Add<HConstant>(seed_value); 1646 HValue* hash = AddUncasted<HBitwise>(Token::BIT_XOR, index, seed); 1647 1648 // hash = ~hash + (hash << 15); 1649 HValue* shifted_hash = AddUncasted<HShl>(hash, Add<HConstant>(15)); 1650 HValue* not_hash = AddUncasted<HBitwise>(Token::BIT_XOR, hash, 1651 graph()->GetConstantMinus1()); 1652 hash = AddUncasted<HAdd>(shifted_hash, not_hash); 1653 1654 // hash = hash ^ (hash >> 12); 1655 shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(12)); 1656 hash = AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash); 1657 1658 // hash = hash + (hash << 2); 1659 shifted_hash = AddUncasted<HShl>(hash, Add<HConstant>(2)); 1660 hash = AddUncasted<HAdd>(hash, shifted_hash); 1661 1662 // hash = hash ^ (hash >> 4); 1663 shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(4)); 1664 hash = AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash); 1665 1666 // hash = hash * 2057; 1667 hash = AddUncasted<HMul>(hash, Add<HConstant>(2057)); 1668 hash->ClearFlag(HValue::kCanOverflow); 1669 1670 // hash = hash ^ (hash >> 16); 1671 shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(16)); 1672 return AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash); 1673 } 1674 1675 HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoad(HValue* receiver, 1676 HValue* elements, 1677 HValue* key, 1678 HValue* hash) { 1679 HValue* capacity = 1680 Add<HLoadKeyed>(elements, Add<HConstant>(NameDictionary::kCapacityIndex), 1681 nullptr, nullptr, FAST_ELEMENTS); 1682 1683 HValue* mask = AddUncasted<HSub>(capacity, graph()->GetConstant1()); 1684 mask->ChangeRepresentation(Representation::Integer32()); 1685 mask->ClearFlag(HValue::kCanOverflow); 1686 1687 HValue* entry = hash; 1688 HValue* count = graph()->GetConstant1(); 1689 Push(entry); 1690 Push(count); 1691 1692 HIfContinuation return_or_loop_continuation(graph()->CreateBasicBlock(), 1693 graph()->CreateBasicBlock()); 1694 HIfContinuation found_key_match_continuation(graph()->CreateBasicBlock(), 1695 graph()->CreateBasicBlock()); 1696 LoopBuilder probe_loop(this); 1697 probe_loop.BeginBody(2); // Drop entry, count from last environment to 1698 // appease live range building without simulates. 1699 1700 count = Pop(); 1701 entry = Pop(); 1702 entry = AddUncasted<HBitwise>(Token::BIT_AND, entry, mask); 1703 int entry_size = SeededNumberDictionary::kEntrySize; 1704 HValue* base_index = AddUncasted<HMul>(entry, Add<HConstant>(entry_size)); 1705 base_index->ClearFlag(HValue::kCanOverflow); 1706 int start_offset = SeededNumberDictionary::kElementsStartIndex; 1707 HValue* key_index = 1708 AddUncasted<HAdd>(base_index, Add<HConstant>(start_offset)); 1709 key_index->ClearFlag(HValue::kCanOverflow); 1710 1711 HValue* candidate_key = 1712 Add<HLoadKeyed>(elements, key_index, nullptr, nullptr, FAST_ELEMENTS); 1713 IfBuilder if_undefined(this); 1714 if_undefined.If<HCompareObjectEqAndBranch>(candidate_key, 1715 graph()->GetConstantUndefined()); 1716 if_undefined.Then(); 1717 { 1718 // element == undefined means "not found". Call the runtime. 1719 // TODO(jkummerow): walk the prototype chain instead. 1720 Add<HPushArguments>(receiver, key); 1721 Push(Add<HCallRuntime>(Runtime::FunctionForId(Runtime::kKeyedGetProperty), 1722 2)); 1723 } 1724 if_undefined.Else(); 1725 { 1726 IfBuilder if_match(this); 1727 if_match.If<HCompareObjectEqAndBranch>(candidate_key, key); 1728 if_match.Then(); 1729 if_match.Else(); 1730 1731 // Update non-internalized string in the dictionary with internalized key? 1732 IfBuilder if_update_with_internalized(this); 1733 HValue* smi_check = 1734 if_update_with_internalized.IfNot<HIsSmiAndBranch>(candidate_key); 1735 if_update_with_internalized.And(); 1736 HValue* map = AddLoadMap(candidate_key, smi_check); 1737 HValue* instance_type = 1738 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapInstanceType()); 1739 HValue* not_internalized_bit = AddUncasted<HBitwise>( 1740 Token::BIT_AND, instance_type, 1741 Add<HConstant>(static_cast<int>(kIsNotInternalizedMask))); 1742 if_update_with_internalized.If<HCompareNumericAndBranch>( 1743 not_internalized_bit, graph()->GetConstant0(), Token::NE); 1744 if_update_with_internalized.And(); 1745 if_update_with_internalized.IfNot<HCompareObjectEqAndBranch>( 1746 candidate_key, graph()->GetConstantHole()); 1747 if_update_with_internalized.AndIf<HStringCompareAndBranch>(candidate_key, 1748 key, Token::EQ); 1749 if_update_with_internalized.Then(); 1750 // Replace a key that is a non-internalized string by the equivalent 1751 // internalized string for faster further lookups. 1752 Add<HStoreKeyed>(elements, key_index, key, nullptr, FAST_ELEMENTS); 1753 if_update_with_internalized.Else(); 1754 1755 if_update_with_internalized.JoinContinuation(&found_key_match_continuation); 1756 if_match.JoinContinuation(&found_key_match_continuation); 1757 1758 IfBuilder found_key_match(this, &found_key_match_continuation); 1759 found_key_match.Then(); 1760 // Key at current probe matches. Relevant bits in the |details| field must 1761 // be zero, otherwise the dictionary element requires special handling. 1762 HValue* details_index = 1763 AddUncasted<HAdd>(base_index, Add<HConstant>(start_offset + 2)); 1764 details_index->ClearFlag(HValue::kCanOverflow); 1765 HValue* details = Add<HLoadKeyed>(elements, details_index, nullptr, nullptr, 1766 FAST_ELEMENTS); 1767 int details_mask = PropertyDetails::TypeField::kMask; 1768 details = AddUncasted<HBitwise>(Token::BIT_AND, details, 1769 Add<HConstant>(details_mask)); 1770 IfBuilder details_compare(this); 1771 details_compare.If<HCompareNumericAndBranch>( 1772 details, graph()->GetConstant0(), Token::EQ); 1773 details_compare.Then(); 1774 HValue* result_index = 1775 AddUncasted<HAdd>(base_index, Add<HConstant>(start_offset + 1)); 1776 result_index->ClearFlag(HValue::kCanOverflow); 1777 Push(Add<HLoadKeyed>(elements, result_index, nullptr, nullptr, 1778 FAST_ELEMENTS)); 1779 details_compare.Else(); 1780 Add<HPushArguments>(receiver, key); 1781 Push(Add<HCallRuntime>(Runtime::FunctionForId(Runtime::kKeyedGetProperty), 1782 2)); 1783 details_compare.End(); 1784 1785 found_key_match.Else(); 1786 found_key_match.JoinContinuation(&return_or_loop_continuation); 1787 } 1788 if_undefined.JoinContinuation(&return_or_loop_continuation); 1789 1790 IfBuilder return_or_loop(this, &return_or_loop_continuation); 1791 return_or_loop.Then(); 1792 probe_loop.Break(); 1793 1794 return_or_loop.Else(); 1795 entry = AddUncasted<HAdd>(entry, count); 1796 entry->ClearFlag(HValue::kCanOverflow); 1797 count = AddUncasted<HAdd>(count, graph()->GetConstant1()); 1798 count->ClearFlag(HValue::kCanOverflow); 1799 Push(entry); 1800 Push(count); 1801 1802 probe_loop.EndBody(); 1803 1804 return_or_loop.End(); 1805 1806 return Pop(); 1807 } 1808 1809 HValue* HGraphBuilder::BuildCreateIterResultObject(HValue* value, 1810 HValue* done) { 1811 NoObservableSideEffectsScope scope(this); 1812 1813 // Allocate the JSIteratorResult object. 1814 HValue* result = 1815 Add<HAllocate>(Add<HConstant>(JSIteratorResult::kSize), HType::JSObject(), 1816 NOT_TENURED, JS_OBJECT_TYPE, graph()->GetConstant0()); 1817 1818 // Initialize the JSIteratorResult object. 1819 HValue* native_context = BuildGetNativeContext(); 1820 HValue* map = Add<HLoadNamedField>( 1821 native_context, nullptr, 1822 HObjectAccess::ForContextSlot(Context::ITERATOR_RESULT_MAP_INDEX)); 1823 Add<HStoreNamedField>(result, HObjectAccess::ForMap(), map); 1824 HValue* empty_fixed_array = Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex); 1825 Add<HStoreNamedField>(result, HObjectAccess::ForPropertiesPointer(), 1826 empty_fixed_array); 1827 Add<HStoreNamedField>(result, HObjectAccess::ForElementsPointer(), 1828 empty_fixed_array); 1829 Add<HStoreNamedField>(result, HObjectAccess::ForObservableJSObjectOffset( 1830 JSIteratorResult::kValueOffset), 1831 value); 1832 Add<HStoreNamedField>(result, HObjectAccess::ForObservableJSObjectOffset( 1833 JSIteratorResult::kDoneOffset), 1834 done); 1835 STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize); 1836 return result; 1837 } 1838 1839 1840 HValue* HGraphBuilder::BuildNumberToString(HValue* object, AstType* type) { 1841 NoObservableSideEffectsScope scope(this); 1842 1843 // Convert constant numbers at compile time. 1844 if (object->IsConstant() && HConstant::cast(object)->HasNumberValue()) { 1845 Handle<Object> number = HConstant::cast(object)->handle(isolate()); 1846 Handle<String> result = isolate()->factory()->NumberToString(number); 1847 return Add<HConstant>(result); 1848 } 1849 1850 // Create a joinable continuation. 1851 HIfContinuation found(graph()->CreateBasicBlock(), 1852 graph()->CreateBasicBlock()); 1853 1854 // Load the number string cache. 1855 HValue* number_string_cache = 1856 Add<HLoadRoot>(Heap::kNumberStringCacheRootIndex); 1857 1858 // Make the hash mask from the length of the number string cache. It 1859 // contains two elements (number and string) for each cache entry. 1860 HValue* mask = AddLoadFixedArrayLength(number_string_cache); 1861 mask->set_type(HType::Smi()); 1862 mask = AddUncasted<HSar>(mask, graph()->GetConstant1()); 1863 mask = AddUncasted<HSub>(mask, graph()->GetConstant1()); 1864 1865 // Check whether object is a smi. 1866 IfBuilder if_objectissmi(this); 1867 if_objectissmi.If<HIsSmiAndBranch>(object); 1868 if_objectissmi.Then(); 1869 { 1870 // Compute hash for smi similar to smi_get_hash(). 1871 HValue* hash = AddUncasted<HBitwise>(Token::BIT_AND, object, mask); 1872 1873 // Load the key. 1874 HValue* key_index = AddUncasted<HShl>(hash, graph()->GetConstant1()); 1875 HValue* key = Add<HLoadKeyed>(number_string_cache, key_index, nullptr, 1876 nullptr, FAST_ELEMENTS, ALLOW_RETURN_HOLE); 1877 1878 // Check if object == key. 1879 IfBuilder if_objectiskey(this); 1880 if_objectiskey.If<HCompareObjectEqAndBranch>(object, key); 1881 if_objectiskey.Then(); 1882 { 1883 // Make the key_index available. 1884 Push(key_index); 1885 } 1886 if_objectiskey.JoinContinuation(&found); 1887 } 1888 if_objectissmi.Else(); 1889 { 1890 if (type->Is(AstType::SignedSmall())) { 1891 if_objectissmi.Deopt(DeoptimizeReason::kExpectedSmi); 1892 } else { 1893 // Check if the object is a heap number. 1894 IfBuilder if_objectisnumber(this); 1895 HValue* objectisnumber = if_objectisnumber.If<HCompareMap>( 1896 object, isolate()->factory()->heap_number_map()); 1897 if_objectisnumber.Then(); 1898 { 1899 // Compute hash for heap number similar to double_get_hash(). 1900 HValue* low = Add<HLoadNamedField>( 1901 object, objectisnumber, 1902 HObjectAccess::ForHeapNumberValueLowestBits()); 1903 HValue* high = Add<HLoadNamedField>( 1904 object, objectisnumber, 1905 HObjectAccess::ForHeapNumberValueHighestBits()); 1906 HValue* hash = AddUncasted<HBitwise>(Token::BIT_XOR, low, high); 1907 hash = AddUncasted<HBitwise>(Token::BIT_AND, hash, mask); 1908 1909 // Load the key. 1910 HValue* key_index = AddUncasted<HShl>(hash, graph()->GetConstant1()); 1911 HValue* key = 1912 Add<HLoadKeyed>(number_string_cache, key_index, nullptr, nullptr, 1913 FAST_ELEMENTS, ALLOW_RETURN_HOLE); 1914 1915 // Check if the key is a heap number and compare it with the object. 1916 IfBuilder if_keyisnotsmi(this); 1917 HValue* keyisnotsmi = if_keyisnotsmi.IfNot<HIsSmiAndBranch>(key); 1918 if_keyisnotsmi.Then(); 1919 { 1920 IfBuilder if_keyisheapnumber(this); 1921 if_keyisheapnumber.If<HCompareMap>( 1922 key, isolate()->factory()->heap_number_map()); 1923 if_keyisheapnumber.Then(); 1924 { 1925 // Check if values of key and object match. 1926 IfBuilder if_keyeqobject(this); 1927 if_keyeqobject.If<HCompareNumericAndBranch>( 1928 Add<HLoadNamedField>(key, keyisnotsmi, 1929 HObjectAccess::ForHeapNumberValue()), 1930 Add<HLoadNamedField>(object, objectisnumber, 1931 HObjectAccess::ForHeapNumberValue()), 1932 Token::EQ); 1933 if_keyeqobject.Then(); 1934 { 1935 // Make the key_index available. 1936 Push(key_index); 1937 } 1938 if_keyeqobject.JoinContinuation(&found); 1939 } 1940 if_keyisheapnumber.JoinContinuation(&found); 1941 } 1942 if_keyisnotsmi.JoinContinuation(&found); 1943 } 1944 if_objectisnumber.Else(); 1945 { 1946 if (type->Is(AstType::Number())) { 1947 if_objectisnumber.Deopt(DeoptimizeReason::kExpectedHeapNumber); 1948 } 1949 } 1950 if_objectisnumber.JoinContinuation(&found); 1951 } 1952 } 1953 if_objectissmi.JoinContinuation(&found); 1954 1955 // Check for cache hit. 1956 IfBuilder if_found(this, &found); 1957 if_found.Then(); 1958 { 1959 // Count number to string operation in native code. 1960 AddIncrementCounter(isolate()->counters()->number_to_string_native()); 1961 1962 // Load the value in case of cache hit. 1963 HValue* key_index = Pop(); 1964 HValue* value_index = AddUncasted<HAdd>(key_index, graph()->GetConstant1()); 1965 Push(Add<HLoadKeyed>(number_string_cache, value_index, nullptr, nullptr, 1966 FAST_ELEMENTS, ALLOW_RETURN_HOLE)); 1967 } 1968 if_found.Else(); 1969 { 1970 // Cache miss, fallback to runtime. 1971 Add<HPushArguments>(object); 1972 Push(Add<HCallRuntime>( 1973 Runtime::FunctionForId(Runtime::kNumberToStringSkipCache), 1974 1)); 1975 } 1976 if_found.End(); 1977 1978 return Pop(); 1979 } 1980 1981 HValue* HGraphBuilder::BuildToNumber(HValue* input) { 1982 if (input->type().IsTaggedNumber() || 1983 input->representation().IsSpecialization()) { 1984 return input; 1985 } 1986 Callable callable = CodeFactory::ToNumber(isolate()); 1987 HValue* stub = Add<HConstant>(callable.code()); 1988 HValue* values[] = {input}; 1989 HCallWithDescriptor* instr = Add<HCallWithDescriptor>( 1990 stub, 0, callable.descriptor(), ArrayVector(values)); 1991 instr->set_type(HType::TaggedNumber()); 1992 return instr; 1993 } 1994 1995 1996 HValue* HGraphBuilder::BuildToObject(HValue* receiver) { 1997 NoObservableSideEffectsScope scope(this); 1998 1999 // Create a joinable continuation. 2000 HIfContinuation wrap(graph()->CreateBasicBlock(), 2001 graph()->CreateBasicBlock()); 2002 2003 // Determine the proper global constructor function required to wrap 2004 // {receiver} into a JSValue, unless {receiver} is already a {JSReceiver}, in 2005 // which case we just return it. Deopts to Runtime::kToObject if {receiver} 2006 // is undefined or null. 2007 IfBuilder receiver_is_smi(this); 2008 receiver_is_smi.If<HIsSmiAndBranch>(receiver); 2009 receiver_is_smi.Then(); 2010 { 2011 // Use global Number function. 2012 Push(Add<HConstant>(Context::NUMBER_FUNCTION_INDEX)); 2013 } 2014 receiver_is_smi.Else(); 2015 { 2016 // Determine {receiver} map and instance type. 2017 HValue* receiver_map = 2018 Add<HLoadNamedField>(receiver, nullptr, HObjectAccess::ForMap()); 2019 HValue* receiver_instance_type = Add<HLoadNamedField>( 2020 receiver_map, nullptr, HObjectAccess::ForMapInstanceType()); 2021 2022 // First check whether {receiver} is already a spec object (fast case). 2023 IfBuilder receiver_is_not_spec_object(this); 2024 receiver_is_not_spec_object.If<HCompareNumericAndBranch>( 2025 receiver_instance_type, Add<HConstant>(FIRST_JS_RECEIVER_TYPE), 2026 Token::LT); 2027 receiver_is_not_spec_object.Then(); 2028 { 2029 // Load the constructor function index from the {receiver} map. 2030 HValue* constructor_function_index = Add<HLoadNamedField>( 2031 receiver_map, nullptr, 2032 HObjectAccess::ForMapInObjectPropertiesOrConstructorFunctionIndex()); 2033 2034 // Check if {receiver} has a constructor (null and undefined have no 2035 // constructors, so we deoptimize to the runtime to throw an exception). 2036 IfBuilder constructor_function_index_is_invalid(this); 2037 constructor_function_index_is_invalid.If<HCompareNumericAndBranch>( 2038 constructor_function_index, 2039 Add<HConstant>(Map::kNoConstructorFunctionIndex), Token::EQ); 2040 constructor_function_index_is_invalid.ThenDeopt( 2041 DeoptimizeReason::kUndefinedOrNullInToObject); 2042 constructor_function_index_is_invalid.End(); 2043 2044 // Use the global constructor function. 2045 Push(constructor_function_index); 2046 } 2047 receiver_is_not_spec_object.JoinContinuation(&wrap); 2048 } 2049 receiver_is_smi.JoinContinuation(&wrap); 2050 2051 // Wrap the receiver if necessary. 2052 IfBuilder if_wrap(this, &wrap); 2053 if_wrap.Then(); 2054 { 2055 // Grab the constructor function index. 2056 HValue* constructor_index = Pop(); 2057 2058 // Load native context. 2059 HValue* native_context = BuildGetNativeContext(); 2060 2061 // Determine the initial map for the global constructor. 2062 HValue* constructor = Add<HLoadKeyed>(native_context, constructor_index, 2063 nullptr, nullptr, FAST_ELEMENTS); 2064 HValue* constructor_initial_map = Add<HLoadNamedField>( 2065 constructor, nullptr, HObjectAccess::ForPrototypeOrInitialMap()); 2066 // Allocate and initialize a JSValue wrapper. 2067 HValue* value = 2068 BuildAllocate(Add<HConstant>(JSValue::kSize), HType::JSObject(), 2069 JS_VALUE_TYPE, HAllocationMode()); 2070 Add<HStoreNamedField>(value, HObjectAccess::ForMap(), 2071 constructor_initial_map); 2072 HValue* empty_fixed_array = Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex); 2073 Add<HStoreNamedField>(value, HObjectAccess::ForPropertiesPointer(), 2074 empty_fixed_array); 2075 Add<HStoreNamedField>(value, HObjectAccess::ForElementsPointer(), 2076 empty_fixed_array); 2077 Add<HStoreNamedField>(value, HObjectAccess::ForObservableJSObjectOffset( 2078 JSValue::kValueOffset), 2079 receiver); 2080 Push(value); 2081 } 2082 if_wrap.Else(); 2083 { Push(receiver); } 2084 if_wrap.End(); 2085 return Pop(); 2086 } 2087 2088 2089 HAllocate* HGraphBuilder::BuildAllocate( 2090 HValue* object_size, 2091 HType type, 2092 InstanceType instance_type, 2093 HAllocationMode allocation_mode) { 2094 // Compute the effective allocation size. 2095 HValue* size = object_size; 2096 if (allocation_mode.CreateAllocationMementos()) { 2097 size = AddUncasted<HAdd>(size, Add<HConstant>(AllocationMemento::kSize)); 2098 size->ClearFlag(HValue::kCanOverflow); 2099 } 2100 2101 // Perform the actual allocation. 2102 HAllocate* object = Add<HAllocate>( 2103 size, type, allocation_mode.GetPretenureMode(), instance_type, 2104 graph()->GetConstant0(), allocation_mode.feedback_site()); 2105 2106 // Setup the allocation memento. 2107 if (allocation_mode.CreateAllocationMementos()) { 2108 BuildCreateAllocationMemento( 2109 object, object_size, allocation_mode.current_site()); 2110 } 2111 2112 return object; 2113 } 2114 2115 2116 HValue* HGraphBuilder::BuildAddStringLengths(HValue* left_length, 2117 HValue* right_length) { 2118 // Compute the combined string length and check against max string length. 2119 HValue* length = AddUncasted<HAdd>(left_length, right_length); 2120 // Check that length <= kMaxLength <=> length < MaxLength + 1. 2121 HValue* max_length = Add<HConstant>(String::kMaxLength + 1); 2122 if (top_info()->IsStub() || !isolate()->IsStringLengthOverflowIntact()) { 2123 // This is a mitigation for crbug.com/627934; the real fix 2124 // will be to migrate the StringAddStub to TurboFan one day. 2125 IfBuilder if_invalid(this); 2126 if_invalid.If<HCompareNumericAndBranch>(length, max_length, Token::GT); 2127 if_invalid.Then(); 2128 { 2129 Add<HCallRuntime>( 2130 Runtime::FunctionForId(Runtime::kThrowInvalidStringLength), 0); 2131 } 2132 if_invalid.End(); 2133 } else { 2134 graph()->MarkDependsOnStringLengthOverflow(); 2135 Add<HBoundsCheck>(length, max_length); 2136 } 2137 return length; 2138 } 2139 2140 2141 HValue* HGraphBuilder::BuildCreateConsString( 2142 HValue* length, 2143 HValue* left, 2144 HValue* right, 2145 HAllocationMode allocation_mode) { 2146 // Determine the string instance types. 2147 HInstruction* left_instance_type = AddLoadStringInstanceType(left); 2148 HInstruction* right_instance_type = AddLoadStringInstanceType(right); 2149 2150 // Allocate the cons string object. HAllocate does not care whether we 2151 // pass CONS_STRING_TYPE or CONS_ONE_BYTE_STRING_TYPE here, so we just use 2152 // CONS_STRING_TYPE here. Below we decide whether the cons string is 2153 // one-byte or two-byte and set the appropriate map. 2154 DCHECK(HAllocate::CompatibleInstanceTypes(CONS_STRING_TYPE, 2155 CONS_ONE_BYTE_STRING_TYPE)); 2156 HAllocate* result = BuildAllocate(Add<HConstant>(ConsString::kSize), 2157 HType::String(), CONS_STRING_TYPE, 2158 allocation_mode); 2159 2160 // Compute intersection and difference of instance types. 2161 HValue* anded_instance_types = AddUncasted<HBitwise>( 2162 Token::BIT_AND, left_instance_type, right_instance_type); 2163 HValue* xored_instance_types = AddUncasted<HBitwise>( 2164 Token::BIT_XOR, left_instance_type, right_instance_type); 2165 2166 // We create a one-byte cons string if 2167 // 1. both strings are one-byte, or 2168 // 2. at least one of the strings is two-byte, but happens to contain only 2169 // one-byte characters. 2170 // To do this, we check 2171 // 1. if both strings are one-byte, or if the one-byte data hint is set in 2172 // both strings, or 2173 // 2. if one of the strings has the one-byte data hint set and the other 2174 // string is one-byte. 2175 IfBuilder if_onebyte(this); 2176 STATIC_ASSERT(kOneByteStringTag != 0); 2177 STATIC_ASSERT(kOneByteDataHintMask != 0); 2178 if_onebyte.If<HCompareNumericAndBranch>( 2179 AddUncasted<HBitwise>( 2180 Token::BIT_AND, anded_instance_types, 2181 Add<HConstant>(static_cast<int32_t>( 2182 kStringEncodingMask | kOneByteDataHintMask))), 2183 graph()->GetConstant0(), Token::NE); 2184 if_onebyte.Or(); 2185 STATIC_ASSERT(kOneByteStringTag != 0 && 2186 kOneByteDataHintTag != 0 && 2187 kOneByteDataHintTag != kOneByteStringTag); 2188 if_onebyte.If<HCompareNumericAndBranch>( 2189 AddUncasted<HBitwise>( 2190 Token::BIT_AND, xored_instance_types, 2191 Add<HConstant>(static_cast<int32_t>( 2192 kOneByteStringTag | kOneByteDataHintTag))), 2193 Add<HConstant>(static_cast<int32_t>( 2194 kOneByteStringTag | kOneByteDataHintTag)), Token::EQ); 2195 if_onebyte.Then(); 2196 { 2197 // We can safely skip the write barrier for storing the map here. 2198 Add<HStoreNamedField>( 2199 result, HObjectAccess::ForMap(), 2200 Add<HConstant>(isolate()->factory()->cons_one_byte_string_map())); 2201 } 2202 if_onebyte.Else(); 2203 { 2204 // We can safely skip the write barrier for storing the map here. 2205 Add<HStoreNamedField>( 2206 result, HObjectAccess::ForMap(), 2207 Add<HConstant>(isolate()->factory()->cons_string_map())); 2208 } 2209 if_onebyte.End(); 2210 2211 // Initialize the cons string fields. 2212 Add<HStoreNamedField>(result, HObjectAccess::ForStringHashField(), 2213 Add<HConstant>(String::kEmptyHashField)); 2214 Add<HStoreNamedField>(result, HObjectAccess::ForStringLength(), length); 2215 Add<HStoreNamedField>(result, HObjectAccess::ForConsStringFirst(), left); 2216 Add<HStoreNamedField>(result, HObjectAccess::ForConsStringSecond(), right); 2217 2218 // Count the native string addition. 2219 AddIncrementCounter(isolate()->counters()->string_add_native()); 2220 2221 return result; 2222 } 2223 2224 2225 void HGraphBuilder::BuildCopySeqStringChars(HValue* src, 2226 HValue* src_offset, 2227 String::Encoding src_encoding, 2228 HValue* dst, 2229 HValue* dst_offset, 2230 String::Encoding dst_encoding, 2231 HValue* length) { 2232 DCHECK(dst_encoding != String::ONE_BYTE_ENCODING || 2233 src_encoding == String::ONE_BYTE_ENCODING); 2234 LoopBuilder loop(this, context(), LoopBuilder::kPostIncrement); 2235 HValue* index = loop.BeginBody(graph()->GetConstant0(), length, Token::LT); 2236 { 2237 HValue* src_index = AddUncasted<HAdd>(src_offset, index); 2238 HValue* value = 2239 AddUncasted<HSeqStringGetChar>(src_encoding, src, src_index); 2240 HValue* dst_index = AddUncasted<HAdd>(dst_offset, index); 2241 Add<HSeqStringSetChar>(dst_encoding, dst, dst_index, value); 2242 } 2243 loop.EndBody(); 2244 } 2245 2246 2247 HValue* HGraphBuilder::BuildObjectSizeAlignment( 2248 HValue* unaligned_size, int header_size) { 2249 DCHECK((header_size & kObjectAlignmentMask) == 0); 2250 HValue* size = AddUncasted<HAdd>( 2251 unaligned_size, Add<HConstant>(static_cast<int32_t>( 2252 header_size + kObjectAlignmentMask))); 2253 size->ClearFlag(HValue::kCanOverflow); 2254 return AddUncasted<HBitwise>( 2255 Token::BIT_AND, size, Add<HConstant>(static_cast<int32_t>( 2256 ~kObjectAlignmentMask))); 2257 } 2258 2259 2260 HValue* HGraphBuilder::BuildUncheckedStringAdd( 2261 HValue* left, 2262 HValue* right, 2263 HAllocationMode allocation_mode) { 2264 // Determine the string lengths. 2265 HValue* left_length = AddLoadStringLength(left); 2266 HValue* right_length = AddLoadStringLength(right); 2267 2268 // Compute the combined string length. 2269 HValue* length = BuildAddStringLengths(left_length, right_length); 2270 2271 // Do some manual constant folding here. 2272 if (left_length->IsConstant()) { 2273 HConstant* c_left_length = HConstant::cast(left_length); 2274 DCHECK_NE(0, c_left_length->Integer32Value()); 2275 if (c_left_length->Integer32Value() + 1 >= ConsString::kMinLength) { 2276 // The right string contains at least one character. 2277 return BuildCreateConsString(length, left, right, allocation_mode); 2278 } 2279 } else if (right_length->IsConstant()) { 2280 HConstant* c_right_length = HConstant::cast(right_length); 2281 DCHECK_NE(0, c_right_length->Integer32Value()); 2282 if (c_right_length->Integer32Value() + 1 >= ConsString::kMinLength) { 2283 // The left string contains at least one character. 2284 return BuildCreateConsString(length, left, right, allocation_mode); 2285 } 2286 } 2287 2288 // Check if we should create a cons string. 2289 IfBuilder if_createcons(this); 2290 if_createcons.If<HCompareNumericAndBranch>( 2291 length, Add<HConstant>(ConsString::kMinLength), Token::GTE); 2292 if_createcons.Then(); 2293 { 2294 // Create a cons string. 2295 Push(BuildCreateConsString(length, left, right, allocation_mode)); 2296 } 2297 if_createcons.Else(); 2298 { 2299 // Determine the string instance types. 2300 HValue* left_instance_type = AddLoadStringInstanceType(left); 2301 HValue* right_instance_type = AddLoadStringInstanceType(right); 2302 2303 // Compute union and difference of instance types. 2304 HValue* ored_instance_types = AddUncasted<HBitwise>( 2305 Token::BIT_OR, left_instance_type, right_instance_type); 2306 HValue* xored_instance_types = AddUncasted<HBitwise>( 2307 Token::BIT_XOR, left_instance_type, right_instance_type); 2308 2309 // Check if both strings have the same encoding and both are 2310 // sequential. 2311 IfBuilder if_sameencodingandsequential(this); 2312 if_sameencodingandsequential.If<HCompareNumericAndBranch>( 2313 AddUncasted<HBitwise>( 2314 Token::BIT_AND, xored_instance_types, 2315 Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))), 2316 graph()->GetConstant0(), Token::EQ); 2317 if_sameencodingandsequential.And(); 2318 STATIC_ASSERT(kSeqStringTag == 0); 2319 if_sameencodingandsequential.If<HCompareNumericAndBranch>( 2320 AddUncasted<HBitwise>( 2321 Token::BIT_AND, ored_instance_types, 2322 Add<HConstant>(static_cast<int32_t>(kStringRepresentationMask))), 2323 graph()->GetConstant0(), Token::EQ); 2324 if_sameencodingandsequential.Then(); 2325 { 2326 HConstant* string_map = 2327 Add<HConstant>(isolate()->factory()->string_map()); 2328 HConstant* one_byte_string_map = 2329 Add<HConstant>(isolate()->factory()->one_byte_string_map()); 2330 2331 // Determine map and size depending on whether result is one-byte string. 2332 IfBuilder if_onebyte(this); 2333 STATIC_ASSERT(kOneByteStringTag != 0); 2334 if_onebyte.If<HCompareNumericAndBranch>( 2335 AddUncasted<HBitwise>( 2336 Token::BIT_AND, ored_instance_types, 2337 Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))), 2338 graph()->GetConstant0(), Token::NE); 2339 if_onebyte.Then(); 2340 { 2341 // Allocate sequential one-byte string object. 2342 Push(length); 2343 Push(one_byte_string_map); 2344 } 2345 if_onebyte.Else(); 2346 { 2347 // Allocate sequential two-byte string object. 2348 HValue* size = AddUncasted<HShl>(length, graph()->GetConstant1()); 2349 size->ClearFlag(HValue::kCanOverflow); 2350 size->SetFlag(HValue::kUint32); 2351 Push(size); 2352 Push(string_map); 2353 } 2354 if_onebyte.End(); 2355 HValue* map = Pop(); 2356 2357 // Calculate the number of bytes needed for the characters in the 2358 // string while observing object alignment. 2359 STATIC_ASSERT((SeqString::kHeaderSize & kObjectAlignmentMask) == 0); 2360 HValue* size = BuildObjectSizeAlignment(Pop(), SeqString::kHeaderSize); 2361 2362 IfBuilder if_size(this); 2363 if_size.If<HCompareNumericAndBranch>( 2364 size, Add<HConstant>(kMaxRegularHeapObjectSize), Token::LT); 2365 if_size.Then(); 2366 { 2367 // Allocate the string object. HAllocate does not care whether we pass 2368 // STRING_TYPE or ONE_BYTE_STRING_TYPE here, so we just use STRING_TYPE. 2369 HAllocate* result = 2370 BuildAllocate(size, HType::String(), STRING_TYPE, allocation_mode); 2371 Add<HStoreNamedField>(result, HObjectAccess::ForMap(), map); 2372 2373 // Initialize the string fields. 2374 Add<HStoreNamedField>(result, HObjectAccess::ForStringHashField(), 2375 Add<HConstant>(String::kEmptyHashField)); 2376 Add<HStoreNamedField>(result, HObjectAccess::ForStringLength(), length); 2377 2378 // Copy characters to the result string. 2379 IfBuilder if_twobyte(this); 2380 if_twobyte.If<HCompareObjectEqAndBranch>(map, string_map); 2381 if_twobyte.Then(); 2382 { 2383 // Copy characters from the left string. 2384 BuildCopySeqStringChars( 2385 left, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, result, 2386 graph()->GetConstant0(), String::TWO_BYTE_ENCODING, left_length); 2387 2388 // Copy characters from the right string. 2389 BuildCopySeqStringChars( 2390 right, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, result, 2391 left_length, String::TWO_BYTE_ENCODING, right_length); 2392 } 2393 if_twobyte.Else(); 2394 { 2395 // Copy characters from the left string. 2396 BuildCopySeqStringChars( 2397 left, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, result, 2398 graph()->GetConstant0(), String::ONE_BYTE_ENCODING, left_length); 2399 2400 // Copy characters from the right string. 2401 BuildCopySeqStringChars( 2402 right, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, result, 2403 left_length, String::ONE_BYTE_ENCODING, right_length); 2404 } 2405 if_twobyte.End(); 2406 2407 // Count the native string addition. 2408 AddIncrementCounter(isolate()->counters()->string_add_native()); 2409 2410 // Return the sequential string. 2411 Push(result); 2412 } 2413 if_size.Else(); 2414 { 2415 // Fallback to the runtime to add the two strings. The string has to be 2416 // allocated in LO space. 2417 Add<HPushArguments>(left, right); 2418 Push(Add<HCallRuntime>(Runtime::FunctionForId(Runtime::kStringAdd), 2)); 2419 } 2420 if_size.End(); 2421 } 2422 if_sameencodingandsequential.Else(); 2423 { 2424 // Fallback to the runtime to add the two strings. 2425 Add<HPushArguments>(left, right); 2426 Push(Add<HCallRuntime>(Runtime::FunctionForId(Runtime::kStringAdd), 2)); 2427 } 2428 if_sameencodingandsequential.End(); 2429 } 2430 if_createcons.End(); 2431 2432 return Pop(); 2433 } 2434 2435 2436 HValue* HGraphBuilder::BuildStringAdd( 2437 HValue* left, 2438 HValue* right, 2439 HAllocationMode allocation_mode) { 2440 NoObservableSideEffectsScope no_effects(this); 2441 2442 // Determine string lengths. 2443 HValue* left_length = AddLoadStringLength(left); 2444 HValue* right_length = AddLoadStringLength(right); 2445 2446 // Check if left string is empty. 2447 IfBuilder if_leftempty(this); 2448 if_leftempty.If<HCompareNumericAndBranch>( 2449 left_length, graph()->GetConstant0(), Token::EQ); 2450 if_leftempty.Then(); 2451 { 2452 // Count the native string addition. 2453 AddIncrementCounter(isolate()->counters()->string_add_native()); 2454 2455 // Just return the right string. 2456 Push(right); 2457 } 2458 if_leftempty.Else(); 2459 { 2460 // Check if right string is empty. 2461 IfBuilder if_rightempty(this); 2462 if_rightempty.If<HCompareNumericAndBranch>( 2463 right_length, graph()->GetConstant0(), Token::EQ); 2464 if_rightempty.Then(); 2465 { 2466 // Count the native string addition. 2467 AddIncrementCounter(isolate()->counters()->string_add_native()); 2468 2469 // Just return the left string. 2470 Push(left); 2471 } 2472 if_rightempty.Else(); 2473 { 2474 // Add the two non-empty strings. 2475 Push(BuildUncheckedStringAdd(left, right, allocation_mode)); 2476 } 2477 if_rightempty.End(); 2478 } 2479 if_leftempty.End(); 2480 2481 return Pop(); 2482 } 2483 2484 2485 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( 2486 HValue* checked_object, 2487 HValue* key, 2488 HValue* val, 2489 bool is_js_array, 2490 ElementsKind elements_kind, 2491 PropertyAccessType access_type, 2492 LoadKeyedHoleMode load_mode, 2493 KeyedAccessStoreMode store_mode) { 2494 DCHECK(top_info()->IsStub() || checked_object->IsCompareMap() || 2495 checked_object->IsCheckMaps()); 2496 DCHECK(!IsFixedTypedArrayElementsKind(elements_kind) || !is_js_array); 2497 // No GVNFlag is necessary for ElementsKind if there is an explicit dependency 2498 // on a HElementsTransition instruction. The flag can also be removed if the 2499 // map to check has FAST_HOLEY_ELEMENTS, since there can be no further 2500 // ElementsKind transitions. Finally, the dependency can be removed for stores 2501 // for FAST_ELEMENTS, since a transition to HOLEY elements won't change the 2502 // generated store code. 2503 if ((elements_kind == FAST_HOLEY_ELEMENTS) || 2504 (elements_kind == FAST_ELEMENTS && access_type == STORE)) { 2505 checked_object->ClearDependsOnFlag(kElementsKind); 2506 } 2507 2508 bool fast_smi_only_elements = IsFastSmiElementsKind(elements_kind); 2509 bool fast_elements = IsFastObjectElementsKind(elements_kind); 2510 HValue* elements = AddLoadElements(checked_object); 2511 if (access_type == STORE && (fast_elements || fast_smi_only_elements) && 2512 store_mode != STORE_NO_TRANSITION_HANDLE_COW) { 2513 HCheckMaps* check_cow_map = Add<HCheckMaps>( 2514 elements, isolate()->factory()->fixed_array_map()); 2515 check_cow_map->ClearDependsOnFlag(kElementsKind); 2516 } 2517 HInstruction* length = NULL; 2518 if (is_js_array) { 2519 length = Add<HLoadNamedField>( 2520 checked_object->ActualValue(), checked_object, 2521 HObjectAccess::ForArrayLength(elements_kind)); 2522 } else { 2523 length = AddLoadFixedArrayLength(elements); 2524 } 2525 length->set_type(HType::Smi()); 2526 HValue* checked_key = NULL; 2527 if (IsFixedTypedArrayElementsKind(elements_kind)) { 2528 checked_object = Add<HCheckArrayBufferNotNeutered>(checked_object); 2529 2530 HValue* external_pointer = Add<HLoadNamedField>( 2531 elements, nullptr, 2532 HObjectAccess::ForFixedTypedArrayBaseExternalPointer()); 2533 HValue* base_pointer = Add<HLoadNamedField>( 2534 elements, nullptr, HObjectAccess::ForFixedTypedArrayBaseBasePointer()); 2535 HValue* backing_store = AddUncasted<HAdd>(external_pointer, base_pointer, 2536 AddOfExternalAndTagged); 2537 2538 if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) { 2539 NoObservableSideEffectsScope no_effects(this); 2540 IfBuilder length_checker(this); 2541 length_checker.If<HCompareNumericAndBranch>(key, length, Token::LT); 2542 length_checker.Then(); 2543 IfBuilder negative_checker(this); 2544 HValue* bounds_check = negative_checker.If<HCompareNumericAndBranch>( 2545 key, graph()->GetConstant0(), Token::GTE); 2546 negative_checker.Then(); 2547 HInstruction* result = AddElementAccess( 2548 backing_store, key, val, bounds_check, checked_object->ActualValue(), 2549 elements_kind, access_type); 2550 negative_checker.ElseDeopt(DeoptimizeReason::kNegativeKeyEncountered); 2551 negative_checker.End(); 2552 length_checker.End(); 2553 return result; 2554 } else { 2555 DCHECK(store_mode == STANDARD_STORE); 2556 checked_key = Add<HBoundsCheck>(key, length); 2557 return AddElementAccess(backing_store, checked_key, val, checked_object, 2558 checked_object->ActualValue(), elements_kind, 2559 access_type); 2560 } 2561 } 2562 DCHECK(fast_smi_only_elements || 2563 fast_elements || 2564 IsFastDoubleElementsKind(elements_kind)); 2565 2566 // In case val is stored into a fast smi array, assure that the value is a smi 2567 // before manipulating the backing store. Otherwise the actual store may 2568 // deopt, leaving the backing store in an invalid state. 2569 if (access_type == STORE && IsFastSmiElementsKind(elements_kind) && 2570 !val->type().IsSmi()) { 2571 val = AddUncasted<HForceRepresentation>(val, Representation::Smi()); 2572 } 2573 2574 if (IsGrowStoreMode(store_mode)) { 2575 NoObservableSideEffectsScope no_effects(this); 2576 Representation representation = HStoreKeyed::RequiredValueRepresentation( 2577 elements_kind, STORE_TO_INITIALIZED_ENTRY); 2578 val = AddUncasted<HForceRepresentation>(val, representation); 2579 elements = BuildCheckForCapacityGrow(checked_object, elements, 2580 elements_kind, length, key, 2581 is_js_array, access_type); 2582 checked_key = key; 2583 } else { 2584 checked_key = Add<HBoundsCheck>(key, length); 2585 2586 if (access_type == STORE && (fast_elements || fast_smi_only_elements)) { 2587 if (store_mode == STORE_NO_TRANSITION_HANDLE_COW) { 2588 NoObservableSideEffectsScope no_effects(this); 2589 elements = BuildCopyElementsOnWrite(checked_object, elements, 2590 elements_kind, length); 2591 } else { 2592 HCheckMaps* check_cow_map = Add<HCheckMaps>( 2593 elements, isolate()->factory()->fixed_array_map()); 2594 check_cow_map->ClearDependsOnFlag(kElementsKind); 2595 } 2596 } 2597 } 2598 return AddElementAccess(elements, checked_key, val, checked_object, nullptr, 2599 elements_kind, access_type, load_mode); 2600 } 2601 2602 2603 HValue* HGraphBuilder::BuildCalculateElementsSize(ElementsKind kind, 2604 HValue* capacity) { 2605 int elements_size = IsFastDoubleElementsKind(kind) 2606 ? kDoubleSize 2607 : kPointerSize; 2608 2609 HConstant* elements_size_value = Add<HConstant>(elements_size); 2610 HInstruction* mul = 2611 HMul::NewImul(isolate(), zone(), context(), capacity->ActualValue(), 2612 elements_size_value); 2613 AddInstruction(mul); 2614 mul->ClearFlag(HValue::kCanOverflow); 2615 2616 STATIC_ASSERT(FixedDoubleArray::kHeaderSize == FixedArray::kHeaderSize); 2617 2618 HConstant* header_size = Add<HConstant>(FixedArray::kHeaderSize); 2619 HValue* total_size = AddUncasted<HAdd>(mul, header_size); 2620 total_size->ClearFlag(HValue::kCanOverflow); 2621 return total_size; 2622 } 2623 2624 2625 HAllocate* HGraphBuilder::AllocateJSArrayObject(AllocationSiteMode mode) { 2626 int base_size = JSArray::kSize; 2627 if (mode == TRACK_ALLOCATION_SITE) { 2628 base_size += AllocationMemento::kSize; 2629 } 2630 HConstant* size_in_bytes = Add<HConstant>(base_size); 2631 return Add<HAllocate>(size_in_bytes, HType::JSArray(), NOT_TENURED, 2632 JS_OBJECT_TYPE, graph()->GetConstant0()); 2633 } 2634 2635 2636 HConstant* HGraphBuilder::EstablishElementsAllocationSize( 2637 ElementsKind kind, 2638 int capacity) { 2639 int base_size = IsFastDoubleElementsKind(kind) 2640 ? FixedDoubleArray::SizeFor(capacity) 2641 : FixedArray::SizeFor(capacity); 2642 2643 return Add<HConstant>(base_size); 2644 } 2645 2646 2647 HAllocate* HGraphBuilder::BuildAllocateElements(ElementsKind kind, 2648 HValue* size_in_bytes) { 2649 InstanceType instance_type = IsFastDoubleElementsKind(kind) 2650 ? FIXED_DOUBLE_ARRAY_TYPE 2651 : FIXED_ARRAY_TYPE; 2652 2653 return Add<HAllocate>(size_in_bytes, HType::HeapObject(), NOT_TENURED, 2654 instance_type, graph()->GetConstant0()); 2655 } 2656 2657 2658 void HGraphBuilder::BuildInitializeElementsHeader(HValue* elements, 2659 ElementsKind kind, 2660 HValue* capacity) { 2661 Factory* factory = isolate()->factory(); 2662 Handle<Map> map = IsFastDoubleElementsKind(kind) 2663 ? factory->fixed_double_array_map() 2664 : factory->fixed_array_map(); 2665 2666 Add<HStoreNamedField>(elements, HObjectAccess::ForMap(), Add<HConstant>(map)); 2667 Add<HStoreNamedField>(elements, HObjectAccess::ForFixedArrayLength(), 2668 capacity); 2669 } 2670 2671 2672 HValue* HGraphBuilder::BuildAllocateAndInitializeArray(ElementsKind kind, 2673 HValue* capacity) { 2674 // The HForceRepresentation is to prevent possible deopt on int-smi 2675 // conversion after allocation but before the new object fields are set. 2676 capacity = AddUncasted<HForceRepresentation>(capacity, Representation::Smi()); 2677 HValue* size_in_bytes = BuildCalculateElementsSize(kind, capacity); 2678 HValue* new_array = BuildAllocateElements(kind, size_in_bytes); 2679 BuildInitializeElementsHeader(new_array, kind, capacity); 2680 return new_array; 2681 } 2682 2683 2684 void HGraphBuilder::BuildJSArrayHeader(HValue* array, 2685 HValue* array_map, 2686 HValue* elements, 2687 AllocationSiteMode mode, 2688 ElementsKind elements_kind, 2689 HValue* allocation_site_payload, 2690 HValue* length_field) { 2691 Add<HStoreNamedField>(array, HObjectAccess::ForMap(), array_map); 2692 2693 HValue* empty_fixed_array = Add<HLoadRoot>(Heap::kEmptyFixedArrayRootIndex); 2694 2695 Add<HStoreNamedField>( 2696 array, HObjectAccess::ForPropertiesPointer(), empty_fixed_array); 2697 2698 Add<HStoreNamedField>(array, HObjectAccess::ForElementsPointer(), 2699 elements != nullptr ? elements : empty_fixed_array); 2700 2701 Add<HStoreNamedField>( 2702 array, HObjectAccess::ForArrayLength(elements_kind), length_field); 2703 2704 if (mode == TRACK_ALLOCATION_SITE) { 2705 BuildCreateAllocationMemento( 2706 array, Add<HConstant>(JSArray::kSize), allocation_site_payload); 2707 } 2708 } 2709 2710 2711 HInstruction* HGraphBuilder::AddElementAccess( 2712 HValue* elements, HValue* checked_key, HValue* val, HValue* dependency, 2713 HValue* backing_store_owner, ElementsKind elements_kind, 2714 PropertyAccessType access_type, LoadKeyedHoleMode load_mode) { 2715 if (access_type == STORE) { 2716 DCHECK(val != NULL); 2717 if (elements_kind == UINT8_CLAMPED_ELEMENTS) { 2718 val = Add<HClampToUint8>(val); 2719 } 2720 return Add<HStoreKeyed>(elements, checked_key, val, backing_store_owner, 2721 elements_kind, STORE_TO_INITIALIZED_ENTRY); 2722 } 2723 2724 DCHECK(access_type == LOAD); 2725 DCHECK(val == NULL); 2726 HLoadKeyed* load = 2727 Add<HLoadKeyed>(elements, checked_key, dependency, backing_store_owner, 2728 elements_kind, load_mode); 2729 if (elements_kind == UINT32_ELEMENTS) { 2730 graph()->RecordUint32Instruction(load); 2731 } 2732 return load; 2733 } 2734 2735 2736 HLoadNamedField* HGraphBuilder::AddLoadMap(HValue* object, 2737 HValue* dependency) { 2738 return Add<HLoadNamedField>(object, dependency, HObjectAccess::ForMap()); 2739 } 2740 2741 2742 HLoadNamedField* HGraphBuilder::AddLoadElements(HValue* object, 2743 HValue* dependency) { 2744 return Add<HLoadNamedField>( 2745 object, dependency, HObjectAccess::ForElementsPointer()); 2746 } 2747 2748 2749 HLoadNamedField* HGraphBuilder::AddLoadFixedArrayLength( 2750 HValue* array, 2751 HValue* dependency) { 2752 return Add<HLoadNamedField>( 2753 array, dependency, HObjectAccess::ForFixedArrayLength()); 2754 } 2755 2756 2757 HLoadNamedField* HGraphBuilder::AddLoadArrayLength(HValue* array, 2758 ElementsKind kind, 2759 HValue* dependency) { 2760 return Add<HLoadNamedField>( 2761 array, dependency, HObjectAccess::ForArrayLength(kind)); 2762 } 2763 2764 2765 HValue* HGraphBuilder::BuildNewElementsCapacity(HValue* old_capacity) { 2766 HValue* half_old_capacity = AddUncasted<HShr>(old_capacity, 2767 graph_->GetConstant1()); 2768 2769 HValue* new_capacity = AddUncasted<HAdd>(half_old_capacity, old_capacity); 2770 new_capacity->ClearFlag(HValue::kCanOverflow); 2771 2772 HValue* min_growth = Add<HConstant>(16); 2773 2774 new_capacity = AddUncasted<HAdd>(new_capacity, min_growth); 2775 new_capacity->ClearFlag(HValue::kCanOverflow); 2776 2777 return new_capacity; 2778 } 2779 2780 2781 HValue* HGraphBuilder::BuildGrowElementsCapacity(HValue* object, 2782 HValue* elements, 2783 ElementsKind kind, 2784 ElementsKind new_kind, 2785 HValue* length, 2786 HValue* new_capacity) { 2787 Add<HBoundsCheck>( 2788 new_capacity, 2789 Add<HConstant>((kMaxRegularHeapObjectSize - FixedArray::kHeaderSize) >> 2790 ElementsKindToShiftSize(new_kind))); 2791 2792 HValue* new_elements = 2793 BuildAllocateAndInitializeArray(new_kind, new_capacity); 2794 2795 BuildCopyElements(elements, kind, new_elements, 2796 new_kind, length, new_capacity); 2797 2798 Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(), 2799 new_elements); 2800 2801 return new_elements; 2802 } 2803 2804 2805 void HGraphBuilder::BuildFillElementsWithValue(HValue* elements, 2806 ElementsKind elements_kind, 2807 HValue* from, 2808 HValue* to, 2809 HValue* value) { 2810 if (to == NULL) { 2811 to = AddLoadFixedArrayLength(elements); 2812 } 2813 2814 // Special loop unfolding case 2815 STATIC_ASSERT(JSArray::kPreallocatedArrayElements <= 2816 kElementLoopUnrollThreshold); 2817 int initial_capacity = -1; 2818 if (from->IsInteger32Constant() && to->IsInteger32Constant()) { 2819 int constant_from = from->GetInteger32Constant(); 2820 int constant_to = to->GetInteger32Constant(); 2821 2822 if (constant_from == 0 && constant_to <= kElementLoopUnrollThreshold) { 2823 initial_capacity = constant_to; 2824 } 2825 } 2826 2827 if (initial_capacity >= 0) { 2828 for (int i = 0; i < initial_capacity; i++) { 2829 HInstruction* key = Add<HConstant>(i); 2830 Add<HStoreKeyed>(elements, key, value, nullptr, elements_kind); 2831 } 2832 } else { 2833 // Carefully loop backwards so that the "from" remains live through the loop 2834 // rather than the to. This often corresponds to keeping length live rather 2835 // then capacity, which helps register allocation, since length is used more 2836 // other than capacity after filling with holes. 2837 LoopBuilder builder(this, context(), LoopBuilder::kPostDecrement); 2838 2839 HValue* key = builder.BeginBody(to, from, Token::GT); 2840 2841 HValue* adjusted_key = AddUncasted<HSub>(key, graph()->GetConstant1()); 2842 adjusted_key->ClearFlag(HValue::kCanOverflow); 2843 2844 Add<HStoreKeyed>(elements, adjusted_key, value, nullptr, elements_kind); 2845 2846 builder.EndBody(); 2847 } 2848 } 2849 2850 2851 void HGraphBuilder::BuildFillElementsWithHole(HValue* elements, 2852 ElementsKind elements_kind, 2853 HValue* from, 2854 HValue* to) { 2855 // Fast elements kinds need to be initialized in case statements below cause a 2856 // garbage collection. 2857 2858 HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind) 2859 ? graph()->GetConstantHole() 2860 : Add<HConstant>(HConstant::kHoleNaN); 2861 2862 // Since we're about to store a hole value, the store instruction below must 2863 // assume an elements kind that supports heap object values. 2864 if (IsFastSmiOrObjectElementsKind(elements_kind)) { 2865 elements_kind = FAST_HOLEY_ELEMENTS; 2866 } 2867 2868 BuildFillElementsWithValue(elements, elements_kind, from, to, hole); 2869 } 2870 2871 2872 void HGraphBuilder::BuildCopyProperties(HValue* from_properties, 2873 HValue* to_properties, HValue* length, 2874 HValue* capacity) { 2875 ElementsKind kind = FAST_ELEMENTS; 2876 2877 BuildFillElementsWithValue(to_properties, kind, length, capacity, 2878 graph()->GetConstantUndefined()); 2879 2880 LoopBuilder builder(this, context(), LoopBuilder::kPostDecrement); 2881 2882 HValue* key = builder.BeginBody(length, graph()->GetConstant0(), Token::GT); 2883 2884 key = AddUncasted<HSub>(key, graph()->GetConstant1()); 2885 key->ClearFlag(HValue::kCanOverflow); 2886 2887 HValue* element = 2888 Add<HLoadKeyed>(from_properties, key, nullptr, nullptr, kind); 2889 2890 Add<HStoreKeyed>(to_properties, key, element, nullptr, kind); 2891 2892 builder.EndBody(); 2893 } 2894 2895 2896 void HGraphBuilder::BuildCopyElements(HValue* from_elements, 2897 ElementsKind from_elements_kind, 2898 HValue* to_elements, 2899 ElementsKind to_elements_kind, 2900 HValue* length, 2901 HValue* capacity) { 2902 int constant_capacity = -1; 2903 if (capacity != NULL && 2904 capacity->IsConstant() && 2905 HConstant::cast(capacity)->HasInteger32Value()) { 2906 int constant_candidate = HConstant::cast(capacity)->Integer32Value(); 2907 if (constant_candidate <= kElementLoopUnrollThreshold) { 2908 constant_capacity = constant_candidate; 2909 } 2910 } 2911 2912 bool pre_fill_with_holes = 2913 IsFastDoubleElementsKind(from_elements_kind) && 2914 IsFastObjectElementsKind(to_elements_kind); 2915 if (pre_fill_with_holes) { 2916 // If the copy might trigger a GC, make sure that the FixedArray is 2917 // pre-initialized with holes to make sure that it's always in a 2918 // consistent state. 2919 BuildFillElementsWithHole(to_elements, to_elements_kind, 2920 graph()->GetConstant0(), NULL); 2921 } 2922 2923 if (constant_capacity != -1) { 2924 // Unroll the loop for small elements kinds. 2925 for (int i = 0; i < constant_capacity; i++) { 2926 HValue* key_constant = Add<HConstant>(i); 2927 HInstruction* value = Add<HLoadKeyed>( 2928 from_elements, key_constant, nullptr, nullptr, from_elements_kind); 2929 Add<HStoreKeyed>(to_elements, key_constant, value, nullptr, 2930 to_elements_kind); 2931 } 2932 } else { 2933 if (!pre_fill_with_holes && 2934 (capacity == NULL || !length->Equals(capacity))) { 2935 BuildFillElementsWithHole(to_elements, to_elements_kind, 2936 length, NULL); 2937 } 2938 2939 LoopBuilder builder(this, context(), LoopBuilder::kPostDecrement); 2940 2941 HValue* key = builder.BeginBody(length, graph()->GetConstant0(), 2942 Token::GT); 2943 2944 key = AddUncasted<HSub>(key, graph()->GetConstant1()); 2945 key->ClearFlag(HValue::kCanOverflow); 2946 2947 HValue* element = Add<HLoadKeyed>(from_elements, key, nullptr, nullptr, 2948 from_elements_kind, ALLOW_RETURN_HOLE); 2949 2950 ElementsKind kind = (IsHoleyElementsKind(from_elements_kind) && 2951 IsFastSmiElementsKind(to_elements_kind)) 2952 ? FAST_HOLEY_ELEMENTS : to_elements_kind; 2953 2954 if (IsHoleyElementsKind(from_elements_kind) && 2955 from_elements_kind != to_elements_kind) { 2956 IfBuilder if_hole(this); 2957 if_hole.If<HCompareHoleAndBranch>(element); 2958 if_hole.Then(); 2959 HConstant* hole_constant = IsFastDoubleElementsKind(to_elements_kind) 2960 ? Add<HConstant>(HConstant::kHoleNaN) 2961 : graph()->GetConstantHole(); 2962 Add<HStoreKeyed>(to_elements, key, hole_constant, nullptr, kind); 2963 if_hole.Else(); 2964 HStoreKeyed* store = 2965 Add<HStoreKeyed>(to_elements, key, element, nullptr, kind); 2966 store->SetFlag(HValue::kTruncatingToNumber); 2967 if_hole.End(); 2968 } else { 2969 HStoreKeyed* store = 2970 Add<HStoreKeyed>(to_elements, key, element, nullptr, kind); 2971 store->SetFlag(HValue::kTruncatingToNumber); 2972 } 2973 2974 builder.EndBody(); 2975 } 2976 2977 Counters* counters = isolate()->counters(); 2978 AddIncrementCounter(counters->inlined_copied_elements()); 2979 } 2980 2981 void HGraphBuilder::BuildCreateAllocationMemento( 2982 HValue* previous_object, 2983 HValue* previous_object_size, 2984 HValue* allocation_site) { 2985 DCHECK(allocation_site != NULL); 2986 HInnerAllocatedObject* allocation_memento = Add<HInnerAllocatedObject>( 2987 previous_object, previous_object_size, HType::HeapObject()); 2988 AddStoreMapConstant( 2989 allocation_memento, isolate()->factory()->allocation_memento_map()); 2990 Add<HStoreNamedField>( 2991 allocation_memento, 2992 HObjectAccess::ForAllocationMementoSite(), 2993 allocation_site); 2994 if (FLAG_allocation_site_pretenuring) { 2995 HValue* memento_create_count = 2996 Add<HLoadNamedField>(allocation_site, nullptr, 2997 HObjectAccess::ForAllocationSiteOffset( 2998 AllocationSite::kPretenureCreateCountOffset)); 2999 memento_create_count = AddUncasted<HAdd>( 3000 memento_create_count, graph()->GetConstant1()); 3001 // This smi value is reset to zero after every gc, overflow isn't a problem 3002 // since the counter is bounded by the new space size. 3003 memento_create_count->ClearFlag(HValue::kCanOverflow); 3004 Add<HStoreNamedField>( 3005 allocation_site, HObjectAccess::ForAllocationSiteOffset( 3006 AllocationSite::kPretenureCreateCountOffset), memento_create_count); 3007 } 3008 } 3009 3010 3011 HInstruction* HGraphBuilder::BuildGetNativeContext() { 3012 return Add<HLoadNamedField>( 3013 context(), nullptr, 3014 HObjectAccess::ForContextSlot(Context::NATIVE_CONTEXT_INDEX)); 3015 } 3016 3017 3018 HInstruction* HGraphBuilder::BuildGetNativeContext(HValue* closure) { 3019 // Get the global object, then the native context 3020 HInstruction* context = Add<HLoadNamedField>( 3021 closure, nullptr, HObjectAccess::ForFunctionContextPointer()); 3022 return Add<HLoadNamedField>( 3023 context, nullptr, 3024 HObjectAccess::ForContextSlot(Context::NATIVE_CONTEXT_INDEX)); 3025 } 3026 3027 3028 HValue* HGraphBuilder::BuildGetParentContext(HValue* depth, int depth_value) { 3029 HValue* script_context = context(); 3030 if (depth != NULL) { 3031 HValue* zero = graph()->GetConstant0(); 3032 3033 Push(script_context); 3034 Push(depth); 3035 3036 LoopBuilder loop(this); 3037 loop.BeginBody(2); // Drop script_context and depth from last environment 3038 // to appease live range building without simulates. 3039 depth = Pop(); 3040 script_context = Pop(); 3041 3042 script_context = Add<HLoadNamedField>( 3043 script_context, nullptr, 3044 HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX)); 3045 depth = AddUncasted<HSub>(depth, graph()->GetConstant1()); 3046 depth->ClearFlag(HValue::kCanOverflow); 3047 3048 IfBuilder if_break(this); 3049 if_break.If<HCompareNumericAndBranch, HValue*>(depth, zero, Token::EQ); 3050 if_break.Then(); 3051 { 3052 Push(script_context); // The result. 3053 loop.Break(); 3054 } 3055 if_break.Else(); 3056 { 3057 Push(script_context); 3058 Push(depth); 3059 } 3060 loop.EndBody(); 3061 if_break.End(); 3062 3063 script_context = Pop(); 3064 } else if (depth_value > 0) { 3065 // Unroll the above loop. 3066 for (int i = 0; i < depth_value; i++) { 3067 script_context = Add<HLoadNamedField>( 3068 script_context, nullptr, 3069 HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX)); 3070 } 3071 } 3072 return script_context; 3073 } 3074 3075 3076 HInstruction* HGraphBuilder::BuildGetArrayFunction() { 3077 HInstruction* native_context = BuildGetNativeContext(); 3078 HInstruction* index = 3079 Add<HConstant>(static_cast<int32_t>(Context::ARRAY_FUNCTION_INDEX)); 3080 return Add<HLoadKeyed>(native_context, index, nullptr, nullptr, 3081 FAST_ELEMENTS); 3082 } 3083 3084 3085 HValue* HGraphBuilder::BuildArrayBufferViewFieldAccessor(HValue* object, 3086 HValue* checked_object, 3087 FieldIndex index) { 3088 NoObservableSideEffectsScope scope(this); 3089 HObjectAccess access = HObjectAccess::ForObservableJSObjectOffset( 3090 index.offset(), Representation::Tagged()); 3091 HInstruction* buffer = Add<HLoadNamedField>( 3092 object, checked_object, HObjectAccess::ForJSArrayBufferViewBuffer()); 3093 HInstruction* field = Add<HLoadNamedField>(object, checked_object, access); 3094 3095 HInstruction* flags = Add<HLoadNamedField>( 3096 buffer, nullptr, HObjectAccess::ForJSArrayBufferBitField()); 3097 HValue* was_neutered_mask = 3098 Add<HConstant>(1 << JSArrayBuffer::WasNeutered::kShift); 3099 HValue* was_neutered_test = 3100 AddUncasted<HBitwise>(Token::BIT_AND, flags, was_neutered_mask); 3101 3102 IfBuilder if_was_neutered(this); 3103 if_was_neutered.If<HCompareNumericAndBranch>( 3104 was_neutered_test, graph()->GetConstant0(), Token::NE); 3105 if_was_neutered.Then(); 3106 Push(graph()->GetConstant0()); 3107 if_was_neutered.Else(); 3108 Push(field); 3109 if_was_neutered.End(); 3110 3111 return Pop(); 3112 } 3113 3114 HValue* HGraphBuilder::AddLoadJSBuiltin(int context_index) { 3115 HValue* native_context = BuildGetNativeContext(); 3116 HObjectAccess function_access = HObjectAccess::ForContextSlot(context_index); 3117 return Add<HLoadNamedField>(native_context, nullptr, function_access); 3118 } 3119 3120 HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info, 3121 bool track_positions) 3122 : HGraphBuilder(info, CallInterfaceDescriptor(), track_positions), 3123 function_state_(NULL), 3124 initial_function_state_(this, info, NORMAL_RETURN, -1, 3125 TailCallMode::kAllow), 3126 ast_context_(NULL), 3127 break_scope_(NULL), 3128 inlined_count_(0), 3129 globals_(10, info->zone()), 3130 osr_(new (info->zone()) HOsrBuilder(this)), 3131 bounds_(info->zone()) { 3132 // This is not initialized in the initializer list because the 3133 // constructor for the initial state relies on function_state_ == NULL 3134 // to know it's the initial state. 3135 function_state_ = &initial_function_state_; 3136 InitializeAstVisitor(info->isolate()); 3137 } 3138 3139 3140 HBasicBlock* HOptimizedGraphBuilder::CreateJoin(HBasicBlock* first, 3141 HBasicBlock* second, 3142 BailoutId join_id) { 3143 if (first == NULL) { 3144 return second; 3145 } else if (second == NULL) { 3146 return first; 3147 } else { 3148 HBasicBlock* join_block = graph()->CreateBasicBlock(); 3149 Goto(first, join_block); 3150 Goto(second, join_block); 3151 join_block->SetJoinId(join_id); 3152 return join_block; 3153 } 3154 } 3155 3156 HBasicBlock* HOptimizedGraphBuilder::JoinContinue(IterationStatement* statement, 3157 BailoutId continue_id, 3158 HBasicBlock* exit_block, 3159 HBasicBlock* continue_block) { 3160 if (continue_block != NULL) { 3161 if (exit_block != NULL) Goto(exit_block, continue_block); 3162 continue_block->SetJoinId(continue_id); 3163 return continue_block; 3164 } 3165 return exit_block; 3166 } 3167 3168 3169 HBasicBlock* HOptimizedGraphBuilder::CreateLoop(IterationStatement* statement, 3170 HBasicBlock* loop_entry, 3171 HBasicBlock* body_exit, 3172 HBasicBlock* loop_successor, 3173 HBasicBlock* break_block) { 3174 if (body_exit != NULL) Goto(body_exit, loop_entry); 3175 loop_entry->PostProcessLoopHeader(statement); 3176 if (break_block != NULL) { 3177 if (loop_successor != NULL) Goto(loop_successor, break_block); 3178 break_block->SetJoinId(statement->ExitId()); 3179 return break_block; 3180 } 3181 return loop_successor; 3182 } 3183 3184 3185 // Build a new loop header block and set it as the current block. 3186 HBasicBlock* HOptimizedGraphBuilder::BuildLoopEntry() { 3187 HBasicBlock* loop_entry = CreateLoopHeaderBlock(); 3188 Goto(loop_entry); 3189 set_current_block(loop_entry); 3190 return loop_entry; 3191 } 3192 3193 3194 HBasicBlock* HOptimizedGraphBuilder::BuildLoopEntry( 3195 IterationStatement* statement) { 3196 HBasicBlock* loop_entry; 3197 3198 if (osr()->HasOsrEntryAt(statement)) { 3199 loop_entry = osr()->BuildOsrLoopEntry(statement); 3200 if (function_state()->IsInsideDoExpressionScope()) { 3201 Bailout(kDoExpressionUnmodelable); 3202 } 3203 } else { 3204 loop_entry = BuildLoopEntry(); 3205 } 3206 return loop_entry; 3207 } 3208 3209 3210 void HBasicBlock::FinishExit(HControlInstruction* instruction, 3211 SourcePosition position) { 3212 Finish(instruction, position); 3213 ClearEnvironment(); 3214 } 3215 3216 3217 std::ostream& operator<<(std::ostream& os, const HBasicBlock& b) { 3218 return os << "B" << b.block_id(); 3219 } 3220 3221 HGraph::HGraph(CompilationInfo* info, CallInterfaceDescriptor descriptor) 3222 : isolate_(info->isolate()), 3223 next_block_id_(0), 3224 entry_block_(NULL), 3225 blocks_(8, info->zone()), 3226 values_(16, info->zone()), 3227 phi_list_(NULL), 3228 uint32_instructions_(NULL), 3229 osr_(NULL), 3230 info_(info), 3231 descriptor_(descriptor), 3232 zone_(info->zone()), 3233 allow_code_motion_(false), 3234 use_optimistic_licm_(false), 3235 depends_on_empty_array_proto_elements_(false), 3236 depends_on_string_length_overflow_(false), 3237 type_change_checksum_(0), 3238 maximum_environment_size_(0), 3239 no_side_effects_scope_count_(0), 3240 disallow_adding_new_values_(false) { 3241 if (info->IsStub()) { 3242 // For stubs, explicitly add the context to the environment. 3243 start_environment_ = 3244 new (zone_) HEnvironment(zone_, descriptor.GetParameterCount() + 1); 3245 } else { 3246 start_environment_ = 3247 new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_); 3248 } 3249 start_environment_->set_ast_id(BailoutId::FunctionContext()); 3250 entry_block_ = CreateBasicBlock(); 3251 entry_block_->SetInitialEnvironment(start_environment_); 3252 } 3253 3254 3255 HBasicBlock* HGraph::CreateBasicBlock() { 3256 HBasicBlock* result = new(zone()) HBasicBlock(this); 3257 blocks_.Add(result, zone()); 3258 return result; 3259 } 3260 3261 3262 void HGraph::FinalizeUniqueness() { 3263 DisallowHeapAllocation no_gc; 3264 for (int i = 0; i < blocks()->length(); ++i) { 3265 for (HInstructionIterator it(blocks()->at(i)); !it.Done(); it.Advance()) { 3266 it.Current()->FinalizeUniqueness(); 3267 } 3268 } 3269 } 3270 3271 3272 // Block ordering was implemented with two mutually recursive methods, 3273 // HGraph::Postorder and HGraph::PostorderLoopBlocks. 3274 // The recursion could lead to stack overflow so the algorithm has been 3275 // implemented iteratively. 3276 // At a high level the algorithm looks like this: 3277 // 3278 // Postorder(block, loop_header) : { 3279 // if (block has already been visited or is of another loop) return; 3280 // mark block as visited; 3281 // if (block is a loop header) { 3282 // VisitLoopMembers(block, loop_header); 3283 // VisitSuccessorsOfLoopHeader(block); 3284 // } else { 3285 // VisitSuccessors(block) 3286 // } 3287 // put block in result list; 3288 // } 3289 // 3290 // VisitLoopMembers(block, outer_loop_header) { 3291 // foreach (block b in block loop members) { 3292 // VisitSuccessorsOfLoopMember(b, outer_loop_header); 3293 // if (b is loop header) VisitLoopMembers(b); 3294 // } 3295 // } 3296 // 3297 // VisitSuccessorsOfLoopMember(block, outer_loop_header) { 3298 // foreach (block b in block successors) Postorder(b, outer_loop_header) 3299 // } 3300 // 3301 // VisitSuccessorsOfLoopHeader(block) { 3302 // foreach (block b in block successors) Postorder(b, block) 3303 // } 3304 // 3305 // VisitSuccessors(block, loop_header) { 3306 // foreach (block b in block successors) Postorder(b, loop_header) 3307 // } 3308 // 3309 // The ordering is started calling Postorder(entry, NULL). 3310 // 3311 // Each instance of PostorderProcessor represents the "stack frame" of the 3312 // recursion, and particularly keeps the state of the loop (iteration) of the 3313 // "Visit..." function it represents. 3314 // To recycle memory we keep all the frames in a double linked list but 3315 // this means that we cannot use constructors to initialize the frames. 3316 // 3317 class PostorderProcessor : public ZoneObject { 3318 public: 3319 // Back link (towards the stack bottom). 3320 PostorderProcessor* parent() {return father_; } 3321 // Forward link (towards the stack top). 3322 PostorderProcessor* child() {return child_; } 3323 HBasicBlock* block() { return block_; } 3324 HLoopInformation* loop() { return loop_; } 3325 HBasicBlock* loop_header() { return loop_header_; } 3326 3327 static PostorderProcessor* CreateEntryProcessor(Zone* zone, 3328 HBasicBlock* block) { 3329 PostorderProcessor* result = new(zone) PostorderProcessor(NULL); 3330 return result->SetupSuccessors(zone, block, NULL); 3331 } 3332 3333 PostorderProcessor* PerformStep(Zone* zone, 3334 ZoneList<HBasicBlock*>* order) { 3335 PostorderProcessor* next = 3336 PerformNonBacktrackingStep(zone, order); 3337 if (next != NULL) { 3338 return next; 3339 } else { 3340 return Backtrack(zone, order); 3341 } 3342 } 3343 3344 private: 3345 explicit PostorderProcessor(PostorderProcessor* father) 3346 : father_(father), child_(NULL), successor_iterator(NULL) { } 3347 3348 // Each enum value states the cycle whose state is kept by this instance. 3349 enum LoopKind { 3350 NONE, 3351 SUCCESSORS, 3352 SUCCESSORS_OF_LOOP_HEADER, 3353 LOOP_MEMBERS, 3354 SUCCESSORS_OF_LOOP_MEMBER 3355 }; 3356 3357 // Each "Setup..." method is like a constructor for a cycle state. 3358 PostorderProcessor* SetupSuccessors(Zone* zone, 3359 HBasicBlock* block, 3360 HBasicBlock* loop_header) { 3361 if (block == NULL || block->IsOrdered() || 3362 block->parent_loop_header() != loop_header) { 3363 kind_ = NONE; 3364 block_ = NULL; 3365 loop_ = NULL; 3366 loop_header_ = NULL; 3367 return this; 3368 } else { 3369 block_ = block; 3370 loop_ = NULL; 3371 block->MarkAsOrdered(); 3372 3373 if (block->IsLoopHeader()) { 3374 kind_ = SUCCESSORS_OF_LOOP_HEADER; 3375 loop_header_ = block; 3376 InitializeSuccessors(); 3377 PostorderProcessor* result = Push(zone); 3378 return result->SetupLoopMembers(zone, block, block->loop_information(), 3379 loop_header); 3380 } else { 3381 DCHECK(block->IsFinished()); 3382 kind_ = SUCCESSORS; 3383 loop_header_ = loop_header; 3384 InitializeSuccessors(); 3385 return this; 3386 } 3387 } 3388 } 3389 3390 PostorderProcessor* SetupLoopMembers(Zone* zone, 3391 HBasicBlock* block, 3392 HLoopInformation* loop, 3393 HBasicBlock* loop_header) { 3394 kind_ = LOOP_MEMBERS; 3395 block_ = block; 3396 loop_ = loop; 3397 loop_header_ = loop_header; 3398 InitializeLoopMembers(); 3399 return this; 3400 } 3401 3402 PostorderProcessor* SetupSuccessorsOfLoopMember( 3403 HBasicBlock* block, 3404 HLoopInformation* loop, 3405 HBasicBlock* loop_header) { 3406 kind_ = SUCCESSORS_OF_LOOP_MEMBER; 3407 block_ = block; 3408 loop_ = loop; 3409 loop_header_ = loop_header; 3410 InitializeSuccessors(); 3411 return this; 3412 } 3413 3414 // This method "allocates" a new stack frame. 3415 PostorderProcessor* Push(Zone* zone) { 3416 if (child_ == NULL) { 3417 child_ = new(zone) PostorderProcessor(this); 3418 } 3419 return child_; 3420 } 3421 3422 void ClosePostorder(ZoneList<HBasicBlock*>* order, Zone* zone) { 3423 DCHECK(block_->end()->FirstSuccessor() == NULL || 3424 order->Contains(block_->end()->FirstSuccessor()) || 3425 block_->end()->FirstSuccessor()->IsLoopHeader()); 3426 DCHECK(block_->end()->SecondSuccessor() == NULL || 3427 order->Contains(block_->end()->SecondSuccessor()) || 3428 block_->end()->SecondSuccessor()->IsLoopHeader()); 3429 order->Add(block_, zone); 3430 } 3431 3432 // This method is the basic block to walk up the stack. 3433 PostorderProcessor* Pop(Zone* zone, 3434 ZoneList<HBasicBlock*>* order) { 3435 switch (kind_) { 3436 case SUCCESSORS: 3437 case SUCCESSORS_OF_LOOP_HEADER: 3438 ClosePostorder(order, zone); 3439 return father_; 3440 case LOOP_MEMBERS: 3441 return father_; 3442 case SUCCESSORS_OF_LOOP_MEMBER: 3443 if (block()->IsLoopHeader() && block() != loop_->loop_header()) { 3444 // In this case we need to perform a LOOP_MEMBERS cycle so we 3445 // initialize it and return this instead of father. 3446 return SetupLoopMembers(zone, block(), 3447 block()->loop_information(), loop_header_); 3448 } else { 3449 return father_; 3450 } 3451 case NONE: 3452 return father_; 3453 } 3454 UNREACHABLE(); 3455 return NULL; 3456 } 3457 3458 // Walks up the stack. 3459 PostorderProcessor* Backtrack(Zone* zone, 3460 ZoneList<HBasicBlock*>* order) { 3461 PostorderProcessor* parent = Pop(zone, order); 3462 while (parent != NULL) { 3463 PostorderProcessor* next = 3464 parent->PerformNonBacktrackingStep(zone, order); 3465 if (next != NULL) { 3466 return next; 3467 } else { 3468 parent = parent->Pop(zone, order); 3469 } 3470 } 3471 return NULL; 3472 } 3473 3474 PostorderProcessor* PerformNonBacktrackingStep( 3475 Zone* zone, 3476 ZoneList<HBasicBlock*>* order) { 3477 HBasicBlock* next_block; 3478 switch (kind_) { 3479 case SUCCESSORS: 3480 next_block = AdvanceSuccessors(); 3481 if (next_block != NULL) { 3482 PostorderProcessor* result = Push(zone); 3483 return result->SetupSuccessors(zone, next_block, loop_header_); 3484 } 3485 break; 3486 case SUCCESSORS_OF_LOOP_HEADER: 3487 next_block = AdvanceSuccessors(); 3488 if (next_block != NULL) { 3489 PostorderProcessor* result = Push(zone); 3490 return result->SetupSuccessors(zone, next_block, block()); 3491 } 3492 break; 3493 case LOOP_MEMBERS: 3494 next_block = AdvanceLoopMembers(); 3495 if (next_block != NULL) { 3496 PostorderProcessor* result = Push(zone); 3497 return result->SetupSuccessorsOfLoopMember(next_block, 3498 loop_, loop_header_); 3499 } 3500 break; 3501 case SUCCESSORS_OF_LOOP_MEMBER: 3502 next_block = AdvanceSuccessors(); 3503 if (next_block != NULL) { 3504 PostorderProcessor* result = Push(zone); 3505 return result->SetupSuccessors(zone, next_block, loop_header_); 3506 } 3507 break; 3508 case NONE: 3509 return NULL; 3510 } 3511 return NULL; 3512 } 3513 3514 // The following two methods implement a "foreach b in successors" cycle. 3515 void InitializeSuccessors() { 3516 loop_index = 0; 3517 loop_length = 0; 3518 successor_iterator = HSuccessorIterator(block_->end()); 3519 } 3520 3521 HBasicBlock* AdvanceSuccessors() { 3522 if (!successor_iterator.Done()) { 3523 HBasicBlock* result = successor_iterator.Current(); 3524 successor_iterator.Advance(); 3525 return result; 3526 } 3527 return NULL; 3528 } 3529 3530 // The following two methods implement a "foreach b in loop members" cycle. 3531 void InitializeLoopMembers() { 3532 loop_index = 0; 3533 loop_length = loop_->blocks()->length(); 3534 } 3535 3536 HBasicBlock* AdvanceLoopMembers() { 3537 if (loop_index < loop_length) { 3538 HBasicBlock* result = loop_->blocks()->at(loop_index); 3539 loop_index++; 3540 return result; 3541 } else { 3542 return NULL; 3543 } 3544 } 3545 3546 LoopKind kind_; 3547 PostorderProcessor* father_; 3548 PostorderProcessor* child_; 3549 HLoopInformation* loop_; 3550 HBasicBlock* block_; 3551 HBasicBlock* loop_header_; 3552 int loop_index; 3553 int loop_length; 3554 HSuccessorIterator successor_iterator; 3555 }; 3556 3557 3558 void HGraph::OrderBlocks() { 3559 CompilationPhase phase("H_Block ordering", info()); 3560 3561 #ifdef DEBUG 3562 // Initially the blocks must not be ordered. 3563 for (int i = 0; i < blocks_.length(); ++i) { 3564 DCHECK(!blocks_[i]->IsOrdered()); 3565 } 3566 #endif 3567 3568 PostorderProcessor* postorder = 3569 PostorderProcessor::CreateEntryProcessor(zone(), blocks_[0]); 3570 blocks_.Rewind(0); 3571 while (postorder) { 3572 postorder = postorder->PerformStep(zone(), &blocks_); 3573 } 3574 3575 #ifdef DEBUG 3576 // Now all blocks must be marked as ordered. 3577 for (int i = 0; i < blocks_.length(); ++i) { 3578 DCHECK(blocks_[i]->IsOrdered()); 3579 } 3580 #endif 3581 3582 // Reverse block list and assign block IDs. 3583 for (int i = 0, j = blocks_.length(); --j >= i; ++i) { 3584 HBasicBlock* bi = blocks_[i]; 3585 HBasicBlock* bj = blocks_[j]; 3586 bi->set_block_id(j); 3587 bj->set_block_id(i); 3588 blocks_[i] = bj; 3589 blocks_[j] = bi; 3590 } 3591 } 3592 3593 3594 void HGraph::AssignDominators() { 3595 HPhase phase("H_Assign dominators", this); 3596 for (int i = 0; i < blocks_.length(); ++i) { 3597 HBasicBlock* block = blocks_[i]; 3598 if (block->IsLoopHeader()) { 3599 // Only the first predecessor of a loop header is from outside the loop. 3600 // All others are back edges, and thus cannot dominate the loop header. 3601 block->AssignCommonDominator(block->predecessors()->first()); 3602 block->AssignLoopSuccessorDominators(); 3603 } else { 3604 for (int j = blocks_[i]->predecessors()->length() - 1; j >= 0; --j) { 3605 blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->at(j)); 3606 } 3607 } 3608 } 3609 } 3610 3611 3612 bool HGraph::CheckArgumentsPhiUses() { 3613 int block_count = blocks_.length(); 3614 for (int i = 0; i < block_count; ++i) { 3615 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) { 3616 HPhi* phi = blocks_[i]->phis()->at(j); 3617 // We don't support phi uses of arguments for now. 3618 if (phi->CheckFlag(HValue::kIsArguments)) return false; 3619 } 3620 } 3621 return true; 3622 } 3623 3624 3625 bool HGraph::CheckConstPhiUses() { 3626 int block_count = blocks_.length(); 3627 for (int i = 0; i < block_count; ++i) { 3628 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) { 3629 HPhi* phi = blocks_[i]->phis()->at(j); 3630 // Check for the hole value (from an uninitialized const). 3631 for (int k = 0; k < phi->OperandCount(); k++) { 3632 if (phi->OperandAt(k) == GetConstantHole()) return false; 3633 } 3634 } 3635 } 3636 return true; 3637 } 3638 3639 3640 void HGraph::CollectPhis() { 3641 int block_count = blocks_.length(); 3642 phi_list_ = new(zone()) ZoneList<HPhi*>(block_count, zone()); 3643 for (int i = 0; i < block_count; ++i) { 3644 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) { 3645 HPhi* phi = blocks_[i]->phis()->at(j); 3646 phi_list_->Add(phi, zone()); 3647 } 3648 } 3649 } 3650 3651 3652 // Implementation of utility class to encapsulate the translation state for 3653 // a (possibly inlined) function. 3654 FunctionState::FunctionState(HOptimizedGraphBuilder* owner, 3655 CompilationInfo* info, InliningKind inlining_kind, 3656 int inlining_id, TailCallMode tail_call_mode) 3657 : owner_(owner), 3658 compilation_info_(info), 3659 call_context_(NULL), 3660 inlining_kind_(inlining_kind), 3661 tail_call_mode_(tail_call_mode), 3662 function_return_(NULL), 3663 test_context_(NULL), 3664 entry_(NULL), 3665 arguments_object_(NULL), 3666 arguments_elements_(NULL), 3667 inlining_id_(inlining_id), 3668 outer_source_position_(SourcePosition::Unknown()), 3669 do_expression_scope_count_(0), 3670 outer_(owner->function_state()) { 3671 if (outer_ != NULL) { 3672 // State for an inline function. 3673 if (owner->ast_context()->IsTest()) { 3674 HBasicBlock* if_true = owner->graph()->CreateBasicBlock(); 3675 HBasicBlock* if_false = owner->graph()->CreateBasicBlock(); 3676 if_true->MarkAsInlineReturnTarget(owner->current_block()); 3677 if_false->MarkAsInlineReturnTarget(owner->current_block()); 3678 TestContext* outer_test_context = TestContext::cast(owner->ast_context()); 3679 Expression* cond = outer_test_context->condition(); 3680 // The AstContext constructor pushed on the context stack. This newed 3681 // instance is the reason that AstContext can't be BASE_EMBEDDED. 3682 test_context_ = new TestContext(owner, cond, if_true, if_false); 3683 } else { 3684 function_return_ = owner->graph()->CreateBasicBlock(); 3685 function_return()->MarkAsInlineReturnTarget(owner->current_block()); 3686 } 3687 // Set this after possibly allocating a new TestContext above. 3688 call_context_ = owner->ast_context(); 3689 } 3690 3691 // Push on the state stack. 3692 owner->set_function_state(this); 3693 3694 if (owner->is_tracking_positions()) { 3695 outer_source_position_ = owner->source_position(); 3696 owner->EnterInlinedSource(inlining_id); 3697 owner->SetSourcePosition(info->shared_info()->start_position()); 3698 } 3699 } 3700 3701 3702 FunctionState::~FunctionState() { 3703 delete test_context_; 3704 owner_->set_function_state(outer_); 3705 3706 if (owner_->is_tracking_positions()) { 3707 owner_->set_source_position(outer_source_position_); 3708 owner_->EnterInlinedSource(outer_->inlining_id()); 3709 } 3710 } 3711 3712 3713 // Implementation of utility classes to represent an expression's context in 3714 // the AST. 3715 AstContext::AstContext(HOptimizedGraphBuilder* owner, Expression::Context kind) 3716 : owner_(owner), 3717 kind_(kind), 3718 outer_(owner->ast_context()), 3719 typeof_mode_(NOT_INSIDE_TYPEOF) { 3720 owner->set_ast_context(this); // Push. 3721 #ifdef DEBUG 3722 DCHECK_EQ(JS_FUNCTION, owner->environment()->frame_type()); 3723 original_length_ = owner->environment()->length(); 3724 #endif 3725 } 3726 3727 3728 AstContext::~AstContext() { 3729 owner_->set_ast_context(outer_); // Pop. 3730 } 3731 3732 3733 EffectContext::~EffectContext() { 3734 DCHECK(owner()->HasStackOverflow() || owner()->current_block() == NULL || 3735 (owner()->environment()->length() == original_length_ && 3736 (owner()->environment()->frame_type() == JS_FUNCTION || 3737 owner()->environment()->frame_type() == TAIL_CALLER_FUNCTION))); 3738 } 3739 3740 3741 ValueContext::~ValueContext() { 3742 DCHECK(owner()->HasStackOverflow() || owner()->current_block() == NULL || 3743 (owner()->environment()->length() == original_length_ + 1 && 3744 (owner()->environment()->frame_type() == JS_FUNCTION || 3745 owner()->environment()->frame_type() == TAIL_CALLER_FUNCTION))); 3746 } 3747 3748 3749 void EffectContext::ReturnValue(HValue* value) { 3750 // The value is simply ignored. 3751 } 3752 3753 3754 void ValueContext::ReturnValue(HValue* value) { 3755 // The value is tracked in the bailout environment, and communicated 3756 // through the environment as the result of the expression. 3757 if (value->CheckFlag(HValue::kIsArguments)) { 3758 if (flag_ == ARGUMENTS_FAKED) { 3759 value = owner()->graph()->GetConstantUndefined(); 3760 } else if (!arguments_allowed()) { 3761 owner()->Bailout(kBadValueContextForArgumentsValue); 3762 } 3763 } 3764 owner()->Push(value); 3765 } 3766 3767 3768 void TestContext::ReturnValue(HValue* value) { 3769 BuildBranch(value); 3770 } 3771 3772 3773 void EffectContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) { 3774 DCHECK(!instr->IsControlInstruction()); 3775 owner()->AddInstruction(instr); 3776 if (instr->HasObservableSideEffects()) { 3777 owner()->Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); 3778 } 3779 } 3780 3781 3782 void EffectContext::ReturnControl(HControlInstruction* instr, 3783 BailoutId ast_id) { 3784 DCHECK(!instr->HasObservableSideEffects()); 3785 HBasicBlock* empty_true = owner()->graph()->CreateBasicBlock(); 3786 HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock(); 3787 instr->SetSuccessorAt(0, empty_true); 3788 instr->SetSuccessorAt(1, empty_false); 3789 owner()->FinishCurrentBlock(instr); 3790 HBasicBlock* join = owner()->CreateJoin(empty_true, empty_false, ast_id); 3791 owner()->set_current_block(join); 3792 } 3793 3794 3795 void EffectContext::ReturnContinuation(HIfContinuation* continuation, 3796 BailoutId ast_id) { 3797 HBasicBlock* true_branch = NULL; 3798 HBasicBlock* false_branch = NULL; 3799 continuation->Continue(&true_branch, &false_branch); 3800 if (!continuation->IsTrueReachable()) { 3801 owner()->set_current_block(false_branch); 3802 } else if (!continuation->IsFalseReachable()) { 3803 owner()->set_current_block(true_branch); 3804 } else { 3805 HBasicBlock* join = owner()->CreateJoin(true_branch, false_branch, ast_id); 3806 owner()->set_current_block(join); 3807 } 3808 } 3809 3810 3811 void ValueContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) { 3812 DCHECK(!instr->IsControlInstruction()); 3813 if (!arguments_allowed() && instr->CheckFlag(HValue::kIsArguments)) { 3814 return owner()->Bailout(kBadValueContextForArgumentsObjectValue); 3815 } 3816 owner()->AddInstruction(instr); 3817 owner()->Push(instr); 3818 if (instr->HasObservableSideEffects()) { 3819 owner()->Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); 3820 } 3821 } 3822 3823 3824 void ValueContext::ReturnControl(HControlInstruction* instr, BailoutId ast_id) { 3825 DCHECK(!instr->HasObservableSideEffects()); 3826 if (!arguments_allowed() && instr->CheckFlag(HValue::kIsArguments)) { 3827 return owner()->Bailout(kBadValueContextForArgumentsObjectValue); 3828 } 3829 HBasicBlock* materialize_false = owner()->graph()->CreateBasicBlock(); 3830 HBasicBlock* materialize_true = owner()->graph()->CreateBasicBlock(); 3831 instr->SetSuccessorAt(0, materialize_true); 3832 instr->SetSuccessorAt(1, materialize_false); 3833 owner()->FinishCurrentBlock(instr); 3834 owner()->set_current_block(materialize_true); 3835 owner()->Push(owner()->graph()->GetConstantTrue()); 3836 owner()->set_current_block(materialize_false); 3837 owner()->Push(owner()->graph()->GetConstantFalse()); 3838 HBasicBlock* join = 3839 owner()->CreateJoin(materialize_true, materialize_false, ast_id); 3840 owner()->set_current_block(join); 3841 } 3842 3843 3844 void ValueContext::ReturnContinuation(HIfContinuation* continuation, 3845 BailoutId ast_id) { 3846 HBasicBlock* materialize_true = NULL; 3847 HBasicBlock* materialize_false = NULL; 3848 continuation->Continue(&materialize_true, &materialize_false); 3849 if (continuation->IsTrueReachable()) { 3850 owner()->set_current_block(materialize_true); 3851 owner()->Push(owner()->graph()->GetConstantTrue()); 3852 owner()->set_current_block(materialize_true); 3853 } 3854 if (continuation->IsFalseReachable()) { 3855 owner()->set_current_block(materialize_false); 3856 owner()->Push(owner()->graph()->GetConstantFalse()); 3857 owner()->set_current_block(materialize_false); 3858 } 3859 if (continuation->TrueAndFalseReachable()) { 3860 HBasicBlock* join = 3861 owner()->CreateJoin(materialize_true, materialize_false, ast_id); 3862 owner()->set_current_block(join); 3863 } 3864 } 3865 3866 3867 void TestContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) { 3868 DCHECK(!instr->IsControlInstruction()); 3869 HOptimizedGraphBuilder* builder = owner(); 3870 builder->AddInstruction(instr); 3871 // We expect a simulate after every expression with side effects, though 3872 // this one isn't actually needed (and wouldn't work if it were targeted). 3873 if (instr->HasObservableSideEffects()) { 3874 builder->Push(instr); 3875 builder->Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); 3876 builder->Pop(); 3877 } 3878 BuildBranch(instr); 3879 } 3880 3881 3882 void TestContext::ReturnControl(HControlInstruction* instr, BailoutId ast_id) { 3883 DCHECK(!instr->HasObservableSideEffects()); 3884 HBasicBlock* empty_true = owner()->graph()->CreateBasicBlock(); 3885 HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock(); 3886 instr->SetSuccessorAt(0, empty_true); 3887 instr->SetSuccessorAt(1, empty_false); 3888 owner()->FinishCurrentBlock(instr); 3889 owner()->Goto(empty_true, if_true(), owner()->function_state()); 3890 owner()->Goto(empty_false, if_false(), owner()->function_state()); 3891 owner()->set_current_block(NULL); 3892 } 3893 3894 3895 void TestContext::ReturnContinuation(HIfContinuation* continuation, 3896 BailoutId ast_id) { 3897 HBasicBlock* true_branch = NULL; 3898 HBasicBlock* false_branch = NULL; 3899 continuation->Continue(&true_branch, &false_branch); 3900 if (continuation->IsTrueReachable()) { 3901 owner()->Goto(true_branch, if_true(), owner()->function_state()); 3902 } 3903 if (continuation->IsFalseReachable()) { 3904 owner()->Goto(false_branch, if_false(), owner()->function_state()); 3905 } 3906 owner()->set_current_block(NULL); 3907 } 3908 3909 3910 void TestContext::BuildBranch(HValue* value) { 3911 // We expect the graph to be in edge-split form: there is no edge that 3912 // connects a branch node to a join node. We conservatively ensure that 3913 // property by always adding an empty block on the outgoing edges of this 3914 // branch. 3915 HOptimizedGraphBuilder* builder = owner(); 3916 if (value != NULL && value->CheckFlag(HValue::kIsArguments)) { 3917 builder->Bailout(kArgumentsObjectValueInATestContext); 3918 } 3919 ToBooleanHints expected(condition()->to_boolean_types()); 3920 ReturnControl(owner()->New<HBranch>(value, expected), BailoutId::None()); 3921 } 3922 3923 3924 // HOptimizedGraphBuilder infrastructure for bailing out and checking bailouts. 3925 #define CHECK_BAILOUT(call) \ 3926 do { \ 3927 call; \ 3928 if (HasStackOverflow()) return; \ 3929 } while (false) 3930 3931 3932 #define CHECK_ALIVE(call) \ 3933 do { \ 3934 call; \ 3935 if (HasStackOverflow() || current_block() == NULL) return; \ 3936 } while (false) 3937 3938 3939 #define CHECK_ALIVE_OR_RETURN(call, value) \ 3940 do { \ 3941 call; \ 3942 if (HasStackOverflow() || current_block() == NULL) return value; \ 3943 } while (false) 3944 3945 3946 void HOptimizedGraphBuilder::Bailout(BailoutReason reason) { 3947 current_info()->AbortOptimization(reason); 3948 SetStackOverflow(); 3949 } 3950 3951 3952 void HOptimizedGraphBuilder::VisitForEffect(Expression* expr) { 3953 EffectContext for_effect(this); 3954 Visit(expr); 3955 } 3956 3957 3958 void HOptimizedGraphBuilder::VisitForValue(Expression* expr, 3959 ArgumentsAllowedFlag flag) { 3960 ValueContext for_value(this, flag); 3961 Visit(expr); 3962 } 3963 3964 3965 void HOptimizedGraphBuilder::VisitForTypeOf(Expression* expr) { 3966 ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED); 3967 for_value.set_typeof_mode(INSIDE_TYPEOF); 3968 Visit(expr); 3969 } 3970 3971 3972 void HOptimizedGraphBuilder::VisitForControl(Expression* expr, 3973 HBasicBlock* true_block, 3974 HBasicBlock* false_block) { 3975 TestContext for_control(this, expr, true_block, false_block); 3976 Visit(expr); 3977 } 3978 3979 3980 void HOptimizedGraphBuilder::VisitExpressions( 3981 ZoneList<Expression*>* exprs) { 3982 for (int i = 0; i < exprs->length(); ++i) { 3983 CHECK_ALIVE(VisitForValue(exprs->at(i))); 3984 } 3985 } 3986 3987 3988 void HOptimizedGraphBuilder::VisitExpressions(ZoneList<Expression*>* exprs, 3989 ArgumentsAllowedFlag flag) { 3990 for (int i = 0; i < exprs->length(); ++i) { 3991 CHECK_ALIVE(VisitForValue(exprs->at(i), flag)); 3992 } 3993 } 3994 3995 3996 bool HOptimizedGraphBuilder::BuildGraph() { 3997 if (IsSubclassConstructor(current_info()->literal()->kind())) { 3998 Bailout(kSuperReference); 3999 return false; 4000 } 4001 4002 DeclarationScope* scope = current_info()->scope(); 4003 SetUpScope(scope); 4004 4005 // Add an edge to the body entry. This is warty: the graph's start 4006 // environment will be used by the Lithium translation as the initial 4007 // environment on graph entry, but it has now been mutated by the 4008 // Hydrogen translation of the instructions in the start block. This 4009 // environment uses values which have not been defined yet. These 4010 // Hydrogen instructions will then be replayed by the Lithium 4011 // translation, so they cannot have an environment effect. The edge to 4012 // the body's entry block (along with some special logic for the start 4013 // block in HInstruction::InsertAfter) seals the start block from 4014 // getting unwanted instructions inserted. 4015 // 4016 // TODO(kmillikin): Fix this. Stop mutating the initial environment. 4017 // Make the Hydrogen instructions in the initial block into Hydrogen 4018 // values (but not instructions), present in the initial environment and 4019 // not replayed by the Lithium translation. 4020 HEnvironment* initial_env = environment()->CopyWithoutHistory(); 4021 HBasicBlock* body_entry = CreateBasicBlock(initial_env); 4022 Goto(body_entry); 4023 body_entry->SetJoinId(BailoutId::FunctionEntry()); 4024 set_current_block(body_entry); 4025 4026 VisitDeclarations(scope->declarations()); 4027 Add<HSimulate>(BailoutId::Declarations()); 4028 4029 Add<HStackCheck>(HStackCheck::kFunctionEntry); 4030 4031 VisitStatements(current_info()->literal()->body()); 4032 if (HasStackOverflow()) return false; 4033 4034 if (current_block() != NULL) { 4035 Add<HReturn>(graph()->GetConstantUndefined()); 4036 set_current_block(NULL); 4037 } 4038 4039 // If the checksum of the number of type info changes is the same as the 4040 // last time this function was compiled, then this recompile is likely not 4041 // due to missing/inadequate type feedback, but rather too aggressive 4042 // optimization. Disable optimistic LICM in that case. 4043 Handle<Code> unoptimized_code(current_info()->shared_info()->code()); 4044 DCHECK(unoptimized_code->kind() == Code::FUNCTION); 4045 Handle<TypeFeedbackInfo> type_info( 4046 TypeFeedbackInfo::cast(unoptimized_code->type_feedback_info())); 4047 int checksum = type_info->own_type_change_checksum(); 4048 int composite_checksum = graph()->update_type_change_checksum(checksum); 4049 graph()->set_use_optimistic_licm( 4050 !type_info->matches_inlined_type_change_checksum(composite_checksum)); 4051 type_info->set_inlined_type_change_checksum(composite_checksum); 4052 4053 // Set this predicate early to avoid handle deref during graph optimization. 4054 graph()->set_allow_code_motion( 4055 current_info()->IsStub() || 4056 current_info()->shared_info()->opt_count() + 1 < FLAG_max_opt_count); 4057 4058 // Perform any necessary OSR-specific cleanups or changes to the graph. 4059 osr()->FinishGraph(); 4060 4061 return true; 4062 } 4063 4064 4065 bool HGraph::Optimize(BailoutReason* bailout_reason) { 4066 OrderBlocks(); 4067 AssignDominators(); 4068 4069 // We need to create a HConstant "zero" now so that GVN will fold every 4070 // zero-valued constant in the graph together. 4071 // The constant is needed to make idef-based bounds check work: the pass 4072 // evaluates relations with "zero" and that zero cannot be created after GVN. 4073 GetConstant0(); 4074 4075 #ifdef DEBUG 4076 // Do a full verify after building the graph and computing dominators. 4077 Verify(true); 4078 #endif 4079 4080 if (FLAG_analyze_environment_liveness && maximum_environment_size() != 0) { 4081 Run<HEnvironmentLivenessAnalysisPhase>(); 4082 } 4083 4084 if (!CheckConstPhiUses()) { 4085 *bailout_reason = kUnsupportedPhiUseOfConstVariable; 4086 return false; 4087 } 4088 Run<HRedundantPhiEliminationPhase>(); 4089 if (!CheckArgumentsPhiUses()) { 4090 *bailout_reason = kUnsupportedPhiUseOfArguments; 4091 return false; 4092 } 4093 4094 // Find and mark unreachable code to simplify optimizations, especially gvn, 4095 // where unreachable code could unnecessarily defeat LICM. 4096 Run<HMarkUnreachableBlocksPhase>(); 4097 4098 if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>(); 4099 if (FLAG_use_escape_analysis) Run<HEscapeAnalysisPhase>(); 4100 4101 if (FLAG_load_elimination) Run<HLoadEliminationPhase>(); 4102 4103 CollectPhis(); 4104 4105 if (has_osr()) osr()->FinishOsrValues(); 4106 4107 Run<HInferRepresentationPhase>(); 4108 4109 // Remove HSimulate instructions that have turned out not to be needed 4110 // after all by folding them into the following HSimulate. 4111 // This must happen after inferring representations. 4112 Run<HMergeRemovableSimulatesPhase>(); 4113 4114 Run<HRepresentationChangesPhase>(); 4115 4116 Run<HInferTypesPhase>(); 4117 4118 // Must be performed before canonicalization to ensure that Canonicalize 4119 // will not remove semantically meaningful ToInt32 operations e.g. BIT_OR with 4120 // zero. 4121 Run<HUint32AnalysisPhase>(); 4122 4123 if (FLAG_use_canonicalizing) Run<HCanonicalizePhase>(); 4124 4125 if (FLAG_use_gvn) Run<HGlobalValueNumberingPhase>(); 4126 4127 if (FLAG_check_elimination) Run<HCheckEliminationPhase>(); 4128 4129 if (FLAG_store_elimination) Run<HStoreEliminationPhase>(); 4130 4131 Run<HRangeAnalysisPhase>(); 4132 4133 // Eliminate redundant stack checks on backwards branches. 4134 Run<HStackCheckEliminationPhase>(); 4135 4136 if (FLAG_array_bounds_checks_elimination) Run<HBoundsCheckEliminationPhase>(); 4137 if (FLAG_array_index_dehoisting) Run<HDehoistIndexComputationsPhase>(); 4138 if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>(); 4139 4140 RestoreActualValues(); 4141 4142 // Find unreachable code a second time, GVN and other optimizations may have 4143 // made blocks unreachable that were previously reachable. 4144 Run<HMarkUnreachableBlocksPhase>(); 4145 4146 return true; 4147 } 4148 4149 4150 void HGraph::RestoreActualValues() { 4151 HPhase phase("H_Restore actual values", this); 4152 4153 for (int block_index = 0; block_index < blocks()->length(); block_index++) { 4154 HBasicBlock* block = blocks()->at(block_index); 4155 4156 #ifdef DEBUG 4157 for (int i = 0; i < block->phis()->length(); i++) { 4158 HPhi* phi = block->phis()->at(i); 4159 DCHECK(phi->ActualValue() == phi); 4160 } 4161 #endif 4162 4163 for (HInstructionIterator it(block); !it.Done(); it.Advance()) { 4164 HInstruction* instruction = it.Current(); 4165 if (instruction->ActualValue() == instruction) continue; 4166 if (instruction->CheckFlag(HValue::kIsDead)) { 4167 // The instruction was marked as deleted but left in the graph 4168 // as a control flow dependency point for subsequent 4169 // instructions. 4170 instruction->DeleteAndReplaceWith(instruction->ActualValue()); 4171 } else { 4172 DCHECK(instruction->IsInformativeDefinition()); 4173 if (instruction->IsPurelyInformativeDefinition()) { 4174 instruction->DeleteAndReplaceWith(instruction->RedefinedOperand()); 4175 } else { 4176 instruction->ReplaceAllUsesWith(instruction->ActualValue()); 4177 } 4178 } 4179 } 4180 } 4181 } 4182 4183 4184 void HOptimizedGraphBuilder::PushArgumentsFromEnvironment(int count) { 4185 ZoneList<HValue*> arguments(count, zone()); 4186 for (int i = 0; i < count; ++i) { 4187 arguments.Add(Pop(), zone()); 4188 } 4189 4190 HPushArguments* push_args = New<HPushArguments>(); 4191 while (!arguments.is_empty()) { 4192 push_args->AddInput(arguments.RemoveLast()); 4193 } 4194 AddInstruction(push_args); 4195 } 4196 4197 4198 template <class Instruction> 4199 HInstruction* HOptimizedGraphBuilder::PreProcessCall(Instruction* call) { 4200 PushArgumentsFromEnvironment(call->argument_count()); 4201 return call; 4202 } 4203 4204 void HOptimizedGraphBuilder::SetUpScope(DeclarationScope* scope) { 4205 HEnvironment* prolog_env = environment(); 4206 int parameter_count = environment()->parameter_count(); 4207 ZoneList<HValue*> parameters(parameter_count, zone()); 4208 for (int i = 0; i < parameter_count; ++i) { 4209 HInstruction* parameter = Add<HParameter>(static_cast<unsigned>(i)); 4210 parameters.Add(parameter, zone()); 4211 environment()->Bind(i, parameter); 4212 } 4213 4214 HConstant* undefined_constant = graph()->GetConstantUndefined(); 4215 // Initialize specials and locals to undefined. 4216 for (int i = parameter_count + 1; i < environment()->length(); ++i) { 4217 environment()->Bind(i, undefined_constant); 4218 } 4219 Add<HPrologue>(); 4220 4221 HEnvironment* initial_env = environment()->CopyWithoutHistory(); 4222 HBasicBlock* body_entry = CreateBasicBlock(initial_env); 4223 GotoNoSimulate(body_entry); 4224 set_current_block(body_entry); 4225 4226 // Initialize context of prolog environment to undefined. 4227 prolog_env->BindContext(undefined_constant); 4228 4229 // First special is HContext. 4230 HInstruction* context = Add<HContext>(); 4231 environment()->BindContext(context); 4232 4233 // Create an arguments object containing the initial parameters. Set the 4234 // initial values of parameters including "this" having parameter index 0. 4235 DCHECK_EQ(scope->num_parameters() + 1, parameter_count); 4236 HArgumentsObject* arguments_object = New<HArgumentsObject>(parameter_count); 4237 for (int i = 0; i < parameter_count; ++i) { 4238 HValue* parameter = parameters.at(i); 4239 arguments_object->AddArgument(parameter, zone()); 4240 } 4241 4242 AddInstruction(arguments_object); 4243 4244 // Handle the arguments and arguments shadow variables specially (they do 4245 // not have declarations). 4246 if (scope->arguments() != NULL) { 4247 environment()->Bind(scope->arguments(), arguments_object); 4248 } 4249 4250 if (scope->rest_parameter() != nullptr) { 4251 return Bailout(kRestParameter); 4252 } 4253 4254 if (scope->this_function_var() != nullptr || 4255 scope->new_target_var() != nullptr) { 4256 return Bailout(kSuperReference); 4257 } 4258 4259 // Trace the call. 4260 if (FLAG_trace && top_info()->IsOptimizing()) { 4261 Add<HCallRuntime>(Runtime::FunctionForId(Runtime::kTraceEnter), 0); 4262 } 4263 } 4264 4265 4266 void HOptimizedGraphBuilder::VisitStatements(ZoneList<Statement*>* statements) { 4267 for (int i = 0; i < statements->length(); i++) { 4268 Statement* stmt = statements->at(i); 4269 CHECK_ALIVE(Visit(stmt)); 4270 if (stmt->IsJump()) break; 4271 } 4272 } 4273 4274 4275 void HOptimizedGraphBuilder::VisitBlock(Block* stmt) { 4276 DCHECK(!HasStackOverflow()); 4277 DCHECK(current_block() != NULL); 4278 DCHECK(current_block()->HasPredecessor()); 4279 4280 Scope* outer_scope = scope(); 4281 Scope* scope = stmt->scope(); 4282 BreakAndContinueInfo break_info(stmt, outer_scope); 4283 4284 { BreakAndContinueScope push(&break_info, this); 4285 if (scope != NULL) { 4286 if (scope->NeedsContext()) { 4287 // Load the function object. 4288 DeclarationScope* declaration_scope = scope->GetDeclarationScope(); 4289 HInstruction* function; 4290 HValue* outer_context = environment()->context(); 4291 if (declaration_scope->is_script_scope() || 4292 declaration_scope->is_eval_scope()) { 4293 function = new (zone()) 4294 HLoadContextSlot(outer_context, Context::CLOSURE_INDEX, 4295 HLoadContextSlot::kNoCheck); 4296 } else { 4297 function = New<HThisFunction>(); 4298 } 4299 AddInstruction(function); 4300 // Allocate a block context and store it to the stack frame. 4301 HValue* scope_info = Add<HConstant>(scope->scope_info()); 4302 Add<HPushArguments>(scope_info, function); 4303 HInstruction* inner_context = Add<HCallRuntime>( 4304 Runtime::FunctionForId(Runtime::kPushBlockContext), 2); 4305 inner_context->SetFlag(HValue::kHasNoObservableSideEffects); 4306 set_scope(scope); 4307 environment()->BindContext(inner_context); 4308 } 4309 VisitDeclarations(scope->declarations()); 4310 AddSimulate(stmt->DeclsId(), REMOVABLE_SIMULATE); 4311 } 4312 CHECK_BAILOUT(VisitStatements(stmt->statements())); 4313 } 4314 set_scope(outer_scope); 4315 if (scope != NULL && current_block() != NULL && 4316 scope->ContextLocalCount() > 0) { 4317 HValue* inner_context = environment()->context(); 4318 HValue* outer_context = Add<HLoadNamedField>( 4319 inner_context, nullptr, 4320 HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX)); 4321 4322 environment()->BindContext(outer_context); 4323 } 4324 HBasicBlock* break_block = break_info.break_block(); 4325 if (break_block != NULL) { 4326 if (current_block() != NULL) Goto(break_block); 4327 break_block->SetJoinId(stmt->ExitId()); 4328 set_current_block(break_block); 4329 } 4330 } 4331 4332 4333 void HOptimizedGraphBuilder::VisitExpressionStatement( 4334 ExpressionStatement* stmt) { 4335 DCHECK(!HasStackOverflow()); 4336 DCHECK(current_block() != NULL); 4337 DCHECK(current_block()->HasPredecessor()); 4338 VisitForEffect(stmt->expression()); 4339 } 4340 4341 4342 void HOptimizedGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) { 4343 DCHECK(!HasStackOverflow()); 4344 DCHECK(current_block() != NULL); 4345 DCHECK(current_block()->HasPredecessor()); 4346 } 4347 4348 4349 void HOptimizedGraphBuilder::VisitSloppyBlockFunctionStatement( 4350 SloppyBlockFunctionStatement* stmt) { 4351 Visit(stmt->statement()); 4352 } 4353 4354 4355 void HOptimizedGraphBuilder::VisitIfStatement(IfStatement* stmt) { 4356 DCHECK(!HasStackOverflow()); 4357 DCHECK(current_block() != NULL); 4358 DCHECK(current_block()->HasPredecessor()); 4359 if (stmt->condition()->ToBooleanIsTrue()) { 4360 Add<HSimulate>(stmt->ThenId()); 4361 Visit(stmt->then_statement()); 4362 } else if (stmt->condition()->ToBooleanIsFalse()) { 4363 Add<HSimulate>(stmt->ElseId()); 4364 Visit(stmt->else_statement()); 4365 } else { 4366 HBasicBlock* cond_true = graph()->CreateBasicBlock(); 4367 HBasicBlock* cond_false = graph()->CreateBasicBlock(); 4368 CHECK_BAILOUT(VisitForControl(stmt->condition(), cond_true, cond_false)); 4369 4370 // Technically, we should be able to handle the case when one side of 4371 // the test is not connected, but this can trip up liveness analysis 4372 // if we did not fully connect the test context based on some optimistic 4373 // assumption. If such an assumption was violated, we would end up with 4374 // an environment with optimized-out values. So we should always 4375 // conservatively connect the test context. 4376 CHECK(cond_true->HasPredecessor()); 4377 CHECK(cond_false->HasPredecessor()); 4378 4379 cond_true->SetJoinId(stmt->ThenId()); 4380 set_current_block(cond_true); 4381 CHECK_BAILOUT(Visit(stmt->then_statement())); 4382 cond_true = current_block(); 4383 4384 cond_false->SetJoinId(stmt->ElseId()); 4385 set_current_block(cond_false); 4386 CHECK_BAILOUT(Visit(stmt->else_statement())); 4387 cond_false = current_block(); 4388 4389 HBasicBlock* join = CreateJoin(cond_true, cond_false, stmt->IfId()); 4390 set_current_block(join); 4391 } 4392 } 4393 4394 4395 HBasicBlock* HOptimizedGraphBuilder::BreakAndContinueScope::Get( 4396 BreakableStatement* stmt, 4397 BreakType type, 4398 Scope** scope, 4399 int* drop_extra) { 4400 *drop_extra = 0; 4401 BreakAndContinueScope* current = this; 4402 while (current != NULL && current->info()->target() != stmt) { 4403 *drop_extra += current->info()->drop_extra(); 4404 current = current->next(); 4405 } 4406 DCHECK(current != NULL); // Always found (unless stack is malformed). 4407 *scope = current->info()->scope(); 4408 4409 if (type == BREAK) { 4410 *drop_extra += current->info()->drop_extra(); 4411 } 4412 4413 HBasicBlock* block = NULL; 4414 switch (type) { 4415 case BREAK: 4416 block = current->info()->break_block(); 4417 if (block == NULL) { 4418 block = current->owner()->graph()->CreateBasicBlock(); 4419 current->info()->set_break_block(block); 4420 } 4421 break; 4422 4423 case CONTINUE: 4424 block = current->info()->continue_block(); 4425 if (block == NULL) { 4426 block = current->owner()->graph()->CreateBasicBlock(); 4427 current->info()->set_continue_block(block); 4428 } 4429 break; 4430 } 4431 4432 return block; 4433 } 4434 4435 4436 void HOptimizedGraphBuilder::VisitContinueStatement( 4437 ContinueStatement* stmt) { 4438 DCHECK(!HasStackOverflow()); 4439 DCHECK(current_block() != NULL); 4440 DCHECK(current_block()->HasPredecessor()); 4441 4442 if (function_state()->IsInsideDoExpressionScope()) { 4443 return Bailout(kDoExpressionUnmodelable); 4444 } 4445 4446 Scope* outer_scope = NULL; 4447 Scope* inner_scope = scope(); 4448 int drop_extra = 0; 4449 HBasicBlock* continue_block = break_scope()->Get( 4450 stmt->target(), BreakAndContinueScope::CONTINUE, 4451 &outer_scope, &drop_extra); 4452 HValue* context = environment()->context(); 4453 Drop(drop_extra); 4454 int context_pop_count = inner_scope->ContextChainLength(outer_scope); 4455 if (context_pop_count > 0) { 4456 while (context_pop_count-- > 0) { 4457 HInstruction* context_instruction = Add<HLoadNamedField>( 4458 context, nullptr, 4459 HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX)); 4460 context = context_instruction; 4461 } 4462 environment()->BindContext(context); 4463 } 4464 4465 Goto(continue_block); 4466 set_current_block(NULL); 4467 } 4468 4469 4470 void HOptimizedGraphBuilder::VisitBreakStatement(BreakStatement* stmt) { 4471 DCHECK(!HasStackOverflow()); 4472 DCHECK(current_block() != NULL); 4473 DCHECK(current_block()->HasPredecessor()); 4474 4475 if (function_state()->IsInsideDoExpressionScope()) { 4476 return Bailout(kDoExpressionUnmodelable); 4477 } 4478 4479 Scope* outer_scope = NULL; 4480 Scope* inner_scope = scope(); 4481 int drop_extra = 0; 4482 HBasicBlock* break_block = break_scope()->Get( 4483 stmt->target(), BreakAndContinueScope::BREAK, 4484 &outer_scope, &drop_extra); 4485 HValue* context = environment()->context(); 4486 Drop(drop_extra); 4487 int context_pop_count = inner_scope->ContextChainLength(outer_scope); 4488 if (context_pop_count > 0) { 4489 while (context_pop_count-- > 0) { 4490 HInstruction* context_instruction = Add<HLoadNamedField>( 4491 context, nullptr, 4492 HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX)); 4493 context = context_instruction; 4494 } 4495 environment()->BindContext(context); 4496 } 4497 Goto(break_block); 4498 set_current_block(NULL); 4499 } 4500 4501 4502 void HOptimizedGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { 4503 DCHECK(!HasStackOverflow()); 4504 DCHECK(current_block() != NULL); 4505 DCHECK(current_block()->HasPredecessor()); 4506 FunctionState* state = function_state(); 4507 AstContext* context = call_context(); 4508 if (context == NULL) { 4509 // Not an inlined return, so an actual one. 4510 CHECK_ALIVE(VisitForValue(stmt->expression())); 4511 HValue* result = environment()->Pop(); 4512 Add<HReturn>(result); 4513 } else if (state->inlining_kind() == CONSTRUCT_CALL_RETURN) { 4514 // Return from an inlined construct call. In a test context the return value 4515 // will always evaluate to true, in a value context the return value needs 4516 // to be a JSObject. 4517 if (context->IsTest()) { 4518 CHECK_ALIVE(VisitForEffect(stmt->expression())); 4519 context->ReturnValue(graph()->GetConstantTrue()); 4520 } else if (context->IsEffect()) { 4521 CHECK_ALIVE(VisitForEffect(stmt->expression())); 4522 Goto(function_return(), state); 4523 } else { 4524 DCHECK(context->IsValue()); 4525 CHECK_ALIVE(VisitForValue(stmt->expression())); 4526 HValue* return_value = Pop(); 4527 HValue* receiver = environment()->arguments_environment()->Lookup(0); 4528 HHasInstanceTypeAndBranch* typecheck = 4529 New<HHasInstanceTypeAndBranch>(return_value, 4530 FIRST_JS_RECEIVER_TYPE, 4531 LAST_JS_RECEIVER_TYPE); 4532 HBasicBlock* if_spec_object = graph()->CreateBasicBlock(); 4533 HBasicBlock* not_spec_object = graph()->CreateBasicBlock(); 4534 typecheck->SetSuccessorAt(0, if_spec_object); 4535 typecheck->SetSuccessorAt(1, not_spec_object); 4536 FinishCurrentBlock(typecheck); 4537 AddLeaveInlined(if_spec_object, return_value, state); 4538 AddLeaveInlined(not_spec_object, receiver, state); 4539 } 4540 } else if (state->inlining_kind() == SETTER_CALL_RETURN) { 4541 // Return from an inlined setter call. The returned value is never used, the 4542 // value of an assignment is always the value of the RHS of the assignment. 4543 CHECK_ALIVE(VisitForEffect(stmt->expression())); 4544 if (context->IsTest()) { 4545 HValue* rhs = environment()->arguments_environment()->Lookup(1); 4546 context->ReturnValue(rhs); 4547 } else if (context->IsEffect()) { 4548 Goto(function_return(), state); 4549 } else { 4550 DCHECK(context->IsValue()); 4551 HValue* rhs = environment()->arguments_environment()->Lookup(1); 4552 AddLeaveInlined(rhs, state); 4553 } 4554 } else { 4555 // Return from a normal inlined function. Visit the subexpression in the 4556 // expression context of the call. 4557 if (context->IsTest()) { 4558 TestContext* test = TestContext::cast(context); 4559 VisitForControl(stmt->expression(), test->if_true(), test->if_false()); 4560 } else if (context->IsEffect()) { 4561 // Visit in value context and ignore the result. This is needed to keep 4562 // environment in sync with full-codegen since some visitors (e.g. 4563 // VisitCountOperation) use the operand stack differently depending on 4564 // context. 4565 CHECK_ALIVE(VisitForValue(stmt->expression())); 4566 Pop(); 4567 Goto(function_return(), state); 4568 } else { 4569 DCHECK(context->IsValue()); 4570 CHECK_ALIVE(VisitForValue(stmt->expression())); 4571 AddLeaveInlined(Pop(), state); 4572 } 4573 } 4574 set_current_block(NULL); 4575 } 4576 4577 4578 void HOptimizedGraphBuilder::VisitWithStatement(WithStatement* stmt) { 4579 DCHECK(!HasStackOverflow()); 4580 DCHECK(current_block() != NULL); 4581 DCHECK(current_block()->HasPredecessor()); 4582 return Bailout(kWithStatement); 4583 } 4584 4585 4586 void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { 4587 DCHECK(!HasStackOverflow()); 4588 DCHECK(current_block() != NULL); 4589 DCHECK(current_block()->HasPredecessor()); 4590 4591 ZoneList<CaseClause*>* clauses = stmt->cases(); 4592 int clause_count = clauses->length(); 4593 ZoneList<HBasicBlock*> body_blocks(clause_count, zone()); 4594 4595 CHECK_ALIVE(VisitForValue(stmt->tag())); 4596 Add<HSimulate>(stmt->EntryId()); 4597 HValue* tag_value = Top(); 4598 AstType* tag_type = bounds_.get(stmt->tag()).lower; 4599 4600 // 1. Build all the tests, with dangling true branches 4601 BailoutId default_id = BailoutId::None(); 4602 for (int i = 0; i < clause_count; ++i) { 4603 CaseClause* clause = clauses->at(i); 4604 if (clause->is_default()) { 4605 body_blocks.Add(NULL, zone()); 4606 if (default_id.IsNone()) default_id = clause->EntryId(); 4607 continue; 4608 } 4609 4610 // Generate a compare and branch. 4611 CHECK_BAILOUT(VisitForValue(clause->label())); 4612 if (current_block() == NULL) return Bailout(kUnsupportedSwitchStatement); 4613 HValue* label_value = Pop(); 4614 4615 AstType* label_type = bounds_.get(clause->label()).lower; 4616 AstType* combined_type = clause->compare_type(); 4617 HControlInstruction* compare = BuildCompareInstruction( 4618 Token::EQ_STRICT, tag_value, label_value, tag_type, label_type, 4619 combined_type, 4620 ScriptPositionToSourcePosition(stmt->tag()->position()), 4621 ScriptPositionToSourcePosition(clause->label()->position()), 4622 PUSH_BEFORE_SIMULATE, clause->id()); 4623 4624 HBasicBlock* next_test_block = graph()->CreateBasicBlock(); 4625 HBasicBlock* body_block = graph()->CreateBasicBlock(); 4626 body_blocks.Add(body_block, zone()); 4627 compare->SetSuccessorAt(0, body_block); 4628 compare->SetSuccessorAt(1, next_test_block); 4629 FinishCurrentBlock(compare); 4630 4631 set_current_block(body_block); 4632 Drop(1); // tag_value 4633 4634 set_current_block(next_test_block); 4635 } 4636 4637 // Save the current block to use for the default or to join with the 4638 // exit. 4639 HBasicBlock* last_block = current_block(); 4640 Drop(1); // tag_value 4641 4642 // 2. Loop over the clauses and the linked list of tests in lockstep, 4643 // translating the clause bodies. 4644 HBasicBlock* fall_through_block = NULL; 4645 4646 BreakAndContinueInfo break_info(stmt, scope()); 4647 { BreakAndContinueScope push(&break_info, this); 4648 for (int i = 0; i < clause_count; ++i) { 4649 CaseClause* clause = clauses->at(i); 4650 4651 // Identify the block where normal (non-fall-through) control flow 4652 // goes to. 4653 HBasicBlock* normal_block = NULL; 4654 if (clause->is_default()) { 4655 if (last_block == NULL) continue; 4656 normal_block = last_block; 4657 last_block = NULL; // Cleared to indicate we've handled it. 4658 } else { 4659 normal_block = body_blocks[i]; 4660 } 4661 4662 if (fall_through_block == NULL) { 4663 set_current_block(normal_block); 4664 } else { 4665 HBasicBlock* join = CreateJoin(fall_through_block, 4666 normal_block, 4667 clause->EntryId()); 4668 set_current_block(join); 4669 } 4670 4671 CHECK_BAILOUT(VisitStatements(clause->statements())); 4672 fall_through_block = current_block(); 4673 } 4674 } 4675 4676 // Create an up-to-3-way join. Use the break block if it exists since 4677 // it's already a join block. 4678 HBasicBlock* break_block = break_info.break_block(); 4679 if (break_block == NULL) { 4680 set_current_block(CreateJoin(fall_through_block, 4681 last_block, 4682 stmt->ExitId())); 4683 } else { 4684 if (fall_through_block != NULL) Goto(fall_through_block, break_block); 4685 if (last_block != NULL) Goto(last_block, break_block); 4686 break_block->SetJoinId(stmt->ExitId()); 4687 set_current_block(break_block); 4688 } 4689 } 4690 4691 void HOptimizedGraphBuilder::VisitLoopBody(IterationStatement* stmt, 4692 BailoutId stack_check_id, 4693 HBasicBlock* loop_entry) { 4694 Add<HSimulate>(stack_check_id); 4695 HStackCheck* stack_check = 4696 HStackCheck::cast(Add<HStackCheck>(HStackCheck::kBackwardsBranch)); 4697 DCHECK(loop_entry->IsLoopHeader()); 4698 loop_entry->loop_information()->set_stack_check(stack_check); 4699 CHECK_BAILOUT(Visit(stmt->body())); 4700 } 4701 4702 4703 void HOptimizedGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) { 4704 DCHECK(!HasStackOverflow()); 4705 DCHECK(current_block() != NULL); 4706 DCHECK(current_block()->HasPredecessor()); 4707 DCHECK(current_block() != NULL); 4708 HBasicBlock* loop_entry = BuildLoopEntry(stmt); 4709 4710 BreakAndContinueInfo break_info(stmt, scope()); 4711 { 4712 BreakAndContinueScope push(&break_info, this); 4713 CHECK_BAILOUT(VisitLoopBody(stmt, stmt->StackCheckId(), loop_entry)); 4714 } 4715 HBasicBlock* body_exit = JoinContinue( 4716 stmt, stmt->ContinueId(), current_block(), break_info.continue_block()); 4717 HBasicBlock* loop_successor = NULL; 4718 if (body_exit != NULL) { 4719 set_current_block(body_exit); 4720 loop_successor = graph()->CreateBasicBlock(); 4721 if (stmt->cond()->ToBooleanIsFalse()) { 4722 loop_entry->loop_information()->stack_check()->Eliminate(); 4723 Goto(loop_successor); 4724 body_exit = NULL; 4725 } else { 4726 // The block for a true condition, the actual predecessor block of the 4727 // back edge. 4728 body_exit = graph()->CreateBasicBlock(); 4729 CHECK_BAILOUT(VisitForControl(stmt->cond(), body_exit, loop_successor)); 4730 } 4731 if (body_exit != NULL && body_exit->HasPredecessor()) { 4732 body_exit->SetJoinId(stmt->BackEdgeId()); 4733 } else { 4734 body_exit = NULL; 4735 } 4736 if (loop_successor->HasPredecessor()) { 4737 loop_successor->SetJoinId(stmt->ExitId()); 4738 } else { 4739 loop_successor = NULL; 4740 } 4741 } 4742 HBasicBlock* loop_exit = CreateLoop(stmt, 4743 loop_entry, 4744 body_exit, 4745 loop_successor, 4746 break_info.break_block()); 4747 set_current_block(loop_exit); 4748 } 4749 4750 4751 void HOptimizedGraphBuilder::VisitWhileStatement(WhileStatement* stmt) { 4752 DCHECK(!HasStackOverflow()); 4753 DCHECK(current_block() != NULL); 4754 DCHECK(current_block()->HasPredecessor()); 4755 DCHECK(current_block() != NULL); 4756 HBasicBlock* loop_entry = BuildLoopEntry(stmt); 4757 4758 // If the condition is constant true, do not generate a branch. 4759 HBasicBlock* loop_successor = NULL; 4760 HBasicBlock* body_entry = graph()->CreateBasicBlock(); 4761 loop_successor = graph()->CreateBasicBlock(); 4762 CHECK_BAILOUT(VisitForControl(stmt->cond(), body_entry, loop_successor)); 4763 if (body_entry->HasPredecessor()) { 4764 body_entry->SetJoinId(stmt->BodyId()); 4765 set_current_block(body_entry); 4766 } 4767 if (loop_successor->HasPredecessor()) { 4768 loop_successor->SetJoinId(stmt->ExitId()); 4769 } else { 4770 loop_successor = NULL; 4771 } 4772 4773 BreakAndContinueInfo break_info(stmt, scope()); 4774 if (current_block() != NULL) { 4775 BreakAndContinueScope push(&break_info, this); 4776 CHECK_BAILOUT(VisitLoopBody(stmt, stmt->StackCheckId(), loop_entry)); 4777 } 4778 HBasicBlock* body_exit = JoinContinue( 4779 stmt, stmt->ContinueId(), current_block(), break_info.continue_block()); 4780 HBasicBlock* loop_exit = CreateLoop(stmt, 4781 loop_entry, 4782 body_exit, 4783 loop_successor, 4784 break_info.break_block()); 4785 set_current_block(loop_exit); 4786 } 4787 4788 4789 void HOptimizedGraphBuilder::VisitForStatement(ForStatement* stmt) { 4790 DCHECK(!HasStackOverflow()); 4791 DCHECK(current_block() != NULL); 4792 DCHECK(current_block()->HasPredecessor()); 4793 if (stmt->init() != NULL) { 4794 CHECK_ALIVE(Visit(stmt->init())); 4795 } 4796 DCHECK(current_block() != NULL); 4797 HBasicBlock* loop_entry = BuildLoopEntry(stmt); 4798 4799 HBasicBlock* loop_successor = graph()->CreateBasicBlock(); 4800 HBasicBlock* body_entry = graph()->CreateBasicBlock(); 4801 if (stmt->cond() != NULL) { 4802 CHECK_BAILOUT(VisitForControl(stmt->cond(), body_entry, loop_successor)); 4803 if (body_entry->HasPredecessor()) { 4804 body_entry->SetJoinId(stmt->BodyId()); 4805 set_current_block(body_entry); 4806 } 4807 if (loop_successor->HasPredecessor()) { 4808 loop_successor->SetJoinId(stmt->ExitId()); 4809 } else { 4810 loop_successor = NULL; 4811 } 4812 } else { 4813 // Create dummy control flow so that variable liveness analysis 4814 // produces teh correct result. 4815 HControlInstruction* branch = New<HBranch>(graph()->GetConstantTrue()); 4816 branch->SetSuccessorAt(0, body_entry); 4817 branch->SetSuccessorAt(1, loop_successor); 4818 FinishCurrentBlock(branch); 4819 set_current_block(body_entry); 4820 } 4821 4822 BreakAndContinueInfo break_info(stmt, scope()); 4823 if (current_block() != NULL) { 4824 BreakAndContinueScope push(&break_info, this); 4825 CHECK_BAILOUT(VisitLoopBody(stmt, stmt->StackCheckId(), loop_entry)); 4826 } 4827 HBasicBlock* body_exit = JoinContinue( 4828 stmt, stmt->ContinueId(), current_block(), break_info.continue_block()); 4829 4830 if (stmt->next() != NULL && body_exit != NULL) { 4831 set_current_block(body_exit); 4832 CHECK_BAILOUT(Visit(stmt->next())); 4833 body_exit = current_block(); 4834 } 4835 4836 HBasicBlock* loop_exit = CreateLoop(stmt, 4837 loop_entry, 4838 body_exit, 4839 loop_successor, 4840 break_info.break_block()); 4841 set_current_block(loop_exit); 4842 } 4843 4844 4845 void HOptimizedGraphBuilder::VisitForInStatement(ForInStatement* stmt) { 4846 DCHECK(!HasStackOverflow()); 4847 DCHECK(current_block() != NULL); 4848 DCHECK(current_block()->HasPredecessor()); 4849 4850 if (!stmt->each()->IsVariableProxy() || 4851 !stmt->each()->AsVariableProxy()->var()->IsStackLocal()) { 4852 return Bailout(kForInStatementWithNonLocalEachVariable); 4853 } 4854 4855 Variable* each_var = stmt->each()->AsVariableProxy()->var(); 4856 4857 CHECK_ALIVE(VisitForValue(stmt->enumerable())); 4858 HValue* enumerable = Top(); // Leave enumerable at the top. 4859 4860 IfBuilder if_undefined_or_null(this); 4861 if_undefined_or_null.If<HCompareObjectEqAndBranch>( 4862 enumerable, graph()->GetConstantUndefined()); 4863 if_undefined_or_null.Or(); 4864 if_undefined_or_null.If<HCompareObjectEqAndBranch>( 4865 enumerable, graph()->GetConstantNull()); 4866 if_undefined_or_null.ThenDeopt(DeoptimizeReason::kUndefinedOrNullInForIn); 4867 if_undefined_or_null.End(); 4868 BuildForInBody(stmt, each_var, enumerable); 4869 } 4870 4871 4872 void HOptimizedGraphBuilder::BuildForInBody(ForInStatement* stmt, 4873 Variable* each_var, 4874 HValue* enumerable) { 4875 Handle<Map> meta_map = isolate()->factory()->meta_map(); 4876 bool fast = stmt->for_in_type() == ForInStatement::FAST_FOR_IN; 4877 BuildCheckHeapObject(enumerable); 4878 Add<HCheckInstanceType>(enumerable, HCheckInstanceType::IS_JS_RECEIVER); 4879 Add<HSimulate>(stmt->ToObjectId()); 4880 if (fast) { 4881 HForInPrepareMap* map = Add<HForInPrepareMap>(enumerable); 4882 Push(map); 4883 Add<HSimulate>(stmt->EnumId()); 4884 Drop(1); 4885 Add<HCheckMaps>(map, meta_map); 4886 4887 HForInCacheArray* array = Add<HForInCacheArray>( 4888 enumerable, map, DescriptorArray::kEnumCacheBridgeCacheIndex); 4889 HValue* enum_length = BuildEnumLength(map); 4890 4891 HForInCacheArray* index_cache = Add<HForInCacheArray>( 4892 enumerable, map, DescriptorArray::kEnumCacheBridgeIndicesCacheIndex); 4893 array->set_index_cache(index_cache); 4894 4895 Push(map); 4896 Push(array); 4897 Push(enum_length); 4898 Add<HSimulate>(stmt->PrepareId()); 4899 } else { 4900 Runtime::FunctionId function_id = Runtime::kForInEnumerate; 4901 Add<HPushArguments>(enumerable); 4902 HCallRuntime* array = 4903 Add<HCallRuntime>(Runtime::FunctionForId(function_id), 1); 4904 Push(array); 4905 Add<HSimulate>(stmt->EnumId()); 4906 Drop(1); 4907 4908 IfBuilder if_fast(this); 4909 if_fast.If<HCompareMap>(array, meta_map); 4910 if_fast.Then(); 4911 { 4912 HValue* cache_map = array; 4913 HForInCacheArray* cache = Add<HForInCacheArray>( 4914 enumerable, cache_map, DescriptorArray::kEnumCacheBridgeCacheIndex); 4915 HValue* enum_length = BuildEnumLength(cache_map); 4916 Push(cache_map); 4917 Push(cache); 4918 Push(enum_length); 4919 Add<HSimulate>(stmt->PrepareId(), FIXED_SIMULATE); 4920 } 4921 if_fast.Else(); 4922 { 4923 Push(graph()->GetConstant1()); 4924 Push(array); 4925 Push(AddLoadFixedArrayLength(array)); 4926 Add<HSimulate>(stmt->PrepareId(), FIXED_SIMULATE); 4927 } 4928 } 4929 4930 Push(graph()->GetConstant0()); 4931 4932 HBasicBlock* loop_entry = BuildLoopEntry(stmt); 4933 4934 // Reload the values to ensure we have up-to-date values inside of the loop. 4935 // This is relevant especially for OSR where the values don't come from the 4936 // computation above, but from the OSR entry block. 4937 HValue* index = environment()->ExpressionStackAt(0); 4938 HValue* limit = environment()->ExpressionStackAt(1); 4939 HValue* array = environment()->ExpressionStackAt(2); 4940 HValue* type = environment()->ExpressionStackAt(3); 4941 enumerable = environment()->ExpressionStackAt(4); 4942 4943 // Check that we still have more keys. 4944 HCompareNumericAndBranch* compare_index = 4945 New<HCompareNumericAndBranch>(index, limit, Token::LT); 4946 compare_index->set_observed_input_representation( 4947 Representation::Smi(), Representation::Smi()); 4948 4949 HBasicBlock* loop_body = graph()->CreateBasicBlock(); 4950 HBasicBlock* loop_successor = graph()->CreateBasicBlock(); 4951 4952 compare_index->SetSuccessorAt(0, loop_body); 4953 compare_index->SetSuccessorAt(1, loop_successor); 4954 FinishCurrentBlock(compare_index); 4955 4956 set_current_block(loop_successor); 4957 Drop(5); 4958 4959 set_current_block(loop_body); 4960 4961 // Compute the next enumerated value. 4962 HValue* key = Add<HLoadKeyed>(array, index, index, nullptr, FAST_ELEMENTS); 4963 4964 HBasicBlock* continue_block = nullptr; 4965 if (fast) { 4966 // Check if expected map still matches that of the enumerable. 4967 Add<HCheckMapValue>(enumerable, type); 4968 Add<HSimulate>(stmt->FilterId()); 4969 } else { 4970 // We need the continue block here to be able to skip over invalidated keys. 4971 continue_block = graph()->CreateBasicBlock(); 4972 4973 // We cannot use the IfBuilder here, since we need to be able to jump 4974 // over the loop body in case of undefined result from %ForInFilter, 4975 // and the poor soul that is the IfBuilder get's really confused about 4976 // such "advanced control flow requirements". 4977 HBasicBlock* if_fast = graph()->CreateBasicBlock(); 4978 HBasicBlock* if_slow = graph()->CreateBasicBlock(); 4979 HBasicBlock* if_slow_pass = graph()->CreateBasicBlock(); 4980 HBasicBlock* if_slow_skip = graph()->CreateBasicBlock(); 4981 HBasicBlock* if_join = graph()->CreateBasicBlock(); 4982 4983 // Check if expected map still matches that of the enumerable. 4984 HValue* enumerable_map = 4985 Add<HLoadNamedField>(enumerable, nullptr, HObjectAccess::ForMap()); 4986 FinishCurrentBlock( 4987 New<HCompareObjectEqAndBranch>(enumerable_map, type, if_fast, if_slow)); 4988 set_current_block(if_fast); 4989 { 4990 // The enum cache for enumerable is still valid, no need to check key. 4991 Push(key); 4992 Goto(if_join); 4993 } 4994 set_current_block(if_slow); 4995 { 4996 Callable callable = CodeFactory::ForInFilter(isolate()); 4997 HValue* values[] = {key, enumerable}; 4998 HConstant* stub_value = Add<HConstant>(callable.code()); 4999 Push(Add<HCallWithDescriptor>(stub_value, 0, callable.descriptor(), 5000 ArrayVector(values))); 5001 Add<HSimulate>(stmt->FilterId()); 5002 FinishCurrentBlock(New<HCompareObjectEqAndBranch>( 5003 Top(), graph()->GetConstantUndefined(), if_slow_skip, if_slow_pass)); 5004 } 5005 set_current_block(if_slow_pass); 5006 { Goto(if_join); } 5007 set_current_block(if_slow_skip); 5008 { 5009 // The key is no longer valid for enumerable, skip it. 5010 Drop(1); 5011 Goto(continue_block); 5012 } 5013 if_join->SetJoinId(stmt->FilterId()); 5014 set_current_block(if_join); 5015 key = Pop(); 5016 } 5017 5018 Bind(each_var, key); 5019 Add<HSimulate>(stmt->AssignmentId()); 5020 5021 BreakAndContinueInfo break_info(stmt, scope(), 5); 5022 break_info.set_continue_block(continue_block); 5023 { 5024 BreakAndContinueScope push(&break_info, this); 5025 CHECK_BAILOUT(VisitLoopBody(stmt, stmt->StackCheckId(), loop_entry)); 5026 } 5027 5028 HBasicBlock* body_exit = JoinContinue( 5029 stmt, stmt->IncrementId(), current_block(), break_info.continue_block()); 5030 5031 if (body_exit != NULL) { 5032 set_current_block(body_exit); 5033 5034 HValue* current_index = Pop(); 5035 HValue* increment = 5036 AddUncasted<HAdd>(current_index, graph()->GetConstant1()); 5037 increment->ClearFlag(HValue::kCanOverflow); 5038 Push(increment); 5039 body_exit = current_block(); 5040 } 5041 5042 HBasicBlock* loop_exit = CreateLoop(stmt, 5043 loop_entry, 5044 body_exit, 5045 loop_successor, 5046 break_info.break_block()); 5047 5048 set_current_block(loop_exit); 5049 } 5050 5051 5052 void HOptimizedGraphBuilder::VisitForOfStatement(ForOfStatement* stmt) { 5053 DCHECK(!HasStackOverflow()); 5054 DCHECK(current_block() != NULL); 5055 DCHECK(current_block()->HasPredecessor()); 5056 return Bailout(kForOfStatement); 5057 } 5058 5059 5060 void HOptimizedGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) { 5061 DCHECK(!HasStackOverflow()); 5062 DCHECK(current_block() != NULL); 5063 DCHECK(current_block()->HasPredecessor()); 5064 return Bailout(kTryCatchStatement); 5065 } 5066 5067 5068 void HOptimizedGraphBuilder::VisitTryFinallyStatement( 5069 TryFinallyStatement* stmt) { 5070 DCHECK(!HasStackOverflow()); 5071 DCHECK(current_block() != NULL); 5072 DCHECK(current_block()->HasPredecessor()); 5073 return Bailout(kTryFinallyStatement); 5074 } 5075 5076 5077 void HOptimizedGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) { 5078 DCHECK(!HasStackOverflow()); 5079 DCHECK(current_block() != NULL); 5080 DCHECK(current_block()->HasPredecessor()); 5081 return Bailout(kDebuggerStatement); 5082 } 5083 5084 5085 void HOptimizedGraphBuilder::VisitCaseClause(CaseClause* clause) { 5086 UNREACHABLE(); 5087 } 5088 5089 5090 void HOptimizedGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { 5091 DCHECK(!HasStackOverflow()); 5092 DCHECK(current_block() != NULL); 5093 DCHECK(current_block()->HasPredecessor()); 5094 Handle<SharedFunctionInfo> shared_info = Compiler::GetSharedFunctionInfo( 5095 expr, current_info()->script(), top_info()); 5096 // We also have a stack overflow if the recursive compilation did. 5097 if (HasStackOverflow()) return; 5098 // Use the fast case closure allocation code that allocates in new 5099 // space for nested functions that don't need pretenuring. 5100 HConstant* shared_info_value = Add<HConstant>(shared_info); 5101 HInstruction* instr; 5102 if (!expr->pretenure()) { 5103 FastNewClosureStub stub(isolate()); 5104 FastNewClosureDescriptor descriptor(isolate()); 5105 HValue* values[] = {shared_info_value}; 5106 HConstant* stub_value = Add<HConstant>(stub.GetCode()); 5107 instr = New<HCallWithDescriptor>(stub_value, 0, descriptor, 5108 ArrayVector(values)); 5109 } else { 5110 Add<HPushArguments>(shared_info_value); 5111 Runtime::FunctionId function_id = 5112 expr->pretenure() ? Runtime::kNewClosure_Tenured : Runtime::kNewClosure; 5113 instr = New<HCallRuntime>(Runtime::FunctionForId(function_id), 1); 5114 } 5115 return ast_context()->ReturnInstruction(instr, expr->id()); 5116 } 5117 5118 5119 void HOptimizedGraphBuilder::VisitClassLiteral(ClassLiteral* lit) { 5120 DCHECK(!HasStackOverflow()); 5121 DCHECK(current_block() != NULL); 5122 DCHECK(current_block()->HasPredecessor()); 5123 return Bailout(kClassLiteral); 5124 } 5125 5126 5127 void HOptimizedGraphBuilder::VisitNativeFunctionLiteral( 5128 NativeFunctionLiteral* expr) { 5129 DCHECK(!HasStackOverflow()); 5130 DCHECK(current_block() != NULL); 5131 DCHECK(current_block()->HasPredecessor()); 5132 return Bailout(kNativeFunctionLiteral); 5133 } 5134 5135 5136 void HOptimizedGraphBuilder::VisitDoExpression(DoExpression* expr) { 5137 DoExpressionScope scope(this); 5138 DCHECK(!HasStackOverflow()); 5139 DCHECK(current_block() != NULL); 5140 DCHECK(current_block()->HasPredecessor()); 5141 CHECK_ALIVE(VisitBlock(expr->block())); 5142 Visit(expr->result()); 5143 } 5144 5145 5146 void HOptimizedGraphBuilder::VisitConditional(Conditional* expr) { 5147 DCHECK(!HasStackOverflow()); 5148 DCHECK(current_block() != NULL); 5149 DCHECK(current_block()->HasPredecessor()); 5150 HBasicBlock* cond_true = graph()->CreateBasicBlock(); 5151 HBasicBlock* cond_false = graph()->CreateBasicBlock(); 5152 CHECK_BAILOUT(VisitForControl(expr->condition(), cond_true, cond_false)); 5153 5154 // Visit the true and false subexpressions in the same AST context as the 5155 // whole expression. 5156 if (cond_true->HasPredecessor()) { 5157 cond_true->SetJoinId(expr->ThenId()); 5158 set_current_block(cond_true); 5159 CHECK_BAILOUT(Visit(expr->then_expression())); 5160 cond_true = current_block(); 5161 } else { 5162 cond_true = NULL; 5163 } 5164 5165 if (cond_false->HasPredecessor()) { 5166 cond_false->SetJoinId(expr->ElseId()); 5167 set_current_block(cond_false); 5168 CHECK_BAILOUT(Visit(expr->else_expression())); 5169 cond_false = current_block(); 5170 } else { 5171 cond_false = NULL; 5172 } 5173 5174 if (!ast_context()->IsTest()) { 5175 HBasicBlock* join = CreateJoin(cond_true, cond_false, expr->id()); 5176 set_current_block(join); 5177 if (join != NULL && !ast_context()->IsEffect()) { 5178 return ast_context()->ReturnValue(Pop()); 5179 } 5180 } 5181 } 5182 5183 bool HOptimizedGraphBuilder::CanInlineGlobalPropertyAccess( 5184 Variable* var, LookupIterator* it, PropertyAccessType access_type) { 5185 if (var->is_this()) return false; 5186 return CanInlineGlobalPropertyAccess(it, access_type); 5187 } 5188 5189 bool HOptimizedGraphBuilder::CanInlineGlobalPropertyAccess( 5190 LookupIterator* it, PropertyAccessType access_type) { 5191 if (!current_info()->has_global_object()) { 5192 return false; 5193 } 5194 5195 switch (it->state()) { 5196 case LookupIterator::ACCESSOR: 5197 case LookupIterator::ACCESS_CHECK: 5198 case LookupIterator::INTERCEPTOR: 5199 case LookupIterator::INTEGER_INDEXED_EXOTIC: 5200 case LookupIterator::NOT_FOUND: 5201 return false; 5202 case LookupIterator::DATA: 5203 if (access_type == STORE && it->IsReadOnly()) return false; 5204 if (!it->GetHolder<JSObject>()->IsJSGlobalObject()) return false; 5205 return true; 5206 case LookupIterator::JSPROXY: 5207 case LookupIterator::TRANSITION: 5208 UNREACHABLE(); 5209 } 5210 UNREACHABLE(); 5211 return false; 5212 } 5213 5214 5215 HValue* HOptimizedGraphBuilder::BuildContextChainWalk(Variable* var) { 5216 DCHECK(var->IsContextSlot()); 5217 HValue* context = environment()->context(); 5218 int length = scope()->ContextChainLength(var->scope()); 5219 while (length-- > 0) { 5220 context = Add<HLoadNamedField>( 5221 context, nullptr, 5222 HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX)); 5223 } 5224 return context; 5225 } 5226 5227 void HOptimizedGraphBuilder::InlineGlobalPropertyLoad(LookupIterator* it, 5228 BailoutId ast_id) { 5229 Handle<PropertyCell> cell = it->GetPropertyCell(); 5230 top_info()->dependencies()->AssumePropertyCell(cell); 5231 auto cell_type = it->property_details().cell_type(); 5232 if (cell_type == PropertyCellType::kConstant || 5233 cell_type == PropertyCellType::kUndefined) { 5234 Handle<Object> constant_object(cell->value(), isolate()); 5235 if (constant_object->IsConsString()) { 5236 constant_object = String::Flatten(Handle<String>::cast(constant_object)); 5237 } 5238 HConstant* constant = New<HConstant>(constant_object); 5239 return ast_context()->ReturnInstruction(constant, ast_id); 5240 } else { 5241 auto access = HObjectAccess::ForPropertyCellValue(); 5242 UniqueSet<Map>* field_maps = nullptr; 5243 if (cell_type == PropertyCellType::kConstantType) { 5244 switch (cell->GetConstantType()) { 5245 case PropertyCellConstantType::kSmi: 5246 access = access.WithRepresentation(Representation::Smi()); 5247 break; 5248 case PropertyCellConstantType::kStableMap: { 5249 // Check that the map really is stable. The heap object could 5250 // have mutated without the cell updating state. In that case, 5251 // make no promises about the loaded value except that it's a 5252 // heap object. 5253 access = access.WithRepresentation(Representation::HeapObject()); 5254 Handle<Map> map(HeapObject::cast(cell->value())->map()); 5255 if (map->is_stable()) { 5256 field_maps = new (zone()) 5257 UniqueSet<Map>(Unique<Map>::CreateImmovable(map), zone()); 5258 } 5259 break; 5260 } 5261 } 5262 } 5263 HConstant* cell_constant = Add<HConstant>(cell); 5264 HLoadNamedField* instr; 5265 if (field_maps == nullptr) { 5266 instr = New<HLoadNamedField>(cell_constant, nullptr, access); 5267 } else { 5268 instr = New<HLoadNamedField>(cell_constant, nullptr, access, field_maps, 5269 HType::HeapObject()); 5270 } 5271 instr->ClearDependsOnFlag(kInobjectFields); 5272 instr->SetDependsOnFlag(kGlobalVars); 5273 return ast_context()->ReturnInstruction(instr, ast_id); 5274 } 5275 } 5276 5277 void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) { 5278 DCHECK(!HasStackOverflow()); 5279 DCHECK(current_block() != NULL); 5280 DCHECK(current_block()->HasPredecessor()); 5281 Variable* variable = expr->var(); 5282 switch (variable->location()) { 5283 case VariableLocation::UNALLOCATED: { 5284 if (IsLexicalVariableMode(variable->mode())) { 5285 // TODO(rossberg): should this be an DCHECK? 5286 return Bailout(kReferenceToGlobalLexicalVariable); 5287 } 5288 // Handle known global constants like 'undefined' specially to avoid a 5289 // load from a global cell for them. 5290 Handle<Object> constant_value = 5291 isolate()->factory()->GlobalConstantFor(variable->name()); 5292 if (!constant_value.is_null()) { 5293 HConstant* instr = New<HConstant>(constant_value); 5294 return ast_context()->ReturnInstruction(instr, expr->id()); 5295 } 5296 5297 Handle<JSGlobalObject> global(current_info()->global_object()); 5298 5299 // Lookup in script contexts. 5300 { 5301 Handle<ScriptContextTable> script_contexts( 5302 global->native_context()->script_context_table()); 5303 ScriptContextTable::LookupResult lookup; 5304 if (ScriptContextTable::Lookup(script_contexts, variable->name(), 5305 &lookup)) { 5306 Handle<Context> script_context = ScriptContextTable::GetContext( 5307 script_contexts, lookup.context_index); 5308 Handle<Object> current_value = 5309 FixedArray::get(*script_context, lookup.slot_index, isolate()); 5310 5311 // If the values is not the hole, it will stay initialized, 5312 // so no need to generate a check. 5313 if (current_value->IsTheHole(isolate())) { 5314 return Bailout(kReferenceToUninitializedVariable); 5315 } 5316 HInstruction* result = New<HLoadNamedField>( 5317 Add<HConstant>(script_context), nullptr, 5318 HObjectAccess::ForContextSlot(lookup.slot_index)); 5319 return ast_context()->ReturnInstruction(result, expr->id()); 5320 } 5321 } 5322 5323 LookupIterator it(global, variable->name(), LookupIterator::OWN); 5324 it.TryLookupCachedProperty(); 5325 if (CanInlineGlobalPropertyAccess(variable, &it, LOAD)) { 5326 InlineGlobalPropertyLoad(&it, expr->id()); 5327 return; 5328 } else { 5329 Handle<TypeFeedbackVector> vector(current_feedback_vector(), isolate()); 5330 5331 HValue* vector_value = Add<HConstant>(vector); 5332 HValue* slot_value = 5333 Add<HConstant>(vector->GetIndex(expr->VariableFeedbackSlot())); 5334 Callable callable = CodeFactory::LoadGlobalICInOptimizedCode( 5335 isolate(), ast_context()->typeof_mode()); 5336 HValue* stub = Add<HConstant>(callable.code()); 5337 HValue* values[] = {slot_value, vector_value}; 5338 HCallWithDescriptor* instr = New<HCallWithDescriptor>( 5339 Code::LOAD_GLOBAL_IC, stub, 0, callable.descriptor(), 5340 ArrayVector(values)); 5341 return ast_context()->ReturnInstruction(instr, expr->id()); 5342 } 5343 } 5344 5345 case VariableLocation::PARAMETER: 5346 case VariableLocation::LOCAL: { 5347 HValue* value = LookupAndMakeLive(variable); 5348 if (value == graph()->GetConstantHole()) { 5349 DCHECK(IsDeclaredVariableMode(variable->mode()) && 5350 variable->mode() != VAR); 5351 return Bailout(kReferenceToUninitializedVariable); 5352 } 5353 return ast_context()->ReturnValue(value); 5354 } 5355 5356 case VariableLocation::CONTEXT: { 5357 HValue* context = BuildContextChainWalk(variable); 5358 HLoadContextSlot::Mode mode; 5359 switch (variable->mode()) { 5360 case LET: 5361 case CONST: 5362 mode = HLoadContextSlot::kCheckDeoptimize; 5363 break; 5364 default: 5365 mode = HLoadContextSlot::kNoCheck; 5366 break; 5367 } 5368 HLoadContextSlot* instr = 5369 new(zone()) HLoadContextSlot(context, variable->index(), mode); 5370 return ast_context()->ReturnInstruction(instr, expr->id()); 5371 } 5372 5373 case VariableLocation::LOOKUP: 5374 return Bailout(kReferenceToAVariableWhichRequiresDynamicLookup); 5375 5376 case VariableLocation::MODULE: 5377 UNREACHABLE(); 5378 } 5379 } 5380 5381 5382 void HOptimizedGraphBuilder::VisitLiteral(Literal* expr) { 5383 DCHECK(!HasStackOverflow()); 5384 DCHECK(current_block() != NULL); 5385 DCHECK(current_block()->HasPredecessor()); 5386 HConstant* instr = New<HConstant>(expr->value()); 5387 return ast_context()->ReturnInstruction(instr, expr->id()); 5388 } 5389 5390 5391 void HOptimizedGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { 5392 DCHECK(!HasStackOverflow()); 5393 DCHECK(current_block() != NULL); 5394 DCHECK(current_block()->HasPredecessor()); 5395 Callable callable = CodeFactory::FastCloneRegExp(isolate()); 5396 HValue* values[] = {AddThisFunction(), Add<HConstant>(expr->literal_index()), 5397 Add<HConstant>(expr->pattern()), 5398 Add<HConstant>(expr->flags())}; 5399 HConstant* stub_value = Add<HConstant>(callable.code()); 5400 HInstruction* instr = New<HCallWithDescriptor>( 5401 stub_value, 0, callable.descriptor(), ArrayVector(values)); 5402 return ast_context()->ReturnInstruction(instr, expr->id()); 5403 } 5404 5405 5406 static bool CanInlinePropertyAccess(Handle<Map> map) { 5407 if (map->instance_type() == HEAP_NUMBER_TYPE) return true; 5408 if (map->instance_type() < FIRST_NONSTRING_TYPE) return true; 5409 return map->IsJSObjectMap() && !map->is_dictionary_map() && 5410 !map->has_named_interceptor() && 5411 // TODO(verwaest): Whitelist contexts to which we have access. 5412 !map->is_access_check_needed(); 5413 } 5414 5415 5416 // Determines whether the given array or object literal boilerplate satisfies 5417 // all limits to be considered for fast deep-copying and computes the total 5418 // size of all objects that are part of the graph. 5419 static bool IsFastLiteral(Handle<JSObject> boilerplate, 5420 int max_depth, 5421 int* max_properties) { 5422 if (boilerplate->map()->is_deprecated() && 5423 !JSObject::TryMigrateInstance(boilerplate)) { 5424 return false; 5425 } 5426 5427 DCHECK(max_depth >= 0 && *max_properties >= 0); 5428 if (max_depth == 0) return false; 5429 5430 Isolate* isolate = boilerplate->GetIsolate(); 5431 Handle<FixedArrayBase> elements(boilerplate->elements()); 5432 if (elements->length() > 0 && 5433 elements->map() != isolate->heap()->fixed_cow_array_map()) { 5434 if (boilerplate->HasFastSmiOrObjectElements()) { 5435 Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements); 5436 int length = elements->length(); 5437 for (int i = 0; i < length; i++) { 5438 if ((*max_properties)-- == 0) return false; 5439 Handle<Object> value(fast_elements->get(i), isolate); 5440 if (value->IsJSObject()) { 5441 Handle<JSObject> value_object = Handle<JSObject>::cast(value); 5442 if (!IsFastLiteral(value_object, 5443 max_depth - 1, 5444 max_properties)) { 5445 return false; 5446 } 5447 } 5448 } 5449 } else if (!boilerplate->HasFastDoubleElements()) { 5450 return false; 5451 } 5452 } 5453 5454 Handle<FixedArray> properties(boilerplate->properties()); 5455 if (properties->length() > 0) { 5456 return false; 5457 } else { 5458 Handle<DescriptorArray> descriptors( 5459 boilerplate->map()->instance_descriptors()); 5460 int limit = boilerplate->map()->NumberOfOwnDescriptors(); 5461 for (int i = 0; i < limit; i++) { 5462 PropertyDetails details = descriptors->GetDetails(i); 5463 if (details.type() != DATA) continue; 5464 if ((*max_properties)-- == 0) return false; 5465 FieldIndex field_index = FieldIndex::ForDescriptor(boilerplate->map(), i); 5466 if (boilerplate->IsUnboxedDoubleField(field_index)) continue; 5467 Handle<Object> value(boilerplate->RawFastPropertyAt(field_index), 5468 isolate); 5469 if (value->IsJSObject()) { 5470 Handle<JSObject> value_object = Handle<JSObject>::cast(value); 5471 if (!IsFastLiteral(value_object, 5472 max_depth - 1, 5473 max_properties)) { 5474 return false; 5475 } 5476 } 5477 } 5478 } 5479 return true; 5480 } 5481 5482 5483 void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { 5484 DCHECK(!HasStackOverflow()); 5485 DCHECK(current_block() != NULL); 5486 DCHECK(current_block()->HasPredecessor()); 5487 5488 Handle<JSFunction> closure = function_state()->compilation_info()->closure(); 5489 HInstruction* literal; 5490 5491 // Check whether to use fast or slow deep-copying for boilerplate. 5492 int max_properties = kMaxFastLiteralProperties; 5493 Handle<Object> literals_cell( 5494 closure->literals()->literal(expr->literal_index()), isolate()); 5495 Handle<AllocationSite> site; 5496 Handle<JSObject> boilerplate; 5497 if (!literals_cell->IsUndefined(isolate())) { 5498 // Retrieve the boilerplate 5499 site = Handle<AllocationSite>::cast(literals_cell); 5500 boilerplate = Handle<JSObject>(JSObject::cast(site->transition_info()), 5501 isolate()); 5502 } 5503 5504 if (!boilerplate.is_null() && 5505 IsFastLiteral(boilerplate, kMaxFastLiteralDepth, &max_properties)) { 5506 AllocationSiteUsageContext site_context(isolate(), site, false); 5507 site_context.EnterNewScope(); 5508 literal = BuildFastLiteral(boilerplate, &site_context); 5509 site_context.ExitScope(site, boilerplate); 5510 } else { 5511 NoObservableSideEffectsScope no_effects(this); 5512 Handle<FixedArray> constant_properties = expr->constant_properties(); 5513 int literal_index = expr->literal_index(); 5514 int flags = expr->ComputeFlags(true); 5515 5516 Add<HPushArguments>(AddThisFunction(), Add<HConstant>(literal_index), 5517 Add<HConstant>(constant_properties), 5518 Add<HConstant>(flags)); 5519 5520 Runtime::FunctionId function_id = Runtime::kCreateObjectLiteral; 5521 literal = Add<HCallRuntime>(Runtime::FunctionForId(function_id), 4); 5522 } 5523 5524 // The object is expected in the bailout environment during computation 5525 // of the property values and is the value of the entire expression. 5526 Push(literal); 5527 for (int i = 0; i < expr->properties()->length(); i++) { 5528 ObjectLiteral::Property* property = expr->properties()->at(i); 5529 if (property->is_computed_name()) return Bailout(kComputedPropertyName); 5530 if (property->IsCompileTimeValue()) continue; 5531 5532 Literal* key = property->key()->AsLiteral(); 5533 Expression* value = property->value(); 5534 5535 switch (property->kind()) { 5536 case ObjectLiteral::Property::MATERIALIZED_LITERAL: 5537 DCHECK(!CompileTimeValue::IsCompileTimeValue(value)); 5538 // Fall through. 5539 case ObjectLiteral::Property::COMPUTED: 5540 // It is safe to use [[Put]] here because the boilerplate already 5541 // contains computed properties with an uninitialized value. 5542 if (key->IsStringLiteral()) { 5543 DCHECK(key->IsPropertyName()); 5544 if (property->emit_store()) { 5545 CHECK_ALIVE(VisitForValue(value)); 5546 HValue* value = Pop(); 5547 5548 Handle<Map> map = property->GetReceiverType(); 5549 Handle<String> name = key->AsPropertyName(); 5550 HValue* store; 5551 FeedbackVectorSlot slot = property->GetSlot(); 5552 if (map.is_null()) { 5553 // If we don't know the monomorphic type, do a generic store. 5554 CHECK_ALIVE(store = BuildNamedGeneric(STORE, NULL, slot, literal, 5555 name, value)); 5556 } else { 5557 PropertyAccessInfo info(this, STORE, map, name); 5558 if (info.CanAccessMonomorphic()) { 5559 HValue* checked_literal = Add<HCheckMaps>(literal, map); 5560 DCHECK(!info.IsAccessorConstant()); 5561 store = BuildMonomorphicAccess( 5562 &info, literal, checked_literal, value, 5563 BailoutId::None(), BailoutId::None()); 5564 } else { 5565 CHECK_ALIVE(store = BuildNamedGeneric(STORE, NULL, slot, 5566 literal, name, value)); 5567 } 5568 } 5569 if (store->IsInstruction()) { 5570 AddInstruction(HInstruction::cast(store)); 5571 } 5572 DCHECK(store->HasObservableSideEffects()); 5573 Add<HSimulate>(key->id(), REMOVABLE_SIMULATE); 5574 5575 // Add [[HomeObject]] to function literals. 5576 if (FunctionLiteral::NeedsHomeObject(property->value())) { 5577 Handle<Symbol> sym = isolate()->factory()->home_object_symbol(); 5578 HInstruction* store_home = BuildNamedGeneric( 5579 STORE, NULL, property->GetSlot(1), value, sym, literal); 5580 AddInstruction(store_home); 5581 DCHECK(store_home->HasObservableSideEffects()); 5582 Add<HSimulate>(property->value()->id(), REMOVABLE_SIMULATE); 5583 } 5584 } else { 5585 CHECK_ALIVE(VisitForEffect(value)); 5586 } 5587 break; 5588 } 5589 // Fall through. 5590 case ObjectLiteral::Property::PROTOTYPE: 5591 case ObjectLiteral::Property::SETTER: 5592 case ObjectLiteral::Property::GETTER: 5593 return Bailout(kObjectLiteralWithComplexProperty); 5594 default: UNREACHABLE(); 5595 } 5596 } 5597 5598 return ast_context()->ReturnValue(Pop()); 5599 } 5600 5601 5602 void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { 5603 DCHECK(!HasStackOverflow()); 5604 DCHECK(current_block() != NULL); 5605 DCHECK(current_block()->HasPredecessor()); 5606 ZoneList<Expression*>* subexprs = expr->values(); 5607 int length = subexprs->length(); 5608 HInstruction* literal; 5609 5610 Handle<AllocationSite> site; 5611 Handle<LiteralsArray> literals(environment()->closure()->literals(), 5612 isolate()); 5613 Handle<Object> literals_cell(literals->literal(expr->literal_index()), 5614 isolate()); 5615 Handle<JSObject> boilerplate_object; 5616 if (!literals_cell->IsUndefined(isolate())) { 5617 DCHECK(literals_cell->IsAllocationSite()); 5618 site = Handle<AllocationSite>::cast(literals_cell); 5619 boilerplate_object = Handle<JSObject>( 5620 JSObject::cast(site->transition_info()), isolate()); 5621 } 5622 5623 // Check whether to use fast or slow deep-copying for boilerplate. 5624 int max_properties = kMaxFastLiteralProperties; 5625 if (!boilerplate_object.is_null() && 5626 IsFastLiteral(boilerplate_object, kMaxFastLiteralDepth, 5627 &max_properties)) { 5628 DCHECK(site->SitePointsToLiteral()); 5629 AllocationSiteUsageContext site_context(isolate(), site, false); 5630 site_context.EnterNewScope(); 5631 literal = BuildFastLiteral(boilerplate_object, &site_context); 5632 site_context.ExitScope(site, boilerplate_object); 5633 } else { 5634 NoObservableSideEffectsScope no_effects(this); 5635 Handle<FixedArray> constants = expr->constant_elements(); 5636 int literal_index = expr->literal_index(); 5637 int flags = expr->ComputeFlags(true); 5638 5639 Add<HPushArguments>(AddThisFunction(), Add<HConstant>(literal_index), 5640 Add<HConstant>(constants), Add<HConstant>(flags)); 5641 5642 Runtime::FunctionId function_id = Runtime::kCreateArrayLiteral; 5643 literal = Add<HCallRuntime>(Runtime::FunctionForId(function_id), 4); 5644 5645 // Register to deopt if the boilerplate ElementsKind changes. 5646 if (!site.is_null()) { 5647 top_info()->dependencies()->AssumeTransitionStable(site); 5648 } 5649 } 5650 5651 // The array is expected in the bailout environment during computation 5652 // of the property values and is the value of the entire expression. 5653 Push(literal); 5654 5655 HInstruction* elements = NULL; 5656 5657 for (int i = 0; i < length; i++) { 5658 Expression* subexpr = subexprs->at(i); 5659 DCHECK(!subexpr->IsSpread()); 5660 5661 // If the subexpression is a literal or a simple materialized literal it 5662 // is already set in the cloned array. 5663 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; 5664 5665 CHECK_ALIVE(VisitForValue(subexpr)); 5666 HValue* value = Pop(); 5667 if (!Smi::IsValid(i)) return Bailout(kNonSmiKeyInArrayLiteral); 5668 5669 elements = AddLoadElements(literal); 5670 5671 HValue* key = Add<HConstant>(i); 5672 5673 if (!boilerplate_object.is_null()) { 5674 ElementsKind boilerplate_elements_kind = 5675 boilerplate_object->GetElementsKind(); 5676 switch (boilerplate_elements_kind) { 5677 case FAST_SMI_ELEMENTS: 5678 case FAST_HOLEY_SMI_ELEMENTS: 5679 case FAST_ELEMENTS: 5680 case FAST_HOLEY_ELEMENTS: 5681 case FAST_DOUBLE_ELEMENTS: 5682 case FAST_HOLEY_DOUBLE_ELEMENTS: { 5683 Add<HStoreKeyed>(elements, key, value, nullptr, 5684 boilerplate_elements_kind); 5685 break; 5686 } 5687 default: 5688 UNREACHABLE(); 5689 break; 5690 } 5691 } else { 5692 HInstruction* instr = BuildKeyedGeneric( 5693 STORE, expr, expr->LiteralFeedbackSlot(), literal, key, value); 5694 AddInstruction(instr); 5695 } 5696 5697 Add<HSimulate>(expr->GetIdForElement(i)); 5698 } 5699 5700 return ast_context()->ReturnValue(Pop()); 5701 } 5702 5703 5704 HCheckMaps* HOptimizedGraphBuilder::AddCheckMap(HValue* object, 5705 Handle<Map> map) { 5706 BuildCheckHeapObject(object); 5707 return Add<HCheckMaps>(object, map); 5708 } 5709 5710 5711 HInstruction* HOptimizedGraphBuilder::BuildLoadNamedField( 5712 PropertyAccessInfo* info, 5713 HValue* checked_object) { 5714 // See if this is a load for an immutable property 5715 if (checked_object->ActualValue()->IsConstant()) { 5716 Handle<Object> object( 5717 HConstant::cast(checked_object->ActualValue())->handle(isolate())); 5718 5719 if (object->IsJSObject()) { 5720 LookupIterator it(object, info->name(), 5721 LookupIterator::OWN_SKIP_INTERCEPTOR); 5722 Handle<Object> value = JSReceiver::GetDataProperty(&it); 5723 if (it.IsFound() && it.IsReadOnly() && !it.IsConfigurable()) { 5724 return New<HConstant>(value); 5725 } 5726 } 5727 } 5728 5729 HObjectAccess access = info->access(); 5730 if (access.representation().IsDouble() && 5731 (!FLAG_unbox_double_fields || !access.IsInobject())) { 5732 // Load the heap number. 5733 checked_object = Add<HLoadNamedField>( 5734 checked_object, nullptr, 5735 access.WithRepresentation(Representation::Tagged())); 5736 // Load the double value from it. 5737 access = HObjectAccess::ForHeapNumberValue(); 5738 } 5739 5740 SmallMapList* map_list = info->field_maps(); 5741 if (map_list->length() == 0) { 5742 return New<HLoadNamedField>(checked_object, checked_object, access); 5743 } 5744 5745 UniqueSet<Map>* maps = new(zone()) UniqueSet<Map>(map_list->length(), zone()); 5746 for (int i = 0; i < map_list->length(); ++i) { 5747 maps->Add(Unique<Map>::CreateImmovable(map_list->at(i)), zone()); 5748 } 5749 return New<HLoadNamedField>( 5750 checked_object, checked_object, access, maps, info->field_type()); 5751 } 5752 5753 5754 HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField( 5755 PropertyAccessInfo* info, 5756 HValue* checked_object, 5757 HValue* value) { 5758 bool transition_to_field = info->IsTransition(); 5759 // TODO(verwaest): Move this logic into PropertyAccessInfo. 5760 HObjectAccess field_access = info->access(); 5761 5762 HStoreNamedField *instr; 5763 if (field_access.representation().IsDouble() && 5764 (!FLAG_unbox_double_fields || !field_access.IsInobject())) { 5765 HObjectAccess heap_number_access = 5766 field_access.WithRepresentation(Representation::Tagged()); 5767 if (transition_to_field) { 5768 // The store requires a mutable HeapNumber to be allocated. 5769 NoObservableSideEffectsScope no_side_effects(this); 5770 HInstruction* heap_number_size = Add<HConstant>(HeapNumber::kSize); 5771 5772 // TODO(hpayer): Allocation site pretenuring support. 5773 HInstruction* heap_number = 5774 Add<HAllocate>(heap_number_size, HType::HeapObject(), NOT_TENURED, 5775 MUTABLE_HEAP_NUMBER_TYPE, graph()->GetConstant0()); 5776 AddStoreMapConstant( 5777 heap_number, isolate()->factory()->mutable_heap_number_map()); 5778 Add<HStoreNamedField>(heap_number, HObjectAccess::ForHeapNumberValue(), 5779 value); 5780 instr = New<HStoreNamedField>(checked_object->ActualValue(), 5781 heap_number_access, 5782 heap_number); 5783 } else { 5784 // Already holds a HeapNumber; load the box and write its value field. 5785 HInstruction* heap_number = 5786 Add<HLoadNamedField>(checked_object, nullptr, heap_number_access); 5787 instr = New<HStoreNamedField>(heap_number, 5788 HObjectAccess::ForHeapNumberValue(), 5789 value, STORE_TO_INITIALIZED_ENTRY); 5790 } 5791 } else { 5792 if (field_access.representation().IsHeapObject()) { 5793 BuildCheckHeapObject(value); 5794 } 5795 5796 if (!info->field_maps()->is_empty()) { 5797 DCHECK(field_access.representation().IsHeapObject()); 5798 value = Add<HCheckMaps>(value, info->field_maps()); 5799 } 5800 5801 // This is a normal store. 5802 instr = New<HStoreNamedField>( 5803 checked_object->ActualValue(), field_access, value, 5804 transition_to_field ? INITIALIZING_STORE : STORE_TO_INITIALIZED_ENTRY); 5805 } 5806 5807 if (transition_to_field) { 5808 Handle<Map> transition(info->transition()); 5809 DCHECK(!transition->is_deprecated()); 5810 instr->SetTransition(Add<HConstant>(transition)); 5811 } 5812 return instr; 5813 } 5814 5815 Handle<FieldType> 5816 HOptimizedGraphBuilder::PropertyAccessInfo::GetFieldTypeFromMap( 5817 Handle<Map> map) const { 5818 DCHECK(IsFound()); 5819 DCHECK(number_ < map->NumberOfOwnDescriptors()); 5820 return handle(map->instance_descriptors()->GetFieldType(number_), isolate()); 5821 } 5822 5823 bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatible( 5824 PropertyAccessInfo* info) { 5825 if (!CanInlinePropertyAccess(map_)) return false; 5826 5827 // Currently only handle AstType::Number as a polymorphic case. 5828 // TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber 5829 // instruction. 5830 if (IsNumberType()) return false; 5831 5832 // Values are only compatible for monomorphic load if they all behave the same 5833 // regarding value wrappers. 5834 if (IsValueWrapped() != info->IsValueWrapped()) return false; 5835 5836 if (!LookupDescriptor()) return false; 5837 5838 if (!IsFound()) { 5839 return (!info->IsFound() || info->has_holder()) && 5840 map()->prototype() == info->map()->prototype(); 5841 } 5842 5843 // Mismatch if the other access info found the property in the prototype 5844 // chain. 5845 if (info->has_holder()) return false; 5846 5847 if (IsAccessorConstant()) { 5848 return accessor_.is_identical_to(info->accessor_) && 5849 api_holder_.is_identical_to(info->api_holder_); 5850 } 5851 5852 if (IsDataConstant()) { 5853 return constant_.is_identical_to(info->constant_); 5854 } 5855 5856 DCHECK(IsData()); 5857 if (!info->IsData()) return false; 5858 5859 Representation r = access_.representation(); 5860 if (IsLoad()) { 5861 if (!info->access_.representation().IsCompatibleForLoad(r)) return false; 5862 } else { 5863 if (!info->access_.representation().IsCompatibleForStore(r)) return false; 5864 } 5865 if (info->access_.offset() != access_.offset()) return false; 5866 if (info->access_.IsInobject() != access_.IsInobject()) return false; 5867 if (IsLoad()) { 5868 if (field_maps_.is_empty()) { 5869 info->field_maps_.Clear(); 5870 } else if (!info->field_maps_.is_empty()) { 5871 for (int i = 0; i < field_maps_.length(); ++i) { 5872 info->field_maps_.AddMapIfMissing(field_maps_.at(i), info->zone()); 5873 } 5874 info->field_maps_.Sort(); 5875 } 5876 } else { 5877 // We can only merge stores that agree on their field maps. The comparison 5878 // below is safe, since we keep the field maps sorted. 5879 if (field_maps_.length() != info->field_maps_.length()) return false; 5880 for (int i = 0; i < field_maps_.length(); ++i) { 5881 if (!field_maps_.at(i).is_identical_to(info->field_maps_.at(i))) { 5882 return false; 5883 } 5884 } 5885 } 5886 info->GeneralizeRepresentation(r); 5887 info->field_type_ = info->field_type_.Combine(field_type_); 5888 return true; 5889 } 5890 5891 5892 bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupDescriptor() { 5893 if (!map_->IsJSObjectMap()) return true; 5894 LookupDescriptor(*map_, *name_); 5895 return LoadResult(map_); 5896 } 5897 5898 5899 bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadResult(Handle<Map> map) { 5900 if (!IsLoad() && IsProperty() && IsReadOnly()) { 5901 return false; 5902 } 5903 5904 if (IsData()) { 5905 // Construct the object field access. 5906 int index = GetLocalFieldIndexFromMap(map); 5907 access_ = HObjectAccess::ForField(map, index, representation(), name_); 5908 5909 // Load field map for heap objects. 5910 return LoadFieldMaps(map); 5911 } else if (IsAccessorConstant()) { 5912 Handle<Object> accessors = GetAccessorsFromMap(map); 5913 if (!accessors->IsAccessorPair()) return false; 5914 Object* raw_accessor = 5915 IsLoad() ? Handle<AccessorPair>::cast(accessors)->getter() 5916 : Handle<AccessorPair>::cast(accessors)->setter(); 5917 if (!raw_accessor->IsJSFunction() && 5918 !raw_accessor->IsFunctionTemplateInfo()) 5919 return false; 5920 Handle<Object> accessor = handle(HeapObject::cast(raw_accessor)); 5921 CallOptimization call_optimization(accessor); 5922 if (call_optimization.is_simple_api_call()) { 5923 CallOptimization::HolderLookup holder_lookup; 5924 api_holder_ = 5925 call_optimization.LookupHolderOfExpectedType(map_, &holder_lookup); 5926 } 5927 accessor_ = accessor; 5928 } else if (IsDataConstant()) { 5929 constant_ = GetConstantFromMap(map); 5930 } 5931 5932 return true; 5933 } 5934 5935 5936 bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadFieldMaps( 5937 Handle<Map> map) { 5938 // Clear any previously collected field maps/type. 5939 field_maps_.Clear(); 5940 field_type_ = HType::Tagged(); 5941 5942 // Figure out the field type from the accessor map. 5943 Handle<FieldType> field_type = GetFieldTypeFromMap(map); 5944 5945 // Collect the (stable) maps from the field type. 5946 if (field_type->IsClass()) { 5947 DCHECK(access_.representation().IsHeapObject()); 5948 Handle<Map> field_map = field_type->AsClass(); 5949 if (field_map->is_stable()) { 5950 field_maps_.Add(field_map, zone()); 5951 } 5952 } 5953 5954 if (field_maps_.is_empty()) { 5955 // Store is not safe if the field map was cleared. 5956 return IsLoad() || !field_type->IsNone(); 5957 } 5958 5959 // Determine field HType from field type. 5960 field_type_ = HType::FromFieldType(field_type, zone()); 5961 DCHECK(field_type_.IsHeapObject()); 5962 5963 // Add dependency on the map that introduced the field. 5964 top_info()->dependencies()->AssumeFieldOwner(GetFieldOwnerFromMap(map)); 5965 return true; 5966 } 5967 5968 5969 bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() { 5970 Handle<Map> map = this->map(); 5971 if (name_->IsPrivate()) { 5972 NotFound(); 5973 return !map->has_hidden_prototype(); 5974 } 5975 5976 while (map->prototype()->IsJSObject()) { 5977 holder_ = handle(JSObject::cast(map->prototype())); 5978 if (holder_->map()->is_deprecated()) { 5979 JSObject::TryMigrateInstance(holder_); 5980 } 5981 map = Handle<Map>(holder_->map()); 5982 if (!CanInlinePropertyAccess(map)) { 5983 NotFound(); 5984 return false; 5985 } 5986 LookupDescriptor(*map, *name_); 5987 if (IsFound()) return LoadResult(map); 5988 } 5989 5990 NotFound(); 5991 return !map->prototype()->IsJSReceiver(); 5992 } 5993 5994 5995 bool HOptimizedGraphBuilder::PropertyAccessInfo::IsIntegerIndexedExotic() { 5996 InstanceType instance_type = map_->instance_type(); 5997 return instance_type == JS_TYPED_ARRAY_TYPE && name_->IsString() && 5998 IsSpecialIndex(isolate()->unicode_cache(), String::cast(*name_)); 5999 } 6000 6001 6002 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() { 6003 if (!CanInlinePropertyAccess(map_)) return false; 6004 if (IsJSObjectFieldAccessor()) return IsLoad(); 6005 if (map_->IsJSFunctionMap() && map_->is_constructor() && 6006 !map_->has_non_instance_prototype() && 6007 name_.is_identical_to(isolate()->factory()->prototype_string())) { 6008 return IsLoad(); 6009 } 6010 if (!LookupDescriptor()) return false; 6011 if (IsFound()) return IsLoad() || !IsReadOnly(); 6012 if (IsIntegerIndexedExotic()) return false; 6013 if (!LookupInPrototypes()) return false; 6014 if (IsLoad()) return true; 6015 6016 if (IsAccessorConstant()) return true; 6017 LookupTransition(*map_, *name_, NONE); 6018 if (IsTransitionToData() && map_->unused_property_fields() > 0) { 6019 // Construct the object field access. 6020 int descriptor = transition()->LastAdded(); 6021 int index = 6022 transition()->instance_descriptors()->GetFieldIndex(descriptor) - 6023 map_->GetInObjectProperties(); 6024 PropertyDetails details = 6025 transition()->instance_descriptors()->GetDetails(descriptor); 6026 Representation representation = details.representation(); 6027 access_ = HObjectAccess::ForField(map_, index, representation, name_); 6028 6029 // Load field map for heap objects. 6030 return LoadFieldMaps(transition()); 6031 } 6032 return false; 6033 } 6034 6035 6036 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessAsMonomorphic( 6037 SmallMapList* maps) { 6038 DCHECK(map_.is_identical_to(maps->first())); 6039 if (!CanAccessMonomorphic()) return false; 6040 STATIC_ASSERT(kMaxLoadPolymorphism == kMaxStorePolymorphism); 6041 if (maps->length() > kMaxLoadPolymorphism) return false; 6042 HObjectAccess access = HObjectAccess::ForMap(); // bogus default 6043 if (GetJSObjectFieldAccess(&access)) { 6044 for (int i = 1; i < maps->length(); ++i) { 6045 PropertyAccessInfo test_info(builder_, access_type_, maps->at(i), name_); 6046 HObjectAccess test_access = HObjectAccess::ForMap(); // bogus default 6047 if (!test_info.GetJSObjectFieldAccess(&test_access)) return false; 6048 if (!access.Equals(test_access)) return false; 6049 } 6050 return true; 6051 } 6052 6053 // Currently only handle numbers as a polymorphic case. 6054 // TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber 6055 // instruction. 6056 if (IsNumberType()) return false; 6057 6058 // Multiple maps cannot transition to the same target map. 6059 DCHECK(!IsLoad() || !IsTransition()); 6060 if (IsTransition() && maps->length() > 1) return false; 6061 6062 for (int i = 1; i < maps->length(); ++i) { 6063 PropertyAccessInfo test_info(builder_, access_type_, maps->at(i), name_); 6064 if (!test_info.IsCompatible(this)) return false; 6065 } 6066 6067 return true; 6068 } 6069 6070 6071 Handle<Map> HOptimizedGraphBuilder::PropertyAccessInfo::map() { 6072 Handle<JSFunction> ctor; 6073 if (Map::GetConstructorFunction( 6074 map_, handle(current_info()->closure()->context()->native_context())) 6075 .ToHandle(&ctor)) { 6076 return handle(ctor->initial_map()); 6077 } 6078 return map_; 6079 } 6080 6081 6082 static bool NeedsWrapping(Handle<Map> map, Handle<JSFunction> target) { 6083 return !map->IsJSObjectMap() && 6084 is_sloppy(target->shared()->language_mode()) && 6085 !target->shared()->native(); 6086 } 6087 6088 6089 bool HOptimizedGraphBuilder::PropertyAccessInfo::NeedsWrappingFor( 6090 Handle<JSFunction> target) const { 6091 return NeedsWrapping(map_, target); 6092 } 6093 6094 6095 HValue* HOptimizedGraphBuilder::BuildMonomorphicAccess( 6096 PropertyAccessInfo* info, HValue* object, HValue* checked_object, 6097 HValue* value, BailoutId ast_id, BailoutId return_id, 6098 bool can_inline_accessor) { 6099 HObjectAccess access = HObjectAccess::ForMap(); // bogus default 6100 if (info->GetJSObjectFieldAccess(&access)) { 6101 DCHECK(info->IsLoad()); 6102 return New<HLoadNamedField>(object, checked_object, access); 6103 } 6104 6105 if (info->name().is_identical_to(isolate()->factory()->prototype_string()) && 6106 info->map()->IsJSFunctionMap() && info->map()->is_constructor()) { 6107 DCHECK(!info->map()->has_non_instance_prototype()); 6108 return New<HLoadFunctionPrototype>(checked_object); 6109 } 6110 6111 HValue* checked_holder = checked_object; 6112 if (info->has_holder()) { 6113 Handle<JSObject> prototype(JSObject::cast(info->map()->prototype())); 6114 checked_holder = BuildCheckPrototypeMaps(prototype, info->holder()); 6115 } 6116 6117 if (!info->IsFound()) { 6118 DCHECK(info->IsLoad()); 6119 return graph()->GetConstantUndefined(); 6120 } 6121 6122 if (info->IsData()) { 6123 if (info->IsLoad()) { 6124 return BuildLoadNamedField(info, checked_holder); 6125 } else { 6126 return BuildStoreNamedField(info, checked_object, value); 6127 } 6128 } 6129 6130 if (info->IsTransition()) { 6131 DCHECK(!info->IsLoad()); 6132 return BuildStoreNamedField(info, checked_object, value); 6133 } 6134 6135 if (info->IsAccessorConstant()) { 6136 MaybeHandle<Name> maybe_name = 6137 FunctionTemplateInfo::TryGetCachedPropertyName(isolate(), 6138 info->accessor()); 6139 if (!maybe_name.is_null()) { 6140 Handle<Name> name = maybe_name.ToHandleChecked(); 6141 PropertyAccessInfo cache_info(this, LOAD, info->map(), name); 6142 // Load new target. 6143 if (cache_info.CanAccessMonomorphic()) { 6144 return BuildLoadNamedField(&cache_info, checked_object); 6145 } 6146 } 6147 6148 Push(checked_object); 6149 int argument_count = 1; 6150 if (!info->IsLoad()) { 6151 argument_count = 2; 6152 Push(value); 6153 } 6154 6155 if (info->accessor()->IsJSFunction() && 6156 info->NeedsWrappingFor(Handle<JSFunction>::cast(info->accessor()))) { 6157 HValue* function = Add<HConstant>(info->accessor()); 6158 PushArgumentsFromEnvironment(argument_count); 6159 return NewCallFunction(function, argument_count, TailCallMode::kDisallow, 6160 ConvertReceiverMode::kNotNullOrUndefined, 6161 TailCallMode::kDisallow); 6162 } else if (FLAG_inline_accessors && can_inline_accessor) { 6163 bool success = info->IsLoad() 6164 ? TryInlineGetter(info->accessor(), info->map(), ast_id, return_id) 6165 : TryInlineSetter( 6166 info->accessor(), info->map(), ast_id, return_id, value); 6167 if (success || HasStackOverflow()) return NULL; 6168 } 6169 6170 PushArgumentsFromEnvironment(argument_count); 6171 if (!info->accessor()->IsJSFunction()) { 6172 Bailout(kInliningBailedOut); 6173 return nullptr; 6174 } 6175 return NewCallConstantFunction(Handle<JSFunction>::cast(info->accessor()), 6176 argument_count, TailCallMode::kDisallow, 6177 TailCallMode::kDisallow); 6178 } 6179 6180 DCHECK(info->IsDataConstant()); 6181 if (info->IsLoad()) { 6182 return New<HConstant>(info->constant()); 6183 } else { 6184 return New<HCheckValue>(value, Handle<JSFunction>::cast(info->constant())); 6185 } 6186 } 6187 6188 6189 void HOptimizedGraphBuilder::HandlePolymorphicNamedFieldAccess( 6190 PropertyAccessType access_type, Expression* expr, FeedbackVectorSlot slot, 6191 BailoutId ast_id, BailoutId return_id, HValue* object, HValue* value, 6192 SmallMapList* maps, Handle<Name> name) { 6193 // Something did not match; must use a polymorphic load. 6194 int count = 0; 6195 HBasicBlock* join = NULL; 6196 HBasicBlock* number_block = NULL; 6197 bool handled_string = false; 6198 6199 bool handle_smi = false; 6200 STATIC_ASSERT(kMaxLoadPolymorphism == kMaxStorePolymorphism); 6201 int i; 6202 for (i = 0; i < maps->length() && count < kMaxLoadPolymorphism; ++i) { 6203 PropertyAccessInfo info(this, access_type, maps->at(i), name); 6204 if (info.IsStringType()) { 6205 if (handled_string) continue; 6206 handled_string = true; 6207 } 6208 if (info.CanAccessMonomorphic()) { 6209 count++; 6210 if (info.IsNumberType()) { 6211 handle_smi = true; 6212 break; 6213 } 6214 } 6215 } 6216 6217 if (i < maps->length()) { 6218 count = -1; 6219 maps->Clear(); 6220 } else { 6221 count = 0; 6222 } 6223 HControlInstruction* smi_check = NULL; 6224 handled_string = false; 6225 6226 for (i = 0; i < maps->length() && count < kMaxLoadPolymorphism; ++i) { 6227 PropertyAccessInfo info(this, access_type, maps->at(i), name); 6228 if (info.IsStringType()) { 6229 if (handled_string) continue; 6230 handled_string = true; 6231 } 6232 if (!info.CanAccessMonomorphic()) continue; 6233 6234 if (count == 0) { 6235 join = graph()->CreateBasicBlock(); 6236 if (handle_smi) { 6237 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); 6238 HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); 6239 number_block = graph()->CreateBasicBlock(); 6240 smi_check = New<HIsSmiAndBranch>( 6241 object, empty_smi_block, not_smi_block); 6242 FinishCurrentBlock(smi_check); 6243 GotoNoSimulate(empty_smi_block, number_block); 6244 set_current_block(not_smi_block); 6245 } else { 6246 BuildCheckHeapObject(object); 6247 } 6248 } 6249 ++count; 6250 HBasicBlock* if_true = graph()->CreateBasicBlock(); 6251 HBasicBlock* if_false = graph()->CreateBasicBlock(); 6252 HUnaryControlInstruction* compare; 6253 6254 HValue* dependency; 6255 if (info.IsNumberType()) { 6256 Handle<Map> heap_number_map = isolate()->factory()->heap_number_map(); 6257 compare = New<HCompareMap>(object, heap_number_map, if_true, if_false); 6258 dependency = smi_check; 6259 } else if (info.IsStringType()) { 6260 compare = New<HIsStringAndBranch>(object, if_true, if_false); 6261 dependency = compare; 6262 } else { 6263 compare = New<HCompareMap>(object, info.map(), if_true, if_false); 6264 dependency = compare; 6265 } 6266 FinishCurrentBlock(compare); 6267 6268 if (info.IsNumberType()) { 6269 GotoNoSimulate(if_true, number_block); 6270 if_true = number_block; 6271 } 6272 6273 set_current_block(if_true); 6274 6275 HValue* access = 6276 BuildMonomorphicAccess(&info, object, dependency, value, ast_id, 6277 return_id, FLAG_polymorphic_inlining); 6278 6279 HValue* result = NULL; 6280 switch (access_type) { 6281 case LOAD: 6282 result = access; 6283 break; 6284 case STORE: 6285 result = value; 6286 break; 6287 } 6288 6289 if (access == NULL) { 6290 if (HasStackOverflow()) return; 6291 } else { 6292 if (access->IsInstruction()) { 6293 HInstruction* instr = HInstruction::cast(access); 6294 if (!instr->IsLinked()) AddInstruction(instr); 6295 } 6296 if (!ast_context()->IsEffect()) Push(result); 6297 } 6298 6299 if (current_block() != NULL) Goto(join); 6300 set_current_block(if_false); 6301 } 6302 6303 // Finish up. Unconditionally deoptimize if we've handled all the maps we 6304 // know about and do not want to handle ones we've never seen. Otherwise 6305 // use a generic IC. 6306 if (count == maps->length() && FLAG_deoptimize_uncommon_cases) { 6307 FinishExitWithHardDeoptimization( 6308 DeoptimizeReason::kUnknownMapInPolymorphicAccess); 6309 } else { 6310 HInstruction* instr = 6311 BuildNamedGeneric(access_type, expr, slot, object, name, value); 6312 AddInstruction(instr); 6313 if (!ast_context()->IsEffect()) Push(access_type == LOAD ? instr : value); 6314 6315 if (join != NULL) { 6316 Goto(join); 6317 } else { 6318 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); 6319 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); 6320 return; 6321 } 6322 } 6323 6324 DCHECK(join != NULL); 6325 if (join->HasPredecessor()) { 6326 join->SetJoinId(ast_id); 6327 set_current_block(join); 6328 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); 6329 } else { 6330 set_current_block(NULL); 6331 } 6332 } 6333 6334 static bool ComputeReceiverTypes(Expression* expr, HValue* receiver, 6335 SmallMapList** t, 6336 HOptimizedGraphBuilder* builder) { 6337 Zone* zone = builder->zone(); 6338 SmallMapList* maps = expr->GetReceiverTypes(); 6339 *t = maps; 6340 bool monomorphic = expr->IsMonomorphic(); 6341 if (maps != nullptr && receiver->HasMonomorphicJSObjectType()) { 6342 if (maps->length() > 0) { 6343 Map* root_map = receiver->GetMonomorphicJSObjectMap()->FindRootMap(); 6344 maps->FilterForPossibleTransitions(root_map); 6345 monomorphic = maps->length() == 1; 6346 } else { 6347 // No type feedback, see if we can infer the type. This is safely 6348 // possible if the receiver had a known map at some point, and no 6349 // map-changing stores have happened to it since. 6350 Handle<Map> candidate_map = receiver->GetMonomorphicJSObjectMap(); 6351 for (HInstruction* current = builder->current_block()->last(); 6352 current != nullptr; current = current->previous()) { 6353 if (current->IsBlockEntry()) break; 6354 if (current->CheckChangesFlag(kMaps)) { 6355 // Only allow map changes that store the candidate map. We don't 6356 // need to care which object the map is being written into. 6357 if (!current->IsStoreNamedField()) break; 6358 HStoreNamedField* map_change = HStoreNamedField::cast(current); 6359 if (!map_change->value()->IsConstant()) break; 6360 HConstant* map_constant = HConstant::cast(map_change->value()); 6361 if (!map_constant->representation().IsTagged()) break; 6362 Handle<Object> map = map_constant->handle(builder->isolate()); 6363 if (!map.is_identical_to(candidate_map)) break; 6364 } 6365 if (current == receiver) { 6366 // We made it all the way back to the receiver without encountering 6367 // a map change! So we can assume that the receiver still has the 6368 // candidate_map we know about. 6369 maps->Add(candidate_map, zone); 6370 monomorphic = true; 6371 break; 6372 } 6373 } 6374 } 6375 } 6376 return monomorphic && CanInlinePropertyAccess(maps->first()); 6377 } 6378 6379 6380 static bool AreStringTypes(SmallMapList* maps) { 6381 for (int i = 0; i < maps->length(); i++) { 6382 if (maps->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false; 6383 } 6384 return true; 6385 } 6386 6387 void HOptimizedGraphBuilder::BuildStore(Expression* expr, Property* prop, 6388 FeedbackVectorSlot slot, 6389 BailoutId ast_id, BailoutId return_id, 6390 bool is_uninitialized) { 6391 if (!prop->key()->IsPropertyName()) { 6392 // Keyed store. 6393 HValue* value = Pop(); 6394 HValue* key = Pop(); 6395 HValue* object = Pop(); 6396 bool has_side_effects = false; 6397 HValue* result = 6398 HandleKeyedElementAccess(object, key, value, expr, slot, ast_id, 6399 return_id, STORE, &has_side_effects); 6400 if (has_side_effects) { 6401 if (!ast_context()->IsEffect()) Push(value); 6402 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); 6403 if (!ast_context()->IsEffect()) Drop(1); 6404 } 6405 if (result == NULL) return; 6406 return ast_context()->ReturnValue(value); 6407 } 6408 6409 // Named store. 6410 HValue* value = Pop(); 6411 HValue* object = Pop(); 6412 6413 Literal* key = prop->key()->AsLiteral(); 6414 Handle<String> name = Handle<String>::cast(key->value()); 6415 DCHECK(!name.is_null()); 6416 6417 HValue* access = BuildNamedAccess(STORE, ast_id, return_id, expr, slot, 6418 object, name, value, is_uninitialized); 6419 if (access == NULL) return; 6420 6421 if (!ast_context()->IsEffect()) Push(value); 6422 if (access->IsInstruction()) AddInstruction(HInstruction::cast(access)); 6423 if (access->HasObservableSideEffects()) { 6424 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); 6425 } 6426 if (!ast_context()->IsEffect()) Drop(1); 6427 return ast_context()->ReturnValue(value); 6428 } 6429 6430 6431 void HOptimizedGraphBuilder::HandlePropertyAssignment(Assignment* expr) { 6432 Property* prop = expr->target()->AsProperty(); 6433 DCHECK(prop != NULL); 6434 CHECK_ALIVE(VisitForValue(prop->obj())); 6435 if (!prop->key()->IsPropertyName()) { 6436 CHECK_ALIVE(VisitForValue(prop->key())); 6437 } 6438 CHECK_ALIVE(VisitForValue(expr->value())); 6439 BuildStore(expr, prop, expr->AssignmentSlot(), expr->id(), 6440 expr->AssignmentId(), expr->IsUninitialized()); 6441 } 6442 6443 HInstruction* HOptimizedGraphBuilder::InlineGlobalPropertyStore( 6444 LookupIterator* it, HValue* value, BailoutId ast_id) { 6445 Handle<PropertyCell> cell = it->GetPropertyCell(); 6446 top_info()->dependencies()->AssumePropertyCell(cell); 6447 auto cell_type = it->property_details().cell_type(); 6448 if (cell_type == PropertyCellType::kConstant || 6449 cell_type == PropertyCellType::kUndefined) { 6450 Handle<Object> constant(cell->value(), isolate()); 6451 if (value->IsConstant()) { 6452 HConstant* c_value = HConstant::cast(value); 6453 if (!constant.is_identical_to(c_value->handle(isolate()))) { 6454 Add<HDeoptimize>(DeoptimizeReason::kConstantGlobalVariableAssignment, 6455 Deoptimizer::EAGER); 6456 } 6457 } else { 6458 HValue* c_constant = Add<HConstant>(constant); 6459 IfBuilder builder(this); 6460 if (constant->IsNumber()) { 6461 builder.If<HCompareNumericAndBranch>(value, c_constant, Token::EQ); 6462 } else { 6463 builder.If<HCompareObjectEqAndBranch>(value, c_constant); 6464 } 6465 builder.Then(); 6466 builder.Else(); 6467 Add<HDeoptimize>(DeoptimizeReason::kConstantGlobalVariableAssignment, 6468 Deoptimizer::EAGER); 6469 builder.End(); 6470 } 6471 } 6472 HConstant* cell_constant = Add<HConstant>(cell); 6473 auto access = HObjectAccess::ForPropertyCellValue(); 6474 if (cell_type == PropertyCellType::kConstantType) { 6475 switch (cell->GetConstantType()) { 6476 case PropertyCellConstantType::kSmi: 6477 access = access.WithRepresentation(Representation::Smi()); 6478 break; 6479 case PropertyCellConstantType::kStableMap: { 6480 // First check that the previous value of the {cell} still has the 6481 // map that we are about to check the new {value} for. If not, then 6482 // the stable map assumption was invalidated and we cannot continue 6483 // with the optimized code. 6484 Handle<HeapObject> cell_value(HeapObject::cast(cell->value())); 6485 Handle<Map> cell_value_map(cell_value->map()); 6486 if (!cell_value_map->is_stable()) { 6487 Bailout(kUnstableConstantTypeHeapObject); 6488 return nullptr; 6489 } 6490 top_info()->dependencies()->AssumeMapStable(cell_value_map); 6491 // Now check that the new {value} is a HeapObject with the same map 6492 Add<HCheckHeapObject>(value); 6493 value = Add<HCheckMaps>(value, cell_value_map); 6494 access = access.WithRepresentation(Representation::HeapObject()); 6495 break; 6496 } 6497 } 6498 } 6499 HInstruction* instr = New<HStoreNamedField>(cell_constant, access, value); 6500 instr->ClearChangesFlag(kInobjectFields); 6501 instr->SetChangesFlag(kGlobalVars); 6502 return instr; 6503 } 6504 6505 // Because not every expression has a position and there is not common 6506 // superclass of Assignment and CountOperation, we cannot just pass the 6507 // owning expression instead of position and ast_id separately. 6508 void HOptimizedGraphBuilder::HandleGlobalVariableAssignment( 6509 Variable* var, HValue* value, FeedbackVectorSlot slot, BailoutId ast_id) { 6510 Handle<JSGlobalObject> global(current_info()->global_object()); 6511 6512 // Lookup in script contexts. 6513 { 6514 Handle<ScriptContextTable> script_contexts( 6515 global->native_context()->script_context_table()); 6516 ScriptContextTable::LookupResult lookup; 6517 if (ScriptContextTable::Lookup(script_contexts, var->name(), &lookup)) { 6518 if (lookup.mode == CONST) { 6519 return Bailout(kNonInitializerAssignmentToConst); 6520 } 6521 Handle<Context> script_context = 6522 ScriptContextTable::GetContext(script_contexts, lookup.context_index); 6523 6524 Handle<Object> current_value = 6525 FixedArray::get(*script_context, lookup.slot_index, isolate()); 6526 6527 // If the values is not the hole, it will stay initialized, 6528 // so no need to generate a check. 6529 if (current_value->IsTheHole(isolate())) { 6530 return Bailout(kReferenceToUninitializedVariable); 6531 } 6532 6533 HStoreNamedField* instr = Add<HStoreNamedField>( 6534 Add<HConstant>(script_context), 6535 HObjectAccess::ForContextSlot(lookup.slot_index), value); 6536 USE(instr); 6537 DCHECK(instr->HasObservableSideEffects()); 6538 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); 6539 return; 6540 } 6541 } 6542 6543 LookupIterator it(global, var->name(), LookupIterator::OWN); 6544 if (CanInlineGlobalPropertyAccess(var, &it, STORE)) { 6545 HInstruction* instr = InlineGlobalPropertyStore(&it, value, ast_id); 6546 if (!instr) return; 6547 AddInstruction(instr); 6548 if (instr->HasObservableSideEffects()) { 6549 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); 6550 } 6551 } else { 6552 HValue* global_object = Add<HLoadNamedField>( 6553 BuildGetNativeContext(), nullptr, 6554 HObjectAccess::ForContextSlot(Context::EXTENSION_INDEX)); 6555 Handle<TypeFeedbackVector> vector = 6556 handle(current_feedback_vector(), isolate()); 6557 HValue* name = Add<HConstant>(var->name()); 6558 HValue* vector_value = Add<HConstant>(vector); 6559 HValue* slot_value = Add<HConstant>(vector->GetIndex(slot)); 6560 Callable callable = CodeFactory::StoreICInOptimizedCode( 6561 isolate(), function_language_mode()); 6562 HValue* stub = Add<HConstant>(callable.code()); 6563 HValue* values[] = {global_object, name, value, slot_value, vector_value}; 6564 HCallWithDescriptor* instr = Add<HCallWithDescriptor>( 6565 Code::STORE_IC, stub, 0, callable.descriptor(), ArrayVector(values)); 6566 USE(instr); 6567 DCHECK(instr->HasObservableSideEffects()); 6568 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); 6569 } 6570 } 6571 6572 6573 void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) { 6574 Expression* target = expr->target(); 6575 VariableProxy* proxy = target->AsVariableProxy(); 6576 Property* prop = target->AsProperty(); 6577 DCHECK(proxy == NULL || prop == NULL); 6578 6579 // We have a second position recorded in the FullCodeGenerator to have 6580 // type feedback for the binary operation. 6581 BinaryOperation* operation = expr->binary_operation(); 6582 6583 if (proxy != NULL) { 6584 Variable* var = proxy->var(); 6585 if (var->mode() == LET) { 6586 return Bailout(kUnsupportedLetCompoundAssignment); 6587 } 6588 6589 CHECK_ALIVE(VisitForValue(operation)); 6590 6591 switch (var->location()) { 6592 case VariableLocation::UNALLOCATED: 6593 HandleGlobalVariableAssignment(var, Top(), expr->AssignmentSlot(), 6594 expr->AssignmentId()); 6595 break; 6596 6597 case VariableLocation::PARAMETER: 6598 case VariableLocation::LOCAL: 6599 if (var->mode() == CONST) { 6600 return Bailout(kNonInitializerAssignmentToConst); 6601 } 6602 BindIfLive(var, Top()); 6603 break; 6604 6605 case VariableLocation::CONTEXT: { 6606 // Bail out if we try to mutate a parameter value in a function 6607 // using the arguments object. We do not (yet) correctly handle the 6608 // arguments property of the function. 6609 if (current_info()->scope()->arguments() != NULL) { 6610 // Parameters will be allocated to context slots. We have no 6611 // direct way to detect that the variable is a parameter so we do 6612 // a linear search of the parameter variables. 6613 int count = current_info()->scope()->num_parameters(); 6614 for (int i = 0; i < count; ++i) { 6615 if (var == current_info()->scope()->parameter(i)) { 6616 Bailout(kAssignmentToParameterFunctionUsesArgumentsObject); 6617 } 6618 } 6619 } 6620 6621 HStoreContextSlot::Mode mode; 6622 6623 switch (var->mode()) { 6624 case LET: 6625 mode = HStoreContextSlot::kCheckDeoptimize; 6626 break; 6627 case CONST: 6628 if (var->throw_on_const_assignment(function_language_mode())) { 6629 return Bailout(kNonInitializerAssignmentToConst); 6630 } else { 6631 return ast_context()->ReturnValue(Pop()); 6632 } 6633 default: 6634 mode = HStoreContextSlot::kNoCheck; 6635 } 6636 6637 HValue* context = BuildContextChainWalk(var); 6638 HStoreContextSlot* instr = Add<HStoreContextSlot>( 6639 context, var->index(), mode, Top()); 6640 if (instr->HasObservableSideEffects()) { 6641 Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE); 6642 } 6643 break; 6644 } 6645 6646 case VariableLocation::LOOKUP: 6647 return Bailout(kCompoundAssignmentToLookupSlot); 6648 6649 case VariableLocation::MODULE: 6650 UNREACHABLE(); 6651 } 6652 return ast_context()->ReturnValue(Pop()); 6653 6654 } else if (prop != NULL) { 6655 CHECK_ALIVE(VisitForValue(prop->obj())); 6656 HValue* object = Top(); 6657 HValue* key = NULL; 6658 if (!prop->key()->IsPropertyName() || prop->IsStringAccess()) { 6659 CHECK_ALIVE(VisitForValue(prop->key())); 6660 key = Top(); 6661 } 6662 6663 CHECK_ALIVE(PushLoad(prop, object, key)); 6664 6665 CHECK_ALIVE(VisitForValue(expr->value())); 6666 HValue* right = Pop(); 6667 HValue* left = Pop(); 6668 6669 Push(BuildBinaryOperation(operation, left, right, PUSH_BEFORE_SIMULATE)); 6670 6671 BuildStore(expr, prop, expr->AssignmentSlot(), expr->id(), 6672 expr->AssignmentId(), expr->IsUninitialized()); 6673 } else { 6674 return Bailout(kInvalidLhsInCompoundAssignment); 6675 } 6676 } 6677 6678 6679 void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) { 6680 DCHECK(!HasStackOverflow()); 6681 DCHECK(current_block() != NULL); 6682 DCHECK(current_block()->HasPredecessor()); 6683 6684 VariableProxy* proxy = expr->target()->AsVariableProxy(); 6685 Property* prop = expr->target()->AsProperty(); 6686 DCHECK(proxy == NULL || prop == NULL); 6687 6688 if (expr->is_compound()) { 6689 HandleCompoundAssignment(expr); 6690 return; 6691 } 6692 6693 if (prop != NULL) { 6694 HandlePropertyAssignment(expr); 6695 } else if (proxy != NULL) { 6696 Variable* var = proxy->var(); 6697 6698 if (var->mode() == CONST) { 6699 if (expr->op() != Token::INIT) { 6700 if (var->throw_on_const_assignment(function_language_mode())) { 6701 return Bailout(kNonInitializerAssignmentToConst); 6702 } else { 6703 CHECK_ALIVE(VisitForValue(expr->value())); 6704 return ast_context()->ReturnValue(Pop()); 6705 } 6706 } 6707 } 6708 6709 // Handle the assignment. 6710 switch (var->location()) { 6711 case VariableLocation::UNALLOCATED: 6712 CHECK_ALIVE(VisitForValue(expr->value())); 6713 HandleGlobalVariableAssignment(var, Top(), expr->AssignmentSlot(), 6714 expr->AssignmentId()); 6715 return ast_context()->ReturnValue(Pop()); 6716 6717 case VariableLocation::PARAMETER: 6718 case VariableLocation::LOCAL: { 6719 // Perform an initialization check for let declared variables 6720 // or parameters. 6721 if (var->mode() == LET && expr->op() == Token::ASSIGN) { 6722 HValue* env_value = environment()->Lookup(var); 6723 if (env_value == graph()->GetConstantHole()) { 6724 return Bailout(kAssignmentToLetVariableBeforeInitialization); 6725 } 6726 } 6727 // We do not allow the arguments object to occur in a context where it 6728 // may escape, but assignments to stack-allocated locals are 6729 // permitted. 6730 CHECK_ALIVE(VisitForValue(expr->value(), ARGUMENTS_ALLOWED)); 6731 HValue* value = Pop(); 6732 BindIfLive(var, value); 6733 return ast_context()->ReturnValue(value); 6734 } 6735 6736 case VariableLocation::CONTEXT: { 6737 // Bail out if we try to mutate a parameter value in a function using 6738 // the arguments object. We do not (yet) correctly handle the 6739 // arguments property of the function. 6740 if (current_info()->scope()->arguments() != NULL) { 6741 // Parameters will rewrite to context slots. We have no direct way 6742 // to detect that the variable is a parameter. 6743 int count = current_info()->scope()->num_parameters(); 6744 for (int i = 0; i < count; ++i) { 6745 if (var == current_info()->scope()->parameter(i)) { 6746 return Bailout(kAssignmentToParameterInArgumentsObject); 6747 } 6748 } 6749 } 6750 6751 CHECK_ALIVE(VisitForValue(expr->value())); 6752 HStoreContextSlot::Mode mode; 6753 if (expr->op() == Token::ASSIGN) { 6754 switch (var->mode()) { 6755 case LET: 6756 mode = HStoreContextSlot::kCheckDeoptimize; 6757 break; 6758 case CONST: 6759 // If we reached this point, the only possibility 6760 // is a sloppy assignment to a function name. 6761 DCHECK(function_language_mode() == SLOPPY && 6762 !var->throw_on_const_assignment(SLOPPY)); 6763 return ast_context()->ReturnValue(Pop()); 6764 default: 6765 mode = HStoreContextSlot::kNoCheck; 6766 } 6767 } else { 6768 DCHECK_EQ(Token::INIT, expr->op()); 6769 mode = HStoreContextSlot::kNoCheck; 6770 } 6771 6772 HValue* context = BuildContextChainWalk(var); 6773 HStoreContextSlot* instr = Add<HStoreContextSlot>( 6774 context, var->index(), mode, Top()); 6775 if (instr->HasObservableSideEffects()) { 6776 Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE); 6777 } 6778 return ast_context()->ReturnValue(Pop()); 6779 } 6780 6781 case VariableLocation::LOOKUP: 6782 return Bailout(kAssignmentToLOOKUPVariable); 6783 6784 case VariableLocation::MODULE: 6785 UNREACHABLE(); 6786 } 6787 } else { 6788 return Bailout(kInvalidLeftHandSideInAssignment); 6789 } 6790 } 6791 6792 6793 void HOptimizedGraphBuilder::VisitYield(Yield* expr) { 6794 // Generators are not optimized, so we should never get here. 6795 UNREACHABLE(); 6796 } 6797 6798 6799 void HOptimizedGraphBuilder::VisitThrow(Throw* expr) { 6800 DCHECK(!HasStackOverflow()); 6801 DCHECK(current_block() != NULL); 6802 DCHECK(current_block()->HasPredecessor()); 6803 if (!ast_context()->IsEffect()) { 6804 // The parser turns invalid left-hand sides in assignments into throw 6805 // statements, which may not be in effect contexts. We might still try 6806 // to optimize such functions; bail out now if we do. 6807 return Bailout(kInvalidLeftHandSideInAssignment); 6808 } 6809 CHECK_ALIVE(VisitForValue(expr->exception())); 6810 6811 HValue* value = environment()->Pop(); 6812 if (!is_tracking_positions()) SetSourcePosition(expr->position()); 6813 Add<HPushArguments>(value); 6814 Add<HCallRuntime>(Runtime::FunctionForId(Runtime::kThrow), 1); 6815 Add<HSimulate>(expr->id()); 6816 6817 // If the throw definitely exits the function, we can finish with a dummy 6818 // control flow at this point. This is not the case if the throw is inside 6819 // an inlined function which may be replaced. 6820 if (call_context() == NULL) { 6821 FinishExitCurrentBlock(New<HAbnormalExit>()); 6822 } 6823 } 6824 6825 6826 HInstruction* HGraphBuilder::AddLoadStringInstanceType(HValue* string) { 6827 if (string->IsConstant()) { 6828 HConstant* c_string = HConstant::cast(string); 6829 if (c_string->HasStringValue()) { 6830 return Add<HConstant>(c_string->StringValue()->map()->instance_type()); 6831 } 6832 } 6833 return Add<HLoadNamedField>( 6834 Add<HLoadNamedField>(string, nullptr, HObjectAccess::ForMap()), nullptr, 6835 HObjectAccess::ForMapInstanceType()); 6836 } 6837 6838 6839 HInstruction* HGraphBuilder::AddLoadStringLength(HValue* string) { 6840 return AddInstruction(BuildLoadStringLength(string)); 6841 } 6842 6843 6844 HInstruction* HGraphBuilder::BuildLoadStringLength(HValue* string) { 6845 if (string->IsConstant()) { 6846 HConstant* c_string = HConstant::cast(string); 6847 if (c_string->HasStringValue()) { 6848 return New<HConstant>(c_string->StringValue()->length()); 6849 } 6850 } 6851 return New<HLoadNamedField>(string, nullptr, 6852 HObjectAccess::ForStringLength()); 6853 } 6854 6855 6856 HInstruction* HOptimizedGraphBuilder::BuildNamedGeneric( 6857 PropertyAccessType access_type, Expression* expr, FeedbackVectorSlot slot, 6858 HValue* object, Handle<Name> name, HValue* value, bool is_uninitialized) { 6859 if (is_uninitialized) { 6860 Add<HDeoptimize>( 6861 DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess, 6862 Deoptimizer::SOFT); 6863 } 6864 Handle<TypeFeedbackVector> vector(current_feedback_vector(), isolate()); 6865 6866 HValue* key = Add<HConstant>(name); 6867 HValue* vector_value = Add<HConstant>(vector); 6868 HValue* slot_value = Add<HConstant>(vector->GetIndex(slot)); 6869 6870 if (access_type == LOAD) { 6871 HValue* values[] = {object, key, slot_value, vector_value}; 6872 if (!expr->AsProperty()->key()->IsPropertyName()) { 6873 // It's possible that a keyed load of a constant string was converted 6874 // to a named load. Here, at the last minute, we need to make sure to 6875 // use a generic Keyed Load if we are using the type vector, because 6876 // it has to share information with full code. 6877 Callable callable = CodeFactory::KeyedLoadICInOptimizedCode(isolate()); 6878 HValue* stub = Add<HConstant>(callable.code()); 6879 HCallWithDescriptor* result = 6880 New<HCallWithDescriptor>(Code::KEYED_LOAD_IC, stub, 0, 6881 callable.descriptor(), ArrayVector(values)); 6882 return result; 6883 } 6884 Callable callable = CodeFactory::LoadICInOptimizedCode(isolate()); 6885 HValue* stub = Add<HConstant>(callable.code()); 6886 HCallWithDescriptor* result = New<HCallWithDescriptor>( 6887 Code::LOAD_IC, stub, 0, callable.descriptor(), ArrayVector(values)); 6888 return result; 6889 6890 } else { 6891 HValue* values[] = {object, key, value, slot_value, vector_value}; 6892 if (vector->GetKind(slot) == FeedbackVectorSlotKind::KEYED_STORE_IC) { 6893 // It's possible that a keyed store of a constant string was converted 6894 // to a named store. Here, at the last minute, we need to make sure to 6895 // use a generic Keyed Store if we are using the type vector, because 6896 // it has to share information with full code. 6897 Callable callable = CodeFactory::KeyedStoreICInOptimizedCode( 6898 isolate(), function_language_mode()); 6899 HValue* stub = Add<HConstant>(callable.code()); 6900 HCallWithDescriptor* result = 6901 New<HCallWithDescriptor>(Code::KEYED_STORE_IC, stub, 0, 6902 callable.descriptor(), ArrayVector(values)); 6903 return result; 6904 } 6905 Callable callable = CodeFactory::StoreICInOptimizedCode( 6906 isolate(), function_language_mode()); 6907 HValue* stub = Add<HConstant>(callable.code()); 6908 HCallWithDescriptor* result = New<HCallWithDescriptor>( 6909 Code::STORE_IC, stub, 0, callable.descriptor(), ArrayVector(values)); 6910 return result; 6911 } 6912 } 6913 6914 6915 HInstruction* HOptimizedGraphBuilder::BuildKeyedGeneric( 6916 PropertyAccessType access_type, Expression* expr, FeedbackVectorSlot slot, 6917 HValue* object, HValue* key, HValue* value) { 6918 Handle<TypeFeedbackVector> vector(current_feedback_vector(), isolate()); 6919 HValue* vector_value = Add<HConstant>(vector); 6920 HValue* slot_value = Add<HConstant>(vector->GetIndex(slot)); 6921 6922 if (access_type == LOAD) { 6923 HValue* values[] = {object, key, slot_value, vector_value}; 6924 6925 Callable callable = CodeFactory::KeyedLoadICInOptimizedCode(isolate()); 6926 HValue* stub = Add<HConstant>(callable.code()); 6927 HCallWithDescriptor* result = 6928 New<HCallWithDescriptor>(Code::KEYED_LOAD_IC, stub, 0, 6929 callable.descriptor(), ArrayVector(values)); 6930 return result; 6931 } else { 6932 HValue* values[] = {object, key, value, slot_value, vector_value}; 6933 6934 Callable callable = CodeFactory::KeyedStoreICInOptimizedCode( 6935 isolate(), function_language_mode()); 6936 HValue* stub = Add<HConstant>(callable.code()); 6937 HCallWithDescriptor* result = 6938 New<HCallWithDescriptor>(Code::KEYED_STORE_IC, stub, 0, 6939 callable.descriptor(), ArrayVector(values)); 6940 return result; 6941 } 6942 } 6943 6944 6945 LoadKeyedHoleMode HOptimizedGraphBuilder::BuildKeyedHoleMode(Handle<Map> map) { 6946 // Loads from a "stock" fast holey double arrays can elide the hole check. 6947 // Loads from a "stock" fast holey array can convert the hole to undefined 6948 // with impunity. 6949 LoadKeyedHoleMode load_mode = NEVER_RETURN_HOLE; 6950 bool holey_double_elements = 6951 *map == isolate()->get_initial_js_array_map(FAST_HOLEY_DOUBLE_ELEMENTS); 6952 bool holey_elements = 6953 *map == isolate()->get_initial_js_array_map(FAST_HOLEY_ELEMENTS); 6954 if ((holey_double_elements || holey_elements) && 6955 isolate()->IsFastArrayConstructorPrototypeChainIntact()) { 6956 load_mode = 6957 holey_double_elements ? ALLOW_RETURN_HOLE : CONVERT_HOLE_TO_UNDEFINED; 6958 6959 Handle<JSObject> prototype(JSObject::cast(map->prototype()), isolate()); 6960 Handle<JSObject> object_prototype = isolate()->initial_object_prototype(); 6961 BuildCheckPrototypeMaps(prototype, object_prototype); 6962 graph()->MarkDependsOnEmptyArrayProtoElements(); 6963 } 6964 return load_mode; 6965 } 6966 6967 6968 HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess( 6969 HValue* object, 6970 HValue* key, 6971 HValue* val, 6972 HValue* dependency, 6973 Handle<Map> map, 6974 PropertyAccessType access_type, 6975 KeyedAccessStoreMode store_mode) { 6976 HCheckMaps* checked_object = Add<HCheckMaps>(object, map, dependency); 6977 6978 if (access_type == STORE && map->prototype()->IsJSObject()) { 6979 // monomorphic stores need a prototype chain check because shape 6980 // changes could allow callbacks on elements in the chain that 6981 // aren't compatible with monomorphic keyed stores. 6982 PrototypeIterator iter(map); 6983 JSObject* holder = NULL; 6984 while (!iter.IsAtEnd()) { 6985 // JSProxies can't occur here because we wouldn't have installed a 6986 // non-generic IC if there were any. 6987 holder = *PrototypeIterator::GetCurrent<JSObject>(iter); 6988 iter.Advance(); 6989 } 6990 DCHECK(holder && holder->IsJSObject()); 6991 6992 BuildCheckPrototypeMaps(handle(JSObject::cast(map->prototype())), 6993 Handle<JSObject>(holder)); 6994 } 6995 6996 LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map); 6997 return BuildUncheckedMonomorphicElementAccess( 6998 checked_object, key, val, 6999 map->instance_type() == JS_ARRAY_TYPE, 7000 map->elements_kind(), access_type, 7001 load_mode, store_mode); 7002 } 7003 7004 7005 static bool CanInlineElementAccess(Handle<Map> map) { 7006 return map->IsJSObjectMap() && 7007 (map->has_fast_elements() || map->has_fixed_typed_array_elements()) && 7008 !map->has_indexed_interceptor() && !map->is_access_check_needed(); 7009 } 7010 7011 7012 HInstruction* HOptimizedGraphBuilder::TryBuildConsolidatedElementLoad( 7013 HValue* object, 7014 HValue* key, 7015 HValue* val, 7016 SmallMapList* maps) { 7017 // For polymorphic loads of similar elements kinds (i.e. all tagged or all 7018 // double), always use the "worst case" code without a transition. This is 7019 // much faster than transitioning the elements to the worst case, trading a 7020 // HTransitionElements for a HCheckMaps, and avoiding mutation of the array. 7021 bool has_double_maps = false; 7022 bool has_smi_or_object_maps = false; 7023 bool has_js_array_access = false; 7024 bool has_non_js_array_access = false; 7025 bool has_seen_holey_elements = false; 7026 Handle<Map> most_general_consolidated_map; 7027 for (int i = 0; i < maps->length(); ++i) { 7028 Handle<Map> map = maps->at(i); 7029 if (!CanInlineElementAccess(map)) return NULL; 7030 // Don't allow mixing of JSArrays with JSObjects. 7031 if (map->instance_type() == JS_ARRAY_TYPE) { 7032 if (has_non_js_array_access) return NULL; 7033 has_js_array_access = true; 7034 } else if (has_js_array_access) { 7035 return NULL; 7036 } else { 7037 has_non_js_array_access = true; 7038 } 7039 // Don't allow mixed, incompatible elements kinds. 7040 if (map->has_fast_double_elements()) { 7041 if (has_smi_or_object_maps) return NULL; 7042 has_double_maps = true; 7043 } else if (map->has_fast_smi_or_object_elements()) { 7044 if (has_double_maps) return NULL; 7045 has_smi_or_object_maps = true; 7046 } else { 7047 return NULL; 7048 } 7049 // Remember if we've ever seen holey elements. 7050 if (IsHoleyElementsKind(map->elements_kind())) { 7051 has_seen_holey_elements = true; 7052 } 7053 // Remember the most general elements kind, the code for its load will 7054 // properly handle all of the more specific cases. 7055 if ((i == 0) || IsMoreGeneralElementsKindTransition( 7056 most_general_consolidated_map->elements_kind(), 7057 map->elements_kind())) { 7058 most_general_consolidated_map = map; 7059 } 7060 } 7061 if (!has_double_maps && !has_smi_or_object_maps) return NULL; 7062 7063 HCheckMaps* checked_object = Add<HCheckMaps>(object, maps); 7064 // FAST_ELEMENTS is considered more general than FAST_HOLEY_SMI_ELEMENTS. 7065 // If we've seen both, the consolidated load must use FAST_HOLEY_ELEMENTS. 7066 ElementsKind consolidated_elements_kind = has_seen_holey_elements 7067 ? GetHoleyElementsKind(most_general_consolidated_map->elements_kind()) 7068 : most_general_consolidated_map->elements_kind(); 7069 LoadKeyedHoleMode load_mode = NEVER_RETURN_HOLE; 7070 if (has_seen_holey_elements) { 7071 // Make sure that all of the maps we are handling have the initial array 7072 // prototype. 7073 bool saw_non_array_prototype = false; 7074 for (int i = 0; i < maps->length(); ++i) { 7075 Handle<Map> map = maps->at(i); 7076 if (map->prototype() != *isolate()->initial_array_prototype()) { 7077 // We can't guarantee that loading the hole is safe. The prototype may 7078 // have an element at this position. 7079 saw_non_array_prototype = true; 7080 break; 7081 } 7082 } 7083 7084 if (!saw_non_array_prototype) { 7085 Handle<Map> holey_map = handle( 7086 isolate()->get_initial_js_array_map(consolidated_elements_kind)); 7087 load_mode = BuildKeyedHoleMode(holey_map); 7088 if (load_mode != NEVER_RETURN_HOLE) { 7089 for (int i = 0; i < maps->length(); ++i) { 7090 Handle<Map> map = maps->at(i); 7091 // The prototype check was already done for the holey map in 7092 // BuildKeyedHoleMode. 7093 if (!map.is_identical_to(holey_map)) { 7094 Handle<JSObject> prototype(JSObject::cast(map->prototype()), 7095 isolate()); 7096 Handle<JSObject> object_prototype = 7097 isolate()->initial_object_prototype(); 7098 BuildCheckPrototypeMaps(prototype, object_prototype); 7099 } 7100 } 7101 } 7102 } 7103 } 7104 HInstruction* instr = BuildUncheckedMonomorphicElementAccess( 7105 checked_object, key, val, 7106 most_general_consolidated_map->instance_type() == JS_ARRAY_TYPE, 7107 consolidated_elements_kind, LOAD, load_mode, STANDARD_STORE); 7108 return instr; 7109 } 7110 7111 7112 HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( 7113 Expression* expr, FeedbackVectorSlot slot, HValue* object, HValue* key, 7114 HValue* val, SmallMapList* maps, PropertyAccessType access_type, 7115 KeyedAccessStoreMode store_mode, bool* has_side_effects) { 7116 *has_side_effects = false; 7117 BuildCheckHeapObject(object); 7118 7119 if (access_type == LOAD) { 7120 HInstruction* consolidated_load = 7121 TryBuildConsolidatedElementLoad(object, key, val, maps); 7122 if (consolidated_load != NULL) { 7123 *has_side_effects |= consolidated_load->HasObservableSideEffects(); 7124 return consolidated_load; 7125 } 7126 } 7127 7128 // Elements_kind transition support. 7129 MapHandleList transition_target(maps->length()); 7130 // Collect possible transition targets. 7131 MapHandleList possible_transitioned_maps(maps->length()); 7132 for (int i = 0; i < maps->length(); ++i) { 7133 Handle<Map> map = maps->at(i); 7134 // Loads from strings or loads with a mix of string and non-string maps 7135 // shouldn't be handled polymorphically. 7136 DCHECK(access_type != LOAD || !map->IsStringMap()); 7137 ElementsKind elements_kind = map->elements_kind(); 7138 if (CanInlineElementAccess(map) && IsFastElementsKind(elements_kind) && 7139 elements_kind != GetInitialFastElementsKind()) { 7140 possible_transitioned_maps.Add(map); 7141 } 7142 if (IsSloppyArgumentsElements(elements_kind)) { 7143 HInstruction* result = 7144 BuildKeyedGeneric(access_type, expr, slot, object, key, val); 7145 *has_side_effects = result->HasObservableSideEffects(); 7146 return AddInstruction(result); 7147 } 7148 } 7149 // Get transition target for each map (NULL == no transition). 7150 for (int i = 0; i < maps->length(); ++i) { 7151 Handle<Map> map = maps->at(i); 7152 Map* transitioned_map = 7153 map->FindElementsKindTransitionedMap(&possible_transitioned_maps); 7154 if (transitioned_map != nullptr) { 7155 transition_target.Add(handle(transitioned_map)); 7156 } else { 7157 transition_target.Add(Handle<Map>()); 7158 } 7159 } 7160 7161 MapHandleList untransitionable_maps(maps->length()); 7162 HTransitionElementsKind* transition = NULL; 7163 for (int i = 0; i < maps->length(); ++i) { 7164 Handle<Map> map = maps->at(i); 7165 DCHECK(map->IsMap()); 7166 if (!transition_target.at(i).is_null()) { 7167 DCHECK(Map::IsValidElementsTransition( 7168 map->elements_kind(), 7169 transition_target.at(i)->elements_kind())); 7170 transition = Add<HTransitionElementsKind>(object, map, 7171 transition_target.at(i)); 7172 } else { 7173 untransitionable_maps.Add(map); 7174 } 7175 } 7176 7177 // If only one map is left after transitioning, handle this case 7178 // monomorphically. 7179 DCHECK(untransitionable_maps.length() >= 1); 7180 if (untransitionable_maps.length() == 1) { 7181 Handle<Map> untransitionable_map = untransitionable_maps[0]; 7182 HInstruction* instr = NULL; 7183 if (!CanInlineElementAccess(untransitionable_map)) { 7184 instr = AddInstruction( 7185 BuildKeyedGeneric(access_type, expr, slot, object, key, val)); 7186 } else { 7187 instr = BuildMonomorphicElementAccess( 7188 object, key, val, transition, untransitionable_map, access_type, 7189 store_mode); 7190 } 7191 *has_side_effects |= instr->HasObservableSideEffects(); 7192 return access_type == STORE ? val : instr; 7193 } 7194 7195 HBasicBlock* join = graph()->CreateBasicBlock(); 7196 7197 for (int i = 0; i < untransitionable_maps.length(); ++i) { 7198 Handle<Map> map = untransitionable_maps[i]; 7199 ElementsKind elements_kind = map->elements_kind(); 7200 HBasicBlock* this_map = graph()->CreateBasicBlock(); 7201 HBasicBlock* other_map = graph()->CreateBasicBlock(); 7202 HCompareMap* mapcompare = 7203 New<HCompareMap>(object, map, this_map, other_map); 7204 FinishCurrentBlock(mapcompare); 7205 7206 set_current_block(this_map); 7207 HInstruction* access = NULL; 7208 if (!CanInlineElementAccess(map)) { 7209 access = AddInstruction( 7210 BuildKeyedGeneric(access_type, expr, slot, object, key, val)); 7211 } else { 7212 DCHECK(IsFastElementsKind(elements_kind) || 7213 IsFixedTypedArrayElementsKind(elements_kind)); 7214 LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map); 7215 // Happily, mapcompare is a checked object. 7216 access = BuildUncheckedMonomorphicElementAccess( 7217 mapcompare, key, val, 7218 map->instance_type() == JS_ARRAY_TYPE, 7219 elements_kind, access_type, 7220 load_mode, 7221 store_mode); 7222 } 7223 *has_side_effects |= access->HasObservableSideEffects(); 7224 // The caller will use has_side_effects and add a correct Simulate. 7225 access->SetFlag(HValue::kHasNoObservableSideEffects); 7226 if (access_type == LOAD) { 7227 Push(access); 7228 } 7229 NoObservableSideEffectsScope scope(this); 7230 GotoNoSimulate(join); 7231 set_current_block(other_map); 7232 } 7233 7234 // Ensure that we visited at least one map above that goes to join. This is 7235 // necessary because FinishExitWithHardDeoptimization does an AbnormalExit 7236 // rather than joining the join block. If this becomes an issue, insert a 7237 // generic access in the case length() == 0. 7238 DCHECK(join->predecessors()->length() > 0); 7239 // Deopt if none of the cases matched. 7240 NoObservableSideEffectsScope scope(this); 7241 FinishExitWithHardDeoptimization( 7242 DeoptimizeReason::kUnknownMapInPolymorphicElementAccess); 7243 set_current_block(join); 7244 return access_type == STORE ? val : Pop(); 7245 } 7246 7247 HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess( 7248 HValue* obj, HValue* key, HValue* val, Expression* expr, 7249 FeedbackVectorSlot slot, BailoutId ast_id, BailoutId return_id, 7250 PropertyAccessType access_type, bool* has_side_effects) { 7251 // A keyed name access with type feedback may contain the name. 7252 Handle<TypeFeedbackVector> vector = 7253 handle(current_feedback_vector(), isolate()); 7254 HValue* expected_key = key; 7255 if (!key->ActualValue()->IsConstant()) { 7256 Name* name = nullptr; 7257 if (access_type == LOAD) { 7258 KeyedLoadICNexus nexus(vector, slot); 7259 name = nexus.FindFirstName(); 7260 } else { 7261 KeyedStoreICNexus nexus(vector, slot); 7262 name = nexus.FindFirstName(); 7263 } 7264 if (name != nullptr) { 7265 Handle<Name> handle_name(name); 7266 expected_key = Add<HConstant>(handle_name); 7267 // We need a check against the key. 7268 bool in_new_space = isolate()->heap()->InNewSpace(*handle_name); 7269 Unique<Name> unique_name = Unique<Name>::CreateUninitialized(handle_name); 7270 Add<HCheckValue>(key, unique_name, in_new_space); 7271 } 7272 } 7273 if (expected_key->ActualValue()->IsConstant()) { 7274 Handle<Object> constant = 7275 HConstant::cast(expected_key->ActualValue())->handle(isolate()); 7276 uint32_t array_index; 7277 if ((constant->IsString() && 7278 !Handle<String>::cast(constant)->AsArrayIndex(&array_index)) || 7279 constant->IsSymbol()) { 7280 if (!constant->IsUniqueName()) { 7281 constant = isolate()->factory()->InternalizeString( 7282 Handle<String>::cast(constant)); 7283 } 7284 HValue* access = 7285 BuildNamedAccess(access_type, ast_id, return_id, expr, slot, obj, 7286 Handle<Name>::cast(constant), val, false); 7287 if (access == NULL || access->IsPhi() || 7288 HInstruction::cast(access)->IsLinked()) { 7289 *has_side_effects = false; 7290 } else { 7291 HInstruction* instr = HInstruction::cast(access); 7292 AddInstruction(instr); 7293 *has_side_effects = instr->HasObservableSideEffects(); 7294 } 7295 return access; 7296 } 7297 } 7298 7299 DCHECK(!expr->IsPropertyName()); 7300 HInstruction* instr = NULL; 7301 7302 SmallMapList* maps; 7303 bool monomorphic = ComputeReceiverTypes(expr, obj, &maps, this); 7304 7305 bool force_generic = false; 7306 if (expr->GetKeyType() == PROPERTY) { 7307 // Non-Generic accesses assume that elements are being accessed, and will 7308 // deopt for non-index keys, which the IC knows will occur. 7309 // TODO(jkummerow): Consider adding proper support for property accesses. 7310 force_generic = true; 7311 monomorphic = false; 7312 } else if (access_type == STORE && 7313 (monomorphic || (maps != NULL && !maps->is_empty()))) { 7314 // Stores can't be mono/polymorphic if their prototype chain has dictionary 7315 // elements. However a receiver map that has dictionary elements itself 7316 // should be left to normal mono/poly behavior (the other maps may benefit 7317 // from highly optimized stores). 7318 for (int i = 0; i < maps->length(); i++) { 7319 Handle<Map> current_map = maps->at(i); 7320 if (current_map->DictionaryElementsInPrototypeChainOnly()) { 7321 force_generic = true; 7322 monomorphic = false; 7323 break; 7324 } 7325 } 7326 } else if (access_type == LOAD && !monomorphic && 7327 (maps != NULL && !maps->is_empty())) { 7328 // Polymorphic loads have to go generic if any of the maps are strings. 7329 // If some, but not all of the maps are strings, we should go generic 7330 // because polymorphic access wants to key on ElementsKind and isn't 7331 // compatible with strings. 7332 for (int i = 0; i < maps->length(); i++) { 7333 Handle<Map> current_map = maps->at(i); 7334 if (current_map->IsStringMap()) { 7335 force_generic = true; 7336 break; 7337 } 7338 } 7339 } 7340 7341 if (monomorphic) { 7342 Handle<Map> map = maps->first(); 7343 if (!CanInlineElementAccess(map)) { 7344 instr = AddInstruction( 7345 BuildKeyedGeneric(access_type, expr, slot, obj, key, val)); 7346 } else { 7347 BuildCheckHeapObject(obj); 7348 instr = BuildMonomorphicElementAccess( 7349 obj, key, val, NULL, map, access_type, expr->GetStoreMode()); 7350 } 7351 } else if (!force_generic && (maps != NULL && !maps->is_empty())) { 7352 return HandlePolymorphicElementAccess(expr, slot, obj, key, val, maps, 7353 access_type, expr->GetStoreMode(), 7354 has_side_effects); 7355 } else { 7356 if (access_type == STORE) { 7357 if (expr->IsAssignment() && 7358 expr->AsAssignment()->HasNoTypeInformation()) { 7359 Add<HDeoptimize>( 7360 DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess, 7361 Deoptimizer::SOFT); 7362 } 7363 } else { 7364 if (expr->AsProperty()->HasNoTypeInformation()) { 7365 Add<HDeoptimize>( 7366 DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess, 7367 Deoptimizer::SOFT); 7368 } 7369 } 7370 instr = AddInstruction( 7371 BuildKeyedGeneric(access_type, expr, slot, obj, key, val)); 7372 } 7373 *has_side_effects = instr->HasObservableSideEffects(); 7374 return instr; 7375 } 7376 7377 7378 void HOptimizedGraphBuilder::EnsureArgumentsArePushedForAccess() { 7379 // Outermost function already has arguments on the stack. 7380 if (function_state()->outer() == NULL) return; 7381 7382 if (function_state()->arguments_pushed()) return; 7383 7384 // Push arguments when entering inlined function. 7385 HEnterInlined* entry = function_state()->entry(); 7386 entry->set_arguments_pushed(); 7387 7388 HArgumentsObject* arguments = entry->arguments_object(); 7389 const ZoneList<HValue*>* arguments_values = arguments->arguments_values(); 7390 7391 HInstruction* insert_after = entry; 7392 for (int i = 0; i < arguments_values->length(); i++) { 7393 HValue* argument = arguments_values->at(i); 7394 HInstruction* push_argument = New<HPushArguments>(argument); 7395 push_argument->InsertAfter(insert_after); 7396 insert_after = push_argument; 7397 } 7398 7399 HArgumentsElements* arguments_elements = New<HArgumentsElements>(true); 7400 arguments_elements->ClearFlag(HValue::kUseGVN); 7401 arguments_elements->InsertAfter(insert_after); 7402 function_state()->set_arguments_elements(arguments_elements); 7403 } 7404 7405 bool HOptimizedGraphBuilder::IsAnyParameterContextAllocated() { 7406 int count = current_info()->scope()->num_parameters(); 7407 for (int i = 0; i < count; ++i) { 7408 if (current_info()->scope()->parameter(i)->location() == 7409 VariableLocation::CONTEXT) { 7410 return true; 7411 } 7412 } 7413 return false; 7414 } 7415 7416 bool HOptimizedGraphBuilder::TryArgumentsAccess(Property* expr) { 7417 VariableProxy* proxy = expr->obj()->AsVariableProxy(); 7418 if (proxy == NULL) return false; 7419 if (!proxy->var()->IsStackAllocated()) return false; 7420 if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) { 7421 return false; 7422 } 7423 7424 HInstruction* result = NULL; 7425 if (expr->key()->IsPropertyName()) { 7426 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); 7427 if (!String::Equals(name, isolate()->factory()->length_string())) { 7428 return false; 7429 } 7430 7431 // Make sure we visit the arguments object so that the liveness analysis 7432 // still records the access. 7433 CHECK_ALIVE_OR_RETURN(VisitForValue(expr->obj(), ARGUMENTS_ALLOWED), true); 7434 Drop(1); 7435 7436 if (function_state()->outer() == NULL) { 7437 HInstruction* elements = Add<HArgumentsElements>(false); 7438 result = New<HArgumentsLength>(elements); 7439 } else { 7440 // Number of arguments without receiver. 7441 int argument_count = environment()-> 7442 arguments_environment()->parameter_count() - 1; 7443 result = New<HConstant>(argument_count); 7444 } 7445 } else { 7446 // We need to take into account the KEYED_LOAD_IC feedback to guard the 7447 // HBoundsCheck instructions below. 7448 if (!expr->IsMonomorphic() && !expr->IsUninitialized()) return false; 7449 if (IsAnyParameterContextAllocated()) return false; 7450 CHECK_ALIVE_OR_RETURN(VisitForValue(expr->obj(), ARGUMENTS_ALLOWED), true); 7451 CHECK_ALIVE_OR_RETURN(VisitForValue(expr->key()), true); 7452 HValue* key = Pop(); 7453 Drop(1); // Arguments object. 7454 if (function_state()->outer() == NULL) { 7455 HInstruction* elements = Add<HArgumentsElements>(false); 7456 HInstruction* length = Add<HArgumentsLength>(elements); 7457 HInstruction* checked_key = Add<HBoundsCheck>(key, length); 7458 result = New<HAccessArgumentsAt>(elements, length, checked_key); 7459 } else { 7460 EnsureArgumentsArePushedForAccess(); 7461 7462 // Number of arguments without receiver. 7463 HInstruction* elements = function_state()->arguments_elements(); 7464 int argument_count = environment()-> 7465 arguments_environment()->parameter_count() - 1; 7466 HInstruction* length = Add<HConstant>(argument_count); 7467 HInstruction* checked_key = Add<HBoundsCheck>(key, length); 7468 result = New<HAccessArgumentsAt>(elements, length, checked_key); 7469 } 7470 } 7471 ast_context()->ReturnInstruction(result, expr->id()); 7472 return true; 7473 } 7474 7475 HValue* HOptimizedGraphBuilder::BuildNamedAccess( 7476 PropertyAccessType access, BailoutId ast_id, BailoutId return_id, 7477 Expression* expr, FeedbackVectorSlot slot, HValue* object, 7478 Handle<Name> name, HValue* value, bool is_uninitialized) { 7479 SmallMapList* maps; 7480 ComputeReceiverTypes(expr, object, &maps, this); 7481 DCHECK(maps != NULL); 7482 7483 // Check for special case: Access via a single map to the global proxy 7484 // can also be handled monomorphically. 7485 if (maps->length() > 0) { 7486 Handle<Object> map_constructor = 7487 handle(maps->first()->GetConstructor(), isolate()); 7488 if (map_constructor->IsJSFunction()) { 7489 Handle<Context> map_context = 7490 handle(Handle<JSFunction>::cast(map_constructor)->context()); 7491 Handle<Context> current_context(current_info()->context()); 7492 bool is_same_context_global_proxy_access = 7493 maps->length() == 1 && // >1 map => fallback to polymorphic 7494 maps->first()->IsJSGlobalProxyMap() && 7495 (*map_context == *current_context); 7496 if (is_same_context_global_proxy_access) { 7497 Handle<JSGlobalObject> global_object(current_info()->global_object()); 7498 LookupIterator it(global_object, name, LookupIterator::OWN); 7499 if (CanInlineGlobalPropertyAccess(&it, access)) { 7500 BuildCheckHeapObject(object); 7501 Add<HCheckMaps>(object, maps); 7502 if (access == LOAD) { 7503 InlineGlobalPropertyLoad(&it, expr->id()); 7504 return nullptr; 7505 } else { 7506 return InlineGlobalPropertyStore(&it, value, expr->id()); 7507 } 7508 } 7509 } 7510 } 7511 7512 PropertyAccessInfo info(this, access, maps->first(), name); 7513 if (!info.CanAccessAsMonomorphic(maps)) { 7514 HandlePolymorphicNamedFieldAccess(access, expr, slot, ast_id, return_id, 7515 object, value, maps, name); 7516 return NULL; 7517 } 7518 7519 HValue* checked_object; 7520 // AstType::Number() is only supported by polymorphic load/call handling. 7521 DCHECK(!info.IsNumberType()); 7522 BuildCheckHeapObject(object); 7523 if (AreStringTypes(maps)) { 7524 checked_object = 7525 Add<HCheckInstanceType>(object, HCheckInstanceType::IS_STRING); 7526 } else { 7527 checked_object = Add<HCheckMaps>(object, maps); 7528 } 7529 return BuildMonomorphicAccess( 7530 &info, object, checked_object, value, ast_id, return_id); 7531 } 7532 7533 return BuildNamedGeneric(access, expr, slot, object, name, value, 7534 is_uninitialized); 7535 } 7536 7537 7538 void HOptimizedGraphBuilder::PushLoad(Property* expr, 7539 HValue* object, 7540 HValue* key) { 7541 ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED); 7542 Push(object); 7543 if (key != NULL) Push(key); 7544 BuildLoad(expr, expr->LoadId()); 7545 } 7546 7547 7548 void HOptimizedGraphBuilder::BuildLoad(Property* expr, 7549 BailoutId ast_id) { 7550 HInstruction* instr = NULL; 7551 if (expr->IsStringAccess() && expr->GetKeyType() == ELEMENT) { 7552 HValue* index = Pop(); 7553 HValue* string = Pop(); 7554 HInstruction* char_code = BuildStringCharCodeAt(string, index); 7555 AddInstruction(char_code); 7556 instr = NewUncasted<HStringCharFromCode>(char_code); 7557 7558 } else if (expr->key()->IsPropertyName()) { 7559 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); 7560 HValue* object = Pop(); 7561 7562 HValue* value = BuildNamedAccess(LOAD, ast_id, expr->LoadId(), expr, 7563 expr->PropertyFeedbackSlot(), object, name, 7564 NULL, expr->IsUninitialized()); 7565 if (value == NULL) return; 7566 if (value->IsPhi()) return ast_context()->ReturnValue(value); 7567 instr = HInstruction::cast(value); 7568 if (instr->IsLinked()) return ast_context()->ReturnValue(instr); 7569 7570 } else { 7571 HValue* key = Pop(); 7572 HValue* obj = Pop(); 7573 7574 bool has_side_effects = false; 7575 HValue* load = HandleKeyedElementAccess( 7576 obj, key, NULL, expr, expr->PropertyFeedbackSlot(), ast_id, 7577 expr->LoadId(), LOAD, &has_side_effects); 7578 if (has_side_effects) { 7579 if (ast_context()->IsEffect()) { 7580 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); 7581 } else { 7582 Push(load); 7583 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); 7584 Drop(1); 7585 } 7586 } 7587 if (load == NULL) return; 7588 return ast_context()->ReturnValue(load); 7589 } 7590 return ast_context()->ReturnInstruction(instr, ast_id); 7591 } 7592 7593 7594 void HOptimizedGraphBuilder::VisitProperty(Property* expr) { 7595 DCHECK(!HasStackOverflow()); 7596 DCHECK(current_block() != NULL); 7597 DCHECK(current_block()->HasPredecessor()); 7598 7599 if (TryArgumentsAccess(expr)) return; 7600 7601 CHECK_ALIVE(VisitForValue(expr->obj())); 7602 if (!expr->key()->IsPropertyName() || expr->IsStringAccess()) { 7603 CHECK_ALIVE(VisitForValue(expr->key())); 7604 } 7605 7606 BuildLoad(expr, expr->id()); 7607 } 7608 7609 7610 HInstruction* HGraphBuilder::BuildConstantMapCheck(Handle<JSObject> constant) { 7611 HCheckMaps* check = Add<HCheckMaps>( 7612 Add<HConstant>(constant), handle(constant->map())); 7613 check->ClearDependsOnFlag(kElementsKind); 7614 return check; 7615 } 7616 7617 7618 HInstruction* HGraphBuilder::BuildCheckPrototypeMaps(Handle<JSObject> prototype, 7619 Handle<JSObject> holder) { 7620 PrototypeIterator iter(isolate(), prototype, kStartAtReceiver); 7621 while (holder.is_null() || 7622 !PrototypeIterator::GetCurrent(iter).is_identical_to(holder)) { 7623 BuildConstantMapCheck(PrototypeIterator::GetCurrent<JSObject>(iter)); 7624 iter.Advance(); 7625 if (iter.IsAtEnd()) { 7626 return NULL; 7627 } 7628 } 7629 return BuildConstantMapCheck(PrototypeIterator::GetCurrent<JSObject>(iter)); 7630 } 7631 7632 7633 void HOptimizedGraphBuilder::AddCheckPrototypeMaps(Handle<JSObject> holder, 7634 Handle<Map> receiver_map) { 7635 if (!holder.is_null()) { 7636 Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype())); 7637 BuildCheckPrototypeMaps(prototype, holder); 7638 } 7639 } 7640 7641 void HOptimizedGraphBuilder::BuildEnsureCallable(HValue* object) { 7642 NoObservableSideEffectsScope scope(this); 7643 const Runtime::Function* throw_called_non_callable = 7644 Runtime::FunctionForId(Runtime::kThrowCalledNonCallable); 7645 7646 IfBuilder is_not_function(this); 7647 HValue* smi_check = is_not_function.If<HIsSmiAndBranch>(object); 7648 is_not_function.Or(); 7649 HValue* map = AddLoadMap(object, smi_check); 7650 HValue* bit_field = 7651 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapBitField()); 7652 HValue* bit_field_masked = AddUncasted<HBitwise>( 7653 Token::BIT_AND, bit_field, Add<HConstant>(1 << Map::kIsCallable)); 7654 is_not_function.IfNot<HCompareNumericAndBranch>( 7655 bit_field_masked, Add<HConstant>(1 << Map::kIsCallable), Token::EQ); 7656 is_not_function.Then(); 7657 { 7658 Add<HPushArguments>(object); 7659 Add<HCallRuntime>(throw_called_non_callable, 1); 7660 } 7661 is_not_function.End(); 7662 } 7663 7664 HInstruction* HOptimizedGraphBuilder::NewCallFunction( 7665 HValue* function, int argument_count, TailCallMode syntactic_tail_call_mode, 7666 ConvertReceiverMode convert_mode, TailCallMode tail_call_mode) { 7667 if (syntactic_tail_call_mode == TailCallMode::kAllow) { 7668 BuildEnsureCallable(function); 7669 } else { 7670 DCHECK_EQ(TailCallMode::kDisallow, tail_call_mode); 7671 } 7672 HValue* arity = Add<HConstant>(argument_count - 1); 7673 7674 HValue* op_vals[] = {function, arity}; 7675 7676 Callable callable = 7677 CodeFactory::Call(isolate(), convert_mode, tail_call_mode); 7678 HConstant* stub = Add<HConstant>(callable.code()); 7679 7680 return New<HCallWithDescriptor>(stub, argument_count, callable.descriptor(), 7681 ArrayVector(op_vals), 7682 syntactic_tail_call_mode); 7683 } 7684 7685 HInstruction* HOptimizedGraphBuilder::NewCallFunctionViaIC( 7686 HValue* function, int argument_count, TailCallMode syntactic_tail_call_mode, 7687 ConvertReceiverMode convert_mode, TailCallMode tail_call_mode, 7688 FeedbackVectorSlot slot) { 7689 if (syntactic_tail_call_mode == TailCallMode::kAllow) { 7690 BuildEnsureCallable(function); 7691 } else { 7692 DCHECK_EQ(TailCallMode::kDisallow, tail_call_mode); 7693 } 7694 int arity = argument_count - 1; 7695 Handle<TypeFeedbackVector> vector(current_feedback_vector(), isolate()); 7696 HValue* arity_val = Add<HConstant>(arity); 7697 HValue* index_val = Add<HConstant>(vector->GetIndex(slot)); 7698 HValue* vector_val = Add<HConstant>(vector); 7699 7700 HValue* op_vals[] = {function, arity_val, index_val, vector_val}; 7701 Callable callable = CodeFactory::CallICInOptimizedCode( 7702 isolate(), convert_mode, tail_call_mode); 7703 HConstant* stub = Add<HConstant>(callable.code()); 7704 7705 return New<HCallWithDescriptor>(stub, argument_count, callable.descriptor(), 7706 ArrayVector(op_vals), 7707 syntactic_tail_call_mode); 7708 } 7709 7710 HInstruction* HOptimizedGraphBuilder::NewCallConstantFunction( 7711 Handle<JSFunction> function, int argument_count, 7712 TailCallMode syntactic_tail_call_mode, TailCallMode tail_call_mode) { 7713 HValue* target = Add<HConstant>(function); 7714 return New<HInvokeFunction>(target, function, argument_count, 7715 syntactic_tail_call_mode, tail_call_mode); 7716 } 7717 7718 7719 class FunctionSorter { 7720 public: 7721 explicit FunctionSorter(int index = 0, int ticks = 0, int size = 0) 7722 : index_(index), ticks_(ticks), size_(size) {} 7723 7724 int index() const { return index_; } 7725 int ticks() const { return ticks_; } 7726 int size() const { return size_; } 7727 7728 private: 7729 int index_; 7730 int ticks_; 7731 int size_; 7732 }; 7733 7734 7735 inline bool operator<(const FunctionSorter& lhs, const FunctionSorter& rhs) { 7736 int diff = lhs.ticks() - rhs.ticks(); 7737 if (diff != 0) return diff > 0; 7738 return lhs.size() < rhs.size(); 7739 } 7740 7741 7742 void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(Call* expr, 7743 HValue* receiver, 7744 SmallMapList* maps, 7745 Handle<String> name) { 7746 int argument_count = expr->arguments()->length() + 1; // Includes receiver. 7747 FunctionSorter order[kMaxCallPolymorphism]; 7748 7749 bool handle_smi = false; 7750 bool handled_string = false; 7751 int ordered_functions = 0; 7752 7753 TailCallMode syntactic_tail_call_mode = expr->tail_call_mode(); 7754 TailCallMode tail_call_mode = 7755 function_state()->ComputeTailCallMode(syntactic_tail_call_mode); 7756 7757 int i; 7758 for (i = 0; i < maps->length() && ordered_functions < kMaxCallPolymorphism; 7759 ++i) { 7760 PropertyAccessInfo info(this, LOAD, maps->at(i), name); 7761 if (info.CanAccessMonomorphic() && info.IsDataConstant() && 7762 info.constant()->IsJSFunction()) { 7763 if (info.IsStringType()) { 7764 if (handled_string) continue; 7765 handled_string = true; 7766 } 7767 Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant()); 7768 if (info.IsNumberType()) { 7769 handle_smi = true; 7770 } 7771 expr->set_target(target); 7772 order[ordered_functions++] = FunctionSorter( 7773 i, target->shared()->profiler_ticks(), InliningAstSize(target)); 7774 } 7775 } 7776 7777 std::sort(order, order + ordered_functions); 7778 7779 if (i < maps->length()) { 7780 maps->Clear(); 7781 ordered_functions = -1; 7782 } 7783 7784 HBasicBlock* number_block = NULL; 7785 HBasicBlock* join = NULL; 7786 handled_string = false; 7787 int count = 0; 7788 7789 for (int fn = 0; fn < ordered_functions; ++fn) { 7790 int i = order[fn].index(); 7791 PropertyAccessInfo info(this, LOAD, maps->at(i), name); 7792 if (info.IsStringType()) { 7793 if (handled_string) continue; 7794 handled_string = true; 7795 } 7796 // Reloads the target. 7797 info.CanAccessMonomorphic(); 7798 Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant()); 7799 7800 expr->set_target(target); 7801 if (count == 0) { 7802 // Only needed once. 7803 join = graph()->CreateBasicBlock(); 7804 if (handle_smi) { 7805 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); 7806 HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); 7807 number_block = graph()->CreateBasicBlock(); 7808 FinishCurrentBlock(New<HIsSmiAndBranch>( 7809 receiver, empty_smi_block, not_smi_block)); 7810 GotoNoSimulate(empty_smi_block, number_block); 7811 set_current_block(not_smi_block); 7812 } else { 7813 BuildCheckHeapObject(receiver); 7814 } 7815 } 7816 ++count; 7817 HBasicBlock* if_true = graph()->CreateBasicBlock(); 7818 HBasicBlock* if_false = graph()->CreateBasicBlock(); 7819 HUnaryControlInstruction* compare; 7820 7821 Handle<Map> map = info.map(); 7822 if (info.IsNumberType()) { 7823 Handle<Map> heap_number_map = isolate()->factory()->heap_number_map(); 7824 compare = New<HCompareMap>(receiver, heap_number_map, if_true, if_false); 7825 } else if (info.IsStringType()) { 7826 compare = New<HIsStringAndBranch>(receiver, if_true, if_false); 7827 } else { 7828 compare = New<HCompareMap>(receiver, map, if_true, if_false); 7829 } 7830 FinishCurrentBlock(compare); 7831 7832 if (info.IsNumberType()) { 7833 GotoNoSimulate(if_true, number_block); 7834 if_true = number_block; 7835 } 7836 7837 set_current_block(if_true); 7838 7839 AddCheckPrototypeMaps(info.holder(), map); 7840 7841 HValue* function = Add<HConstant>(expr->target()); 7842 environment()->SetExpressionStackAt(0, function); 7843 Push(receiver); 7844 CHECK_ALIVE(VisitExpressions(expr->arguments())); 7845 bool needs_wrapping = info.NeedsWrappingFor(target); 7846 bool try_inline = FLAG_polymorphic_inlining && !needs_wrapping; 7847 if (FLAG_trace_inlining && try_inline) { 7848 Handle<JSFunction> caller = current_info()->closure(); 7849 std::unique_ptr<char[]> caller_name = 7850 caller->shared()->DebugName()->ToCString(); 7851 PrintF("Trying to inline the polymorphic call to %s from %s\n", 7852 name->ToCString().get(), 7853 caller_name.get()); 7854 } 7855 if (try_inline && TryInlineCall(expr)) { 7856 // Trying to inline will signal that we should bailout from the 7857 // entire compilation by setting stack overflow on the visitor. 7858 if (HasStackOverflow()) return; 7859 } else { 7860 // Since HWrapReceiver currently cannot actually wrap numbers and strings, 7861 // use the regular call builtin for method calls to wrap the receiver. 7862 // TODO(verwaest): Support creation of value wrappers directly in 7863 // HWrapReceiver. 7864 HInstruction* call = 7865 needs_wrapping 7866 ? NewCallFunction( 7867 function, argument_count, syntactic_tail_call_mode, 7868 ConvertReceiverMode::kNotNullOrUndefined, tail_call_mode) 7869 : NewCallConstantFunction(target, argument_count, 7870 syntactic_tail_call_mode, 7871 tail_call_mode); 7872 PushArgumentsFromEnvironment(argument_count); 7873 AddInstruction(call); 7874 Drop(1); // Drop the function. 7875 if (!ast_context()->IsEffect()) Push(call); 7876 } 7877 7878 if (current_block() != NULL) Goto(join); 7879 set_current_block(if_false); 7880 } 7881 7882 // Finish up. Unconditionally deoptimize if we've handled all the maps we 7883 // know about and do not want to handle ones we've never seen. Otherwise 7884 // use a generic IC. 7885 if (ordered_functions == maps->length() && FLAG_deoptimize_uncommon_cases) { 7886 FinishExitWithHardDeoptimization( 7887 DeoptimizeReason::kUnknownMapInPolymorphicCall); 7888 } else { 7889 Property* prop = expr->expression()->AsProperty(); 7890 HInstruction* function = 7891 BuildNamedGeneric(LOAD, prop, prop->PropertyFeedbackSlot(), receiver, 7892 name, NULL, prop->IsUninitialized()); 7893 AddInstruction(function); 7894 Push(function); 7895 AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE); 7896 7897 environment()->SetExpressionStackAt(1, function); 7898 environment()->SetExpressionStackAt(0, receiver); 7899 CHECK_ALIVE(VisitExpressions(expr->arguments())); 7900 7901 HInstruction* call = NewCallFunction( 7902 function, argument_count, syntactic_tail_call_mode, 7903 ConvertReceiverMode::kNotNullOrUndefined, tail_call_mode); 7904 7905 PushArgumentsFromEnvironment(argument_count); 7906 7907 Drop(1); // Function. 7908 7909 if (join != NULL) { 7910 AddInstruction(call); 7911 if (!ast_context()->IsEffect()) Push(call); 7912 Goto(join); 7913 } else { 7914 return ast_context()->ReturnInstruction(call, expr->id()); 7915 } 7916 } 7917 7918 // We assume that control flow is always live after an expression. So 7919 // even without predecessors to the join block, we set it as the exit 7920 // block and continue by adding instructions there. 7921 DCHECK(join != NULL); 7922 if (join->HasPredecessor()) { 7923 set_current_block(join); 7924 join->SetJoinId(expr->id()); 7925 if (!ast_context()->IsEffect()) return ast_context()->ReturnValue(Pop()); 7926 } else { 7927 set_current_block(NULL); 7928 } 7929 } 7930 7931 void HOptimizedGraphBuilder::TraceInline(Handle<JSFunction> target, 7932 Handle<JSFunction> caller, 7933 const char* reason, 7934 TailCallMode tail_call_mode) { 7935 if (FLAG_trace_inlining) { 7936 std::unique_ptr<char[]> target_name = 7937 target->shared()->DebugName()->ToCString(); 7938 std::unique_ptr<char[]> caller_name = 7939 caller->shared()->DebugName()->ToCString(); 7940 if (reason == NULL) { 7941 const char* call_mode = 7942 tail_call_mode == TailCallMode::kAllow ? "tail called" : "called"; 7943 PrintF("Inlined %s %s from %s.\n", target_name.get(), call_mode, 7944 caller_name.get()); 7945 } else { 7946 PrintF("Did not inline %s called from %s (%s).\n", 7947 target_name.get(), caller_name.get(), reason); 7948 } 7949 } 7950 } 7951 7952 7953 static const int kNotInlinable = 1000000000; 7954 7955 7956 int HOptimizedGraphBuilder::InliningAstSize(Handle<JSFunction> target) { 7957 if (!FLAG_use_inlining) return kNotInlinable; 7958 7959 // Precondition: call is monomorphic and we have found a target with the 7960 // appropriate arity. 7961 Handle<JSFunction> caller = current_info()->closure(); 7962 Handle<SharedFunctionInfo> target_shared(target->shared()); 7963 7964 // Always inline functions that force inlining. 7965 if (target_shared->force_inline()) { 7966 return 0; 7967 } 7968 if (target->shared()->IsBuiltin()) { 7969 return kNotInlinable; 7970 } 7971 7972 if (target_shared->IsApiFunction()) { 7973 TraceInline(target, caller, "target is api function"); 7974 return kNotInlinable; 7975 } 7976 7977 // Do a quick check on source code length to avoid parsing large 7978 // inlining candidates. 7979 if (target_shared->SourceSize() > 7980 Min(FLAG_max_inlined_source_size, kUnlimitedMaxInlinedSourceSize)) { 7981 TraceInline(target, caller, "target text too big"); 7982 return kNotInlinable; 7983 } 7984 7985 // Target must be inlineable. 7986 BailoutReason noopt_reason = target_shared->disable_optimization_reason(); 7987 if (!target_shared->IsInlineable() && noopt_reason != kHydrogenFilter) { 7988 TraceInline(target, caller, "target not inlineable"); 7989 return kNotInlinable; 7990 } 7991 if (noopt_reason != kNoReason && noopt_reason != kHydrogenFilter) { 7992 TraceInline(target, caller, "target contains unsupported syntax [early]"); 7993 return kNotInlinable; 7994 } 7995 7996 int nodes_added = target_shared->ast_node_count(); 7997 return nodes_added; 7998 } 7999 8000 bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target, 8001 int arguments_count, 8002 HValue* implicit_return_value, 8003 BailoutId ast_id, BailoutId return_id, 8004 InliningKind inlining_kind, 8005 TailCallMode syntactic_tail_call_mode) { 8006 if (target->context()->native_context() != 8007 top_info()->closure()->context()->native_context()) { 8008 return false; 8009 } 8010 int nodes_added = InliningAstSize(target); 8011 if (nodes_added == kNotInlinable) return false; 8012 8013 Handle<JSFunction> caller = current_info()->closure(); 8014 if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) { 8015 TraceInline(target, caller, "target AST is too large [early]"); 8016 return false; 8017 } 8018 8019 // Don't inline deeper than the maximum number of inlining levels. 8020 HEnvironment* env = environment(); 8021 int current_level = 1; 8022 while (env->outer() != NULL) { 8023 if (current_level == FLAG_max_inlining_levels) { 8024 TraceInline(target, caller, "inline depth limit reached"); 8025 return false; 8026 } 8027 if (env->outer()->frame_type() == JS_FUNCTION) { 8028 current_level++; 8029 } 8030 env = env->outer(); 8031 } 8032 8033 // Don't inline recursive functions. 8034 for (FunctionState* state = function_state(); 8035 state != NULL; 8036 state = state->outer()) { 8037 if (*state->compilation_info()->closure() == *target) { 8038 TraceInline(target, caller, "target is recursive"); 8039 return false; 8040 } 8041 } 8042 8043 // We don't want to add more than a certain number of nodes from inlining. 8044 // Always inline small methods (<= 10 nodes). 8045 if (inlined_count_ > Min(FLAG_max_inlined_nodes_cumulative, 8046 kUnlimitedMaxInlinedNodesCumulative)) { 8047 TraceInline(target, caller, "cumulative AST node limit reached"); 8048 return false; 8049 } 8050 8051 // Parse and allocate variables. 8052 // Use the same AstValueFactory for creating strings in the sub-compilation 8053 // step, but don't transfer ownership to target_info. 8054 Handle<SharedFunctionInfo> target_shared(target->shared()); 8055 ParseInfo parse_info(zone(), target_shared); 8056 parse_info.set_ast_value_factory( 8057 top_info()->parse_info()->ast_value_factory()); 8058 parse_info.set_ast_value_factory_owned(false); 8059 8060 CompilationInfo target_info(&parse_info, target); 8061 8062 if (inlining_kind != CONSTRUCT_CALL_RETURN && 8063 IsClassConstructor(target_shared->kind())) { 8064 TraceInline(target, caller, "target is classConstructor"); 8065 return false; 8066 } 8067 8068 if (target_shared->HasDebugInfo()) { 8069 TraceInline(target, caller, "target is being debugged"); 8070 return false; 8071 } 8072 if (!Compiler::ParseAndAnalyze(target_info.parse_info())) { 8073 if (target_info.isolate()->has_pending_exception()) { 8074 // Parse or scope error, never optimize this function. 8075 SetStackOverflow(); 8076 target_shared->DisableOptimization(kParseScopeError); 8077 } 8078 TraceInline(target, caller, "parse failure"); 8079 return false; 8080 } 8081 if (target_shared->dont_crankshaft()) { 8082 TraceInline(target, caller, "ParseAndAnalyze found incompatibility"); 8083 return false; 8084 } 8085 8086 if (target_info.scope()->NeedsContext()) { 8087 TraceInline(target, caller, "target has context-allocated variables"); 8088 return false; 8089 } 8090 8091 if (target_info.scope()->rest_parameter() != nullptr) { 8092 TraceInline(target, caller, "target uses rest parameters"); 8093 return false; 8094 } 8095 8096 FunctionLiteral* function = target_info.literal(); 8097 8098 // The following conditions must be checked again after re-parsing, because 8099 // earlier the information might not have been complete due to lazy parsing. 8100 nodes_added = function->ast_node_count(); 8101 if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) { 8102 TraceInline(target, caller, "target AST is too large [late]"); 8103 return false; 8104 } 8105 if (function->dont_optimize()) { 8106 TraceInline(target, caller, "target contains unsupported syntax [late]"); 8107 return false; 8108 } 8109 8110 // If the function uses the arguments object check that inlining of functions 8111 // with arguments object is enabled and the arguments-variable is 8112 // stack allocated. 8113 if (function->scope()->arguments() != NULL) { 8114 if (!FLAG_inline_arguments) { 8115 TraceInline(target, caller, "target uses arguments object"); 8116 return false; 8117 } 8118 } 8119 8120 // Unsupported variable references present. 8121 if (function->scope()->this_function_var() != nullptr || 8122 function->scope()->new_target_var() != nullptr) { 8123 TraceInline(target, caller, "target uses new target or this function"); 8124 return false; 8125 } 8126 8127 // All declarations must be inlineable. 8128 Declaration::List* decls = target_info.scope()->declarations(); 8129 for (Declaration* decl : *decls) { 8130 if (decl->IsFunctionDeclaration() || 8131 !decl->proxy()->var()->IsStackAllocated()) { 8132 TraceInline(target, caller, "target has non-trivial declaration"); 8133 return false; 8134 } 8135 } 8136 8137 // Generate the deoptimization data for the unoptimized version of 8138 // the target function if we don't already have it. 8139 if (!Compiler::EnsureDeoptimizationSupport(&target_info)) { 8140 TraceInline(target, caller, "could not generate deoptimization info"); 8141 return false; 8142 } 8143 8144 // Remember that we inlined this function. This needs to be called right 8145 // after the EnsureDeoptimizationSupport call so that the code flusher 8146 // does not remove the code with the deoptimization support. 8147 int inlining_id = top_info()->AddInlinedFunction(target_info.shared_info(), 8148 source_position()); 8149 8150 // ---------------------------------------------------------------- 8151 // After this point, we've made a decision to inline this function (so 8152 // TryInline should always return true). 8153 8154 // If target was lazily compiled, it's literals array may not yet be set up. 8155 JSFunction::EnsureLiterals(target); 8156 8157 // Type-check the inlined function. 8158 DCHECK(target_shared->has_deoptimization_support()); 8159 AstTyper(target_info.isolate(), target_info.zone(), target_info.closure(), 8160 target_info.scope(), target_info.osr_ast_id(), target_info.literal(), 8161 &bounds_) 8162 .Run(); 8163 8164 if (is_tracking_positions()) { 8165 TraceInlinedFunction(target_shared, source_position(), inlining_id); 8166 } 8167 8168 // Save the pending call context. Set up new one for the inlined function. 8169 // The function state is new-allocated because we need to delete it 8170 // in two different places. 8171 FunctionState* target_state = new FunctionState( 8172 this, &target_info, inlining_kind, inlining_id, 8173 function_state()->ComputeTailCallMode(syntactic_tail_call_mode)); 8174 8175 HConstant* undefined = graph()->GetConstantUndefined(); 8176 8177 HEnvironment* inner_env = environment()->CopyForInlining( 8178 target, arguments_count, function, undefined, 8179 function_state()->inlining_kind(), syntactic_tail_call_mode); 8180 8181 HConstant* context = Add<HConstant>(Handle<Context>(target->context())); 8182 inner_env->BindContext(context); 8183 8184 // Create a dematerialized arguments object for the function, also copy the 8185 // current arguments values to use them for materialization. 8186 HEnvironment* arguments_env = inner_env->arguments_environment(); 8187 int parameter_count = arguments_env->parameter_count(); 8188 HArgumentsObject* arguments_object = Add<HArgumentsObject>(parameter_count); 8189 for (int i = 0; i < parameter_count; i++) { 8190 arguments_object->AddArgument(arguments_env->Lookup(i), zone()); 8191 } 8192 8193 // If the function uses arguments object then bind bind one. 8194 if (function->scope()->arguments() != NULL) { 8195 DCHECK(function->scope()->arguments()->IsStackAllocated()); 8196 inner_env->Bind(function->scope()->arguments(), arguments_object); 8197 } 8198 8199 // Capture the state before invoking the inlined function for deopt in the 8200 // inlined function. This simulate has no bailout-id since it's not directly 8201 // reachable for deopt, and is only used to capture the state. If the simulate 8202 // becomes reachable by merging, the ast id of the simulate merged into it is 8203 // adopted. 8204 Add<HSimulate>(BailoutId::None()); 8205 8206 current_block()->UpdateEnvironment(inner_env); 8207 Scope* saved_scope = scope(); 8208 set_scope(target_info.scope()); 8209 HEnterInlined* enter_inlined = Add<HEnterInlined>( 8210 return_id, target, context, arguments_count, function, 8211 function_state()->inlining_kind(), function->scope()->arguments(), 8212 arguments_object, syntactic_tail_call_mode); 8213 if (is_tracking_positions()) { 8214 enter_inlined->set_inlining_id(inlining_id); 8215 } 8216 8217 function_state()->set_entry(enter_inlined); 8218 8219 VisitDeclarations(target_info.scope()->declarations()); 8220 VisitStatements(function->body()); 8221 set_scope(saved_scope); 8222 if (HasStackOverflow()) { 8223 // Bail out if the inline function did, as we cannot residualize a call 8224 // instead, but do not disable optimization for the outer function. 8225 TraceInline(target, caller, "inline graph construction failed"); 8226 target_shared->DisableOptimization(kInliningBailedOut); 8227 current_info()->RetryOptimization(kInliningBailedOut); 8228 delete target_state; 8229 return true; 8230 } 8231 8232 // Update inlined nodes count. 8233 inlined_count_ += nodes_added; 8234 8235 Handle<Code> unoptimized_code(target_shared->code()); 8236 DCHECK(unoptimized_code->kind() == Code::FUNCTION); 8237 Handle<TypeFeedbackInfo> type_info( 8238 TypeFeedbackInfo::cast(unoptimized_code->type_feedback_info())); 8239 graph()->update_type_change_checksum(type_info->own_type_change_checksum()); 8240 8241 TraceInline(target, caller, NULL, syntactic_tail_call_mode); 8242 8243 if (current_block() != NULL) { 8244 FunctionState* state = function_state(); 8245 if (state->inlining_kind() == CONSTRUCT_CALL_RETURN) { 8246 // Falling off the end of an inlined construct call. In a test context the 8247 // return value will always evaluate to true, in a value context the 8248 // return value is the newly allocated receiver. 8249 if (call_context()->IsTest()) { 8250 inlined_test_context()->ReturnValue(graph()->GetConstantTrue()); 8251 } else if (call_context()->IsEffect()) { 8252 Goto(function_return(), state); 8253 } else { 8254 DCHECK(call_context()->IsValue()); 8255 AddLeaveInlined(implicit_return_value, state); 8256 } 8257 } else if (state->inlining_kind() == SETTER_CALL_RETURN) { 8258 // Falling off the end of an inlined setter call. The returned value is 8259 // never used, the value of an assignment is always the value of the RHS 8260 // of the assignment. 8261 if (call_context()->IsTest()) { 8262 inlined_test_context()->ReturnValue(implicit_return_value); 8263 } else if (call_context()->IsEffect()) { 8264 Goto(function_return(), state); 8265 } else { 8266 DCHECK(call_context()->IsValue()); 8267 AddLeaveInlined(implicit_return_value, state); 8268 } 8269 } else { 8270 // Falling off the end of a normal inlined function. This basically means 8271 // returning undefined. 8272 if (call_context()->IsTest()) { 8273 inlined_test_context()->ReturnValue(graph()->GetConstantFalse()); 8274 } else if (call_context()->IsEffect()) { 8275 Goto(function_return(), state); 8276 } else { 8277 DCHECK(call_context()->IsValue()); 8278 AddLeaveInlined(undefined, state); 8279 } 8280 } 8281 } 8282 8283 // Fix up the function exits. 8284 if (inlined_test_context() != NULL) { 8285 HBasicBlock* if_true = inlined_test_context()->if_true(); 8286 HBasicBlock* if_false = inlined_test_context()->if_false(); 8287 8288 HEnterInlined* entry = function_state()->entry(); 8289 8290 // Pop the return test context from the expression context stack. 8291 DCHECK(ast_context() == inlined_test_context()); 8292 ClearInlinedTestContext(); 8293 delete target_state; 8294 8295 // Forward to the real test context. 8296 if (if_true->HasPredecessor()) { 8297 entry->RegisterReturnTarget(if_true, zone()); 8298 if_true->SetJoinId(ast_id); 8299 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); 8300 Goto(if_true, true_target, function_state()); 8301 } 8302 if (if_false->HasPredecessor()) { 8303 entry->RegisterReturnTarget(if_false, zone()); 8304 if_false->SetJoinId(ast_id); 8305 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); 8306 Goto(if_false, false_target, function_state()); 8307 } 8308 set_current_block(NULL); 8309 return true; 8310 8311 } else if (function_return()->HasPredecessor()) { 8312 function_state()->entry()->RegisterReturnTarget(function_return(), zone()); 8313 function_return()->SetJoinId(ast_id); 8314 set_current_block(function_return()); 8315 } else { 8316 set_current_block(NULL); 8317 } 8318 delete target_state; 8319 return true; 8320 } 8321 8322 8323 bool HOptimizedGraphBuilder::TryInlineCall(Call* expr) { 8324 return TryInline(expr->target(), expr->arguments()->length(), NULL, 8325 expr->id(), expr->ReturnId(), NORMAL_RETURN, 8326 expr->tail_call_mode()); 8327 } 8328 8329 8330 bool HOptimizedGraphBuilder::TryInlineConstruct(CallNew* expr, 8331 HValue* implicit_return_value) { 8332 return TryInline(expr->target(), expr->arguments()->length(), 8333 implicit_return_value, expr->id(), expr->ReturnId(), 8334 CONSTRUCT_CALL_RETURN, TailCallMode::kDisallow); 8335 } 8336 8337 bool HOptimizedGraphBuilder::TryInlineGetter(Handle<Object> getter, 8338 Handle<Map> receiver_map, 8339 BailoutId ast_id, 8340 BailoutId return_id) { 8341 if (TryInlineApiGetter(getter, receiver_map, ast_id)) return true; 8342 if (getter->IsJSFunction()) { 8343 Handle<JSFunction> getter_function = Handle<JSFunction>::cast(getter); 8344 return TryInlineBuiltinGetterCall(getter_function, receiver_map, ast_id) || 8345 TryInline(getter_function, 0, NULL, ast_id, return_id, 8346 GETTER_CALL_RETURN, TailCallMode::kDisallow); 8347 } 8348 return false; 8349 } 8350 8351 bool HOptimizedGraphBuilder::TryInlineSetter(Handle<Object> setter, 8352 Handle<Map> receiver_map, 8353 BailoutId id, 8354 BailoutId assignment_id, 8355 HValue* implicit_return_value) { 8356 if (TryInlineApiSetter(setter, receiver_map, id)) return true; 8357 return setter->IsJSFunction() && 8358 TryInline(Handle<JSFunction>::cast(setter), 1, implicit_return_value, 8359 id, assignment_id, SETTER_CALL_RETURN, 8360 TailCallMode::kDisallow); 8361 } 8362 8363 8364 bool HOptimizedGraphBuilder::TryInlineIndirectCall(Handle<JSFunction> function, 8365 Call* expr, 8366 int arguments_count) { 8367 return TryInline(function, arguments_count, NULL, expr->id(), 8368 expr->ReturnId(), NORMAL_RETURN, expr->tail_call_mode()); 8369 } 8370 8371 8372 bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr) { 8373 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; 8374 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); 8375 // We intentionally ignore expr->tail_call_mode() here because builtins 8376 // we inline here do not observe if they were tail called or not. 8377 switch (id) { 8378 case kMathCos: 8379 case kMathExp: 8380 case kMathRound: 8381 case kMathFround: 8382 case kMathFloor: 8383 case kMathAbs: 8384 case kMathSin: 8385 case kMathSqrt: 8386 case kMathLog: 8387 case kMathClz32: 8388 if (expr->arguments()->length() == 1) { 8389 HValue* argument = Pop(); 8390 Drop(2); // Receiver and function. 8391 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); 8392 ast_context()->ReturnInstruction(op, expr->id()); 8393 return true; 8394 } 8395 break; 8396 case kMathImul: 8397 if (expr->arguments()->length() == 2) { 8398 HValue* right = Pop(); 8399 HValue* left = Pop(); 8400 Drop(2); // Receiver and function. 8401 HInstruction* op = 8402 HMul::NewImul(isolate(), zone(), context(), left, right); 8403 ast_context()->ReturnInstruction(op, expr->id()); 8404 return true; 8405 } 8406 break; 8407 default: 8408 // Not supported for inlining yet. 8409 break; 8410 } 8411 return false; 8412 } 8413 8414 8415 // static 8416 bool HOptimizedGraphBuilder::IsReadOnlyLengthDescriptor( 8417 Handle<Map> jsarray_map) { 8418 DCHECK(!jsarray_map->is_dictionary_map()); 8419 Isolate* isolate = jsarray_map->GetIsolate(); 8420 Handle<Name> length_string = isolate->factory()->length_string(); 8421 DescriptorArray* descriptors = jsarray_map->instance_descriptors(); 8422 int number = 8423 descriptors->SearchWithCache(isolate, *length_string, *jsarray_map); 8424 DCHECK_NE(DescriptorArray::kNotFound, number); 8425 return descriptors->GetDetails(number).IsReadOnly(); 8426 } 8427 8428 8429 // static 8430 bool HOptimizedGraphBuilder::CanInlineArrayResizeOperation( 8431 Handle<Map> receiver_map) { 8432 return !receiver_map.is_null() && receiver_map->prototype()->IsJSObject() && 8433 receiver_map->instance_type() == JS_ARRAY_TYPE && 8434 IsFastElementsKind(receiver_map->elements_kind()) && 8435 !receiver_map->is_dictionary_map() && receiver_map->is_extensible() && 8436 (!receiver_map->is_prototype_map() || receiver_map->is_stable()) && 8437 !IsReadOnlyLengthDescriptor(receiver_map); 8438 } 8439 8440 bool HOptimizedGraphBuilder::TryInlineBuiltinGetterCall( 8441 Handle<JSFunction> function, Handle<Map> receiver_map, BailoutId ast_id) { 8442 if (!function->shared()->HasBuiltinFunctionId()) return false; 8443 BuiltinFunctionId id = function->shared()->builtin_function_id(); 8444 8445 // Try to inline getter calls like DataView.prototype.byteLength/byteOffset 8446 // as operations in the calling function. 8447 switch (id) { 8448 case kDataViewBuffer: { 8449 if (!receiver_map->IsJSDataViewMap()) return false; 8450 HObjectAccess access = HObjectAccess::ForMapAndOffset( 8451 receiver_map, JSDataView::kBufferOffset); 8452 HValue* object = Pop(); // receiver 8453 HInstruction* result = New<HLoadNamedField>(object, object, access); 8454 ast_context()->ReturnInstruction(result, ast_id); 8455 return true; 8456 } 8457 case kDataViewByteLength: 8458 case kDataViewByteOffset: { 8459 if (!receiver_map->IsJSDataViewMap()) return false; 8460 int offset = (id == kDataViewByteLength) ? JSDataView::kByteLengthOffset 8461 : JSDataView::kByteOffsetOffset; 8462 HObjectAccess access = 8463 HObjectAccess::ForMapAndOffset(receiver_map, offset); 8464 HValue* object = Pop(); // receiver 8465 HValue* checked_object = Add<HCheckArrayBufferNotNeutered>(object); 8466 HInstruction* result = 8467 New<HLoadNamedField>(object, checked_object, access); 8468 ast_context()->ReturnInstruction(result, ast_id); 8469 return true; 8470 } 8471 case kTypedArrayByteLength: 8472 case kTypedArrayByteOffset: 8473 case kTypedArrayLength: { 8474 if (!receiver_map->IsJSTypedArrayMap()) return false; 8475 int offset = (id == kTypedArrayLength) 8476 ? JSTypedArray::kLengthOffset 8477 : (id == kTypedArrayByteLength) 8478 ? JSTypedArray::kByteLengthOffset 8479 : JSTypedArray::kByteOffsetOffset; 8480 HObjectAccess access = 8481 HObjectAccess::ForMapAndOffset(receiver_map, offset); 8482 HValue* object = Pop(); // receiver 8483 HValue* checked_object = Add<HCheckArrayBufferNotNeutered>(object); 8484 HInstruction* result = 8485 New<HLoadNamedField>(object, checked_object, access); 8486 ast_context()->ReturnInstruction(result, ast_id); 8487 return true; 8488 } 8489 default: 8490 return false; 8491 } 8492 } 8493 8494 bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( 8495 Handle<JSFunction> function, Handle<Map> receiver_map, BailoutId ast_id, 8496 int args_count_no_receiver) { 8497 if (!function->shared()->HasBuiltinFunctionId()) return false; 8498 BuiltinFunctionId id = function->shared()->builtin_function_id(); 8499 int argument_count = args_count_no_receiver + 1; // Plus receiver. 8500 8501 if (receiver_map.is_null()) { 8502 HValue* receiver = environment()->ExpressionStackAt(args_count_no_receiver); 8503 if (receiver->IsConstant() && 8504 HConstant::cast(receiver)->handle(isolate())->IsHeapObject()) { 8505 receiver_map = 8506 handle(Handle<HeapObject>::cast( 8507 HConstant::cast(receiver)->handle(isolate()))->map()); 8508 } 8509 } 8510 // Try to inline calls like Math.* as operations in the calling function. 8511 switch (id) { 8512 case kObjectHasOwnProperty: { 8513 // It's not safe to look through the phi for elements if we're compiling 8514 // for osr. 8515 if (top_info()->is_osr()) return false; 8516 if (argument_count != 2) return false; 8517 HValue* key = Top(); 8518 if (!key->IsLoadKeyed()) return false; 8519 HValue* elements = HLoadKeyed::cast(key)->elements(); 8520 if (!elements->IsPhi() || elements->OperandCount() != 1) return false; 8521 if (!elements->OperandAt(0)->IsForInCacheArray()) return false; 8522 HForInCacheArray* cache = HForInCacheArray::cast(elements->OperandAt(0)); 8523 HValue* receiver = environment()->ExpressionStackAt(1); 8524 if (!receiver->IsPhi() || receiver->OperandCount() != 1) return false; 8525 if (cache->enumerable() != receiver->OperandAt(0)) return false; 8526 Drop(3); // key, receiver, function 8527 Add<HCheckMapValue>(receiver, cache->map()); 8528 ast_context()->ReturnValue(graph()->GetConstantTrue()); 8529 return true; 8530 } 8531 case kStringCharCodeAt: 8532 case kStringCharAt: 8533 if (argument_count == 2) { 8534 HValue* index = Pop(); 8535 HValue* string = Pop(); 8536 Drop(1); // Function. 8537 HInstruction* char_code = 8538 BuildStringCharCodeAt(string, index); 8539 if (id == kStringCharCodeAt) { 8540 ast_context()->ReturnInstruction(char_code, ast_id); 8541 return true; 8542 } 8543 AddInstruction(char_code); 8544 HInstruction* result = NewUncasted<HStringCharFromCode>(char_code); 8545 ast_context()->ReturnInstruction(result, ast_id); 8546 return true; 8547 } 8548 break; 8549 case kStringFromCharCode: 8550 if (argument_count == 2) { 8551 HValue* argument = Pop(); 8552 Drop(2); // Receiver and function. 8553 argument = AddUncasted<HForceRepresentation>( 8554 argument, Representation::Integer32()); 8555 argument->SetFlag(HValue::kTruncatingToInt32); 8556 HInstruction* result = NewUncasted<HStringCharFromCode>(argument); 8557 ast_context()->ReturnInstruction(result, ast_id); 8558 return true; 8559 } 8560 break; 8561 case kMathCos: 8562 case kMathExp: 8563 case kMathRound: 8564 case kMathFround: 8565 case kMathFloor: 8566 case kMathAbs: 8567 case kMathSin: 8568 case kMathSqrt: 8569 case kMathLog: 8570 case kMathClz32: 8571 if (argument_count == 2) { 8572 HValue* argument = Pop(); 8573 Drop(2); // Receiver and function. 8574 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); 8575 ast_context()->ReturnInstruction(op, ast_id); 8576 return true; 8577 } 8578 break; 8579 case kMathPow: 8580 if (argument_count == 3) { 8581 HValue* right = Pop(); 8582 HValue* left = Pop(); 8583 Drop(2); // Receiver and function. 8584 HInstruction* result = NULL; 8585 // Use sqrt() if exponent is 0.5 or -0.5. 8586 if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { 8587 double exponent = HConstant::cast(right)->DoubleValue(); 8588 if (exponent == 0.5) { 8589 result = NewUncasted<HUnaryMathOperation>(left, kMathPowHalf); 8590 } else if (exponent == -0.5) { 8591 HValue* one = graph()->GetConstant1(); 8592 HInstruction* sqrt = AddUncasted<HUnaryMathOperation>( 8593 left, kMathPowHalf); 8594 // MathPowHalf doesn't have side effects so there's no need for 8595 // an environment simulation here. 8596 DCHECK(!sqrt->HasObservableSideEffects()); 8597 result = NewUncasted<HDiv>(one, sqrt); 8598 } else if (exponent == 2.0) { 8599 result = NewUncasted<HMul>(left, left); 8600 } 8601 } 8602 8603 if (result == NULL) { 8604 result = NewUncasted<HPower>(left, right); 8605 } 8606 ast_context()->ReturnInstruction(result, ast_id); 8607 return true; 8608 } 8609 break; 8610 case kMathMax: 8611 case kMathMin: 8612 if (argument_count == 3) { 8613 HValue* right = Pop(); 8614 HValue* left = Pop(); 8615 Drop(2); // Receiver and function. 8616 HMathMinMax::Operation op = (id == kMathMin) ? HMathMinMax::kMathMin 8617 : HMathMinMax::kMathMax; 8618 HInstruction* result = NewUncasted<HMathMinMax>(left, right, op); 8619 ast_context()->ReturnInstruction(result, ast_id); 8620 return true; 8621 } 8622 break; 8623 case kMathImul: 8624 if (argument_count == 3) { 8625 HValue* right = Pop(); 8626 HValue* left = Pop(); 8627 Drop(2); // Receiver and function. 8628 HInstruction* result = 8629 HMul::NewImul(isolate(), zone(), context(), left, right); 8630 ast_context()->ReturnInstruction(result, ast_id); 8631 return true; 8632 } 8633 break; 8634 case kArrayPop: { 8635 if (!CanInlineArrayResizeOperation(receiver_map)) return false; 8636 ElementsKind elements_kind = receiver_map->elements_kind(); 8637 8638 Drop(args_count_no_receiver); 8639 HValue* result; 8640 HValue* reduced_length; 8641 HValue* receiver = Pop(); 8642 8643 HValue* checked_object = AddCheckMap(receiver, receiver_map); 8644 HValue* length = 8645 Add<HLoadNamedField>(checked_object, nullptr, 8646 HObjectAccess::ForArrayLength(elements_kind)); 8647 8648 Drop(1); // Function. 8649 8650 { NoObservableSideEffectsScope scope(this); 8651 IfBuilder length_checker(this); 8652 8653 HValue* bounds_check = length_checker.If<HCompareNumericAndBranch>( 8654 length, graph()->GetConstant0(), Token::EQ); 8655 length_checker.Then(); 8656 8657 if (!ast_context()->IsEffect()) Push(graph()->GetConstantUndefined()); 8658 8659 length_checker.Else(); 8660 HValue* elements = AddLoadElements(checked_object); 8661 // Ensure that we aren't popping from a copy-on-write array. 8662 if (IsFastSmiOrObjectElementsKind(elements_kind)) { 8663 elements = BuildCopyElementsOnWrite(checked_object, elements, 8664 elements_kind, length); 8665 } 8666 reduced_length = AddUncasted<HSub>(length, graph()->GetConstant1()); 8667 result = AddElementAccess(elements, reduced_length, nullptr, 8668 bounds_check, nullptr, elements_kind, LOAD); 8669 HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind) 8670 ? graph()->GetConstantHole() 8671 : Add<HConstant>(HConstant::kHoleNaN); 8672 if (IsFastSmiOrObjectElementsKind(elements_kind)) { 8673 elements_kind = FAST_HOLEY_ELEMENTS; 8674 } 8675 AddElementAccess(elements, reduced_length, hole, bounds_check, nullptr, 8676 elements_kind, STORE); 8677 Add<HStoreNamedField>( 8678 checked_object, HObjectAccess::ForArrayLength(elements_kind), 8679 reduced_length, STORE_TO_INITIALIZED_ENTRY); 8680 8681 if (!ast_context()->IsEffect()) Push(result); 8682 8683 length_checker.End(); 8684 } 8685 result = ast_context()->IsEffect() ? graph()->GetConstant0() : Top(); 8686 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); 8687 if (!ast_context()->IsEffect()) Drop(1); 8688 8689 ast_context()->ReturnValue(result); 8690 return true; 8691 } 8692 case kArrayPush: { 8693 if (!CanInlineArrayResizeOperation(receiver_map)) return false; 8694 ElementsKind elements_kind = receiver_map->elements_kind(); 8695 8696 // If there may be elements accessors in the prototype chain, the fast 8697 // inlined version can't be used. 8698 if (receiver_map->DictionaryElementsInPrototypeChainOnly()) return false; 8699 // If there currently can be no elements accessors on the prototype chain, 8700 // it doesn't mean that there won't be any later. Install a full prototype 8701 // chain check to trap element accessors being installed on the prototype 8702 // chain, which would cause elements to go to dictionary mode and result 8703 // in a map change. 8704 Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype())); 8705 BuildCheckPrototypeMaps(prototype, Handle<JSObject>()); 8706 8707 // Protect against adding elements to the Array prototype, which needs to 8708 // route through appropriate bottlenecks. 8709 if (isolate()->IsFastArrayConstructorPrototypeChainIntact() && 8710 !prototype->IsJSArray()) { 8711 return false; 8712 } 8713 8714 const int argc = args_count_no_receiver; 8715 if (argc != 1) return false; 8716 8717 HValue* value_to_push = Pop(); 8718 HValue* array = Pop(); 8719 Drop(1); // Drop function. 8720 8721 HInstruction* new_size = NULL; 8722 HValue* length = NULL; 8723 8724 { 8725 NoObservableSideEffectsScope scope(this); 8726 8727 length = Add<HLoadNamedField>( 8728 array, nullptr, HObjectAccess::ForArrayLength(elements_kind)); 8729 8730 new_size = AddUncasted<HAdd>(length, graph()->GetConstant1()); 8731 8732 bool is_array = receiver_map->instance_type() == JS_ARRAY_TYPE; 8733 HValue* checked_array = Add<HCheckMaps>(array, receiver_map); 8734 BuildUncheckedMonomorphicElementAccess( 8735 checked_array, length, value_to_push, is_array, elements_kind, 8736 STORE, NEVER_RETURN_HOLE, STORE_AND_GROW_NO_TRANSITION); 8737 8738 if (!ast_context()->IsEffect()) Push(new_size); 8739 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); 8740 if (!ast_context()->IsEffect()) Drop(1); 8741 } 8742 8743 ast_context()->ReturnValue(new_size); 8744 return true; 8745 } 8746 case kArrayShift: { 8747 if (!CanInlineArrayResizeOperation(receiver_map)) return false; 8748 ElementsKind kind = receiver_map->elements_kind(); 8749 8750 // If there may be elements accessors in the prototype chain, the fast 8751 // inlined version can't be used. 8752 if (receiver_map->DictionaryElementsInPrototypeChainOnly()) return false; 8753 8754 // If there currently can be no elements accessors on the prototype chain, 8755 // it doesn't mean that there won't be any later. Install a full prototype 8756 // chain check to trap element accessors being installed on the prototype 8757 // chain, which would cause elements to go to dictionary mode and result 8758 // in a map change. 8759 BuildCheckPrototypeMaps( 8760 handle(JSObject::cast(receiver_map->prototype()), isolate()), 8761 Handle<JSObject>::null()); 8762 8763 // Threshold for fast inlined Array.shift(). 8764 HConstant* inline_threshold = Add<HConstant>(static_cast<int32_t>(16)); 8765 8766 Drop(args_count_no_receiver); 8767 HValue* result; 8768 HValue* receiver = Pop(); 8769 HValue* checked_object = AddCheckMap(receiver, receiver_map); 8770 HValue* length = Add<HLoadNamedField>( 8771 receiver, checked_object, HObjectAccess::ForArrayLength(kind)); 8772 8773 Drop(1); // Function. 8774 { 8775 NoObservableSideEffectsScope scope(this); 8776 8777 IfBuilder if_lengthiszero(this); 8778 HValue* lengthiszero = if_lengthiszero.If<HCompareNumericAndBranch>( 8779 length, graph()->GetConstant0(), Token::EQ); 8780 if_lengthiszero.Then(); 8781 { 8782 if (!ast_context()->IsEffect()) Push(graph()->GetConstantUndefined()); 8783 } 8784 if_lengthiszero.Else(); 8785 { 8786 HValue* elements = AddLoadElements(receiver); 8787 8788 // Check if we can use the fast inlined Array.shift(). 8789 IfBuilder if_inline(this); 8790 if_inline.If<HCompareNumericAndBranch>( 8791 length, inline_threshold, Token::LTE); 8792 if (IsFastSmiOrObjectElementsKind(kind)) { 8793 // We cannot handle copy-on-write backing stores here. 8794 if_inline.AndIf<HCompareMap>( 8795 elements, isolate()->factory()->fixed_array_map()); 8796 } 8797 if_inline.Then(); 8798 { 8799 // Remember the result. 8800 if (!ast_context()->IsEffect()) { 8801 Push(AddElementAccess(elements, graph()->GetConstant0(), nullptr, 8802 lengthiszero, nullptr, kind, LOAD)); 8803 } 8804 8805 // Compute the new length. 8806 HValue* new_length = AddUncasted<HSub>( 8807 length, graph()->GetConstant1()); 8808 new_length->ClearFlag(HValue::kCanOverflow); 8809 8810 // Copy the remaining elements. 8811 LoopBuilder loop(this, context(), LoopBuilder::kPostIncrement); 8812 { 8813 HValue* new_key = loop.BeginBody( 8814 graph()->GetConstant0(), new_length, Token::LT); 8815 HValue* key = AddUncasted<HAdd>(new_key, graph()->GetConstant1()); 8816 key->ClearFlag(HValue::kCanOverflow); 8817 ElementsKind copy_kind = 8818 kind == FAST_HOLEY_SMI_ELEMENTS ? FAST_HOLEY_ELEMENTS : kind; 8819 HValue* element = 8820 AddUncasted<HLoadKeyed>(elements, key, lengthiszero, nullptr, 8821 copy_kind, ALLOW_RETURN_HOLE); 8822 HStoreKeyed* store = Add<HStoreKeyed>(elements, new_key, element, 8823 nullptr, copy_kind); 8824 store->SetFlag(HValue::kTruncatingToNumber); 8825 } 8826 loop.EndBody(); 8827 8828 // Put a hole at the end. 8829 HValue* hole = IsFastSmiOrObjectElementsKind(kind) 8830 ? graph()->GetConstantHole() 8831 : Add<HConstant>(HConstant::kHoleNaN); 8832 if (IsFastSmiOrObjectElementsKind(kind)) kind = FAST_HOLEY_ELEMENTS; 8833 Add<HStoreKeyed>(elements, new_length, hole, nullptr, kind, 8834 INITIALIZING_STORE); 8835 8836 // Remember new length. 8837 Add<HStoreNamedField>( 8838 receiver, HObjectAccess::ForArrayLength(kind), 8839 new_length, STORE_TO_INITIALIZED_ENTRY); 8840 } 8841 if_inline.Else(); 8842 { 8843 Add<HPushArguments>(receiver); 8844 result = AddInstruction(NewCallConstantFunction( 8845 function, 1, TailCallMode::kDisallow, TailCallMode::kDisallow)); 8846 if (!ast_context()->IsEffect()) Push(result); 8847 } 8848 if_inline.End(); 8849 } 8850 if_lengthiszero.End(); 8851 } 8852 result = ast_context()->IsEffect() ? graph()->GetConstant0() : Top(); 8853 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); 8854 if (!ast_context()->IsEffect()) Drop(1); 8855 ast_context()->ReturnValue(result); 8856 return true; 8857 } 8858 case kArrayIndexOf: 8859 case kArrayLastIndexOf: { 8860 if (receiver_map.is_null()) return false; 8861 if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false; 8862 if (!receiver_map->prototype()->IsJSObject()) return false; 8863 ElementsKind kind = receiver_map->elements_kind(); 8864 if (!IsFastElementsKind(kind)) return false; 8865 if (argument_count != 2) return false; 8866 if (!receiver_map->is_extensible()) return false; 8867 8868 // If there may be elements accessors in the prototype chain, the fast 8869 // inlined version can't be used. 8870 if (receiver_map->DictionaryElementsInPrototypeChainOnly()) return false; 8871 8872 // If there currently can be no elements accessors on the prototype chain, 8873 // it doesn't mean that there won't be any later. Install a full prototype 8874 // chain check to trap element accessors being installed on the prototype 8875 // chain, which would cause elements to go to dictionary mode and result 8876 // in a map change. 8877 BuildCheckPrototypeMaps( 8878 handle(JSObject::cast(receiver_map->prototype()), isolate()), 8879 Handle<JSObject>::null()); 8880 8881 HValue* search_element = Pop(); 8882 HValue* receiver = Pop(); 8883 Drop(1); // Drop function. 8884 8885 ArrayIndexOfMode mode = (id == kArrayIndexOf) 8886 ? kFirstIndexOf : kLastIndexOf; 8887 HValue* index = BuildArrayIndexOf(receiver, search_element, kind, mode); 8888 8889 if (!ast_context()->IsEffect()) Push(index); 8890 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); 8891 if (!ast_context()->IsEffect()) Drop(1); 8892 ast_context()->ReturnValue(index); 8893 return true; 8894 } 8895 default: 8896 // Not yet supported for inlining. 8897 break; 8898 } 8899 return false; 8900 } 8901 8902 8903 bool HOptimizedGraphBuilder::TryInlineApiFunctionCall(Call* expr, 8904 HValue* receiver) { 8905 if (V8_UNLIKELY(FLAG_runtime_stats)) return false; 8906 Handle<JSFunction> function = expr->target(); 8907 int argc = expr->arguments()->length(); 8908 SmallMapList receiver_maps; 8909 return TryInlineApiCall(function, receiver, &receiver_maps, argc, expr->id(), 8910 kCallApiFunction, expr->tail_call_mode()); 8911 } 8912 8913 8914 bool HOptimizedGraphBuilder::TryInlineApiMethodCall( 8915 Call* expr, 8916 HValue* receiver, 8917 SmallMapList* receiver_maps) { 8918 if (V8_UNLIKELY(FLAG_runtime_stats)) return false; 8919 Handle<JSFunction> function = expr->target(); 8920 int argc = expr->arguments()->length(); 8921 return TryInlineApiCall(function, receiver, receiver_maps, argc, expr->id(), 8922 kCallApiMethod, expr->tail_call_mode()); 8923 } 8924 8925 bool HOptimizedGraphBuilder::TryInlineApiGetter(Handle<Object> function, 8926 Handle<Map> receiver_map, 8927 BailoutId ast_id) { 8928 if (V8_UNLIKELY(FLAG_runtime_stats)) return false; 8929 SmallMapList receiver_maps(1, zone()); 8930 receiver_maps.Add(receiver_map, zone()); 8931 return TryInlineApiCall(function, 8932 NULL, // Receiver is on expression stack. 8933 &receiver_maps, 0, ast_id, kCallApiGetter, 8934 TailCallMode::kDisallow); 8935 } 8936 8937 bool HOptimizedGraphBuilder::TryInlineApiSetter(Handle<Object> function, 8938 Handle<Map> receiver_map, 8939 BailoutId ast_id) { 8940 SmallMapList receiver_maps(1, zone()); 8941 receiver_maps.Add(receiver_map, zone()); 8942 return TryInlineApiCall(function, 8943 NULL, // Receiver is on expression stack. 8944 &receiver_maps, 1, ast_id, kCallApiSetter, 8945 TailCallMode::kDisallow); 8946 } 8947 8948 bool HOptimizedGraphBuilder::TryInlineApiCall( 8949 Handle<Object> function, HValue* receiver, SmallMapList* receiver_maps, 8950 int argc, BailoutId ast_id, ApiCallType call_type, 8951 TailCallMode syntactic_tail_call_mode) { 8952 if (V8_UNLIKELY(FLAG_runtime_stats)) return false; 8953 if (function->IsJSFunction() && 8954 Handle<JSFunction>::cast(function)->context()->native_context() != 8955 top_info()->closure()->context()->native_context()) { 8956 return false; 8957 } 8958 if (argc > CallApiCallbackStub::kArgMax) { 8959 return false; 8960 } 8961 8962 CallOptimization optimization(function); 8963 if (!optimization.is_simple_api_call()) return false; 8964 Handle<Map> holder_map; 8965 for (int i = 0; i < receiver_maps->length(); ++i) { 8966 auto map = receiver_maps->at(i); 8967 // Don't inline calls to receivers requiring accesschecks. 8968 if (map->is_access_check_needed()) return false; 8969 } 8970 if (call_type == kCallApiFunction) { 8971 // Cannot embed a direct reference to the global proxy map 8972 // as it maybe dropped on deserialization. 8973 CHECK(!isolate()->serializer_enabled()); 8974 DCHECK(function->IsJSFunction()); 8975 DCHECK_EQ(0, receiver_maps->length()); 8976 receiver_maps->Add( 8977 handle(Handle<JSFunction>::cast(function)->global_proxy()->map()), 8978 zone()); 8979 } 8980 CallOptimization::HolderLookup holder_lookup = 8981 CallOptimization::kHolderNotFound; 8982 Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType( 8983 receiver_maps->first(), &holder_lookup); 8984 if (holder_lookup == CallOptimization::kHolderNotFound) return false; 8985 8986 if (FLAG_trace_inlining) { 8987 PrintF("Inlining api function "); 8988 function->ShortPrint(); 8989 PrintF("\n"); 8990 } 8991 8992 bool is_function = false; 8993 bool is_store = false; 8994 switch (call_type) { 8995 case kCallApiFunction: 8996 case kCallApiMethod: 8997 // Need to check that none of the receiver maps could have changed. 8998 Add<HCheckMaps>(receiver, receiver_maps); 8999 // Need to ensure the chain between receiver and api_holder is intact. 9000 if (holder_lookup == CallOptimization::kHolderFound) { 9001 AddCheckPrototypeMaps(api_holder, receiver_maps->first()); 9002 } else { 9003 DCHECK_EQ(holder_lookup, CallOptimization::kHolderIsReceiver); 9004 } 9005 // Includes receiver. 9006 PushArgumentsFromEnvironment(argc + 1); 9007 is_function = true; 9008 break; 9009 case kCallApiGetter: 9010 // Receiver and prototype chain cannot have changed. 9011 DCHECK_EQ(0, argc); 9012 DCHECK_NULL(receiver); 9013 // Receiver is on expression stack. 9014 receiver = Pop(); 9015 Add<HPushArguments>(receiver); 9016 break; 9017 case kCallApiSetter: 9018 { 9019 is_store = true; 9020 // Receiver and prototype chain cannot have changed. 9021 DCHECK_EQ(1, argc); 9022 DCHECK_NULL(receiver); 9023 // Receiver and value are on expression stack. 9024 HValue* value = Pop(); 9025 receiver = Pop(); 9026 Add<HPushArguments>(receiver, value); 9027 break; 9028 } 9029 } 9030 9031 HValue* holder = NULL; 9032 switch (holder_lookup) { 9033 case CallOptimization::kHolderFound: 9034 holder = Add<HConstant>(api_holder); 9035 break; 9036 case CallOptimization::kHolderIsReceiver: 9037 holder = receiver; 9038 break; 9039 case CallOptimization::kHolderNotFound: 9040 UNREACHABLE(); 9041 break; 9042 } 9043 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); 9044 Handle<Object> call_data_obj(api_call_info->data(), isolate()); 9045 bool call_data_undefined = call_data_obj->IsUndefined(isolate()); 9046 HValue* call_data = Add<HConstant>(call_data_obj); 9047 ApiFunction fun(v8::ToCData<Address>(api_call_info->callback())); 9048 ExternalReference ref = ExternalReference(&fun, 9049 ExternalReference::DIRECT_API_CALL, 9050 isolate()); 9051 HValue* api_function_address = Add<HConstant>(ExternalReference(ref)); 9052 9053 HValue* op_vals[] = {Add<HConstant>(function), call_data, holder, 9054 api_function_address}; 9055 9056 HInstruction* call = nullptr; 9057 CHECK(argc <= CallApiCallbackStub::kArgMax); 9058 if (!is_function) { 9059 CallApiCallbackStub stub(isolate(), is_store, call_data_undefined, 9060 !optimization.is_constant_call()); 9061 Handle<Code> code = stub.GetCode(); 9062 HConstant* code_value = Add<HConstant>(code); 9063 call = New<HCallWithDescriptor>( 9064 code_value, argc + 1, stub.GetCallInterfaceDescriptor(), 9065 Vector<HValue*>(op_vals, arraysize(op_vals)), syntactic_tail_call_mode); 9066 } else { 9067 CallApiCallbackStub stub(isolate(), argc, call_data_undefined, false); 9068 Handle<Code> code = stub.GetCode(); 9069 HConstant* code_value = Add<HConstant>(code); 9070 call = New<HCallWithDescriptor>( 9071 code_value, argc + 1, stub.GetCallInterfaceDescriptor(), 9072 Vector<HValue*>(op_vals, arraysize(op_vals)), syntactic_tail_call_mode); 9073 Drop(1); // Drop function. 9074 } 9075 9076 ast_context()->ReturnInstruction(call, ast_id); 9077 return true; 9078 } 9079 9080 9081 void HOptimizedGraphBuilder::HandleIndirectCall(Call* expr, HValue* function, 9082 int arguments_count) { 9083 Handle<JSFunction> known_function; 9084 int args_count_no_receiver = arguments_count - 1; 9085 if (function->IsConstant() && 9086 HConstant::cast(function)->handle(isolate())->IsJSFunction()) { 9087 known_function = 9088 Handle<JSFunction>::cast(HConstant::cast(function)->handle(isolate())); 9089 if (TryInlineBuiltinMethodCall(known_function, Handle<Map>(), expr->id(), 9090 args_count_no_receiver)) { 9091 if (FLAG_trace_inlining) { 9092 PrintF("Inlining builtin "); 9093 known_function->ShortPrint(); 9094 PrintF("\n"); 9095 } 9096 return; 9097 } 9098 9099 if (TryInlineIndirectCall(known_function, expr, args_count_no_receiver)) { 9100 return; 9101 } 9102 } 9103 9104 TailCallMode syntactic_tail_call_mode = expr->tail_call_mode(); 9105 TailCallMode tail_call_mode = 9106 function_state()->ComputeTailCallMode(syntactic_tail_call_mode); 9107 9108 PushArgumentsFromEnvironment(arguments_count); 9109 HInvokeFunction* call = 9110 New<HInvokeFunction>(function, known_function, arguments_count, 9111 syntactic_tail_call_mode, tail_call_mode); 9112 Drop(1); // Function 9113 ast_context()->ReturnInstruction(call, expr->id()); 9114 } 9115 9116 9117 bool HOptimizedGraphBuilder::TryIndirectCall(Call* expr) { 9118 DCHECK(expr->expression()->IsProperty()); 9119 9120 if (!expr->IsMonomorphic()) { 9121 return false; 9122 } 9123 Handle<Map> function_map = expr->GetReceiverTypes()->first(); 9124 if (function_map->instance_type() != JS_FUNCTION_TYPE || 9125 !expr->target()->shared()->HasBuiltinFunctionId()) { 9126 return false; 9127 } 9128 9129 switch (expr->target()->shared()->builtin_function_id()) { 9130 case kFunctionCall: { 9131 if (expr->arguments()->length() == 0) return false; 9132 BuildFunctionCall(expr); 9133 return true; 9134 } 9135 case kFunctionApply: { 9136 // For .apply, only the pattern f.apply(receiver, arguments) 9137 // is supported. 9138 if (!CanBeFunctionApplyArguments(expr)) return false; 9139 9140 BuildFunctionApply(expr); 9141 return true; 9142 } 9143 default: { return false; } 9144 } 9145 UNREACHABLE(); 9146 } 9147 9148 9149 // f.apply(...) 9150 void HOptimizedGraphBuilder::BuildFunctionApply(Call* expr) { 9151 ZoneList<Expression*>* args = expr->arguments(); 9152 CHECK_ALIVE(VisitForValue(args->at(0))); 9153 HValue* receiver = Pop(); // receiver 9154 HValue* function = Pop(); // f 9155 Drop(1); // apply 9156 9157 // Make sure the arguments object is live. 9158 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); 9159 LookupAndMakeLive(arg_two->var()); 9160 9161 Handle<Map> function_map = expr->GetReceiverTypes()->first(); 9162 HValue* checked_function = AddCheckMap(function, function_map); 9163 9164 if (function_state()->outer() == NULL) { 9165 TailCallMode syntactic_tail_call_mode = expr->tail_call_mode(); 9166 TailCallMode tail_call_mode = 9167 function_state()->ComputeTailCallMode(syntactic_tail_call_mode); 9168 9169 HInstruction* elements = Add<HArgumentsElements>(false); 9170 HInstruction* length = Add<HArgumentsLength>(elements); 9171 HValue* wrapped_receiver = BuildWrapReceiver(receiver, checked_function); 9172 HInstruction* result = New<HApplyArguments>( 9173 function, wrapped_receiver, length, elements, tail_call_mode); 9174 ast_context()->ReturnInstruction(result, expr->id()); 9175 } else { 9176 // We are inside inlined function and we know exactly what is inside 9177 // arguments object. But we need to be able to materialize at deopt. 9178 DCHECK_EQ(environment()->arguments_environment()->parameter_count(), 9179 function_state()->entry()->arguments_object()->arguments_count()); 9180 HArgumentsObject* args = function_state()->entry()->arguments_object(); 9181 const ZoneList<HValue*>* arguments_values = args->arguments_values(); 9182 int arguments_count = arguments_values->length(); 9183 Push(function); 9184 Push(BuildWrapReceiver(receiver, checked_function)); 9185 for (int i = 1; i < arguments_count; i++) { 9186 Push(arguments_values->at(i)); 9187 } 9188 HandleIndirectCall(expr, function, arguments_count); 9189 } 9190 } 9191 9192 9193 // f.call(...) 9194 void HOptimizedGraphBuilder::BuildFunctionCall(Call* expr) { 9195 HValue* function = Top(); // f 9196 Handle<Map> function_map = expr->GetReceiverTypes()->first(); 9197 HValue* checked_function = AddCheckMap(function, function_map); 9198 9199 // f and call are on the stack in the unoptimized code 9200 // during evaluation of the arguments. 9201 CHECK_ALIVE(VisitExpressions(expr->arguments())); 9202 9203 int args_length = expr->arguments()->length(); 9204 int receiver_index = args_length - 1; 9205 // Patch the receiver. 9206 HValue* receiver = BuildWrapReceiver( 9207 environment()->ExpressionStackAt(receiver_index), checked_function); 9208 environment()->SetExpressionStackAt(receiver_index, receiver); 9209 9210 // Call must not be on the stack from now on. 9211 int call_index = args_length + 1; 9212 environment()->RemoveExpressionStackAt(call_index); 9213 9214 HandleIndirectCall(expr, function, args_length); 9215 } 9216 9217 9218 HValue* HOptimizedGraphBuilder::ImplicitReceiverFor(HValue* function, 9219 Handle<JSFunction> target) { 9220 SharedFunctionInfo* shared = target->shared(); 9221 if (is_sloppy(shared->language_mode()) && !shared->native()) { 9222 // Cannot embed a direct reference to the global proxy 9223 // as is it dropped on deserialization. 9224 CHECK(!isolate()->serializer_enabled()); 9225 Handle<JSObject> global_proxy(target->context()->global_proxy()); 9226 return Add<HConstant>(global_proxy); 9227 } 9228 return graph()->GetConstantUndefined(); 9229 } 9230 9231 9232 HValue* HOptimizedGraphBuilder::BuildArrayIndexOf(HValue* receiver, 9233 HValue* search_element, 9234 ElementsKind kind, 9235 ArrayIndexOfMode mode) { 9236 DCHECK(IsFastElementsKind(kind)); 9237 9238 NoObservableSideEffectsScope no_effects(this); 9239 9240 HValue* elements = AddLoadElements(receiver); 9241 HValue* length = AddLoadArrayLength(receiver, kind); 9242 9243 HValue* initial; 9244 HValue* terminating; 9245 Token::Value token; 9246 LoopBuilder::Direction direction; 9247 if (mode == kFirstIndexOf) { 9248 initial = graph()->GetConstant0(); 9249 terminating = length; 9250 token = Token::LT; 9251 direction = LoopBuilder::kPostIncrement; 9252 } else { 9253 DCHECK_EQ(kLastIndexOf, mode); 9254 initial = length; 9255 terminating = graph()->GetConstant0(); 9256 token = Token::GT; 9257 direction = LoopBuilder::kPreDecrement; 9258 } 9259 9260 Push(graph()->GetConstantMinus1()); 9261 if (IsFastDoubleElementsKind(kind) || IsFastSmiElementsKind(kind)) { 9262 // Make sure that we can actually compare numbers correctly below, see 9263 // https://code.google.com/p/chromium/issues/detail?id=407946 for details. 9264 search_element = AddUncasted<HForceRepresentation>( 9265 search_element, IsFastSmiElementsKind(kind) ? Representation::Smi() 9266 : Representation::Double()); 9267 9268 LoopBuilder loop(this, context(), direction); 9269 { 9270 HValue* index = loop.BeginBody(initial, terminating, token); 9271 HValue* element = AddUncasted<HLoadKeyed>( 9272 elements, index, nullptr, nullptr, kind, ALLOW_RETURN_HOLE); 9273 IfBuilder if_issame(this); 9274 if_issame.If<HCompareNumericAndBranch>(element, search_element, 9275 Token::EQ_STRICT); 9276 if_issame.Then(); 9277 { 9278 Drop(1); 9279 Push(index); 9280 loop.Break(); 9281 } 9282 if_issame.End(); 9283 } 9284 loop.EndBody(); 9285 } else { 9286 IfBuilder if_isstring(this); 9287 if_isstring.If<HIsStringAndBranch>(search_element); 9288 if_isstring.Then(); 9289 { 9290 LoopBuilder loop(this, context(), direction); 9291 { 9292 HValue* index = loop.BeginBody(initial, terminating, token); 9293 HValue* element = AddUncasted<HLoadKeyed>( 9294 elements, index, nullptr, nullptr, kind, ALLOW_RETURN_HOLE); 9295 IfBuilder if_issame(this); 9296 if_issame.If<HIsStringAndBranch>(element); 9297 if_issame.AndIf<HStringCompareAndBranch>( 9298 element, search_element, Token::EQ_STRICT); 9299 if_issame.Then(); 9300 { 9301 Drop(1); 9302 Push(index); 9303 loop.Break(); 9304 } 9305 if_issame.End(); 9306 } 9307 loop.EndBody(); 9308 } 9309 if_isstring.Else(); 9310 { 9311 IfBuilder if_isnumber(this); 9312 if_isnumber.If<HIsSmiAndBranch>(search_element); 9313 if_isnumber.OrIf<HCompareMap>( 9314 search_element, isolate()->factory()->heap_number_map()); 9315 if_isnumber.Then(); 9316 { 9317 HValue* search_number = 9318 AddUncasted<HForceRepresentation>(search_element, 9319 Representation::Double()); 9320 LoopBuilder loop(this, context(), direction); 9321 { 9322 HValue* index = loop.BeginBody(initial, terminating, token); 9323 HValue* element = AddUncasted<HLoadKeyed>( 9324 elements, index, nullptr, nullptr, kind, ALLOW_RETURN_HOLE); 9325 9326 IfBuilder if_element_isnumber(this); 9327 if_element_isnumber.If<HIsSmiAndBranch>(element); 9328 if_element_isnumber.OrIf<HCompareMap>( 9329 element, isolate()->factory()->heap_number_map()); 9330 if_element_isnumber.Then(); 9331 { 9332 HValue* number = 9333 AddUncasted<HForceRepresentation>(element, 9334 Representation::Double()); 9335 IfBuilder if_issame(this); 9336 if_issame.If<HCompareNumericAndBranch>( 9337 number, search_number, Token::EQ_STRICT); 9338 if_issame.Then(); 9339 { 9340 Drop(1); 9341 Push(index); 9342 loop.Break(); 9343 } 9344 if_issame.End(); 9345 } 9346 if_element_isnumber.End(); 9347 } 9348 loop.EndBody(); 9349 } 9350 if_isnumber.Else(); 9351 { 9352 LoopBuilder loop(this, context(), direction); 9353 { 9354 HValue* index = loop.BeginBody(initial, terminating, token); 9355 HValue* element = AddUncasted<HLoadKeyed>( 9356 elements, index, nullptr, nullptr, kind, ALLOW_RETURN_HOLE); 9357 IfBuilder if_issame(this); 9358 if_issame.If<HCompareObjectEqAndBranch>( 9359 element, search_element); 9360 if_issame.Then(); 9361 { 9362 Drop(1); 9363 Push(index); 9364 loop.Break(); 9365 } 9366 if_issame.End(); 9367 } 9368 loop.EndBody(); 9369 } 9370 if_isnumber.End(); 9371 } 9372 if_isstring.End(); 9373 } 9374 9375 return Pop(); 9376 } 9377 9378 template <class T> 9379 bool HOptimizedGraphBuilder::TryHandleArrayCall(T* expr, HValue* function) { 9380 if (!array_function().is_identical_to(expr->target())) { 9381 return false; 9382 } 9383 9384 Handle<AllocationSite> site = expr->allocation_site(); 9385 if (site.is_null()) return false; 9386 9387 Add<HCheckValue>(function, array_function()); 9388 9389 int arguments_count = expr->arguments()->length(); 9390 if (TryInlineArrayCall(expr, arguments_count, site)) return true; 9391 9392 HInstruction* call = PreProcessCall(New<HCallNewArray>( 9393 function, arguments_count + 1, site->GetElementsKind(), site)); 9394 if (expr->IsCall()) Drop(1); 9395 ast_context()->ReturnInstruction(call, expr->id()); 9396 9397 return true; 9398 } 9399 9400 9401 bool HOptimizedGraphBuilder::CanBeFunctionApplyArguments(Call* expr) { 9402 ZoneList<Expression*>* args = expr->arguments(); 9403 if (args->length() != 2) return false; 9404 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); 9405 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; 9406 HValue* arg_two_value = environment()->Lookup(arg_two->var()); 9407 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; 9408 DCHECK_NOT_NULL(current_info()->scope()->arguments()); 9409 return true; 9410 } 9411 9412 9413 void HOptimizedGraphBuilder::VisitCall(Call* expr) { 9414 DCHECK(!HasStackOverflow()); 9415 DCHECK(current_block() != NULL); 9416 DCHECK(current_block()->HasPredecessor()); 9417 if (!is_tracking_positions()) SetSourcePosition(expr->position()); 9418 Expression* callee = expr->expression(); 9419 int argument_count = expr->arguments()->length() + 1; // Plus receiver. 9420 HInstruction* call = NULL; 9421 9422 TailCallMode syntactic_tail_call_mode = expr->tail_call_mode(); 9423 TailCallMode tail_call_mode = 9424 function_state()->ComputeTailCallMode(syntactic_tail_call_mode); 9425 9426 Property* prop = callee->AsProperty(); 9427 if (prop != NULL) { 9428 CHECK_ALIVE(VisitForValue(prop->obj())); 9429 HValue* receiver = Top(); 9430 9431 SmallMapList* maps; 9432 ComputeReceiverTypes(expr, receiver, &maps, this); 9433 9434 if (prop->key()->IsPropertyName() && maps->length() > 0) { 9435 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); 9436 PropertyAccessInfo info(this, LOAD, maps->first(), name); 9437 if (!info.CanAccessAsMonomorphic(maps)) { 9438 HandlePolymorphicCallNamed(expr, receiver, maps, name); 9439 return; 9440 } 9441 } 9442 HValue* key = NULL; 9443 if (!prop->key()->IsPropertyName()) { 9444 CHECK_ALIVE(VisitForValue(prop->key())); 9445 key = Pop(); 9446 } 9447 9448 CHECK_ALIVE(PushLoad(prop, receiver, key)); 9449 HValue* function = Pop(); 9450 9451 if (function->IsConstant() && 9452 HConstant::cast(function)->handle(isolate())->IsJSFunction()) { 9453 // Push the function under the receiver. 9454 environment()->SetExpressionStackAt(0, function); 9455 Push(receiver); 9456 9457 Handle<JSFunction> known_function = Handle<JSFunction>::cast( 9458 HConstant::cast(function)->handle(isolate())); 9459 expr->set_target(known_function); 9460 9461 if (TryIndirectCall(expr)) return; 9462 CHECK_ALIVE(VisitExpressions(expr->arguments())); 9463 9464 Handle<Map> map = maps->length() == 1 ? maps->first() : Handle<Map>(); 9465 if (TryInlineBuiltinMethodCall(known_function, map, expr->id(), 9466 expr->arguments()->length())) { 9467 if (FLAG_trace_inlining) { 9468 PrintF("Inlining builtin "); 9469 known_function->ShortPrint(); 9470 PrintF("\n"); 9471 } 9472 return; 9473 } 9474 if (TryInlineApiMethodCall(expr, receiver, maps)) return; 9475 9476 // Wrap the receiver if necessary. 9477 if (NeedsWrapping(maps->first(), known_function)) { 9478 // Since HWrapReceiver currently cannot actually wrap numbers and 9479 // strings, use the regular call builtin for method calls to wrap 9480 // the receiver. 9481 // TODO(verwaest): Support creation of value wrappers directly in 9482 // HWrapReceiver. 9483 call = NewCallFunction( 9484 function, argument_count, syntactic_tail_call_mode, 9485 ConvertReceiverMode::kNotNullOrUndefined, tail_call_mode); 9486 } else if (TryInlineCall(expr)) { 9487 return; 9488 } else { 9489 call = 9490 NewCallConstantFunction(known_function, argument_count, 9491 syntactic_tail_call_mode, tail_call_mode); 9492 } 9493 9494 } else { 9495 ArgumentsAllowedFlag arguments_flag = ARGUMENTS_NOT_ALLOWED; 9496 if (CanBeFunctionApplyArguments(expr) && expr->is_uninitialized()) { 9497 // We have to use EAGER deoptimization here because Deoptimizer::SOFT 9498 // gets ignored by the always-opt flag, which leads to incorrect code. 9499 Add<HDeoptimize>( 9500 DeoptimizeReason::kInsufficientTypeFeedbackForCallWithArguments, 9501 Deoptimizer::EAGER); 9502 arguments_flag = ARGUMENTS_FAKED; 9503 } 9504 9505 // Push the function under the receiver. 9506 environment()->SetExpressionStackAt(0, function); 9507 Push(receiver); 9508 9509 CHECK_ALIVE(VisitExpressions(expr->arguments(), arguments_flag)); 9510 call = NewCallFunction(function, argument_count, syntactic_tail_call_mode, 9511 ConvertReceiverMode::kNotNullOrUndefined, 9512 tail_call_mode); 9513 } 9514 PushArgumentsFromEnvironment(argument_count); 9515 9516 } else { 9517 if (expr->is_possibly_eval()) { 9518 return Bailout(kPossibleDirectCallToEval); 9519 } 9520 9521 // The function is on the stack in the unoptimized code during 9522 // evaluation of the arguments. 9523 CHECK_ALIVE(VisitForValue(expr->expression())); 9524 HValue* function = Top(); 9525 if (function->IsConstant() && 9526 HConstant::cast(function)->handle(isolate())->IsJSFunction()) { 9527 Handle<Object> constant = HConstant::cast(function)->handle(isolate()); 9528 Handle<JSFunction> target = Handle<JSFunction>::cast(constant); 9529 expr->SetKnownGlobalTarget(target); 9530 } 9531 9532 // Placeholder for the receiver. 9533 Push(graph()->GetConstantUndefined()); 9534 CHECK_ALIVE(VisitExpressions(expr->arguments())); 9535 9536 if (expr->IsMonomorphic() && 9537 !IsClassConstructor(expr->target()->shared()->kind())) { 9538 Add<HCheckValue>(function, expr->target()); 9539 9540 // Patch the global object on the stack by the expected receiver. 9541 HValue* receiver = ImplicitReceiverFor(function, expr->target()); 9542 const int receiver_index = argument_count - 1; 9543 environment()->SetExpressionStackAt(receiver_index, receiver); 9544 9545 if (TryInlineBuiltinFunctionCall(expr)) { 9546 if (FLAG_trace_inlining) { 9547 PrintF("Inlining builtin "); 9548 expr->target()->ShortPrint(); 9549 PrintF("\n"); 9550 } 9551 return; 9552 } 9553 if (TryInlineApiFunctionCall(expr, receiver)) return; 9554 if (TryHandleArrayCall(expr, function)) return; 9555 if (TryInlineCall(expr)) return; 9556 9557 PushArgumentsFromEnvironment(argument_count); 9558 call = NewCallConstantFunction(expr->target(), argument_count, 9559 syntactic_tail_call_mode, tail_call_mode); 9560 } else { 9561 PushArgumentsFromEnvironment(argument_count); 9562 if (expr->is_uninitialized()) { 9563 // We've never seen this call before, so let's have Crankshaft learn 9564 // through the type vector. 9565 call = NewCallFunctionViaIC(function, argument_count, 9566 syntactic_tail_call_mode, 9567 ConvertReceiverMode::kNullOrUndefined, 9568 tail_call_mode, expr->CallFeedbackICSlot()); 9569 } else { 9570 call = NewCallFunction( 9571 function, argument_count, syntactic_tail_call_mode, 9572 ConvertReceiverMode::kNullOrUndefined, tail_call_mode); 9573 } 9574 } 9575 } 9576 9577 Drop(1); // Drop the function. 9578 return ast_context()->ReturnInstruction(call, expr->id()); 9579 } 9580 9581 bool HOptimizedGraphBuilder::TryInlineArrayCall(Expression* expression, 9582 int argument_count, 9583 Handle<AllocationSite> site) { 9584 Handle<JSFunction> caller = current_info()->closure(); 9585 Handle<JSFunction> target = array_function(); 9586 9587 if (!site->CanInlineCall()) { 9588 TraceInline(target, caller, "AllocationSite requested no inlining."); 9589 return false; 9590 } 9591 9592 if (argument_count > 1) { 9593 TraceInline(target, caller, "Too many arguments to inline."); 9594 return false; 9595 } 9596 9597 int array_length = 0; 9598 // Do not inline if the constant length argument is not a smi or outside the 9599 // valid range for unrolled loop initialization. 9600 if (argument_count == 1) { 9601 HValue* argument = Top(); 9602 if (!argument->IsConstant()) { 9603 TraceInline(target, caller, 9604 "Dont inline [new] Array(n) where n isn't constant."); 9605 return false; 9606 } 9607 9608 HConstant* constant_argument = HConstant::cast(argument); 9609 if (!constant_argument->HasSmiValue()) { 9610 TraceInline(target, caller, 9611 "Constant length outside of valid inlining range."); 9612 return false; 9613 } 9614 array_length = constant_argument->Integer32Value(); 9615 if (array_length < 0 || array_length > kElementLoopUnrollThreshold) { 9616 TraceInline(target, caller, 9617 "Constant length outside of valid inlining range."); 9618 return false; 9619 } 9620 } 9621 9622 TraceInline(target, caller, NULL); 9623 9624 NoObservableSideEffectsScope no_effects(this); 9625 9626 // Register on the site for deoptimization if the transition feedback changes. 9627 top_info()->dependencies()->AssumeTransitionStable(site); 9628 9629 // Build the array. 9630 ElementsKind kind = site->GetElementsKind(); 9631 HValue* capacity; 9632 HValue* length; 9633 if (array_length == 0) { 9634 STATIC_ASSERT(0 < JSArray::kPreallocatedArrayElements); 9635 const int initial_capacity = JSArray::kPreallocatedArrayElements; 9636 capacity = Add<HConstant>(initial_capacity); 9637 length = graph()->GetConstant0(); 9638 } else { 9639 length = Top(); 9640 capacity = length; 9641 kind = GetHoleyElementsKind(kind); 9642 } 9643 9644 // These HForceRepresentations are because we store these as fields in the 9645 // objects we construct, and an int32-to-smi HChange could deopt. Accept 9646 // the deopt possibility now, before allocation occurs. 9647 length = AddUncasted<HForceRepresentation>(length, Representation::Smi()); 9648 capacity = AddUncasted<HForceRepresentation>(capacity, Representation::Smi()); 9649 9650 // Generate size calculation code here in order to make it dominate 9651 // the JSArray allocation. 9652 HValue* elements_size = BuildCalculateElementsSize(kind, capacity); 9653 9654 // Bail out for large objects. 9655 HValue* max_size = Add<HConstant>(kMaxRegularHeapObjectSize); 9656 Add<HBoundsCheck>(elements_size, max_size); 9657 9658 // Allocate (dealing with failure appropriately). 9659 AllocationSiteMode mode = DONT_TRACK_ALLOCATION_SITE; 9660 HAllocate* new_object = AllocateJSArrayObject(mode); 9661 9662 // Fill in the fields: map, properties, length. 9663 Handle<Map> map_constant(isolate()->get_initial_js_array_map(kind)); 9664 HValue* map = Add<HConstant>(map_constant); 9665 9666 BuildJSArrayHeader(new_object, map, 9667 nullptr, // set elements to empty fixed array 9668 mode, kind, nullptr, length); 9669 9670 // Allocate and initialize the elements. 9671 HAllocate* elements = BuildAllocateElements(kind, elements_size); 9672 BuildInitializeElementsHeader(elements, kind, capacity); 9673 BuildFillElementsWithHole(elements, kind, graph()->GetConstant0(), capacity); 9674 9675 // Set the elements. 9676 Add<HStoreNamedField>(new_object, HObjectAccess::ForElementsPointer(), 9677 elements); 9678 9679 int args_to_drop = argument_count + (expression->IsCall() ? 2 : 1); 9680 Drop(args_to_drop); 9681 ast_context()->ReturnValue(new_object); 9682 return true; 9683 } 9684 9685 9686 // Checks whether allocation using the given constructor can be inlined. 9687 static bool IsAllocationInlineable(Handle<JSFunction> constructor) { 9688 return constructor->has_initial_map() && 9689 !IsSubclassConstructor(constructor->shared()->kind()) && 9690 constructor->initial_map()->instance_type() == JS_OBJECT_TYPE && 9691 constructor->initial_map()->instance_size() < 9692 HAllocate::kMaxInlineSize; 9693 } 9694 9695 void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { 9696 DCHECK(!HasStackOverflow()); 9697 DCHECK(current_block() != NULL); 9698 DCHECK(current_block()->HasPredecessor()); 9699 if (!is_tracking_positions()) SetSourcePosition(expr->position()); 9700 int argument_count = expr->arguments()->length() + 1; // Plus constructor. 9701 Factory* factory = isolate()->factory(); 9702 9703 // The constructor function is on the stack in the unoptimized code 9704 // during evaluation of the arguments. 9705 CHECK_ALIVE(VisitForValue(expr->expression())); 9706 HValue* function = Top(); 9707 CHECK_ALIVE(VisitExpressions(expr->arguments())); 9708 9709 if (function->IsConstant() && 9710 HConstant::cast(function)->handle(isolate())->IsJSFunction()) { 9711 Handle<Object> constant = HConstant::cast(function)->handle(isolate()); 9712 expr->SetKnownGlobalTarget(Handle<JSFunction>::cast(constant)); 9713 } 9714 9715 if (FLAG_inline_construct && 9716 expr->IsMonomorphic() && 9717 IsAllocationInlineable(expr->target())) { 9718 Handle<JSFunction> constructor = expr->target(); 9719 DCHECK( 9720 constructor->shared()->construct_stub() == 9721 isolate()->builtins()->builtin(Builtins::kJSConstructStubGeneric) || 9722 constructor->shared()->construct_stub() == 9723 isolate()->builtins()->builtin(Builtins::kJSConstructStubApi)); 9724 HValue* check = Add<HCheckValue>(function, constructor); 9725 9726 // Force completion of inobject slack tracking before generating 9727 // allocation code to finalize instance size. 9728 constructor->CompleteInobjectSlackTrackingIfActive(); 9729 9730 // Calculate instance size from initial map of constructor. 9731 DCHECK(constructor->has_initial_map()); 9732 Handle<Map> initial_map(constructor->initial_map()); 9733 int instance_size = initial_map->instance_size(); 9734 9735 // Allocate an instance of the implicit receiver object. 9736 HValue* size_in_bytes = Add<HConstant>(instance_size); 9737 HAllocationMode allocation_mode; 9738 HAllocate* receiver = BuildAllocate( 9739 size_in_bytes, HType::JSObject(), JS_OBJECT_TYPE, allocation_mode); 9740 receiver->set_known_initial_map(initial_map); 9741 9742 // Initialize map and fields of the newly allocated object. 9743 { NoObservableSideEffectsScope no_effects(this); 9744 DCHECK(initial_map->instance_type() == JS_OBJECT_TYPE); 9745 Add<HStoreNamedField>(receiver, 9746 HObjectAccess::ForMapAndOffset(initial_map, JSObject::kMapOffset), 9747 Add<HConstant>(initial_map)); 9748 HValue* empty_fixed_array = Add<HConstant>(factory->empty_fixed_array()); 9749 Add<HStoreNamedField>(receiver, 9750 HObjectAccess::ForMapAndOffset(initial_map, 9751 JSObject::kPropertiesOffset), 9752 empty_fixed_array); 9753 Add<HStoreNamedField>(receiver, 9754 HObjectAccess::ForMapAndOffset(initial_map, 9755 JSObject::kElementsOffset), 9756 empty_fixed_array); 9757 BuildInitializeInobjectProperties(receiver, initial_map); 9758 } 9759 9760 // Replace the constructor function with a newly allocated receiver using 9761 // the index of the receiver from the top of the expression stack. 9762 const int receiver_index = argument_count - 1; 9763 DCHECK(environment()->ExpressionStackAt(receiver_index) == function); 9764 environment()->SetExpressionStackAt(receiver_index, receiver); 9765 9766 if (TryInlineConstruct(expr, receiver)) { 9767 // Inlining worked, add a dependency on the initial map to make sure that 9768 // this code is deoptimized whenever the initial map of the constructor 9769 // changes. 9770 top_info()->dependencies()->AssumeInitialMapCantChange(initial_map); 9771 return; 9772 } 9773 9774 // TODO(mstarzinger): For now we remove the previous HAllocate and all 9775 // corresponding instructions and instead add HPushArguments for the 9776 // arguments in case inlining failed. What we actually should do is for 9777 // inlining to try to build a subgraph without mutating the parent graph. 9778 HInstruction* instr = current_block()->last(); 9779 do { 9780 HInstruction* prev_instr = instr->previous(); 9781 instr->DeleteAndReplaceWith(NULL); 9782 instr = prev_instr; 9783 } while (instr != check); 9784 environment()->SetExpressionStackAt(receiver_index, function); 9785 } else { 9786 // The constructor function is both an operand to the instruction and an 9787 // argument to the construct call. 9788 if (TryHandleArrayCall(expr, function)) return; 9789 } 9790 9791 HValue* arity = Add<HConstant>(argument_count - 1); 9792 HValue* op_vals[] = {function, function, arity}; 9793 Callable callable = CodeFactory::Construct(isolate()); 9794 HConstant* stub = Add<HConstant>(callable.code()); 9795 PushArgumentsFromEnvironment(argument_count); 9796 HInstruction* construct = New<HCallWithDescriptor>( 9797 stub, argument_count, callable.descriptor(), ArrayVector(op_vals)); 9798 return ast_context()->ReturnInstruction(construct, expr->id()); 9799 } 9800 9801 9802 void HOptimizedGraphBuilder::BuildInitializeInobjectProperties( 9803 HValue* receiver, Handle<Map> initial_map) { 9804 if (initial_map->GetInObjectProperties() != 0) { 9805 HConstant* undefined = graph()->GetConstantUndefined(); 9806 for (int i = 0; i < initial_map->GetInObjectProperties(); i++) { 9807 int property_offset = initial_map->GetInObjectPropertyOffset(i); 9808 Add<HStoreNamedField>(receiver, HObjectAccess::ForMapAndOffset( 9809 initial_map, property_offset), 9810 undefined); 9811 } 9812 } 9813 } 9814 9815 9816 HValue* HGraphBuilder::BuildAllocateEmptyArrayBuffer(HValue* byte_length) { 9817 // We HForceRepresentation here to avoid allocations during an *-to-tagged 9818 // HChange that could cause GC while the array buffer object is not fully 9819 // initialized. 9820 HObjectAccess byte_length_access(HObjectAccess::ForJSArrayBufferByteLength()); 9821 byte_length = AddUncasted<HForceRepresentation>( 9822 byte_length, byte_length_access.representation()); 9823 HAllocate* result = 9824 BuildAllocate(Add<HConstant>(JSArrayBuffer::kSizeWithInternalFields), 9825 HType::JSObject(), JS_ARRAY_BUFFER_TYPE, HAllocationMode()); 9826 9827 HValue* native_context = BuildGetNativeContext(); 9828 Add<HStoreNamedField>( 9829 result, HObjectAccess::ForMap(), 9830 Add<HLoadNamedField>( 9831 native_context, nullptr, 9832 HObjectAccess::ForContextSlot(Context::ARRAY_BUFFER_MAP_INDEX))); 9833 9834 HConstant* empty_fixed_array = 9835 Add<HConstant>(isolate()->factory()->empty_fixed_array()); 9836 Add<HStoreNamedField>( 9837 result, HObjectAccess::ForJSArrayOffset(JSArray::kPropertiesOffset), 9838 empty_fixed_array); 9839 Add<HStoreNamedField>( 9840 result, HObjectAccess::ForJSArrayOffset(JSArray::kElementsOffset), 9841 empty_fixed_array); 9842 Add<HStoreNamedField>( 9843 result, HObjectAccess::ForJSArrayBufferBackingStore().WithRepresentation( 9844 Representation::Smi()), 9845 graph()->GetConstant0()); 9846 Add<HStoreNamedField>(result, byte_length_access, byte_length); 9847 Add<HStoreNamedField>(result, HObjectAccess::ForJSArrayBufferBitFieldSlot(), 9848 graph()->GetConstant0()); 9849 Add<HStoreNamedField>( 9850 result, HObjectAccess::ForJSArrayBufferBitField(), 9851 Add<HConstant>((1 << JSArrayBuffer::IsExternal::kShift) | 9852 (1 << JSArrayBuffer::IsNeuterable::kShift))); 9853 9854 for (int field = 0; field < v8::ArrayBuffer::kInternalFieldCount; ++field) { 9855 Add<HStoreNamedField>( 9856 result, 9857 HObjectAccess::ForObservableJSObjectOffset( 9858 JSArrayBuffer::kSize + field * kPointerSize, Representation::Smi()), 9859 graph()->GetConstant0()); 9860 } 9861 9862 return result; 9863 } 9864 9865 9866 template <class ViewClass> 9867 void HGraphBuilder::BuildArrayBufferViewInitialization( 9868 HValue* obj, 9869 HValue* buffer, 9870 HValue* byte_offset, 9871 HValue* byte_length) { 9872 9873 for (int offset = ViewClass::kSize; 9874 offset < ViewClass::kSizeWithInternalFields; 9875 offset += kPointerSize) { 9876 Add<HStoreNamedField>(obj, 9877 HObjectAccess::ForObservableJSObjectOffset(offset), 9878 graph()->GetConstant0()); 9879 } 9880 9881 Add<HStoreNamedField>( 9882 obj, 9883 HObjectAccess::ForJSArrayBufferViewByteOffset(), 9884 byte_offset); 9885 Add<HStoreNamedField>( 9886 obj, 9887 HObjectAccess::ForJSArrayBufferViewByteLength(), 9888 byte_length); 9889 Add<HStoreNamedField>(obj, HObjectAccess::ForJSArrayBufferViewBuffer(), 9890 buffer); 9891 } 9892 9893 9894 HValue* HOptimizedGraphBuilder::BuildAllocateExternalElements( 9895 ExternalArrayType array_type, 9896 bool is_zero_byte_offset, 9897 HValue* buffer, HValue* byte_offset, HValue* length) { 9898 Handle<Map> external_array_map( 9899 isolate()->heap()->MapForFixedTypedArray(array_type)); 9900 9901 // The HForceRepresentation is to prevent possible deopt on int-smi 9902 // conversion after allocation but before the new object fields are set. 9903 length = AddUncasted<HForceRepresentation>(length, Representation::Smi()); 9904 HValue* elements = Add<HAllocate>( 9905 Add<HConstant>(FixedTypedArrayBase::kHeaderSize), HType::HeapObject(), 9906 NOT_TENURED, external_array_map->instance_type(), 9907 graph()->GetConstant0()); 9908 9909 AddStoreMapConstant(elements, external_array_map); 9910 Add<HStoreNamedField>(elements, 9911 HObjectAccess::ForFixedArrayLength(), length); 9912 9913 HValue* backing_store = Add<HLoadNamedField>( 9914 buffer, nullptr, HObjectAccess::ForJSArrayBufferBackingStore()); 9915 9916 HValue* typed_array_start; 9917 if (is_zero_byte_offset) { 9918 typed_array_start = backing_store; 9919 } else { 9920 HInstruction* external_pointer = 9921 AddUncasted<HAdd>(backing_store, byte_offset); 9922 // Arguments are checked prior to call to TypedArrayInitialize, 9923 // including byte_offset. 9924 external_pointer->ClearFlag(HValue::kCanOverflow); 9925 typed_array_start = external_pointer; 9926 } 9927 9928 Add<HStoreNamedField>(elements, 9929 HObjectAccess::ForFixedTypedArrayBaseBasePointer(), 9930 graph()->GetConstant0()); 9931 Add<HStoreNamedField>(elements, 9932 HObjectAccess::ForFixedTypedArrayBaseExternalPointer(), 9933 typed_array_start); 9934 9935 return elements; 9936 } 9937 9938 9939 HValue* HOptimizedGraphBuilder::BuildAllocateFixedTypedArray( 9940 ExternalArrayType array_type, size_t element_size, 9941 ElementsKind fixed_elements_kind, HValue* byte_length, HValue* length, 9942 bool initialize) { 9943 STATIC_ASSERT( 9944 (FixedTypedArrayBase::kHeaderSize & kObjectAlignmentMask) == 0); 9945 HValue* total_size; 9946 9947 // if fixed array's elements are not aligned to object's alignment, 9948 // we need to align the whole array to object alignment. 9949 if (element_size % kObjectAlignment != 0) { 9950 total_size = BuildObjectSizeAlignment( 9951 byte_length, FixedTypedArrayBase::kHeaderSize); 9952 } else { 9953 total_size = AddUncasted<HAdd>(byte_length, 9954 Add<HConstant>(FixedTypedArrayBase::kHeaderSize)); 9955 total_size->ClearFlag(HValue::kCanOverflow); 9956 } 9957 9958 // The HForceRepresentation is to prevent possible deopt on int-smi 9959 // conversion after allocation but before the new object fields are set. 9960 length = AddUncasted<HForceRepresentation>(length, Representation::Smi()); 9961 Handle<Map> fixed_typed_array_map( 9962 isolate()->heap()->MapForFixedTypedArray(array_type)); 9963 HAllocate* elements = Add<HAllocate>( 9964 total_size, HType::HeapObject(), NOT_TENURED, 9965 fixed_typed_array_map->instance_type(), graph()->GetConstant0()); 9966 9967 #ifndef V8_HOST_ARCH_64_BIT 9968 if (array_type == kExternalFloat64Array) { 9969 elements->MakeDoubleAligned(); 9970 } 9971 #endif 9972 9973 AddStoreMapConstant(elements, fixed_typed_array_map); 9974 9975 Add<HStoreNamedField>(elements, 9976 HObjectAccess::ForFixedArrayLength(), 9977 length); 9978 Add<HStoreNamedField>( 9979 elements, HObjectAccess::ForFixedTypedArrayBaseBasePointer(), elements); 9980 9981 Add<HStoreNamedField>( 9982 elements, HObjectAccess::ForFixedTypedArrayBaseExternalPointer(), 9983 Add<HConstant>(ExternalReference::fixed_typed_array_base_data_offset())); 9984 9985 HValue* filler = Add<HConstant>(static_cast<int32_t>(0)); 9986 9987 if (initialize) { 9988 LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement); 9989 9990 HValue* backing_store = AddUncasted<HAdd>( 9991 Add<HConstant>(ExternalReference::fixed_typed_array_base_data_offset()), 9992 elements, AddOfExternalAndTagged); 9993 9994 HValue* key = builder.BeginBody( 9995 Add<HConstant>(static_cast<int32_t>(0)), 9996 length, Token::LT); 9997 Add<HStoreKeyed>(backing_store, key, filler, elements, fixed_elements_kind); 9998 9999 builder.EndBody(); 10000 } 10001 return elements; 10002 } 10003 10004 10005 void HOptimizedGraphBuilder::GenerateTypedArrayInitialize( 10006 CallRuntime* expr) { 10007 ZoneList<Expression*>* arguments = expr->arguments(); 10008 10009 static const int kObjectArg = 0; 10010 static const int kArrayIdArg = 1; 10011 static const int kBufferArg = 2; 10012 static const int kByteOffsetArg = 3; 10013 static const int kByteLengthArg = 4; 10014 static const int kInitializeArg = 5; 10015 static const int kArgsLength = 6; 10016 DCHECK(arguments->length() == kArgsLength); 10017 10018 10019 CHECK_ALIVE(VisitForValue(arguments->at(kObjectArg))); 10020 HValue* obj = Pop(); 10021 10022 if (!arguments->at(kArrayIdArg)->IsLiteral()) { 10023 // This should never happen in real use, but can happen when fuzzing. 10024 // Just bail out. 10025 Bailout(kNeedSmiLiteral); 10026 return; 10027 } 10028 Handle<Object> value = 10029 static_cast<Literal*>(arguments->at(kArrayIdArg))->value(); 10030 if (!value->IsSmi()) { 10031 // This should never happen in real use, but can happen when fuzzing. 10032 // Just bail out. 10033 Bailout(kNeedSmiLiteral); 10034 return; 10035 } 10036 int array_id = Smi::cast(*value)->value(); 10037 10038 HValue* buffer; 10039 if (!arguments->at(kBufferArg)->IsNullLiteral()) { 10040 CHECK_ALIVE(VisitForValue(arguments->at(kBufferArg))); 10041 buffer = Pop(); 10042 } else { 10043 buffer = NULL; 10044 } 10045 10046 HValue* byte_offset; 10047 bool is_zero_byte_offset; 10048 10049 if (arguments->at(kByteOffsetArg)->IsLiteral() && 10050 Smi::kZero == 10051 *static_cast<Literal*>(arguments->at(kByteOffsetArg))->value()) { 10052 byte_offset = Add<HConstant>(static_cast<int32_t>(0)); 10053 is_zero_byte_offset = true; 10054 } else { 10055 CHECK_ALIVE(VisitForValue(arguments->at(kByteOffsetArg))); 10056 byte_offset = Pop(); 10057 is_zero_byte_offset = false; 10058 DCHECK(buffer != NULL); 10059 } 10060 10061 CHECK_ALIVE(VisitForValue(arguments->at(kByteLengthArg))); 10062 HValue* byte_length = Pop(); 10063 10064 CHECK(arguments->at(kInitializeArg)->IsLiteral()); 10065 bool initialize = static_cast<Literal*>(arguments->at(kInitializeArg)) 10066 ->value() 10067 ->BooleanValue(); 10068 10069 NoObservableSideEffectsScope scope(this); 10070 IfBuilder byte_offset_smi(this); 10071 10072 if (!is_zero_byte_offset) { 10073 byte_offset_smi.If<HIsSmiAndBranch>(byte_offset); 10074 byte_offset_smi.Then(); 10075 } 10076 10077 ExternalArrayType array_type = 10078 kExternalInt8Array; // Bogus initialization. 10079 size_t element_size = 1; // Bogus initialization. 10080 ElementsKind fixed_elements_kind = // Bogus initialization. 10081 INT8_ELEMENTS; 10082 Runtime::ArrayIdToTypeAndSize(array_id, 10083 &array_type, 10084 &fixed_elements_kind, 10085 &element_size); 10086 10087 10088 { // byte_offset is Smi. 10089 HValue* allocated_buffer = buffer; 10090 if (buffer == NULL) { 10091 allocated_buffer = BuildAllocateEmptyArrayBuffer(byte_length); 10092 } 10093 BuildArrayBufferViewInitialization<JSTypedArray>(obj, allocated_buffer, 10094 byte_offset, byte_length); 10095 10096 10097 HInstruction* length = AddUncasted<HDiv>(byte_length, 10098 Add<HConstant>(static_cast<int32_t>(element_size))); 10099 // Callers (in typedarray.js) ensure that length <= %_MaxSmi(). 10100 length = AddUncasted<HForceRepresentation>(length, Representation::Smi()); 10101 10102 Add<HStoreNamedField>(obj, 10103 HObjectAccess::ForJSTypedArrayLength(), 10104 length); 10105 10106 HValue* elements; 10107 if (buffer != NULL) { 10108 elements = BuildAllocateExternalElements( 10109 array_type, is_zero_byte_offset, buffer, byte_offset, length); 10110 } else { 10111 DCHECK(is_zero_byte_offset); 10112 elements = BuildAllocateFixedTypedArray(array_type, element_size, 10113 fixed_elements_kind, byte_length, 10114 length, initialize); 10115 } 10116 Add<HStoreNamedField>( 10117 obj, HObjectAccess::ForElementsPointer(), elements); 10118 } 10119 10120 if (!is_zero_byte_offset) { 10121 byte_offset_smi.Else(); 10122 { // byte_offset is not Smi. 10123 Push(obj); 10124 CHECK_ALIVE(VisitForValue(arguments->at(kArrayIdArg))); 10125 Push(buffer); 10126 Push(byte_offset); 10127 Push(byte_length); 10128 CHECK_ALIVE(VisitForValue(arguments->at(kInitializeArg))); 10129 PushArgumentsFromEnvironment(kArgsLength); 10130 Add<HCallRuntime>(expr->function(), kArgsLength); 10131 } 10132 } 10133 byte_offset_smi.End(); 10134 } 10135 10136 10137 void HOptimizedGraphBuilder::GenerateMaxSmi(CallRuntime* expr) { 10138 DCHECK(expr->arguments()->length() == 0); 10139 HConstant* max_smi = New<HConstant>(static_cast<int32_t>(Smi::kMaxValue)); 10140 return ast_context()->ReturnInstruction(max_smi, expr->id()); 10141 } 10142 10143 10144 void HOptimizedGraphBuilder::GenerateTypedArrayMaxSizeInHeap( 10145 CallRuntime* expr) { 10146 DCHECK(expr->arguments()->length() == 0); 10147 HConstant* result = New<HConstant>(static_cast<int32_t>( 10148 FLAG_typed_array_max_size_in_heap)); 10149 return ast_context()->ReturnInstruction(result, expr->id()); 10150 } 10151 10152 10153 void HOptimizedGraphBuilder::GenerateArrayBufferGetByteLength( 10154 CallRuntime* expr) { 10155 DCHECK(expr->arguments()->length() == 1); 10156 CHECK_ALIVE(VisitForValue(expr->arguments()->at(0))); 10157 HValue* buffer = Pop(); 10158 HInstruction* result = New<HLoadNamedField>( 10159 buffer, nullptr, HObjectAccess::ForJSArrayBufferByteLength()); 10160 return ast_context()->ReturnInstruction(result, expr->id()); 10161 } 10162 10163 10164 void HOptimizedGraphBuilder::GenerateArrayBufferViewGetByteLength( 10165 CallRuntime* expr) { 10166 NoObservableSideEffectsScope scope(this); 10167 DCHECK(expr->arguments()->length() == 1); 10168 CHECK_ALIVE(VisitForValue(expr->arguments()->at(0))); 10169 HValue* view = Pop(); 10170 10171 return ast_context()->ReturnValue(BuildArrayBufferViewFieldAccessor( 10172 view, nullptr, 10173 FieldIndex::ForInObjectOffset(JSArrayBufferView::kByteLengthOffset))); 10174 } 10175 10176 10177 void HOptimizedGraphBuilder::GenerateArrayBufferViewGetByteOffset( 10178 CallRuntime* expr) { 10179 NoObservableSideEffectsScope scope(this); 10180 DCHECK(expr->arguments()->length() == 1); 10181 CHECK_ALIVE(VisitForValue(expr->arguments()->at(0))); 10182 HValue* view = Pop(); 10183 10184 return ast_context()->ReturnValue(BuildArrayBufferViewFieldAccessor( 10185 view, nullptr, 10186 FieldIndex::ForInObjectOffset(JSArrayBufferView::kByteOffsetOffset))); 10187 } 10188 10189 10190 void HOptimizedGraphBuilder::GenerateTypedArrayGetLength( 10191 CallRuntime* expr) { 10192 NoObservableSideEffectsScope scope(this); 10193 DCHECK(expr->arguments()->length() == 1); 10194 CHECK_ALIVE(VisitForValue(expr->arguments()->at(0))); 10195 HValue* view = Pop(); 10196 10197 return ast_context()->ReturnValue(BuildArrayBufferViewFieldAccessor( 10198 view, nullptr, 10199 FieldIndex::ForInObjectOffset(JSTypedArray::kLengthOffset))); 10200 } 10201 10202 10203 void HOptimizedGraphBuilder::VisitCallRuntime(CallRuntime* expr) { 10204 DCHECK(!HasStackOverflow()); 10205 DCHECK(current_block() != NULL); 10206 DCHECK(current_block()->HasPredecessor()); 10207 if (expr->is_jsruntime()) { 10208 // Crankshaft always specializes to the native context, so we can just grab 10209 // the constant function from the current native context and embed that into 10210 // the code object. 10211 Handle<JSFunction> known_function( 10212 JSFunction::cast( 10213 current_info()->native_context()->get(expr->context_index())), 10214 isolate()); 10215 10216 // The callee and the receiver both have to be pushed onto the operand stack 10217 // before arguments are being evaluated. 10218 HConstant* function = Add<HConstant>(known_function); 10219 HValue* receiver = ImplicitReceiverFor(function, known_function); 10220 Push(function); 10221 Push(receiver); 10222 10223 int argument_count = expr->arguments()->length() + 1; // Count receiver. 10224 CHECK_ALIVE(VisitExpressions(expr->arguments())); 10225 PushArgumentsFromEnvironment(argument_count); 10226 HInstruction* call = NewCallConstantFunction(known_function, argument_count, 10227 TailCallMode::kDisallow, 10228 TailCallMode::kDisallow); 10229 Drop(1); // Function 10230 return ast_context()->ReturnInstruction(call, expr->id()); 10231 } 10232 10233 const Runtime::Function* function = expr->function(); 10234 DCHECK(function != NULL); 10235 switch (function->function_id) { 10236 #define CALL_INTRINSIC_GENERATOR(Name) \ 10237 case Runtime::kInline##Name: \ 10238 return Generate##Name(expr); 10239 10240 FOR_EACH_HYDROGEN_INTRINSIC(CALL_INTRINSIC_GENERATOR) 10241 #undef CALL_INTRINSIC_GENERATOR 10242 default: { 10243 int argument_count = expr->arguments()->length(); 10244 CHECK_ALIVE(VisitExpressions(expr->arguments())); 10245 PushArgumentsFromEnvironment(argument_count); 10246 HCallRuntime* call = New<HCallRuntime>(function, argument_count); 10247 return ast_context()->ReturnInstruction(call, expr->id()); 10248 } 10249 } 10250 } 10251 10252 10253 void HOptimizedGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { 10254 DCHECK(!HasStackOverflow()); 10255 DCHECK(current_block() != NULL); 10256 DCHECK(current_block()->HasPredecessor()); 10257 switch (expr->op()) { 10258 case Token::DELETE: return VisitDelete(expr); 10259 case Token::VOID: return VisitVoid(expr); 10260 case Token::TYPEOF: return VisitTypeof(expr); 10261 case Token::NOT: return VisitNot(expr); 10262 default: UNREACHABLE(); 10263 } 10264 } 10265 10266 10267 void HOptimizedGraphBuilder::VisitDelete(UnaryOperation* expr) { 10268 Property* prop = expr->expression()->AsProperty(); 10269 VariableProxy* proxy = expr->expression()->AsVariableProxy(); 10270 if (prop != NULL) { 10271 CHECK_ALIVE(VisitForValue(prop->obj())); 10272 CHECK_ALIVE(VisitForValue(prop->key())); 10273 HValue* key = Pop(); 10274 HValue* obj = Pop(); 10275 Add<HPushArguments>(obj, key); 10276 HInstruction* instr = New<HCallRuntime>( 10277 Runtime::FunctionForId(is_strict(function_language_mode()) 10278 ? Runtime::kDeleteProperty_Strict 10279 : Runtime::kDeleteProperty_Sloppy), 10280 2); 10281 return ast_context()->ReturnInstruction(instr, expr->id()); 10282 } else if (proxy != NULL) { 10283 Variable* var = proxy->var(); 10284 if (var->IsUnallocated()) { 10285 Bailout(kDeleteWithGlobalVariable); 10286 } else if (var->IsStackAllocated() || var->IsContextSlot()) { 10287 // Result of deleting non-global variables is false. 'this' is not really 10288 // a variable, though we implement it as one. The subexpression does not 10289 // have side effects. 10290 HValue* value = var->is_this() ? graph()->GetConstantTrue() 10291 : graph()->GetConstantFalse(); 10292 return ast_context()->ReturnValue(value); 10293 } else { 10294 Bailout(kDeleteWithNonGlobalVariable); 10295 } 10296 } else { 10297 // Result of deleting non-property, non-variable reference is true. 10298 // Evaluate the subexpression for side effects. 10299 CHECK_ALIVE(VisitForEffect(expr->expression())); 10300 return ast_context()->ReturnValue(graph()->GetConstantTrue()); 10301 } 10302 } 10303 10304 10305 void HOptimizedGraphBuilder::VisitVoid(UnaryOperation* expr) { 10306 CHECK_ALIVE(VisitForEffect(expr->expression())); 10307 return ast_context()->ReturnValue(graph()->GetConstantUndefined()); 10308 } 10309 10310 10311 void HOptimizedGraphBuilder::VisitTypeof(UnaryOperation* expr) { 10312 CHECK_ALIVE(VisitForTypeOf(expr->expression())); 10313 HValue* value = Pop(); 10314 HInstruction* instr = New<HTypeof>(value); 10315 return ast_context()->ReturnInstruction(instr, expr->id()); 10316 } 10317 10318 10319 void HOptimizedGraphBuilder::VisitNot(UnaryOperation* expr) { 10320 if (ast_context()->IsTest()) { 10321 TestContext* context = TestContext::cast(ast_context()); 10322 VisitForControl(expr->expression(), 10323 context->if_false(), 10324 context->if_true()); 10325 return; 10326 } 10327 10328 if (ast_context()->IsEffect()) { 10329 VisitForEffect(expr->expression()); 10330 return; 10331 } 10332 10333 DCHECK(ast_context()->IsValue()); 10334 HBasicBlock* materialize_false = graph()->CreateBasicBlock(); 10335 HBasicBlock* materialize_true = graph()->CreateBasicBlock(); 10336 CHECK_BAILOUT(VisitForControl(expr->expression(), 10337 materialize_false, 10338 materialize_true)); 10339 10340 if (materialize_false->HasPredecessor()) { 10341 materialize_false->SetJoinId(expr->MaterializeFalseId()); 10342 set_current_block(materialize_false); 10343 Push(graph()->GetConstantFalse()); 10344 } else { 10345 materialize_false = NULL; 10346 } 10347 10348 if (materialize_true->HasPredecessor()) { 10349 materialize_true->SetJoinId(expr->MaterializeTrueId()); 10350 set_current_block(materialize_true); 10351 Push(graph()->GetConstantTrue()); 10352 } else { 10353 materialize_true = NULL; 10354 } 10355 10356 HBasicBlock* join = 10357 CreateJoin(materialize_false, materialize_true, expr->id()); 10358 set_current_block(join); 10359 if (join != NULL) return ast_context()->ReturnValue(Pop()); 10360 } 10361 10362 static Representation RepresentationFor(AstType* type) { 10363 DisallowHeapAllocation no_allocation; 10364 if (type->Is(AstType::None())) return Representation::None(); 10365 if (type->Is(AstType::SignedSmall())) return Representation::Smi(); 10366 if (type->Is(AstType::Signed32())) return Representation::Integer32(); 10367 if (type->Is(AstType::Number())) return Representation::Double(); 10368 return Representation::Tagged(); 10369 } 10370 10371 HInstruction* HOptimizedGraphBuilder::BuildIncrement(CountOperation* expr) { 10372 // The input to the count operation is on top of the expression stack. 10373 Representation rep = RepresentationFor(expr->type()); 10374 if (rep.IsNone() || rep.IsTagged()) { 10375 rep = Representation::Smi(); 10376 } 10377 10378 // We need an explicit HValue representing ToNumber(input). The 10379 // actual HChange instruction we need is (sometimes) added in a later 10380 // phase, so it is not available now to be used as an input to HAdd and 10381 // as the return value. 10382 HInstruction* number_input = AddUncasted<HForceRepresentation>(Pop(), rep); 10383 if (!rep.IsDouble()) { 10384 number_input->SetFlag(HInstruction::kFlexibleRepresentation); 10385 number_input->SetFlag(HInstruction::kCannotBeTagged); 10386 } 10387 Push(number_input); 10388 10389 // The addition has no side effects, so we do not need 10390 // to simulate the expression stack after this instruction. 10391 // Any later failures deopt to the load of the input or earlier. 10392 HConstant* delta = (expr->op() == Token::INC) 10393 ? graph()->GetConstant1() 10394 : graph()->GetConstantMinus1(); 10395 HInstruction* instr = AddUncasted<HAdd>(Top(), delta); 10396 if (instr->IsAdd()) { 10397 HAdd* add = HAdd::cast(instr); 10398 add->set_observed_input_representation(1, rep); 10399 add->set_observed_input_representation(2, Representation::Smi()); 10400 } 10401 instr->ClearAllSideEffects(); 10402 instr->SetFlag(HInstruction::kCannotBeTagged); 10403 return instr; 10404 } 10405 10406 void HOptimizedGraphBuilder::BuildStoreForEffect( 10407 Expression* expr, Property* prop, FeedbackVectorSlot slot, BailoutId ast_id, 10408 BailoutId return_id, HValue* object, HValue* key, HValue* value) { 10409 EffectContext for_effect(this); 10410 Push(object); 10411 if (key != NULL) Push(key); 10412 Push(value); 10413 BuildStore(expr, prop, slot, ast_id, return_id); 10414 } 10415 10416 10417 void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) { 10418 DCHECK(!HasStackOverflow()); 10419 DCHECK(current_block() != NULL); 10420 DCHECK(current_block()->HasPredecessor()); 10421 if (!is_tracking_positions()) SetSourcePosition(expr->position()); 10422 Expression* target = expr->expression(); 10423 VariableProxy* proxy = target->AsVariableProxy(); 10424 Property* prop = target->AsProperty(); 10425 if (proxy == NULL && prop == NULL) { 10426 return Bailout(kInvalidLhsInCountOperation); 10427 } 10428 10429 // Match the full code generator stack by simulating an extra stack 10430 // element for postfix operations in a non-effect context. The return 10431 // value is ToNumber(input). 10432 bool returns_original_input = 10433 expr->is_postfix() && !ast_context()->IsEffect(); 10434 HValue* input = NULL; // ToNumber(original_input). 10435 HValue* after = NULL; // The result after incrementing or decrementing. 10436 10437 if (proxy != NULL) { 10438 Variable* var = proxy->var(); 10439 if (var->mode() == CONST) { 10440 return Bailout(kNonInitializerAssignmentToConst); 10441 } 10442 // Argument of the count operation is a variable, not a property. 10443 DCHECK(prop == NULL); 10444 CHECK_ALIVE(VisitForValue(target)); 10445 10446 after = BuildIncrement(expr); 10447 input = returns_original_input ? Top() : Pop(); 10448 Push(after); 10449 10450 switch (var->location()) { 10451 case VariableLocation::UNALLOCATED: 10452 HandleGlobalVariableAssignment(var, after, expr->CountSlot(), 10453 expr->AssignmentId()); 10454 break; 10455 10456 case VariableLocation::PARAMETER: 10457 case VariableLocation::LOCAL: 10458 BindIfLive(var, after); 10459 break; 10460 10461 case VariableLocation::CONTEXT: { 10462 HValue* context = BuildContextChainWalk(var); 10463 HStoreContextSlot::Mode mode = IsLexicalVariableMode(var->mode()) 10464 ? HStoreContextSlot::kCheckDeoptimize : HStoreContextSlot::kNoCheck; 10465 HStoreContextSlot* instr = Add<HStoreContextSlot>(context, var->index(), 10466 mode, after); 10467 if (instr->HasObservableSideEffects()) { 10468 Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE); 10469 } 10470 break; 10471 } 10472 10473 case VariableLocation::LOOKUP: 10474 return Bailout(kLookupVariableInCountOperation); 10475 10476 case VariableLocation::MODULE: 10477 UNREACHABLE(); 10478 } 10479 10480 Drop(returns_original_input ? 2 : 1); 10481 return ast_context()->ReturnValue(expr->is_postfix() ? input : after); 10482 } 10483 10484 // Argument of the count operation is a property. 10485 DCHECK(prop != NULL); 10486 if (returns_original_input) Push(graph()->GetConstantUndefined()); 10487 10488 CHECK_ALIVE(VisitForValue(prop->obj())); 10489 HValue* object = Top(); 10490 10491 HValue* key = NULL; 10492 if (!prop->key()->IsPropertyName() || prop->IsStringAccess()) { 10493 CHECK_ALIVE(VisitForValue(prop->key())); 10494 key = Top(); 10495 } 10496 10497 CHECK_ALIVE(PushLoad(prop, object, key)); 10498 10499 after = BuildIncrement(expr); 10500 10501 if (returns_original_input) { 10502 input = Pop(); 10503 // Drop object and key to push it again in the effect context below. 10504 Drop(key == NULL ? 1 : 2); 10505 environment()->SetExpressionStackAt(0, input); 10506 CHECK_ALIVE(BuildStoreForEffect(expr, prop, expr->CountSlot(), expr->id(), 10507 expr->AssignmentId(), object, key, after)); 10508 return ast_context()->ReturnValue(Pop()); 10509 } 10510 10511 environment()->SetExpressionStackAt(0, after); 10512 return BuildStore(expr, prop, expr->CountSlot(), expr->id(), 10513 expr->AssignmentId()); 10514 } 10515 10516 10517 HInstruction* HOptimizedGraphBuilder::BuildStringCharCodeAt( 10518 HValue* string, 10519 HValue* index) { 10520 if (string->IsConstant() && index->IsConstant()) { 10521 HConstant* c_string = HConstant::cast(string); 10522 HConstant* c_index = HConstant::cast(index); 10523 if (c_string->HasStringValue() && c_index->HasNumberValue()) { 10524 int32_t i = c_index->NumberValueAsInteger32(); 10525 Handle<String> s = c_string->StringValue(); 10526 if (i < 0 || i >= s->length()) { 10527 return New<HConstant>(std::numeric_limits<double>::quiet_NaN()); 10528 } 10529 return New<HConstant>(s->Get(i)); 10530 } 10531 } 10532 string = BuildCheckString(string); 10533 index = Add<HBoundsCheck>(index, AddLoadStringLength(string)); 10534 return New<HStringCharCodeAt>(string, index); 10535 } 10536 10537 10538 // Checks if the given shift amounts have following forms: 10539 // (N1) and (N2) with N1 + N2 = 32; (sa) and (32 - sa). 10540 static bool ShiftAmountsAllowReplaceByRotate(HValue* sa, 10541 HValue* const32_minus_sa) { 10542 if (sa->IsConstant() && const32_minus_sa->IsConstant()) { 10543 const HConstant* c1 = HConstant::cast(sa); 10544 const HConstant* c2 = HConstant::cast(const32_minus_sa); 10545 return c1->HasInteger32Value() && c2->HasInteger32Value() && 10546 (c1->Integer32Value() + c2->Integer32Value() == 32); 10547 } 10548 if (!const32_minus_sa->IsSub()) return false; 10549 HSub* sub = HSub::cast(const32_minus_sa); 10550 return sub->left()->EqualsInteger32Constant(32) && sub->right() == sa; 10551 } 10552 10553 10554 // Checks if the left and the right are shift instructions with the oposite 10555 // directions that can be replaced by one rotate right instruction or not. 10556 // Returns the operand and the shift amount for the rotate instruction in the 10557 // former case. 10558 bool HGraphBuilder::MatchRotateRight(HValue* left, 10559 HValue* right, 10560 HValue** operand, 10561 HValue** shift_amount) { 10562 HShl* shl; 10563 HShr* shr; 10564 if (left->IsShl() && right->IsShr()) { 10565 shl = HShl::cast(left); 10566 shr = HShr::cast(right); 10567 } else if (left->IsShr() && right->IsShl()) { 10568 shl = HShl::cast(right); 10569 shr = HShr::cast(left); 10570 } else { 10571 return false; 10572 } 10573 if (shl->left() != shr->left()) return false; 10574 10575 if (!ShiftAmountsAllowReplaceByRotate(shl->right(), shr->right()) && 10576 !ShiftAmountsAllowReplaceByRotate(shr->right(), shl->right())) { 10577 return false; 10578 } 10579 *operand = shr->left(); 10580 *shift_amount = shr->right(); 10581 return true; 10582 } 10583 10584 10585 bool CanBeZero(HValue* right) { 10586 if (right->IsConstant()) { 10587 HConstant* right_const = HConstant::cast(right); 10588 if (right_const->HasInteger32Value() && 10589 (right_const->Integer32Value() & 0x1f) != 0) { 10590 return false; 10591 } 10592 } 10593 return true; 10594 } 10595 10596 HValue* HGraphBuilder::EnforceNumberType(HValue* number, AstType* expected) { 10597 if (expected->Is(AstType::SignedSmall())) { 10598 return AddUncasted<HForceRepresentation>(number, Representation::Smi()); 10599 } 10600 if (expected->Is(AstType::Signed32())) { 10601 return AddUncasted<HForceRepresentation>(number, 10602 Representation::Integer32()); 10603 } 10604 return number; 10605 } 10606 10607 HValue* HGraphBuilder::TruncateToNumber(HValue* value, AstType** expected) { 10608 if (value->IsConstant()) { 10609 HConstant* constant = HConstant::cast(value); 10610 Maybe<HConstant*> number = 10611 constant->CopyToTruncatedNumber(isolate(), zone()); 10612 if (number.IsJust()) { 10613 *expected = AstType::Number(); 10614 return AddInstruction(number.FromJust()); 10615 } 10616 } 10617 10618 // We put temporary values on the stack, which don't correspond to anything 10619 // in baseline code. Since nothing is observable we avoid recording those 10620 // pushes with a NoObservableSideEffectsScope. 10621 NoObservableSideEffectsScope no_effects(this); 10622 10623 AstType* expected_type = *expected; 10624 10625 // Separate the number type from the rest. 10626 AstType* expected_obj = 10627 AstType::Intersect(expected_type, AstType::NonNumber(), zone()); 10628 AstType* expected_number = 10629 AstType::Intersect(expected_type, AstType::Number(), zone()); 10630 10631 // We expect to get a number. 10632 // (We need to check first, since AstType::None->Is(AstType::Any()) == true. 10633 if (expected_obj->Is(AstType::None())) { 10634 DCHECK(!expected_number->Is(AstType::None())); 10635 return value; 10636 } 10637 10638 if (expected_obj->Is(AstType::Undefined())) { 10639 // This is already done by HChange. 10640 *expected = AstType::Union(expected_number, AstType::Number(), zone()); 10641 return value; 10642 } 10643 10644 return value; 10645 } 10646 10647 10648 HValue* HOptimizedGraphBuilder::BuildBinaryOperation( 10649 BinaryOperation* expr, 10650 HValue* left, 10651 HValue* right, 10652 PushBeforeSimulateBehavior push_sim_result) { 10653 AstType* left_type = bounds_.get(expr->left()).lower; 10654 AstType* right_type = bounds_.get(expr->right()).lower; 10655 AstType* result_type = bounds_.get(expr).lower; 10656 Maybe<int> fixed_right_arg = expr->fixed_right_arg(); 10657 Handle<AllocationSite> allocation_site = expr->allocation_site(); 10658 10659 HAllocationMode allocation_mode; 10660 if (FLAG_allocation_site_pretenuring && !allocation_site.is_null()) { 10661 allocation_mode = HAllocationMode(allocation_site); 10662 } 10663 HValue* result = HGraphBuilder::BuildBinaryOperation( 10664 expr->op(), left, right, left_type, right_type, result_type, 10665 fixed_right_arg, allocation_mode, expr->id()); 10666 // Add a simulate after instructions with observable side effects, and 10667 // after phis, which are the result of BuildBinaryOperation when we 10668 // inlined some complex subgraph. 10669 if (result->HasObservableSideEffects() || result->IsPhi()) { 10670 if (push_sim_result == PUSH_BEFORE_SIMULATE) { 10671 Push(result); 10672 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); 10673 Drop(1); 10674 } else { 10675 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); 10676 } 10677 } 10678 return result; 10679 } 10680 10681 HValue* HGraphBuilder::BuildBinaryOperation( 10682 Token::Value op, HValue* left, HValue* right, AstType* left_type, 10683 AstType* right_type, AstType* result_type, Maybe<int> fixed_right_arg, 10684 HAllocationMode allocation_mode, BailoutId opt_id) { 10685 bool maybe_string_add = false; 10686 if (op == Token::ADD) { 10687 // If we are adding constant string with something for which we don't have 10688 // a feedback yet, assume that it's also going to be a string and don't 10689 // generate deopt instructions. 10690 if (!left_type->IsInhabited() && right->IsConstant() && 10691 HConstant::cast(right)->HasStringValue()) { 10692 left_type = AstType::String(); 10693 } 10694 10695 if (!right_type->IsInhabited() && left->IsConstant() && 10696 HConstant::cast(left)->HasStringValue()) { 10697 right_type = AstType::String(); 10698 } 10699 10700 maybe_string_add = (left_type->Maybe(AstType::String()) || 10701 left_type->Maybe(AstType::Receiver()) || 10702 right_type->Maybe(AstType::String()) || 10703 right_type->Maybe(AstType::Receiver())); 10704 } 10705 10706 Representation left_rep = RepresentationFor(left_type); 10707 Representation right_rep = RepresentationFor(right_type); 10708 10709 if (!left_type->IsInhabited()) { 10710 Add<HDeoptimize>( 10711 DeoptimizeReason::kInsufficientTypeFeedbackForLHSOfBinaryOperation, 10712 Deoptimizer::SOFT); 10713 left_type = AstType::Any(); 10714 left_rep = RepresentationFor(left_type); 10715 maybe_string_add = op == Token::ADD; 10716 } 10717 10718 if (!right_type->IsInhabited()) { 10719 Add<HDeoptimize>( 10720 DeoptimizeReason::kInsufficientTypeFeedbackForRHSOfBinaryOperation, 10721 Deoptimizer::SOFT); 10722 right_type = AstType::Any(); 10723 right_rep = RepresentationFor(right_type); 10724 maybe_string_add = op == Token::ADD; 10725 } 10726 10727 if (!maybe_string_add) { 10728 left = TruncateToNumber(left, &left_type); 10729 right = TruncateToNumber(right, &right_type); 10730 } 10731 10732 // Special case for string addition here. 10733 if (op == Token::ADD && 10734 (left_type->Is(AstType::String()) || right_type->Is(AstType::String()))) { 10735 // Validate type feedback for left argument. 10736 if (left_type->Is(AstType::String())) { 10737 left = BuildCheckString(left); 10738 } 10739 10740 // Validate type feedback for right argument. 10741 if (right_type->Is(AstType::String())) { 10742 right = BuildCheckString(right); 10743 } 10744 10745 // Convert left argument as necessary. 10746 if (left_type->Is(AstType::Number())) { 10747 DCHECK(right_type->Is(AstType::String())); 10748 left = BuildNumberToString(left, left_type); 10749 } else if (!left_type->Is(AstType::String())) { 10750 DCHECK(right_type->Is(AstType::String())); 10751 return AddUncasted<HStringAdd>( 10752 left, right, allocation_mode.GetPretenureMode(), 10753 STRING_ADD_CONVERT_LEFT, allocation_mode.feedback_site()); 10754 } 10755 10756 // Convert right argument as necessary. 10757 if (right_type->Is(AstType::Number())) { 10758 DCHECK(left_type->Is(AstType::String())); 10759 right = BuildNumberToString(right, right_type); 10760 } else if (!right_type->Is(AstType::String())) { 10761 DCHECK(left_type->Is(AstType::String())); 10762 return AddUncasted<HStringAdd>( 10763 left, right, allocation_mode.GetPretenureMode(), 10764 STRING_ADD_CONVERT_RIGHT, allocation_mode.feedback_site()); 10765 } 10766 10767 // Fast paths for empty constant strings. 10768 Handle<String> left_string = 10769 left->IsConstant() && HConstant::cast(left)->HasStringValue() 10770 ? HConstant::cast(left)->StringValue() 10771 : Handle<String>(); 10772 Handle<String> right_string = 10773 right->IsConstant() && HConstant::cast(right)->HasStringValue() 10774 ? HConstant::cast(right)->StringValue() 10775 : Handle<String>(); 10776 if (!left_string.is_null() && left_string->length() == 0) return right; 10777 if (!right_string.is_null() && right_string->length() == 0) return left; 10778 if (!left_string.is_null() && !right_string.is_null()) { 10779 return AddUncasted<HStringAdd>( 10780 left, right, allocation_mode.GetPretenureMode(), 10781 STRING_ADD_CHECK_NONE, allocation_mode.feedback_site()); 10782 } 10783 10784 // Register the dependent code with the allocation site. 10785 if (!allocation_mode.feedback_site().is_null()) { 10786 DCHECK(!graph()->info()->IsStub()); 10787 Handle<AllocationSite> site(allocation_mode.feedback_site()); 10788 top_info()->dependencies()->AssumeTenuringDecision(site); 10789 } 10790 10791 // Inline the string addition into the stub when creating allocation 10792 // mementos to gather allocation site feedback, or if we can statically 10793 // infer that we're going to create a cons string. 10794 if ((graph()->info()->IsStub() && 10795 allocation_mode.CreateAllocationMementos()) || 10796 (left->IsConstant() && 10797 HConstant::cast(left)->HasStringValue() && 10798 HConstant::cast(left)->StringValue()->length() + 1 >= 10799 ConsString::kMinLength) || 10800 (right->IsConstant() && 10801 HConstant::cast(right)->HasStringValue() && 10802 HConstant::cast(right)->StringValue()->length() + 1 >= 10803 ConsString::kMinLength)) { 10804 return BuildStringAdd(left, right, allocation_mode); 10805 } 10806 10807 // Fallback to using the string add stub. 10808 return AddUncasted<HStringAdd>( 10809 left, right, allocation_mode.GetPretenureMode(), STRING_ADD_CHECK_NONE, 10810 allocation_mode.feedback_site()); 10811 } 10812 10813 // Special case for +x here. 10814 if (op == Token::MUL) { 10815 if (left->EqualsInteger32Constant(1)) { 10816 return BuildToNumber(right); 10817 } 10818 if (right->EqualsInteger32Constant(1)) { 10819 return BuildToNumber(left); 10820 } 10821 } 10822 10823 if (graph()->info()->IsStub()) { 10824 left = EnforceNumberType(left, left_type); 10825 right = EnforceNumberType(right, right_type); 10826 } 10827 10828 Representation result_rep = RepresentationFor(result_type); 10829 10830 bool is_non_primitive = (left_rep.IsTagged() && !left_rep.IsSmi()) || 10831 (right_rep.IsTagged() && !right_rep.IsSmi()); 10832 10833 HInstruction* instr = NULL; 10834 // Only the stub is allowed to call into the runtime, since otherwise we would 10835 // inline several instructions (including the two pushes) for every tagged 10836 // operation in optimized code, which is more expensive, than a stub call. 10837 if (graph()->info()->IsStub() && is_non_primitive) { 10838 HValue* values[] = {left, right}; 10839 #define GET_STUB(Name) \ 10840 do { \ 10841 Callable callable = CodeFactory::Name(isolate()); \ 10842 HValue* stub = Add<HConstant>(callable.code()); \ 10843 instr = AddUncasted<HCallWithDescriptor>(stub, 0, callable.descriptor(), \ 10844 ArrayVector(values)); \ 10845 } while (false) 10846 10847 switch (op) { 10848 default: 10849 UNREACHABLE(); 10850 case Token::ADD: 10851 GET_STUB(Add); 10852 break; 10853 case Token::SUB: 10854 GET_STUB(Subtract); 10855 break; 10856 case Token::MUL: 10857 GET_STUB(Multiply); 10858 break; 10859 case Token::DIV: 10860 GET_STUB(Divide); 10861 break; 10862 case Token::MOD: 10863 GET_STUB(Modulus); 10864 break; 10865 case Token::BIT_OR: 10866 GET_STUB(BitwiseOr); 10867 break; 10868 case Token::BIT_AND: 10869 GET_STUB(BitwiseAnd); 10870 break; 10871 case Token::BIT_XOR: 10872 GET_STUB(BitwiseXor); 10873 break; 10874 case Token::SAR: 10875 GET_STUB(ShiftRight); 10876 break; 10877 case Token::SHR: 10878 GET_STUB(ShiftRightLogical); 10879 break; 10880 case Token::SHL: 10881 GET_STUB(ShiftLeft); 10882 break; 10883 } 10884 #undef GET_STUB 10885 } else { 10886 switch (op) { 10887 case Token::ADD: 10888 instr = AddUncasted<HAdd>(left, right); 10889 break; 10890 case Token::SUB: 10891 instr = AddUncasted<HSub>(left, right); 10892 break; 10893 case Token::MUL: 10894 instr = AddUncasted<HMul>(left, right); 10895 break; 10896 case Token::MOD: { 10897 if (fixed_right_arg.IsJust() && 10898 !right->EqualsInteger32Constant(fixed_right_arg.FromJust())) { 10899 HConstant* fixed_right = 10900 Add<HConstant>(static_cast<int>(fixed_right_arg.FromJust())); 10901 IfBuilder if_same(this); 10902 if_same.If<HCompareNumericAndBranch>(right, fixed_right, Token::EQ); 10903 if_same.Then(); 10904 if_same.ElseDeopt(DeoptimizeReason::kUnexpectedRHSOfBinaryOperation); 10905 right = fixed_right; 10906 } 10907 instr = AddUncasted<HMod>(left, right); 10908 break; 10909 } 10910 case Token::DIV: 10911 instr = AddUncasted<HDiv>(left, right); 10912 break; 10913 case Token::BIT_XOR: 10914 case Token::BIT_AND: 10915 instr = AddUncasted<HBitwise>(op, left, right); 10916 break; 10917 case Token::BIT_OR: { 10918 HValue *operand, *shift_amount; 10919 if (left_type->Is(AstType::Signed32()) && 10920 right_type->Is(AstType::Signed32()) && 10921 MatchRotateRight(left, right, &operand, &shift_amount)) { 10922 instr = AddUncasted<HRor>(operand, shift_amount); 10923 } else { 10924 instr = AddUncasted<HBitwise>(op, left, right); 10925 } 10926 break; 10927 } 10928 case Token::SAR: 10929 instr = AddUncasted<HSar>(left, right); 10930 break; 10931 case Token::SHR: 10932 instr = AddUncasted<HShr>(left, right); 10933 if (instr->IsShr() && CanBeZero(right)) { 10934 graph()->RecordUint32Instruction(instr); 10935 } 10936 break; 10937 case Token::SHL: 10938 instr = AddUncasted<HShl>(left, right); 10939 break; 10940 default: 10941 UNREACHABLE(); 10942 } 10943 } 10944 10945 if (instr->IsBinaryOperation()) { 10946 HBinaryOperation* binop = HBinaryOperation::cast(instr); 10947 binop->set_observed_input_representation(1, left_rep); 10948 binop->set_observed_input_representation(2, right_rep); 10949 binop->initialize_output_representation(result_rep); 10950 if (graph()->info()->IsStub()) { 10951 // Stub should not call into stub. 10952 instr->SetFlag(HValue::kCannotBeTagged); 10953 // And should truncate on HForceRepresentation already. 10954 if (left->IsForceRepresentation()) { 10955 left->CopyFlag(HValue::kTruncatingToSmi, instr); 10956 left->CopyFlag(HValue::kTruncatingToInt32, instr); 10957 } 10958 if (right->IsForceRepresentation()) { 10959 right->CopyFlag(HValue::kTruncatingToSmi, instr); 10960 right->CopyFlag(HValue::kTruncatingToInt32, instr); 10961 } 10962 } 10963 } 10964 return instr; 10965 } 10966 10967 10968 // Check for the form (%_ClassOf(foo) === 'BarClass'). 10969 static bool IsClassOfTest(CompareOperation* expr) { 10970 if (expr->op() != Token::EQ_STRICT) return false; 10971 CallRuntime* call = expr->left()->AsCallRuntime(); 10972 if (call == NULL) return false; 10973 Literal* literal = expr->right()->AsLiteral(); 10974 if (literal == NULL) return false; 10975 if (!literal->value()->IsString()) return false; 10976 if (!call->is_jsruntime() && 10977 call->function()->function_id != Runtime::kInlineClassOf) { 10978 return false; 10979 } 10980 DCHECK(call->arguments()->length() == 1); 10981 return true; 10982 } 10983 10984 10985 void HOptimizedGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { 10986 DCHECK(!HasStackOverflow()); 10987 DCHECK(current_block() != NULL); 10988 DCHECK(current_block()->HasPredecessor()); 10989 switch (expr->op()) { 10990 case Token::COMMA: 10991 return VisitComma(expr); 10992 case Token::OR: 10993 case Token::AND: 10994 return VisitLogicalExpression(expr); 10995 default: 10996 return VisitArithmeticExpression(expr); 10997 } 10998 } 10999 11000 11001 void HOptimizedGraphBuilder::VisitComma(BinaryOperation* expr) { 11002 CHECK_ALIVE(VisitForEffect(expr->left())); 11003 // Visit the right subexpression in the same AST context as the entire 11004 // expression. 11005 Visit(expr->right()); 11006 } 11007 11008 11009 void HOptimizedGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) { 11010 bool is_logical_and = expr->op() == Token::AND; 11011 if (ast_context()->IsTest()) { 11012 TestContext* context = TestContext::cast(ast_context()); 11013 // Translate left subexpression. 11014 HBasicBlock* eval_right = graph()->CreateBasicBlock(); 11015 if (is_logical_and) { 11016 CHECK_BAILOUT(VisitForControl(expr->left(), 11017 eval_right, 11018 context->if_false())); 11019 } else { 11020 CHECK_BAILOUT(VisitForControl(expr->left(), 11021 context->if_true(), 11022 eval_right)); 11023 } 11024 11025 // Translate right subexpression by visiting it in the same AST 11026 // context as the entire expression. 11027 CHECK(eval_right->HasPredecessor()); 11028 eval_right->SetJoinId(expr->RightId()); 11029 set_current_block(eval_right); 11030 Visit(expr->right()); 11031 } else if (ast_context()->IsValue()) { 11032 CHECK_ALIVE(VisitForValue(expr->left())); 11033 DCHECK(current_block() != NULL); 11034 HValue* left_value = Top(); 11035 11036 // Short-circuit left values that always evaluate to the same boolean value. 11037 if (expr->left()->ToBooleanIsTrue() || expr->left()->ToBooleanIsFalse()) { 11038 // l (evals true) && r -> r 11039 // l (evals true) || r -> l 11040 // l (evals false) && r -> l 11041 // l (evals false) || r -> r 11042 if (is_logical_and == expr->left()->ToBooleanIsTrue()) { 11043 Drop(1); 11044 CHECK_ALIVE(VisitForValue(expr->right())); 11045 } 11046 return ast_context()->ReturnValue(Pop()); 11047 } 11048 11049 // We need an extra block to maintain edge-split form. 11050 HBasicBlock* empty_block = graph()->CreateBasicBlock(); 11051 HBasicBlock* eval_right = graph()->CreateBasicBlock(); 11052 ToBooleanHints expected(expr->left()->to_boolean_types()); 11053 HBranch* test = is_logical_and 11054 ? New<HBranch>(left_value, expected, eval_right, empty_block) 11055 : New<HBranch>(left_value, expected, empty_block, eval_right); 11056 FinishCurrentBlock(test); 11057 11058 set_current_block(eval_right); 11059 Drop(1); // Value of the left subexpression. 11060 CHECK_BAILOUT(VisitForValue(expr->right())); 11061 11062 HBasicBlock* join_block = 11063 CreateJoin(empty_block, current_block(), expr->id()); 11064 set_current_block(join_block); 11065 return ast_context()->ReturnValue(Pop()); 11066 11067 } else { 11068 DCHECK(ast_context()->IsEffect()); 11069 // In an effect context, we don't need the value of the left subexpression, 11070 // only its control flow and side effects. We need an extra block to 11071 // maintain edge-split form. 11072 HBasicBlock* empty_block = graph()->CreateBasicBlock(); 11073 HBasicBlock* right_block = graph()->CreateBasicBlock(); 11074 if (is_logical_and) { 11075 CHECK_BAILOUT(VisitForControl(expr->left(), right_block, empty_block)); 11076 } else { 11077 CHECK_BAILOUT(VisitForControl(expr->left(), empty_block, right_block)); 11078 } 11079 11080 // TODO(kmillikin): Find a way to fix this. It's ugly that there are 11081 // actually two empty blocks (one here and one inserted by 11082 // TestContext::BuildBranch, and that they both have an HSimulate though the 11083 // second one is not a merge node, and that we really have no good AST ID to 11084 // put on that first HSimulate. 11085 11086 // Technically, we should be able to handle the case when one side of 11087 // the test is not connected, but this can trip up liveness analysis 11088 // if we did not fully connect the test context based on some optimistic 11089 // assumption. If such an assumption was violated, we would end up with 11090 // an environment with optimized-out values. So we should always 11091 // conservatively connect the test context. 11092 11093 CHECK(right_block->HasPredecessor()); 11094 CHECK(empty_block->HasPredecessor()); 11095 11096 empty_block->SetJoinId(expr->id()); 11097 11098 right_block->SetJoinId(expr->RightId()); 11099 set_current_block(right_block); 11100 CHECK_BAILOUT(VisitForEffect(expr->right())); 11101 right_block = current_block(); 11102 11103 HBasicBlock* join_block = 11104 CreateJoin(empty_block, right_block, expr->id()); 11105 set_current_block(join_block); 11106 // We did not materialize any value in the predecessor environments, 11107 // so there is no need to handle it here. 11108 } 11109 } 11110 11111 11112 void HOptimizedGraphBuilder::VisitArithmeticExpression(BinaryOperation* expr) { 11113 CHECK_ALIVE(VisitForValue(expr->left())); 11114 CHECK_ALIVE(VisitForValue(expr->right())); 11115 SetSourcePosition(expr->position()); 11116 HValue* right = Pop(); 11117 HValue* left = Pop(); 11118 HValue* result = 11119 BuildBinaryOperation(expr, left, right, 11120 ast_context()->IsEffect() ? NO_PUSH_BEFORE_SIMULATE 11121 : PUSH_BEFORE_SIMULATE); 11122 return ast_context()->ReturnValue(result); 11123 } 11124 11125 11126 void HOptimizedGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* expr, 11127 Expression* sub_expr, 11128 Handle<String> check) { 11129 CHECK_ALIVE(VisitForTypeOf(sub_expr)); 11130 SetSourcePosition(expr->position()); 11131 HValue* value = Pop(); 11132 HTypeofIsAndBranch* instr = New<HTypeofIsAndBranch>(value, check); 11133 return ast_context()->ReturnControl(instr, expr->id()); 11134 } 11135 11136 namespace { 11137 11138 bool IsLiteralCompareStrict(Isolate* isolate, HValue* left, Token::Value op, 11139 HValue* right) { 11140 return op == Token::EQ_STRICT && 11141 ((left->IsConstant() && 11142 !HConstant::cast(left)->handle(isolate)->IsNumber() && 11143 !HConstant::cast(left)->handle(isolate)->IsSimd128Value() && 11144 !HConstant::cast(left)->handle(isolate)->IsString()) || 11145 (right->IsConstant() && 11146 !HConstant::cast(right)->handle(isolate)->IsNumber() && 11147 !HConstant::cast(right)->handle(isolate)->IsSimd128Value() && 11148 !HConstant::cast(right)->handle(isolate)->IsString())); 11149 } 11150 11151 } // namespace 11152 11153 void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) { 11154 DCHECK(!HasStackOverflow()); 11155 DCHECK(current_block() != NULL); 11156 DCHECK(current_block()->HasPredecessor()); 11157 11158 if (!is_tracking_positions()) SetSourcePosition(expr->position()); 11159 11160 // Check for a few fast cases. The AST visiting behavior must be in sync 11161 // with the full codegen: We don't push both left and right values onto 11162 // the expression stack when one side is a special-case literal. 11163 Expression* sub_expr = NULL; 11164 Handle<String> check; 11165 if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) { 11166 return HandleLiteralCompareTypeof(expr, sub_expr, check); 11167 } 11168 if (expr->IsLiteralCompareUndefined(&sub_expr)) { 11169 return HandleLiteralCompareNil(expr, sub_expr, kUndefinedValue); 11170 } 11171 if (expr->IsLiteralCompareNull(&sub_expr)) { 11172 return HandleLiteralCompareNil(expr, sub_expr, kNullValue); 11173 } 11174 11175 if (IsClassOfTest(expr)) { 11176 CallRuntime* call = expr->left()->AsCallRuntime(); 11177 DCHECK(call->arguments()->length() == 1); 11178 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11179 HValue* value = Pop(); 11180 Literal* literal = expr->right()->AsLiteral(); 11181 Handle<String> rhs = Handle<String>::cast(literal->value()); 11182 HClassOfTestAndBranch* instr = New<HClassOfTestAndBranch>(value, rhs); 11183 return ast_context()->ReturnControl(instr, expr->id()); 11184 } 11185 11186 AstType* left_type = bounds_.get(expr->left()).lower; 11187 AstType* right_type = bounds_.get(expr->right()).lower; 11188 AstType* combined_type = expr->combined_type(); 11189 11190 CHECK_ALIVE(VisitForValue(expr->left())); 11191 CHECK_ALIVE(VisitForValue(expr->right())); 11192 11193 HValue* right = Pop(); 11194 HValue* left = Pop(); 11195 Token::Value op = expr->op(); 11196 11197 if (IsLiteralCompareStrict(isolate(), left, op, right)) { 11198 HCompareObjectEqAndBranch* result = 11199 New<HCompareObjectEqAndBranch>(left, right); 11200 return ast_context()->ReturnControl(result, expr->id()); 11201 } 11202 11203 if (op == Token::INSTANCEOF) { 11204 // Check to see if the rhs of the instanceof is a known function. 11205 if (right->IsConstant() && 11206 HConstant::cast(right)->handle(isolate())->IsJSFunction()) { 11207 Handle<JSFunction> function = 11208 Handle<JSFunction>::cast(HConstant::cast(right)->handle(isolate())); 11209 // Make sure that the {function} already has a meaningful initial map 11210 // (i.e. we constructed at least one instance using the constructor 11211 // {function}). 11212 if (function->has_initial_map()) { 11213 // Lookup @@hasInstance on the {function}. 11214 Handle<Map> function_map(function->map(), isolate()); 11215 PropertyAccessInfo has_instance( 11216 this, LOAD, function_map, 11217 isolate()->factory()->has_instance_symbol()); 11218 // Check if we are using the Function.prototype[@@hasInstance]. 11219 if (has_instance.CanAccessMonomorphic() && 11220 has_instance.IsDataConstant() && 11221 has_instance.constant().is_identical_to( 11222 isolate()->function_has_instance())) { 11223 // Add appropriate receiver map check and prototype chain 11224 // checks to guard the @@hasInstance lookup chain. 11225 AddCheckMap(right, function_map); 11226 if (has_instance.has_holder()) { 11227 Handle<JSObject> prototype( 11228 JSObject::cast(has_instance.map()->prototype()), isolate()); 11229 BuildCheckPrototypeMaps(prototype, has_instance.holder()); 11230 } 11231 // Perform the prototype chain walk. 11232 Handle<Map> initial_map(function->initial_map(), isolate()); 11233 top_info()->dependencies()->AssumeInitialMapCantChange(initial_map); 11234 HInstruction* prototype = 11235 Add<HConstant>(handle(initial_map->prototype(), isolate())); 11236 HHasInPrototypeChainAndBranch* result = 11237 New<HHasInPrototypeChainAndBranch>(left, prototype); 11238 return ast_context()->ReturnControl(result, expr->id()); 11239 } 11240 } 11241 } 11242 11243 Callable callable = CodeFactory::InstanceOf(isolate()); 11244 HValue* stub = Add<HConstant>(callable.code()); 11245 HValue* values[] = {left, right}; 11246 HCallWithDescriptor* result = New<HCallWithDescriptor>( 11247 stub, 0, callable.descriptor(), ArrayVector(values)); 11248 result->set_type(HType::Boolean()); 11249 return ast_context()->ReturnInstruction(result, expr->id()); 11250 11251 } else if (op == Token::IN) { 11252 Callable callable = CodeFactory::HasProperty(isolate()); 11253 HValue* stub = Add<HConstant>(callable.code()); 11254 HValue* values[] = {left, right}; 11255 HInstruction* result = 11256 New<HCallWithDescriptor>(stub, 0, callable.descriptor(), 11257 Vector<HValue*>(values, arraysize(values))); 11258 return ast_context()->ReturnInstruction(result, expr->id()); 11259 } 11260 11261 PushBeforeSimulateBehavior push_behavior = 11262 ast_context()->IsEffect() ? NO_PUSH_BEFORE_SIMULATE 11263 : PUSH_BEFORE_SIMULATE; 11264 HControlInstruction* compare = BuildCompareInstruction( 11265 op, left, right, left_type, right_type, combined_type, 11266 ScriptPositionToSourcePosition(expr->left()->position()), 11267 ScriptPositionToSourcePosition(expr->right()->position()), 11268 push_behavior, expr->id()); 11269 if (compare == NULL) return; // Bailed out. 11270 return ast_context()->ReturnControl(compare, expr->id()); 11271 } 11272 11273 HControlInstruction* HOptimizedGraphBuilder::BuildCompareInstruction( 11274 Token::Value op, HValue* left, HValue* right, AstType* left_type, 11275 AstType* right_type, AstType* combined_type, SourcePosition left_position, 11276 SourcePosition right_position, PushBeforeSimulateBehavior push_sim_result, 11277 BailoutId bailout_id) { 11278 // Cases handled below depend on collected type feedback. They should 11279 // soft deoptimize when there is no type feedback. 11280 if (!combined_type->IsInhabited()) { 11281 Add<HDeoptimize>( 11282 DeoptimizeReason:: 11283 kInsufficientTypeFeedbackForCombinedTypeOfBinaryOperation, 11284 Deoptimizer::SOFT); 11285 combined_type = left_type = right_type = AstType::Any(); 11286 } 11287 11288 Representation left_rep = RepresentationFor(left_type); 11289 Representation right_rep = RepresentationFor(right_type); 11290 Representation combined_rep = RepresentationFor(combined_type); 11291 11292 if (combined_type->Is(AstType::Receiver())) { 11293 if (Token::IsEqualityOp(op)) { 11294 // HCompareObjectEqAndBranch can only deal with object, so 11295 // exclude numbers. 11296 if ((left->IsConstant() && 11297 HConstant::cast(left)->HasNumberValue()) || 11298 (right->IsConstant() && 11299 HConstant::cast(right)->HasNumberValue())) { 11300 Add<HDeoptimize>( 11301 DeoptimizeReason::kTypeMismatchBetweenFeedbackAndConstant, 11302 Deoptimizer::SOFT); 11303 // The caller expects a branch instruction, so make it happy. 11304 return New<HBranch>(graph()->GetConstantTrue()); 11305 } 11306 if (op == Token::EQ) { 11307 // For abstract equality we need to check both sides are receivers. 11308 if (combined_type->IsClass()) { 11309 Handle<Map> map = combined_type->AsClass()->Map(); 11310 AddCheckMap(left, map); 11311 AddCheckMap(right, map); 11312 } else { 11313 BuildCheckHeapObject(left); 11314 Add<HCheckInstanceType>(left, HCheckInstanceType::IS_JS_RECEIVER); 11315 BuildCheckHeapObject(right); 11316 Add<HCheckInstanceType>(right, HCheckInstanceType::IS_JS_RECEIVER); 11317 } 11318 } else { 11319 // For strict equality we only need to check one side. 11320 HValue* operand_to_check = 11321 left->block()->block_id() < right->block()->block_id() ? left 11322 : right; 11323 if (combined_type->IsClass()) { 11324 Handle<Map> map = combined_type->AsClass()->Map(); 11325 AddCheckMap(operand_to_check, map); 11326 } else { 11327 BuildCheckHeapObject(operand_to_check); 11328 Add<HCheckInstanceType>(operand_to_check, 11329 HCheckInstanceType::IS_JS_RECEIVER); 11330 } 11331 } 11332 HCompareObjectEqAndBranch* result = 11333 New<HCompareObjectEqAndBranch>(left, right); 11334 return result; 11335 } else { 11336 if (combined_type->IsClass()) { 11337 // TODO(bmeurer): This is an optimized version of an x < y, x > y, 11338 // x <= y or x >= y, where both x and y are spec objects with the 11339 // same map. The CompareIC collects this map for us. So if we know 11340 // that there's no @@toPrimitive on the map (including the prototype 11341 // chain), and both valueOf and toString are the default initial 11342 // implementations (on the %ObjectPrototype%), then we can reduce 11343 // the comparison to map checks on x and y, because the comparison 11344 // will turn into a comparison of "[object CLASS]" to itself (the 11345 // default outcome of toString, since valueOf returns a spec object). 11346 // This is pretty much adhoc, so in TurboFan we could do a lot better 11347 // and inline the interesting parts of ToPrimitive (actually we could 11348 // even do that in Crankshaft but we don't want to waste too much 11349 // time on this now). 11350 DCHECK(Token::IsOrderedRelationalCompareOp(op)); 11351 Handle<Map> map = combined_type->AsClass()->Map(); 11352 PropertyAccessInfo value_of(this, LOAD, map, 11353 isolate()->factory()->valueOf_string()); 11354 PropertyAccessInfo to_primitive( 11355 this, LOAD, map, isolate()->factory()->to_primitive_symbol()); 11356 PropertyAccessInfo to_string(this, LOAD, map, 11357 isolate()->factory()->toString_string()); 11358 PropertyAccessInfo to_string_tag( 11359 this, LOAD, map, isolate()->factory()->to_string_tag_symbol()); 11360 if (to_primitive.CanAccessMonomorphic() && !to_primitive.IsFound() && 11361 to_string_tag.CanAccessMonomorphic() && 11362 (!to_string_tag.IsFound() || to_string_tag.IsData() || 11363 to_string_tag.IsDataConstant()) && 11364 value_of.CanAccessMonomorphic() && value_of.IsDataConstant() && 11365 value_of.constant().is_identical_to(isolate()->object_value_of()) && 11366 to_string.CanAccessMonomorphic() && to_string.IsDataConstant() && 11367 to_string.constant().is_identical_to( 11368 isolate()->object_to_string())) { 11369 // We depend on the prototype chain to stay the same, because we 11370 // also need to deoptimize when someone installs @@toPrimitive 11371 // or @@toStringTag somewhere in the prototype chain. 11372 Handle<Object> prototype(map->prototype(), isolate()); 11373 if (prototype->IsJSObject()) { 11374 BuildCheckPrototypeMaps(Handle<JSObject>::cast(prototype), 11375 Handle<JSObject>::null()); 11376 } 11377 AddCheckMap(left, map); 11378 AddCheckMap(right, map); 11379 // The caller expects a branch instruction, so make it happy. 11380 return New<HBranch>( 11381 graph()->GetConstantBool(op == Token::LTE || op == Token::GTE)); 11382 } 11383 } 11384 Bailout(kUnsupportedNonPrimitiveCompare); 11385 return NULL; 11386 } 11387 } else if (combined_type->Is(AstType::InternalizedString()) && 11388 Token::IsEqualityOp(op)) { 11389 // If we have a constant argument, it should be consistent with the type 11390 // feedback (otherwise we fail assertions in HCompareObjectEqAndBranch). 11391 if ((left->IsConstant() && 11392 !HConstant::cast(left)->HasInternalizedStringValue()) || 11393 (right->IsConstant() && 11394 !HConstant::cast(right)->HasInternalizedStringValue())) { 11395 Add<HDeoptimize>( 11396 DeoptimizeReason::kTypeMismatchBetweenFeedbackAndConstant, 11397 Deoptimizer::SOFT); 11398 // The caller expects a branch instruction, so make it happy. 11399 return New<HBranch>(graph()->GetConstantTrue()); 11400 } 11401 BuildCheckHeapObject(left); 11402 Add<HCheckInstanceType>(left, HCheckInstanceType::IS_INTERNALIZED_STRING); 11403 BuildCheckHeapObject(right); 11404 Add<HCheckInstanceType>(right, HCheckInstanceType::IS_INTERNALIZED_STRING); 11405 HCompareObjectEqAndBranch* result = 11406 New<HCompareObjectEqAndBranch>(left, right); 11407 return result; 11408 } else if (combined_type->Is(AstType::String())) { 11409 BuildCheckHeapObject(left); 11410 Add<HCheckInstanceType>(left, HCheckInstanceType::IS_STRING); 11411 BuildCheckHeapObject(right); 11412 Add<HCheckInstanceType>(right, HCheckInstanceType::IS_STRING); 11413 HStringCompareAndBranch* result = 11414 New<HStringCompareAndBranch>(left, right, op); 11415 return result; 11416 } else if (combined_type->Is(AstType::Boolean())) { 11417 AddCheckMap(left, isolate()->factory()->boolean_map()); 11418 AddCheckMap(right, isolate()->factory()->boolean_map()); 11419 if (Token::IsEqualityOp(op)) { 11420 HCompareObjectEqAndBranch* result = 11421 New<HCompareObjectEqAndBranch>(left, right); 11422 return result; 11423 } 11424 left = Add<HLoadNamedField>( 11425 left, nullptr, 11426 HObjectAccess::ForOddballToNumber(Representation::Smi())); 11427 right = Add<HLoadNamedField>( 11428 right, nullptr, 11429 HObjectAccess::ForOddballToNumber(Representation::Smi())); 11430 HCompareNumericAndBranch* result = 11431 New<HCompareNumericAndBranch>(left, right, op); 11432 return result; 11433 } else { 11434 if (op == Token::EQ) { 11435 if (left->IsConstant() && 11436 HConstant::cast(left)->GetInstanceType() == ODDBALL_TYPE && 11437 HConstant::cast(left)->IsUndetectable()) { 11438 return New<HIsUndetectableAndBranch>(right); 11439 } 11440 11441 if (right->IsConstant() && 11442 HConstant::cast(right)->GetInstanceType() == ODDBALL_TYPE && 11443 HConstant::cast(right)->IsUndetectable()) { 11444 return New<HIsUndetectableAndBranch>(left); 11445 } 11446 } 11447 11448 if (combined_rep.IsTagged() || combined_rep.IsNone()) { 11449 HCompareGeneric* result = Add<HCompareGeneric>(left, right, op); 11450 result->set_observed_input_representation(1, left_rep); 11451 result->set_observed_input_representation(2, right_rep); 11452 if (result->HasObservableSideEffects()) { 11453 if (push_sim_result == PUSH_BEFORE_SIMULATE) { 11454 Push(result); 11455 AddSimulate(bailout_id, REMOVABLE_SIMULATE); 11456 Drop(1); 11457 } else { 11458 AddSimulate(bailout_id, REMOVABLE_SIMULATE); 11459 } 11460 } 11461 // TODO(jkummerow): Can we make this more efficient? 11462 HBranch* branch = New<HBranch>(result); 11463 return branch; 11464 } else { 11465 HCompareNumericAndBranch* result = 11466 New<HCompareNumericAndBranch>(left, right, op); 11467 result->set_observed_input_representation(left_rep, right_rep); 11468 return result; 11469 } 11470 } 11471 } 11472 11473 11474 void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr, 11475 Expression* sub_expr, 11476 NilValue nil) { 11477 DCHECK(!HasStackOverflow()); 11478 DCHECK(current_block() != NULL); 11479 DCHECK(current_block()->HasPredecessor()); 11480 DCHECK(expr->op() == Token::EQ || expr->op() == Token::EQ_STRICT); 11481 if (!is_tracking_positions()) SetSourcePosition(expr->position()); 11482 CHECK_ALIVE(VisitForValue(sub_expr)); 11483 HValue* value = Pop(); 11484 HControlInstruction* instr; 11485 if (expr->op() == Token::EQ_STRICT) { 11486 HConstant* nil_constant = nil == kNullValue 11487 ? graph()->GetConstantNull() 11488 : graph()->GetConstantUndefined(); 11489 instr = New<HCompareObjectEqAndBranch>(value, nil_constant); 11490 } else { 11491 DCHECK_EQ(Token::EQ, expr->op()); 11492 instr = New<HIsUndetectableAndBranch>(value); 11493 } 11494 return ast_context()->ReturnControl(instr, expr->id()); 11495 } 11496 11497 11498 void HOptimizedGraphBuilder::VisitSpread(Spread* expr) { UNREACHABLE(); } 11499 11500 11501 void HOptimizedGraphBuilder::VisitEmptyParentheses(EmptyParentheses* expr) { 11502 UNREACHABLE(); 11503 } 11504 11505 11506 HValue* HOptimizedGraphBuilder::AddThisFunction() { 11507 return AddInstruction(BuildThisFunction()); 11508 } 11509 11510 11511 HInstruction* HOptimizedGraphBuilder::BuildThisFunction() { 11512 // If we share optimized code between different closures, the 11513 // this-function is not a constant, except inside an inlined body. 11514 if (function_state()->outer() != NULL) { 11515 return New<HConstant>( 11516 function_state()->compilation_info()->closure()); 11517 } else { 11518 return New<HThisFunction>(); 11519 } 11520 } 11521 11522 11523 HInstruction* HOptimizedGraphBuilder::BuildFastLiteral( 11524 Handle<JSObject> boilerplate_object, 11525 AllocationSiteUsageContext* site_context) { 11526 NoObservableSideEffectsScope no_effects(this); 11527 Handle<Map> initial_map(boilerplate_object->map()); 11528 InstanceType instance_type = initial_map->instance_type(); 11529 DCHECK(instance_type == JS_ARRAY_TYPE || instance_type == JS_OBJECT_TYPE); 11530 11531 HType type = instance_type == JS_ARRAY_TYPE 11532 ? HType::JSArray() : HType::JSObject(); 11533 HValue* object_size_constant = Add<HConstant>(initial_map->instance_size()); 11534 11535 PretenureFlag pretenure_flag = NOT_TENURED; 11536 Handle<AllocationSite> top_site(*site_context->top(), isolate()); 11537 if (FLAG_allocation_site_pretenuring) { 11538 pretenure_flag = top_site->GetPretenureMode(); 11539 } 11540 11541 Handle<AllocationSite> current_site(*site_context->current(), isolate()); 11542 if (*top_site == *current_site) { 11543 // We install a dependency for pretenuring only on the outermost literal. 11544 top_info()->dependencies()->AssumeTenuringDecision(top_site); 11545 } 11546 top_info()->dependencies()->AssumeTransitionStable(current_site); 11547 11548 HInstruction* object = 11549 Add<HAllocate>(object_size_constant, type, pretenure_flag, instance_type, 11550 graph()->GetConstant0(), top_site); 11551 11552 // If allocation folding reaches kMaxRegularHeapObjectSize the 11553 // elements array may not get folded into the object. Hence, we set the 11554 // elements pointer to empty fixed array and let store elimination remove 11555 // this store in the folding case. 11556 HConstant* empty_fixed_array = Add<HConstant>( 11557 isolate()->factory()->empty_fixed_array()); 11558 Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(), 11559 empty_fixed_array); 11560 11561 BuildEmitObjectHeader(boilerplate_object, object); 11562 11563 // Similarly to the elements pointer, there is no guarantee that all 11564 // property allocations can get folded, so pre-initialize all in-object 11565 // properties to a safe value. 11566 BuildInitializeInobjectProperties(object, initial_map); 11567 11568 Handle<FixedArrayBase> elements(boilerplate_object->elements()); 11569 int elements_size = (elements->length() > 0 && 11570 elements->map() != isolate()->heap()->fixed_cow_array_map()) ? 11571 elements->Size() : 0; 11572 11573 if (pretenure_flag == TENURED && 11574 elements->map() == isolate()->heap()->fixed_cow_array_map() && 11575 isolate()->heap()->InNewSpace(*elements)) { 11576 // If we would like to pretenure a fixed cow array, we must ensure that the 11577 // array is already in old space, otherwise we'll create too many old-to- 11578 // new-space pointers (overflowing the store buffer). 11579 elements = Handle<FixedArrayBase>( 11580 isolate()->factory()->CopyAndTenureFixedCOWArray( 11581 Handle<FixedArray>::cast(elements))); 11582 boilerplate_object->set_elements(*elements); 11583 } 11584 11585 HInstruction* object_elements = NULL; 11586 if (elements_size > 0) { 11587 HValue* object_elements_size = Add<HConstant>(elements_size); 11588 InstanceType instance_type = boilerplate_object->HasFastDoubleElements() 11589 ? FIXED_DOUBLE_ARRAY_TYPE : FIXED_ARRAY_TYPE; 11590 object_elements = Add<HAllocate>(object_elements_size, HType::HeapObject(), 11591 pretenure_flag, instance_type, 11592 graph()->GetConstant0(), top_site); 11593 BuildEmitElements(boilerplate_object, elements, object_elements, 11594 site_context); 11595 Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(), 11596 object_elements); 11597 } else { 11598 Handle<Object> elements_field = 11599 Handle<Object>(boilerplate_object->elements(), isolate()); 11600 HInstruction* object_elements_cow = Add<HConstant>(elements_field); 11601 Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(), 11602 object_elements_cow); 11603 } 11604 11605 // Copy in-object properties. 11606 if (initial_map->NumberOfFields() != 0 || 11607 initial_map->unused_property_fields() > 0) { 11608 BuildEmitInObjectProperties(boilerplate_object, object, site_context, 11609 pretenure_flag); 11610 } 11611 return object; 11612 } 11613 11614 11615 void HOptimizedGraphBuilder::BuildEmitObjectHeader( 11616 Handle<JSObject> boilerplate_object, 11617 HInstruction* object) { 11618 DCHECK(boilerplate_object->properties()->length() == 0); 11619 11620 Handle<Map> boilerplate_object_map(boilerplate_object->map()); 11621 AddStoreMapConstant(object, boilerplate_object_map); 11622 11623 Handle<Object> properties_field = 11624 Handle<Object>(boilerplate_object->properties(), isolate()); 11625 DCHECK(*properties_field == isolate()->heap()->empty_fixed_array()); 11626 HInstruction* properties = Add<HConstant>(properties_field); 11627 HObjectAccess access = HObjectAccess::ForPropertiesPointer(); 11628 Add<HStoreNamedField>(object, access, properties); 11629 11630 if (boilerplate_object->IsJSArray()) { 11631 Handle<JSArray> boilerplate_array = 11632 Handle<JSArray>::cast(boilerplate_object); 11633 Handle<Object> length_field = 11634 Handle<Object>(boilerplate_array->length(), isolate()); 11635 HInstruction* length = Add<HConstant>(length_field); 11636 11637 DCHECK(boilerplate_array->length()->IsSmi()); 11638 Add<HStoreNamedField>(object, HObjectAccess::ForArrayLength( 11639 boilerplate_array->GetElementsKind()), length); 11640 } 11641 } 11642 11643 11644 void HOptimizedGraphBuilder::BuildEmitInObjectProperties( 11645 Handle<JSObject> boilerplate_object, 11646 HInstruction* object, 11647 AllocationSiteUsageContext* site_context, 11648 PretenureFlag pretenure_flag) { 11649 Handle<Map> boilerplate_map(boilerplate_object->map()); 11650 Handle<DescriptorArray> descriptors(boilerplate_map->instance_descriptors()); 11651 int limit = boilerplate_map->NumberOfOwnDescriptors(); 11652 11653 int copied_fields = 0; 11654 for (int i = 0; i < limit; i++) { 11655 PropertyDetails details = descriptors->GetDetails(i); 11656 if (details.type() != DATA) continue; 11657 copied_fields++; 11658 FieldIndex field_index = FieldIndex::ForDescriptor(*boilerplate_map, i); 11659 11660 11661 int property_offset = field_index.offset(); 11662 Handle<Name> name(descriptors->GetKey(i)); 11663 11664 // The access for the store depends on the type of the boilerplate. 11665 HObjectAccess access = boilerplate_object->IsJSArray() ? 11666 HObjectAccess::ForJSArrayOffset(property_offset) : 11667 HObjectAccess::ForMapAndOffset(boilerplate_map, property_offset); 11668 11669 if (boilerplate_object->IsUnboxedDoubleField(field_index)) { 11670 CHECK(!boilerplate_object->IsJSArray()); 11671 double value = boilerplate_object->RawFastDoublePropertyAt(field_index); 11672 access = access.WithRepresentation(Representation::Double()); 11673 Add<HStoreNamedField>(object, access, Add<HConstant>(value)); 11674 continue; 11675 } 11676 Handle<Object> value(boilerplate_object->RawFastPropertyAt(field_index), 11677 isolate()); 11678 11679 if (value->IsJSObject()) { 11680 Handle<JSObject> value_object = Handle<JSObject>::cast(value); 11681 Handle<AllocationSite> current_site = site_context->EnterNewScope(); 11682 HInstruction* result = 11683 BuildFastLiteral(value_object, site_context); 11684 site_context->ExitScope(current_site, value_object); 11685 Add<HStoreNamedField>(object, access, result); 11686 } else { 11687 Representation representation = details.representation(); 11688 HInstruction* value_instruction; 11689 11690 if (representation.IsDouble()) { 11691 // Allocate a HeapNumber box and store the value into it. 11692 HValue* heap_number_constant = Add<HConstant>(HeapNumber::kSize); 11693 HInstruction* double_box = Add<HAllocate>( 11694 heap_number_constant, HType::HeapObject(), pretenure_flag, 11695 MUTABLE_HEAP_NUMBER_TYPE, graph()->GetConstant0()); 11696 AddStoreMapConstant(double_box, 11697 isolate()->factory()->mutable_heap_number_map()); 11698 // Unwrap the mutable heap number from the boilerplate. 11699 HValue* double_value = 11700 Add<HConstant>(Handle<HeapNumber>::cast(value)->value()); 11701 Add<HStoreNamedField>( 11702 double_box, HObjectAccess::ForHeapNumberValue(), double_value); 11703 value_instruction = double_box; 11704 } else if (representation.IsSmi()) { 11705 value_instruction = value->IsUninitialized(isolate()) 11706 ? graph()->GetConstant0() 11707 : Add<HConstant>(value); 11708 // Ensure that value is stored as smi. 11709 access = access.WithRepresentation(representation); 11710 } else { 11711 value_instruction = Add<HConstant>(value); 11712 } 11713 11714 Add<HStoreNamedField>(object, access, value_instruction); 11715 } 11716 } 11717 11718 int inobject_properties = boilerplate_object->map()->GetInObjectProperties(); 11719 HInstruction* value_instruction = 11720 Add<HConstant>(isolate()->factory()->one_pointer_filler_map()); 11721 for (int i = copied_fields; i < inobject_properties; i++) { 11722 DCHECK(boilerplate_object->IsJSObject()); 11723 int property_offset = boilerplate_object->GetInObjectPropertyOffset(i); 11724 HObjectAccess access = 11725 HObjectAccess::ForMapAndOffset(boilerplate_map, property_offset); 11726 Add<HStoreNamedField>(object, access, value_instruction); 11727 } 11728 } 11729 11730 11731 void HOptimizedGraphBuilder::BuildEmitElements( 11732 Handle<JSObject> boilerplate_object, 11733 Handle<FixedArrayBase> elements, 11734 HValue* object_elements, 11735 AllocationSiteUsageContext* site_context) { 11736 ElementsKind kind = boilerplate_object->map()->elements_kind(); 11737 int elements_length = elements->length(); 11738 HValue* object_elements_length = Add<HConstant>(elements_length); 11739 BuildInitializeElementsHeader(object_elements, kind, object_elements_length); 11740 11741 // Copy elements backing store content. 11742 if (elements->IsFixedDoubleArray()) { 11743 BuildEmitFixedDoubleArray(elements, kind, object_elements); 11744 } else if (elements->IsFixedArray()) { 11745 BuildEmitFixedArray(elements, kind, object_elements, 11746 site_context); 11747 } else { 11748 UNREACHABLE(); 11749 } 11750 } 11751 11752 11753 void HOptimizedGraphBuilder::BuildEmitFixedDoubleArray( 11754 Handle<FixedArrayBase> elements, 11755 ElementsKind kind, 11756 HValue* object_elements) { 11757 HInstruction* boilerplate_elements = Add<HConstant>(elements); 11758 int elements_length = elements->length(); 11759 for (int i = 0; i < elements_length; i++) { 11760 HValue* key_constant = Add<HConstant>(i); 11761 HInstruction* value_instruction = 11762 Add<HLoadKeyed>(boilerplate_elements, key_constant, nullptr, nullptr, 11763 kind, ALLOW_RETURN_HOLE); 11764 HInstruction* store = Add<HStoreKeyed>(object_elements, key_constant, 11765 value_instruction, nullptr, kind); 11766 store->SetFlag(HValue::kTruncatingToNumber); 11767 } 11768 } 11769 11770 11771 void HOptimizedGraphBuilder::BuildEmitFixedArray( 11772 Handle<FixedArrayBase> elements, 11773 ElementsKind kind, 11774 HValue* object_elements, 11775 AllocationSiteUsageContext* site_context) { 11776 HInstruction* boilerplate_elements = Add<HConstant>(elements); 11777 int elements_length = elements->length(); 11778 Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements); 11779 for (int i = 0; i < elements_length; i++) { 11780 Handle<Object> value(fast_elements->get(i), isolate()); 11781 HValue* key_constant = Add<HConstant>(i); 11782 if (value->IsJSObject()) { 11783 Handle<JSObject> value_object = Handle<JSObject>::cast(value); 11784 Handle<AllocationSite> current_site = site_context->EnterNewScope(); 11785 HInstruction* result = 11786 BuildFastLiteral(value_object, site_context); 11787 site_context->ExitScope(current_site, value_object); 11788 Add<HStoreKeyed>(object_elements, key_constant, result, nullptr, kind); 11789 } else { 11790 ElementsKind copy_kind = 11791 kind == FAST_HOLEY_SMI_ELEMENTS ? FAST_HOLEY_ELEMENTS : kind; 11792 HInstruction* value_instruction = 11793 Add<HLoadKeyed>(boilerplate_elements, key_constant, nullptr, nullptr, 11794 copy_kind, ALLOW_RETURN_HOLE); 11795 Add<HStoreKeyed>(object_elements, key_constant, value_instruction, 11796 nullptr, copy_kind); 11797 } 11798 } 11799 } 11800 11801 11802 void HOptimizedGraphBuilder::VisitThisFunction(ThisFunction* expr) { 11803 DCHECK(!HasStackOverflow()); 11804 DCHECK(current_block() != NULL); 11805 DCHECK(current_block()->HasPredecessor()); 11806 HInstruction* instr = BuildThisFunction(); 11807 return ast_context()->ReturnInstruction(instr, expr->id()); 11808 } 11809 11810 11811 void HOptimizedGraphBuilder::VisitSuperPropertyReference( 11812 SuperPropertyReference* expr) { 11813 DCHECK(!HasStackOverflow()); 11814 DCHECK(current_block() != NULL); 11815 DCHECK(current_block()->HasPredecessor()); 11816 return Bailout(kSuperReference); 11817 } 11818 11819 11820 void HOptimizedGraphBuilder::VisitSuperCallReference(SuperCallReference* expr) { 11821 DCHECK(!HasStackOverflow()); 11822 DCHECK(current_block() != NULL); 11823 DCHECK(current_block()->HasPredecessor()); 11824 return Bailout(kSuperReference); 11825 } 11826 11827 void HOptimizedGraphBuilder::VisitDeclarations( 11828 Declaration::List* declarations) { 11829 DCHECK(globals_.is_empty()); 11830 AstVisitor<HOptimizedGraphBuilder>::VisitDeclarations(declarations); 11831 if (!globals_.is_empty()) { 11832 Handle<FixedArray> array = 11833 isolate()->factory()->NewFixedArray(globals_.length(), TENURED); 11834 for (int i = 0; i < globals_.length(); ++i) array->set(i, *globals_.at(i)); 11835 int flags = current_info()->GetDeclareGlobalsFlags(); 11836 Handle<TypeFeedbackVector> vector(current_feedback_vector(), isolate()); 11837 Add<HDeclareGlobals>(array, flags, vector); 11838 globals_.Rewind(0); 11839 } 11840 } 11841 11842 11843 void HOptimizedGraphBuilder::VisitVariableDeclaration( 11844 VariableDeclaration* declaration) { 11845 VariableProxy* proxy = declaration->proxy(); 11846 Variable* variable = proxy->var(); 11847 switch (variable->location()) { 11848 case VariableLocation::UNALLOCATED: { 11849 DCHECK(!variable->binding_needs_init()); 11850 FeedbackVectorSlot slot = proxy->VariableFeedbackSlot(); 11851 DCHECK(!slot.IsInvalid()); 11852 globals_.Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone()); 11853 globals_.Add(isolate()->factory()->undefined_value(), zone()); 11854 return; 11855 } 11856 case VariableLocation::PARAMETER: 11857 case VariableLocation::LOCAL: 11858 if (variable->binding_needs_init()) { 11859 HValue* value = graph()->GetConstantHole(); 11860 environment()->Bind(variable, value); 11861 } 11862 break; 11863 case VariableLocation::CONTEXT: 11864 if (variable->binding_needs_init()) { 11865 HValue* value = graph()->GetConstantHole(); 11866 HValue* context = environment()->context(); 11867 HStoreContextSlot* store = Add<HStoreContextSlot>( 11868 context, variable->index(), HStoreContextSlot::kNoCheck, value); 11869 if (store->HasObservableSideEffects()) { 11870 Add<HSimulate>(proxy->id(), REMOVABLE_SIMULATE); 11871 } 11872 } 11873 break; 11874 case VariableLocation::LOOKUP: 11875 return Bailout(kUnsupportedLookupSlotInDeclaration); 11876 case VariableLocation::MODULE: 11877 UNREACHABLE(); 11878 } 11879 } 11880 11881 11882 void HOptimizedGraphBuilder::VisitFunctionDeclaration( 11883 FunctionDeclaration* declaration) { 11884 VariableProxy* proxy = declaration->proxy(); 11885 Variable* variable = proxy->var(); 11886 switch (variable->location()) { 11887 case VariableLocation::UNALLOCATED: { 11888 FeedbackVectorSlot slot = proxy->VariableFeedbackSlot(); 11889 DCHECK(!slot.IsInvalid()); 11890 globals_.Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone()); 11891 Handle<SharedFunctionInfo> function = Compiler::GetSharedFunctionInfo( 11892 declaration->fun(), current_info()->script(), top_info()); 11893 // Check for stack-overflow exception. 11894 if (function.is_null()) return SetStackOverflow(); 11895 globals_.Add(function, zone()); 11896 return; 11897 } 11898 case VariableLocation::PARAMETER: 11899 case VariableLocation::LOCAL: { 11900 CHECK_ALIVE(VisitForValue(declaration->fun())); 11901 HValue* value = Pop(); 11902 BindIfLive(variable, value); 11903 break; 11904 } 11905 case VariableLocation::CONTEXT: { 11906 CHECK_ALIVE(VisitForValue(declaration->fun())); 11907 HValue* value = Pop(); 11908 HValue* context = environment()->context(); 11909 HStoreContextSlot* store = Add<HStoreContextSlot>( 11910 context, variable->index(), HStoreContextSlot::kNoCheck, value); 11911 if (store->HasObservableSideEffects()) { 11912 Add<HSimulate>(proxy->id(), REMOVABLE_SIMULATE); 11913 } 11914 break; 11915 } 11916 case VariableLocation::LOOKUP: 11917 return Bailout(kUnsupportedLookupSlotInDeclaration); 11918 case VariableLocation::MODULE: 11919 UNREACHABLE(); 11920 } 11921 } 11922 11923 11924 void HOptimizedGraphBuilder::VisitRewritableExpression( 11925 RewritableExpression* node) { 11926 CHECK_ALIVE(Visit(node->expression())); 11927 } 11928 11929 11930 // Generators for inline runtime functions. 11931 // Support for types. 11932 void HOptimizedGraphBuilder::GenerateIsSmi(CallRuntime* call) { 11933 DCHECK(call->arguments()->length() == 1); 11934 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11935 HValue* value = Pop(); 11936 HIsSmiAndBranch* result = New<HIsSmiAndBranch>(value); 11937 return ast_context()->ReturnControl(result, call->id()); 11938 } 11939 11940 11941 void HOptimizedGraphBuilder::GenerateIsJSReceiver(CallRuntime* call) { 11942 DCHECK(call->arguments()->length() == 1); 11943 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11944 HValue* value = Pop(); 11945 HHasInstanceTypeAndBranch* result = 11946 New<HHasInstanceTypeAndBranch>(value, 11947 FIRST_JS_RECEIVER_TYPE, 11948 LAST_JS_RECEIVER_TYPE); 11949 return ast_context()->ReturnControl(result, call->id()); 11950 } 11951 11952 void HOptimizedGraphBuilder::GenerateIsArray(CallRuntime* call) { 11953 DCHECK(call->arguments()->length() == 1); 11954 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11955 HValue* value = Pop(); 11956 HHasInstanceTypeAndBranch* result = 11957 New<HHasInstanceTypeAndBranch>(value, JS_ARRAY_TYPE); 11958 return ast_context()->ReturnControl(result, call->id()); 11959 } 11960 11961 11962 void HOptimizedGraphBuilder::GenerateIsTypedArray(CallRuntime* call) { 11963 DCHECK(call->arguments()->length() == 1); 11964 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11965 HValue* value = Pop(); 11966 HHasInstanceTypeAndBranch* result = 11967 New<HHasInstanceTypeAndBranch>(value, JS_TYPED_ARRAY_TYPE); 11968 return ast_context()->ReturnControl(result, call->id()); 11969 } 11970 11971 11972 void HOptimizedGraphBuilder::GenerateIsRegExp(CallRuntime* call) { 11973 DCHECK(call->arguments()->length() == 1); 11974 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11975 HValue* value = Pop(); 11976 HHasInstanceTypeAndBranch* result = 11977 New<HHasInstanceTypeAndBranch>(value, JS_REGEXP_TYPE); 11978 return ast_context()->ReturnControl(result, call->id()); 11979 } 11980 11981 11982 void HOptimizedGraphBuilder::GenerateToInteger(CallRuntime* call) { 11983 DCHECK_EQ(1, call->arguments()->length()); 11984 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11985 HValue* input = Pop(); 11986 if (input->type().IsSmi()) { 11987 return ast_context()->ReturnValue(input); 11988 } else { 11989 Callable callable = CodeFactory::ToInteger(isolate()); 11990 HValue* stub = Add<HConstant>(callable.code()); 11991 HValue* values[] = {input}; 11992 HInstruction* result = New<HCallWithDescriptor>( 11993 stub, 0, callable.descriptor(), ArrayVector(values)); 11994 return ast_context()->ReturnInstruction(result, call->id()); 11995 } 11996 } 11997 11998 11999 void HOptimizedGraphBuilder::GenerateToObject(CallRuntime* call) { 12000 DCHECK_EQ(1, call->arguments()->length()); 12001 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 12002 HValue* value = Pop(); 12003 HValue* result = BuildToObject(value); 12004 return ast_context()->ReturnValue(result); 12005 } 12006 12007 12008 void HOptimizedGraphBuilder::GenerateToString(CallRuntime* call) { 12009 DCHECK_EQ(1, call->arguments()->length()); 12010 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 12011 HValue* input = Pop(); 12012 if (input->type().IsString()) { 12013 return ast_context()->ReturnValue(input); 12014 } else { 12015 Callable callable = CodeFactory::ToString(isolate()); 12016 HValue* stub = Add<HConstant>(callable.code()); 12017 HValue* values[] = {input}; 12018 HInstruction* result = New<HCallWithDescriptor>( 12019 stub, 0, callable.descriptor(), ArrayVector(values)); 12020 return ast_context()->ReturnInstruction(result, call->id()); 12021 } 12022 } 12023 12024 12025 void HOptimizedGraphBuilder::GenerateToLength(CallRuntime* call) { 12026 DCHECK_EQ(1, call->arguments()->length()); 12027 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 12028 Callable callable = CodeFactory::ToLength(isolate()); 12029 HValue* input = Pop(); 12030 HValue* stub = Add<HConstant>(callable.code()); 12031 HValue* values[] = {input}; 12032 HInstruction* result = New<HCallWithDescriptor>( 12033 stub, 0, callable.descriptor(), ArrayVector(values)); 12034 return ast_context()->ReturnInstruction(result, call->id()); 12035 } 12036 12037 12038 void HOptimizedGraphBuilder::GenerateToNumber(CallRuntime* call) { 12039 DCHECK_EQ(1, call->arguments()->length()); 12040 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 12041 Callable callable = CodeFactory::ToNumber(isolate()); 12042 HValue* input = Pop(); 12043 HValue* result = BuildToNumber(input); 12044 if (result->HasObservableSideEffects()) { 12045 if (!ast_context()->IsEffect()) Push(result); 12046 Add<HSimulate>(call->id(), REMOVABLE_SIMULATE); 12047 if (!ast_context()->IsEffect()) result = Pop(); 12048 } 12049 return ast_context()->ReturnValue(result); 12050 } 12051 12052 12053 void HOptimizedGraphBuilder::GenerateIsJSProxy(CallRuntime* call) { 12054 DCHECK(call->arguments()->length() == 1); 12055 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 12056 HValue* value = Pop(); 12057 HIfContinuation continuation; 12058 IfBuilder if_proxy(this); 12059 12060 HValue* smicheck = if_proxy.IfNot<HIsSmiAndBranch>(value); 12061 if_proxy.And(); 12062 HValue* map = Add<HLoadNamedField>(value, smicheck, HObjectAccess::ForMap()); 12063 HValue* instance_type = 12064 Add<HLoadNamedField>(map, nullptr, HObjectAccess::ForMapInstanceType()); 12065 if_proxy.If<HCompareNumericAndBranch>( 12066 instance_type, Add<HConstant>(JS_PROXY_TYPE), Token::EQ); 12067 12068 if_proxy.CaptureContinuation(&continuation); 12069 return ast_context()->ReturnContinuation(&continuation, call->id()); 12070 } 12071 12072 12073 void HOptimizedGraphBuilder::GenerateHasFastPackedElements(CallRuntime* call) { 12074 DCHECK(call->arguments()->length() == 1); 12075 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 12076 HValue* object = Pop(); 12077 HIfContinuation continuation(graph()->CreateBasicBlock(), 12078 graph()->CreateBasicBlock()); 12079 IfBuilder if_not_smi(this); 12080 if_not_smi.IfNot<HIsSmiAndBranch>(object); 12081 if_not_smi.Then(); 12082 { 12083 NoObservableSideEffectsScope no_effects(this); 12084 12085 IfBuilder if_fast_packed(this); 12086 HValue* elements_kind = BuildGetElementsKind(object); 12087 if_fast_packed.If<HCompareNumericAndBranch>( 12088 elements_kind, Add<HConstant>(FAST_SMI_ELEMENTS), Token::EQ); 12089 if_fast_packed.Or(); 12090 if_fast_packed.If<HCompareNumericAndBranch>( 12091 elements_kind, Add<HConstant>(FAST_ELEMENTS), Token::EQ); 12092 if_fast_packed.Or(); 12093 if_fast_packed.If<HCompareNumericAndBranch>( 12094 elements_kind, Add<HConstant>(FAST_DOUBLE_ELEMENTS), Token::EQ); 12095 if_fast_packed.JoinContinuation(&continuation); 12096 } 12097 if_not_smi.JoinContinuation(&continuation); 12098 return ast_context()->ReturnContinuation(&continuation, call->id()); 12099 } 12100 12101 12102 // Fast support for charCodeAt(n). 12103 void HOptimizedGraphBuilder::GenerateStringCharCodeAt(CallRuntime* call) { 12104 DCHECK(call->arguments()->length() == 2); 12105 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 12106 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); 12107 HValue* index = Pop(); 12108 HValue* string = Pop(); 12109 HInstruction* result = BuildStringCharCodeAt(string, index); 12110 return ast_context()->ReturnInstruction(result, call->id()); 12111 } 12112 12113 12114 // Fast support for SubString. 12115 void HOptimizedGraphBuilder::GenerateSubString(CallRuntime* call) { 12116 DCHECK_EQ(3, call->arguments()->length()); 12117 CHECK_ALIVE(VisitExpressions(call->arguments())); 12118 Callable callable = CodeFactory::SubString(isolate()); 12119 HValue* stub = Add<HConstant>(callable.code()); 12120 HValue* to = Pop(); 12121 HValue* from = Pop(); 12122 HValue* string = Pop(); 12123 HValue* values[] = {string, from, to}; 12124 HInstruction* result = New<HCallWithDescriptor>( 12125 stub, 0, callable.descriptor(), ArrayVector(values)); 12126 result->set_type(HType::String()); 12127 return ast_context()->ReturnInstruction(result, call->id()); 12128 } 12129 12130 // Support for direct creation of new objects. 12131 void HOptimizedGraphBuilder::GenerateNewObject(CallRuntime* call) { 12132 DCHECK_EQ(2, call->arguments()->length()); 12133 CHECK_ALIVE(VisitExpressions(call->arguments())); 12134 FastNewObjectStub stub(isolate()); 12135 FastNewObjectDescriptor descriptor(isolate()); 12136 HValue* values[] = {Pop(), Pop()}; 12137 HConstant* stub_value = Add<HConstant>(stub.GetCode()); 12138 HInstruction* result = 12139 New<HCallWithDescriptor>(stub_value, 0, descriptor, ArrayVector(values)); 12140 return ast_context()->ReturnInstruction(result, call->id()); 12141 } 12142 12143 // Support for direct calls from JavaScript to native RegExp code. 12144 void HOptimizedGraphBuilder::GenerateRegExpExec(CallRuntime* call) { 12145 DCHECK_EQ(4, call->arguments()->length()); 12146 CHECK_ALIVE(VisitExpressions(call->arguments())); 12147 Callable callable = CodeFactory::RegExpExec(isolate()); 12148 HValue* last_match_info = Pop(); 12149 HValue* index = Pop(); 12150 HValue* subject = Pop(); 12151 HValue* regexp_object = Pop(); 12152 HValue* stub = Add<HConstant>(callable.code()); 12153 HValue* values[] = {regexp_object, subject, index, last_match_info}; 12154 HInstruction* result = New<HCallWithDescriptor>( 12155 stub, 0, callable.descriptor(), ArrayVector(values)); 12156 return ast_context()->ReturnInstruction(result, call->id()); 12157 } 12158 12159 12160 // Fast support for number to string. 12161 void HOptimizedGraphBuilder::GenerateNumberToString(CallRuntime* call) { 12162 DCHECK_EQ(1, call->arguments()->length()); 12163 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 12164 HValue* number = Pop(); 12165 HValue* result = BuildNumberToString(number, AstType::Any()); 12166 return ast_context()->ReturnValue(result); 12167 } 12168 12169 12170 // Fast support for calls. 12171 void HOptimizedGraphBuilder::GenerateCall(CallRuntime* call) { 12172 DCHECK_LE(2, call->arguments()->length()); 12173 CHECK_ALIVE(VisitExpressions(call->arguments())); 12174 CallTrampolineDescriptor descriptor(isolate()); 12175 PushArgumentsFromEnvironment(call->arguments()->length() - 1); 12176 HValue* trampoline = Add<HConstant>(isolate()->builtins()->Call()); 12177 HValue* target = Pop(); 12178 HValue* values[] = {target, Add<HConstant>(call->arguments()->length() - 2)}; 12179 HInstruction* result = 12180 New<HCallWithDescriptor>(trampoline, call->arguments()->length() - 1, 12181 descriptor, ArrayVector(values)); 12182 return ast_context()->ReturnInstruction(result, call->id()); 12183 } 12184 12185 12186 void HOptimizedGraphBuilder::GenerateFixedArrayGet(CallRuntime* call) { 12187 DCHECK(call->arguments()->length() == 2); 12188 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 12189 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); 12190 HValue* index = Pop(); 12191 HValue* object = Pop(); 12192 HInstruction* result = New<HLoadKeyed>( 12193 object, index, nullptr, nullptr, FAST_HOLEY_ELEMENTS, ALLOW_RETURN_HOLE); 12194 return ast_context()->ReturnInstruction(result, call->id()); 12195 } 12196 12197 12198 void HOptimizedGraphBuilder::GenerateFixedArraySet(CallRuntime* call) { 12199 DCHECK(call->arguments()->length() == 3); 12200 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 12201 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); 12202 CHECK_ALIVE(VisitForValue(call->arguments()->at(2))); 12203 HValue* value = Pop(); 12204 HValue* index = Pop(); 12205 HValue* object = Pop(); 12206 NoObservableSideEffectsScope no_effects(this); 12207 Add<HStoreKeyed>(object, index, value, nullptr, FAST_HOLEY_ELEMENTS); 12208 return ast_context()->ReturnValue(graph()->GetConstantUndefined()); 12209 } 12210 12211 12212 void HOptimizedGraphBuilder::GenerateTheHole(CallRuntime* call) { 12213 DCHECK(call->arguments()->length() == 0); 12214 return ast_context()->ReturnValue(graph()->GetConstantHole()); 12215 } 12216 12217 12218 void HOptimizedGraphBuilder::GenerateCreateIterResultObject(CallRuntime* call) { 12219 DCHECK_EQ(2, call->arguments()->length()); 12220 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 12221 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); 12222 HValue* done = Pop(); 12223 HValue* value = Pop(); 12224 HValue* result = BuildCreateIterResultObject(value, done); 12225 return ast_context()->ReturnValue(result); 12226 } 12227 12228 12229 void HOptimizedGraphBuilder::GenerateJSCollectionGetTable(CallRuntime* call) { 12230 DCHECK(call->arguments()->length() == 1); 12231 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 12232 HValue* receiver = Pop(); 12233 HInstruction* result = New<HLoadNamedField>( 12234 receiver, nullptr, HObjectAccess::ForJSCollectionTable()); 12235 return ast_context()->ReturnInstruction(result, call->id()); 12236 } 12237 12238 12239 void HOptimizedGraphBuilder::GenerateStringGetRawHashField(CallRuntime* call) { 12240 DCHECK(call->arguments()->length() == 1); 12241 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 12242 HValue* object = Pop(); 12243 HInstruction* result = New<HLoadNamedField>( 12244 object, nullptr, HObjectAccess::ForStringHashField()); 12245 return ast_context()->ReturnInstruction(result, call->id()); 12246 } 12247 12248 12249 template <typename CollectionType> 12250 HValue* HOptimizedGraphBuilder::BuildAllocateOrderedHashTable() { 12251 static const int kCapacity = CollectionType::kMinCapacity; 12252 static const int kBucketCount = kCapacity / CollectionType::kLoadFactor; 12253 static const int kFixedArrayLength = CollectionType::kHashTableStartIndex + 12254 kBucketCount + 12255 (kCapacity * CollectionType::kEntrySize); 12256 static const int kSizeInBytes = 12257 FixedArray::kHeaderSize + (kFixedArrayLength * kPointerSize); 12258 12259 // Allocate the table and add the proper map. 12260 HValue* table = 12261 Add<HAllocate>(Add<HConstant>(kSizeInBytes), HType::HeapObject(), 12262 NOT_TENURED, FIXED_ARRAY_TYPE, graph()->GetConstant0()); 12263 AddStoreMapConstant(table, isolate()->factory()->ordered_hash_table_map()); 12264 12265 // Initialize the FixedArray... 12266 HValue* length = Add<HConstant>(kFixedArrayLength); 12267 Add<HStoreNamedField>(table, HObjectAccess::ForFixedArrayLength(), length); 12268 12269 // ...and the OrderedHashTable fields. 12270 Add<HStoreNamedField>( 12271 table, 12272 HObjectAccess::ForOrderedHashTableNumberOfBuckets<CollectionType>(), 12273 Add<HConstant>(kBucketCount)); 12274 Add<HStoreNamedField>( 12275 table, 12276 HObjectAccess::ForOrderedHashTableNumberOfElements<CollectionType>(), 12277 graph()->GetConstant0()); 12278 Add<HStoreNamedField>( 12279 table, HObjectAccess::ForOrderedHashTableNumberOfDeletedElements< 12280 CollectionType>(), 12281 graph()->GetConstant0()); 12282 12283 // Fill the buckets with kNotFound. 12284 HValue* not_found = Add<HConstant>(CollectionType::kNotFound); 12285 for (int i = 0; i < kBucketCount; ++i) { 12286 Add<HStoreNamedField>( 12287 table, HObjectAccess::ForOrderedHashTableBucket<CollectionType>(i), 12288 not_found); 12289 } 12290 12291 // Fill the data table with undefined. 12292 HValue* undefined = graph()->GetConstantUndefined(); 12293 for (int i = 0; i < (kCapacity * CollectionType::kEntrySize); ++i) { 12294 Add<HStoreNamedField>(table, 12295 HObjectAccess::ForOrderedHashTableDataTableIndex< 12296 CollectionType, kBucketCount>(i), 12297 undefined); 12298 } 12299 12300 return table; 12301 } 12302 12303 12304 void HOptimizedGraphBuilder::GenerateSetInitialize(CallRuntime* call) { 12305 DCHECK(call->arguments()->length() == 1); 12306 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 12307 HValue* receiver = Pop(); 12308 12309 NoObservableSideEffectsScope no_effects(this); 12310 HValue* table = BuildAllocateOrderedHashTable<OrderedHashSet>(); 12311 Add<HStoreNamedField>(receiver, HObjectAccess::ForJSCollectionTable(), table); 12312 return ast_context()->ReturnValue(receiver); 12313 } 12314 12315 12316 void HOptimizedGraphBuilder::GenerateMapInitialize(CallRuntime* call) { 12317 DCHECK(call->arguments()->length() == 1); 12318 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 12319 HValue* receiver = Pop(); 12320 12321 NoObservableSideEffectsScope no_effects(this); 12322 HValue* table = BuildAllocateOrderedHashTable<OrderedHashMap>(); 12323 Add<HStoreNamedField>(receiver, HObjectAccess::ForJSCollectionTable(), table); 12324 return ast_context()->ReturnValue(receiver); 12325 } 12326 12327 12328 template <typename CollectionType> 12329 void HOptimizedGraphBuilder::BuildOrderedHashTableClear(HValue* receiver) { 12330 HValue* old_table = Add<HLoadNamedField>( 12331 receiver, nullptr, HObjectAccess::ForJSCollectionTable()); 12332 HValue* new_table = BuildAllocateOrderedHashTable<CollectionType>(); 12333 Add<HStoreNamedField>( 12334 old_table, HObjectAccess::ForOrderedHashTableNextTable<CollectionType>(), 12335 new_table); 12336 Add<HStoreNamedField>( 12337 old_table, HObjectAccess::ForOrderedHashTableNumberOfDeletedElements< 12338 CollectionType>(), 12339 Add<HConstant>(CollectionType::kClearedTableSentinel)); 12340 Add<HStoreNamedField>(receiver, HObjectAccess::ForJSCollectionTable(), 12341 new_table); 12342 } 12343 12344 12345 void HOptimizedGraphBuilder::GenerateSetClear(CallRuntime* call) { 12346 DCHECK(call->arguments()->length() == 1); 12347 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 12348 HValue* receiver = Pop(); 12349 12350 NoObservableSideEffectsScope no_effects(this); 12351 BuildOrderedHashTableClear<OrderedHashSet>(receiver); 12352 return ast_context()->ReturnValue(graph()->GetConstantUndefined()); 12353 } 12354 12355 12356 void HOptimizedGraphBuilder::GenerateMapClear(CallRuntime* call) { 12357 DCHECK(call->arguments()->length() == 1); 12358 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 12359 HValue* receiver = Pop(); 12360 12361 NoObservableSideEffectsScope no_effects(this); 12362 BuildOrderedHashTableClear<OrderedHashMap>(receiver); 12363 return ast_context()->ReturnValue(graph()->GetConstantUndefined()); 12364 } 12365 12366 void HOptimizedGraphBuilder::GenerateDebugBreakInOptimizedCode( 12367 CallRuntime* call) { 12368 Add<HDebugBreak>(); 12369 return ast_context()->ReturnValue(graph()->GetConstant0()); 12370 } 12371 12372 12373 void HOptimizedGraphBuilder::GenerateDebugIsActive(CallRuntime* call) { 12374 DCHECK(call->arguments()->length() == 0); 12375 HValue* ref = 12376 Add<HConstant>(ExternalReference::debug_is_active_address(isolate())); 12377 HValue* value = 12378 Add<HLoadNamedField>(ref, nullptr, HObjectAccess::ForExternalUInteger8()); 12379 return ast_context()->ReturnValue(value); 12380 } 12381 12382 #undef CHECK_BAILOUT 12383 #undef CHECK_ALIVE 12384 12385 12386 HEnvironment::HEnvironment(HEnvironment* outer, 12387 Scope* scope, 12388 Handle<JSFunction> closure, 12389 Zone* zone) 12390 : closure_(closure), 12391 values_(0, zone), 12392 frame_type_(JS_FUNCTION), 12393 parameter_count_(0), 12394 specials_count_(1), 12395 local_count_(0), 12396 outer_(outer), 12397 entry_(NULL), 12398 pop_count_(0), 12399 push_count_(0), 12400 ast_id_(BailoutId::None()), 12401 zone_(zone) { 12402 DeclarationScope* declaration_scope = scope->GetDeclarationScope(); 12403 Initialize(declaration_scope->num_parameters() + 1, 12404 declaration_scope->num_stack_slots(), 0); 12405 } 12406 12407 12408 HEnvironment::HEnvironment(Zone* zone, int parameter_count) 12409 : values_(0, zone), 12410 frame_type_(STUB), 12411 parameter_count_(parameter_count), 12412 specials_count_(1), 12413 local_count_(0), 12414 outer_(NULL), 12415 entry_(NULL), 12416 pop_count_(0), 12417 push_count_(0), 12418 ast_id_(BailoutId::None()), 12419 zone_(zone) { 12420 Initialize(parameter_count, 0, 0); 12421 } 12422 12423 12424 HEnvironment::HEnvironment(const HEnvironment* other, Zone* zone) 12425 : values_(0, zone), 12426 frame_type_(JS_FUNCTION), 12427 parameter_count_(0), 12428 specials_count_(0), 12429 local_count_(0), 12430 outer_(NULL), 12431 entry_(NULL), 12432 pop_count_(0), 12433 push_count_(0), 12434 ast_id_(other->ast_id()), 12435 zone_(zone) { 12436 Initialize(other); 12437 } 12438 12439 12440 HEnvironment::HEnvironment(HEnvironment* outer, 12441 Handle<JSFunction> closure, 12442 FrameType frame_type, 12443 int arguments, 12444 Zone* zone) 12445 : closure_(closure), 12446 values_(arguments, zone), 12447 frame_type_(frame_type), 12448 parameter_count_(arguments), 12449 specials_count_(0), 12450 local_count_(0), 12451 outer_(outer), 12452 entry_(NULL), 12453 pop_count_(0), 12454 push_count_(0), 12455 ast_id_(BailoutId::None()), 12456 zone_(zone) { 12457 } 12458 12459 12460 void HEnvironment::Initialize(int parameter_count, 12461 int local_count, 12462 int stack_height) { 12463 parameter_count_ = parameter_count; 12464 local_count_ = local_count; 12465 12466 // Avoid reallocating the temporaries' backing store on the first Push. 12467 int total = parameter_count + specials_count_ + local_count + stack_height; 12468 values_.Initialize(total + 4, zone()); 12469 for (int i = 0; i < total; ++i) values_.Add(NULL, zone()); 12470 } 12471 12472 12473 void HEnvironment::Initialize(const HEnvironment* other) { 12474 closure_ = other->closure(); 12475 values_.AddAll(other->values_, zone()); 12476 assigned_variables_.Union(other->assigned_variables_, zone()); 12477 frame_type_ = other->frame_type_; 12478 parameter_count_ = other->parameter_count_; 12479 local_count_ = other->local_count_; 12480 if (other->outer_ != NULL) outer_ = other->outer_->Copy(); // Deep copy. 12481 entry_ = other->entry_; 12482 pop_count_ = other->pop_count_; 12483 push_count_ = other->push_count_; 12484 specials_count_ = other->specials_count_; 12485 ast_id_ = other->ast_id_; 12486 } 12487 12488 12489 void HEnvironment::AddIncomingEdge(HBasicBlock* block, HEnvironment* other) { 12490 DCHECK(!block->IsLoopHeader()); 12491 DCHECK(values_.length() == other->values_.length()); 12492 12493 int length = values_.length(); 12494 for (int i = 0; i < length; ++i) { 12495 HValue* value = values_[i]; 12496 if (value != NULL && value->IsPhi() && value->block() == block) { 12497 // There is already a phi for the i'th value. 12498 HPhi* phi = HPhi::cast(value); 12499 // Assert index is correct and that we haven't missed an incoming edge. 12500 DCHECK(phi->merged_index() == i || !phi->HasMergedIndex()); 12501 DCHECK(phi->OperandCount() == block->predecessors()->length()); 12502 phi->AddInput(other->values_[i]); 12503 } else if (values_[i] != other->values_[i]) { 12504 // There is a fresh value on the incoming edge, a phi is needed. 12505 DCHECK(values_[i] != NULL && other->values_[i] != NULL); 12506 HPhi* phi = block->AddNewPhi(i); 12507 HValue* old_value = values_[i]; 12508 for (int j = 0; j < block->predecessors()->length(); j++) { 12509 phi->AddInput(old_value); 12510 } 12511 phi->AddInput(other->values_[i]); 12512 this->values_[i] = phi; 12513 } 12514 } 12515 } 12516 12517 12518 void HEnvironment::Bind(int index, HValue* value) { 12519 DCHECK(value != NULL); 12520 assigned_variables_.Add(index, zone()); 12521 values_[index] = value; 12522 } 12523 12524 12525 bool HEnvironment::HasExpressionAt(int index) const { 12526 return index >= parameter_count_ + specials_count_ + local_count_; 12527 } 12528 12529 12530 bool HEnvironment::ExpressionStackIsEmpty() const { 12531 DCHECK(length() >= first_expression_index()); 12532 return length() == first_expression_index(); 12533 } 12534 12535 12536 void HEnvironment::SetExpressionStackAt(int index_from_top, HValue* value) { 12537 int count = index_from_top + 1; 12538 int index = values_.length() - count; 12539 DCHECK(HasExpressionAt(index)); 12540 // The push count must include at least the element in question or else 12541 // the new value will not be included in this environment's history. 12542 if (push_count_ < count) { 12543 // This is the same effect as popping then re-pushing 'count' elements. 12544 pop_count_ += (count - push_count_); 12545 push_count_ = count; 12546 } 12547 values_[index] = value; 12548 } 12549 12550 12551 HValue* HEnvironment::RemoveExpressionStackAt(int index_from_top) { 12552 int count = index_from_top + 1; 12553 int index = values_.length() - count; 12554 DCHECK(HasExpressionAt(index)); 12555 // Simulate popping 'count' elements and then 12556 // pushing 'count - 1' elements back. 12557 pop_count_ += Max(count - push_count_, 0); 12558 push_count_ = Max(push_count_ - count, 0) + (count - 1); 12559 return values_.Remove(index); 12560 } 12561 12562 12563 void HEnvironment::Drop(int count) { 12564 for (int i = 0; i < count; ++i) { 12565 Pop(); 12566 } 12567 } 12568 12569 12570 void HEnvironment::Print() const { 12571 OFStream os(stdout); 12572 os << *this << "\n"; 12573 } 12574 12575 12576 HEnvironment* HEnvironment::Copy() const { 12577 return new(zone()) HEnvironment(this, zone()); 12578 } 12579 12580 12581 HEnvironment* HEnvironment::CopyWithoutHistory() const { 12582 HEnvironment* result = Copy(); 12583 result->ClearHistory(); 12584 return result; 12585 } 12586 12587 12588 HEnvironment* HEnvironment::CopyAsLoopHeader(HBasicBlock* loop_header) const { 12589 HEnvironment* new_env = Copy(); 12590 for (int i = 0; i < values_.length(); ++i) { 12591 HPhi* phi = loop_header->AddNewPhi(i); 12592 phi->AddInput(values_[i]); 12593 new_env->values_[i] = phi; 12594 } 12595 new_env->ClearHistory(); 12596 return new_env; 12597 } 12598 12599 12600 HEnvironment* HEnvironment::CreateStubEnvironment(HEnvironment* outer, 12601 Handle<JSFunction> target, 12602 FrameType frame_type, 12603 int arguments) const { 12604 HEnvironment* new_env = 12605 new(zone()) HEnvironment(outer, target, frame_type, 12606 arguments + 1, zone()); 12607 for (int i = 0; i <= arguments; ++i) { // Include receiver. 12608 new_env->Push(ExpressionStackAt(arguments - i)); 12609 } 12610 new_env->ClearHistory(); 12611 return new_env; 12612 } 12613 12614 void HEnvironment::MarkAsTailCaller() { 12615 DCHECK_EQ(JS_FUNCTION, frame_type()); 12616 frame_type_ = TAIL_CALLER_FUNCTION; 12617 } 12618 12619 void HEnvironment::ClearTailCallerMark() { 12620 DCHECK_EQ(TAIL_CALLER_FUNCTION, frame_type()); 12621 frame_type_ = JS_FUNCTION; 12622 } 12623 12624 HEnvironment* HEnvironment::CopyForInlining( 12625 Handle<JSFunction> target, int arguments, FunctionLiteral* function, 12626 HConstant* undefined, InliningKind inlining_kind, 12627 TailCallMode syntactic_tail_call_mode) const { 12628 DCHECK_EQ(JS_FUNCTION, frame_type()); 12629 12630 // Outer environment is a copy of this one without the arguments. 12631 int arity = function->scope()->num_parameters(); 12632 12633 HEnvironment* outer = Copy(); 12634 outer->Drop(arguments + 1); // Including receiver. 12635 outer->ClearHistory(); 12636 12637 if (syntactic_tail_call_mode == TailCallMode::kAllow) { 12638 DCHECK_EQ(NORMAL_RETURN, inlining_kind); 12639 outer->MarkAsTailCaller(); 12640 } 12641 12642 if (inlining_kind == CONSTRUCT_CALL_RETURN) { 12643 // Create artificial constructor stub environment. The receiver should 12644 // actually be the constructor function, but we pass the newly allocated 12645 // object instead, DoComputeConstructStubFrame() relies on that. 12646 outer = CreateStubEnvironment(outer, target, JS_CONSTRUCT, arguments); 12647 } else if (inlining_kind == GETTER_CALL_RETURN) { 12648 // We need an additional StackFrame::INTERNAL frame for restoring the 12649 // correct context. 12650 outer = CreateStubEnvironment(outer, target, JS_GETTER, arguments); 12651 } else if (inlining_kind == SETTER_CALL_RETURN) { 12652 // We need an additional StackFrame::INTERNAL frame for temporarily saving 12653 // the argument of the setter, see StoreStubCompiler::CompileStoreViaSetter. 12654 outer = CreateStubEnvironment(outer, target, JS_SETTER, arguments); 12655 } 12656 12657 if (arity != arguments) { 12658 // Create artificial arguments adaptation environment. 12659 outer = CreateStubEnvironment(outer, target, ARGUMENTS_ADAPTOR, arguments); 12660 } 12661 12662 HEnvironment* inner = 12663 new(zone()) HEnvironment(outer, function->scope(), target, zone()); 12664 // Get the argument values from the original environment. 12665 for (int i = 0; i <= arity; ++i) { // Include receiver. 12666 HValue* push = (i <= arguments) ? 12667 ExpressionStackAt(arguments - i) : undefined; 12668 inner->SetValueAt(i, push); 12669 } 12670 inner->SetValueAt(arity + 1, context()); 12671 for (int i = arity + 2; i < inner->length(); ++i) { 12672 inner->SetValueAt(i, undefined); 12673 } 12674 12675 inner->set_ast_id(BailoutId::FunctionEntry()); 12676 return inner; 12677 } 12678 12679 12680 std::ostream& operator<<(std::ostream& os, const HEnvironment& env) { 12681 for (int i = 0; i < env.length(); i++) { 12682 if (i == 0) os << "parameters\n"; 12683 if (i == env.parameter_count()) os << "specials\n"; 12684 if (i == env.parameter_count() + env.specials_count()) os << "locals\n"; 12685 if (i == env.parameter_count() + env.specials_count() + env.local_count()) { 12686 os << "expressions\n"; 12687 } 12688 HValue* val = env.values()->at(i); 12689 os << i << ": "; 12690 if (val != NULL) { 12691 os << val; 12692 } else { 12693 os << "NULL"; 12694 } 12695 os << "\n"; 12696 } 12697 return os << "\n"; 12698 } 12699 12700 12701 void HTracer::TraceCompilation(CompilationInfo* info) { 12702 Tag tag(this, "compilation"); 12703 std::string name; 12704 if (info->parse_info()) { 12705 Object* source_name = info->script()->name(); 12706 if (source_name->IsString()) { 12707 String* str = String::cast(source_name); 12708 if (str->length() > 0) { 12709 name.append(str->ToCString().get()); 12710 name.append(":"); 12711 } 12712 } 12713 } 12714 std::unique_ptr<char[]> method_name = info->GetDebugName(); 12715 name.append(method_name.get()); 12716 if (info->IsOptimizing()) { 12717 PrintStringProperty("name", name.c_str()); 12718 PrintIndent(); 12719 trace_.Add("method \"%s:%d\"\n", method_name.get(), 12720 info->optimization_id()); 12721 } else { 12722 PrintStringProperty("name", name.c_str()); 12723 PrintStringProperty("method", "stub"); 12724 } 12725 PrintLongProperty("date", 12726 static_cast<int64_t>(base::OS::TimeCurrentMillis())); 12727 } 12728 12729 12730 void HTracer::TraceLithium(const char* name, LChunk* chunk) { 12731 DCHECK(!chunk->isolate()->concurrent_recompilation_enabled()); 12732 AllowHandleDereference allow_deref; 12733 AllowDeferredHandleDereference allow_deferred_deref; 12734 Trace(name, chunk->graph(), chunk); 12735 } 12736 12737 12738 void HTracer::TraceHydrogen(const char* name, HGraph* graph) { 12739 DCHECK(!graph->isolate()->concurrent_recompilation_enabled()); 12740 AllowHandleDereference allow_deref; 12741 AllowDeferredHandleDereference allow_deferred_deref; 12742 Trace(name, graph, NULL); 12743 } 12744 12745 12746 void HTracer::Trace(const char* name, HGraph* graph, LChunk* chunk) { 12747 Tag tag(this, "cfg"); 12748 PrintStringProperty("name", name); 12749 const ZoneList<HBasicBlock*>* blocks = graph->blocks(); 12750 for (int i = 0; i < blocks->length(); i++) { 12751 HBasicBlock* current = blocks->at(i); 12752 Tag block_tag(this, "block"); 12753 PrintBlockProperty("name", current->block_id()); 12754 PrintIntProperty("from_bci", -1); 12755 PrintIntProperty("to_bci", -1); 12756 12757 if (!current->predecessors()->is_empty()) { 12758 PrintIndent(); 12759 trace_.Add("predecessors"); 12760 for (int j = 0; j < current->predecessors()->length(); ++j) { 12761 trace_.Add(" \"B%d\"", current->predecessors()->at(j)->block_id()); 12762 } 12763 trace_.Add("\n"); 12764 } else { 12765 PrintEmptyProperty("predecessors"); 12766 } 12767 12768 if (current->end()->SuccessorCount() == 0) { 12769 PrintEmptyProperty("successors"); 12770 } else { 12771 PrintIndent(); 12772 trace_.Add("successors"); 12773 for (HSuccessorIterator it(current->end()); !it.Done(); it.Advance()) { 12774 trace_.Add(" \"B%d\"", it.Current()->block_id()); 12775 } 12776 trace_.Add("\n"); 12777 } 12778 12779 PrintEmptyProperty("xhandlers"); 12780 12781 { 12782 PrintIndent(); 12783 trace_.Add("flags"); 12784 if (current->IsLoopSuccessorDominator()) { 12785 trace_.Add(" \"dom-loop-succ\""); 12786 } 12787 if (current->IsUnreachable()) { 12788 trace_.Add(" \"dead\""); 12789 } 12790 if (current->is_osr_entry()) { 12791 trace_.Add(" \"osr\""); 12792 } 12793 trace_.Add("\n"); 12794 } 12795 12796 if (current->dominator() != NULL) { 12797 PrintBlockProperty("dominator", current->dominator()->block_id()); 12798 } 12799 12800 PrintIntProperty("loop_depth", current->LoopNestingDepth()); 12801 12802 if (chunk != NULL) { 12803 int first_index = current->first_instruction_index(); 12804 int last_index = current->last_instruction_index(); 12805 PrintIntProperty( 12806 "first_lir_id", 12807 LifetimePosition::FromInstructionIndex(first_index).Value()); 12808 PrintIntProperty( 12809 "last_lir_id", 12810 LifetimePosition::FromInstructionIndex(last_index).Value()); 12811 } 12812 12813 { 12814 Tag states_tag(this, "states"); 12815 Tag locals_tag(this, "locals"); 12816 int total = current->phis()->length(); 12817 PrintIntProperty("size", current->phis()->length()); 12818 PrintStringProperty("method", "None"); 12819 for (int j = 0; j < total; ++j) { 12820 HPhi* phi = current->phis()->at(j); 12821 PrintIndent(); 12822 std::ostringstream os; 12823 os << phi->merged_index() << " " << NameOf(phi) << " " << *phi << "\n"; 12824 trace_.Add(os.str().c_str()); 12825 } 12826 } 12827 12828 { 12829 Tag HIR_tag(this, "HIR"); 12830 for (HInstructionIterator it(current); !it.Done(); it.Advance()) { 12831 HInstruction* instruction = it.Current(); 12832 int uses = instruction->UseCount(); 12833 PrintIndent(); 12834 std::ostringstream os; 12835 os << "0 " << uses << " " << NameOf(instruction) << " " << *instruction; 12836 if (instruction->has_position()) { 12837 const SourcePosition pos = instruction->position(); 12838 os << " pos:"; 12839 if (pos.isInlined()) os << "inlining(" << pos.InliningId() << "),"; 12840 os << pos.ScriptOffset(); 12841 } 12842 os << " <|@\n"; 12843 trace_.Add(os.str().c_str()); 12844 } 12845 } 12846 12847 12848 if (chunk != NULL) { 12849 Tag LIR_tag(this, "LIR"); 12850 int first_index = current->first_instruction_index(); 12851 int last_index = current->last_instruction_index(); 12852 if (first_index != -1 && last_index != -1) { 12853 const ZoneList<LInstruction*>* instructions = chunk->instructions(); 12854 for (int i = first_index; i <= last_index; ++i) { 12855 LInstruction* linstr = instructions->at(i); 12856 if (linstr != NULL) { 12857 PrintIndent(); 12858 trace_.Add("%d ", 12859 LifetimePosition::FromInstructionIndex(i).Value()); 12860 linstr->PrintTo(&trace_); 12861 std::ostringstream os; 12862 os << " [hir:" << NameOf(linstr->hydrogen_value()) << "] <|@\n"; 12863 trace_.Add(os.str().c_str()); 12864 } 12865 } 12866 } 12867 } 12868 } 12869 } 12870 12871 12872 void HTracer::TraceLiveRanges(const char* name, LAllocator* allocator) { 12873 Tag tag(this, "intervals"); 12874 PrintStringProperty("name", name); 12875 12876 const Vector<LiveRange*>* fixed_d = allocator->fixed_double_live_ranges(); 12877 for (int i = 0; i < fixed_d->length(); ++i) { 12878 TraceLiveRange(fixed_d->at(i), "fixed", allocator->zone()); 12879 } 12880 12881 const Vector<LiveRange*>* fixed = allocator->fixed_live_ranges(); 12882 for (int i = 0; i < fixed->length(); ++i) { 12883 TraceLiveRange(fixed->at(i), "fixed", allocator->zone()); 12884 } 12885 12886 const ZoneList<LiveRange*>* live_ranges = allocator->live_ranges(); 12887 for (int i = 0; i < live_ranges->length(); ++i) { 12888 TraceLiveRange(live_ranges->at(i), "object", allocator->zone()); 12889 } 12890 } 12891 12892 12893 void HTracer::TraceLiveRange(LiveRange* range, const char* type, 12894 Zone* zone) { 12895 if (range != NULL && !range->IsEmpty()) { 12896 PrintIndent(); 12897 trace_.Add("%d %s", range->id(), type); 12898 if (range->HasRegisterAssigned()) { 12899 LOperand* op = range->CreateAssignedOperand(zone); 12900 int assigned_reg = op->index(); 12901 if (op->IsDoubleRegister()) { 12902 trace_.Add(" \"%s\"", 12903 GetRegConfig()->GetDoubleRegisterName(assigned_reg)); 12904 } else { 12905 DCHECK(op->IsRegister()); 12906 trace_.Add(" \"%s\"", 12907 GetRegConfig()->GetGeneralRegisterName(assigned_reg)); 12908 } 12909 } else if (range->IsSpilled()) { 12910 LOperand* op = range->TopLevel()->GetSpillOperand(); 12911 if (op->IsDoubleStackSlot()) { 12912 trace_.Add(" \"double_stack:%d\"", op->index()); 12913 } else { 12914 DCHECK(op->IsStackSlot()); 12915 trace_.Add(" \"stack:%d\"", op->index()); 12916 } 12917 } 12918 int parent_index = -1; 12919 if (range->IsChild()) { 12920 parent_index = range->parent()->id(); 12921 } else { 12922 parent_index = range->id(); 12923 } 12924 LOperand* op = range->FirstHint(); 12925 int hint_index = -1; 12926 if (op != NULL && op->IsUnallocated()) { 12927 hint_index = LUnallocated::cast(op)->virtual_register(); 12928 } 12929 trace_.Add(" %d %d", parent_index, hint_index); 12930 UseInterval* cur_interval = range->first_interval(); 12931 while (cur_interval != NULL && range->Covers(cur_interval->start())) { 12932 trace_.Add(" [%d, %d[", 12933 cur_interval->start().Value(), 12934 cur_interval->end().Value()); 12935 cur_interval = cur_interval->next(); 12936 } 12937 12938 UsePosition* current_pos = range->first_pos(); 12939 while (current_pos != NULL) { 12940 if (current_pos->RegisterIsBeneficial() || FLAG_trace_all_uses) { 12941 trace_.Add(" %d M", current_pos->pos().Value()); 12942 } 12943 current_pos = current_pos->next(); 12944 } 12945 12946 trace_.Add(" \"\"\n"); 12947 } 12948 } 12949 12950 12951 void HTracer::FlushToFile() { 12952 AppendChars(filename_.start(), trace_.ToCString().get(), trace_.length(), 12953 false); 12954 trace_.Reset(); 12955 } 12956 12957 12958 void HStatistics::Initialize(CompilationInfo* info) { 12959 if (!info->has_shared_info()) return; 12960 source_size_ += info->shared_info()->SourceSize(); 12961 } 12962 12963 12964 void HStatistics::Print() { 12965 PrintF( 12966 "\n" 12967 "----------------------------------------" 12968 "----------------------------------------\n" 12969 "--- Hydrogen timing results:\n" 12970 "----------------------------------------" 12971 "----------------------------------------\n"); 12972 base::TimeDelta sum; 12973 for (int i = 0; i < times_.length(); ++i) { 12974 sum += times_[i]; 12975 } 12976 12977 for (int i = 0; i < names_.length(); ++i) { 12978 PrintF("%33s", names_[i]); 12979 double ms = times_[i].InMillisecondsF(); 12980 double percent = times_[i].PercentOf(sum); 12981 PrintF(" %8.3f ms / %4.1f %% ", ms, percent); 12982 12983 size_t size = sizes_[i]; 12984 double size_percent = static_cast<double>(size) * 100 / total_size_; 12985 PrintF(" %9zu bytes / %4.1f %%\n", size, size_percent); 12986 } 12987 12988 PrintF( 12989 "----------------------------------------" 12990 "----------------------------------------\n"); 12991 base::TimeDelta total = create_graph_ + optimize_graph_ + generate_code_; 12992 PrintF("%33s %8.3f ms / %4.1f %% \n", "Create graph", 12993 create_graph_.InMillisecondsF(), create_graph_.PercentOf(total)); 12994 PrintF("%33s %8.3f ms / %4.1f %% \n", "Optimize graph", 12995 optimize_graph_.InMillisecondsF(), optimize_graph_.PercentOf(total)); 12996 PrintF("%33s %8.3f ms / %4.1f %% \n", "Generate and install code", 12997 generate_code_.InMillisecondsF(), generate_code_.PercentOf(total)); 12998 PrintF( 12999 "----------------------------------------" 13000 "----------------------------------------\n"); 13001 PrintF("%33s %8.3f ms %9zu bytes\n", "Total", 13002 total.InMillisecondsF(), total_size_); 13003 PrintF("%33s (%.1f times slower than full code gen)\n", "", 13004 total.TimesOf(full_code_gen_)); 13005 13006 double source_size_in_kb = static_cast<double>(source_size_) / 1024; 13007 double normalized_time = source_size_in_kb > 0 13008 ? total.InMillisecondsF() / source_size_in_kb 13009 : 0; 13010 double normalized_size_in_kb = 13011 source_size_in_kb > 0 13012 ? static_cast<double>(total_size_) / 1024 / source_size_in_kb 13013 : 0; 13014 PrintF("%33s %8.3f ms %7.3f kB allocated\n", 13015 "Average per kB source", normalized_time, normalized_size_in_kb); 13016 } 13017 13018 13019 void HStatistics::SaveTiming(const char* name, base::TimeDelta time, 13020 size_t size) { 13021 total_size_ += size; 13022 for (int i = 0; i < names_.length(); ++i) { 13023 if (strcmp(names_[i], name) == 0) { 13024 times_[i] += time; 13025 sizes_[i] += size; 13026 return; 13027 } 13028 } 13029 names_.Add(name); 13030 times_.Add(time); 13031 sizes_.Add(size); 13032 } 13033 13034 13035 HPhase::~HPhase() { 13036 if (ShouldProduceTraceOutput()) { 13037 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); 13038 } 13039 13040 #ifdef DEBUG 13041 graph_->Verify(false); // No full verify. 13042 #endif 13043 } 13044 13045 } // namespace internal 13046 } // namespace v8 13047