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/hydrogen.h" 6 7 #include <algorithm> 8 9 #include "src/v8.h" 10 11 #include "src/allocation-site-scopes.h" 12 #include "src/codegen.h" 13 #include "src/full-codegen.h" 14 #include "src/hashmap.h" 15 #include "src/hydrogen-bce.h" 16 #include "src/hydrogen-bch.h" 17 #include "src/hydrogen-canonicalize.h" 18 #include "src/hydrogen-check-elimination.h" 19 #include "src/hydrogen-dce.h" 20 #include "src/hydrogen-dehoist.h" 21 #include "src/hydrogen-environment-liveness.h" 22 #include "src/hydrogen-escape-analysis.h" 23 #include "src/hydrogen-gvn.h" 24 #include "src/hydrogen-infer-representation.h" 25 #include "src/hydrogen-infer-types.h" 26 #include "src/hydrogen-load-elimination.h" 27 #include "src/hydrogen-mark-deoptimize.h" 28 #include "src/hydrogen-mark-unreachable.h" 29 #include "src/hydrogen-osr.h" 30 #include "src/hydrogen-range-analysis.h" 31 #include "src/hydrogen-redundant-phi.h" 32 #include "src/hydrogen-removable-simulates.h" 33 #include "src/hydrogen-representation-changes.h" 34 #include "src/hydrogen-sce.h" 35 #include "src/hydrogen-store-elimination.h" 36 #include "src/hydrogen-uint32-analysis.h" 37 #include "src/ic/call-optimization.h" 38 #include "src/ic/ic.h" 39 // GetRootConstructor 40 #include "src/ic/ic-inl.h" 41 #include "src/lithium-allocator.h" 42 #include "src/parser.h" 43 #include "src/runtime.h" 44 #include "src/scopeinfo.h" 45 #include "src/scopes.h" 46 #include "src/typing.h" 47 48 #if V8_TARGET_ARCH_IA32 49 #include "src/ia32/lithium-codegen-ia32.h" // NOLINT 50 #elif V8_TARGET_ARCH_X64 51 #include "src/x64/lithium-codegen-x64.h" // NOLINT 52 #elif V8_TARGET_ARCH_ARM64 53 #include "src/arm64/lithium-codegen-arm64.h" // NOLINT 54 #elif V8_TARGET_ARCH_ARM 55 #include "src/arm/lithium-codegen-arm.h" // NOLINT 56 #elif V8_TARGET_ARCH_MIPS 57 #include "src/mips/lithium-codegen-mips.h" // NOLINT 58 #elif V8_TARGET_ARCH_MIPS64 59 #include "src/mips64/lithium-codegen-mips64.h" // NOLINT 60 #elif V8_TARGET_ARCH_X87 61 #include "src/x87/lithium-codegen-x87.h" // NOLINT 62 #else 63 #error Unsupported target architecture. 64 #endif 65 66 namespace v8 { 67 namespace internal { 68 69 HBasicBlock::HBasicBlock(HGraph* graph) 70 : block_id_(graph->GetNextBlockID()), 71 graph_(graph), 72 phis_(4, graph->zone()), 73 first_(NULL), 74 last_(NULL), 75 end_(NULL), 76 loop_information_(NULL), 77 predecessors_(2, graph->zone()), 78 dominator_(NULL), 79 dominated_blocks_(4, graph->zone()), 80 last_environment_(NULL), 81 argument_count_(-1), 82 first_instruction_index_(-1), 83 last_instruction_index_(-1), 84 deleted_phis_(4, graph->zone()), 85 parent_loop_header_(NULL), 86 inlined_entry_block_(NULL), 87 is_inline_return_target_(false), 88 is_reachable_(true), 89 dominates_loop_successors_(false), 90 is_osr_entry_(false), 91 is_ordered_(false) { } 92 93 94 Isolate* HBasicBlock::isolate() const { 95 return graph_->isolate(); 96 } 97 98 99 void HBasicBlock::MarkUnreachable() { 100 is_reachable_ = false; 101 } 102 103 104 void HBasicBlock::AttachLoopInformation() { 105 DCHECK(!IsLoopHeader()); 106 loop_information_ = new(zone()) HLoopInformation(this, zone()); 107 } 108 109 110 void HBasicBlock::DetachLoopInformation() { 111 DCHECK(IsLoopHeader()); 112 loop_information_ = NULL; 113 } 114 115 116 void HBasicBlock::AddPhi(HPhi* phi) { 117 DCHECK(!IsStartBlock()); 118 phis_.Add(phi, zone()); 119 phi->SetBlock(this); 120 } 121 122 123 void HBasicBlock::RemovePhi(HPhi* phi) { 124 DCHECK(phi->block() == this); 125 DCHECK(phis_.Contains(phi)); 126 phi->Kill(); 127 phis_.RemoveElement(phi); 128 phi->SetBlock(NULL); 129 } 130 131 132 void HBasicBlock::AddInstruction(HInstruction* instr, 133 HSourcePosition position) { 134 DCHECK(!IsStartBlock() || !IsFinished()); 135 DCHECK(!instr->IsLinked()); 136 DCHECK(!IsFinished()); 137 138 if (!position.IsUnknown()) { 139 instr->set_position(position); 140 } 141 if (first_ == NULL) { 142 DCHECK(last_environment() != NULL); 143 DCHECK(!last_environment()->ast_id().IsNone()); 144 HBlockEntry* entry = new(zone()) HBlockEntry(); 145 entry->InitializeAsFirst(this); 146 if (!position.IsUnknown()) { 147 entry->set_position(position); 148 } else { 149 DCHECK(!FLAG_hydrogen_track_positions || 150 !graph()->info()->IsOptimizing()); 151 } 152 first_ = last_ = entry; 153 } 154 instr->InsertAfter(last_); 155 } 156 157 158 HPhi* HBasicBlock::AddNewPhi(int merged_index) { 159 if (graph()->IsInsideNoSideEffectsScope()) { 160 merged_index = HPhi::kInvalidMergedIndex; 161 } 162 HPhi* phi = new(zone()) HPhi(merged_index, zone()); 163 AddPhi(phi); 164 return phi; 165 } 166 167 168 HSimulate* HBasicBlock::CreateSimulate(BailoutId ast_id, 169 RemovableSimulate removable) { 170 DCHECK(HasEnvironment()); 171 HEnvironment* environment = last_environment(); 172 DCHECK(ast_id.IsNone() || 173 ast_id == BailoutId::StubEntry() || 174 environment->closure()->shared()->VerifyBailoutId(ast_id)); 175 176 int push_count = environment->push_count(); 177 int pop_count = environment->pop_count(); 178 179 HSimulate* instr = 180 new(zone()) HSimulate(ast_id, pop_count, zone(), removable); 181 #ifdef DEBUG 182 instr->set_closure(environment->closure()); 183 #endif 184 // Order of pushed values: newest (top of stack) first. This allows 185 // HSimulate::MergeWith() to easily append additional pushed values 186 // that are older (from further down the stack). 187 for (int i = 0; i < push_count; ++i) { 188 instr->AddPushedValue(environment->ExpressionStackAt(i)); 189 } 190 for (GrowableBitVector::Iterator it(environment->assigned_variables(), 191 zone()); 192 !it.Done(); 193 it.Advance()) { 194 int index = it.Current(); 195 instr->AddAssignedValue(index, environment->Lookup(index)); 196 } 197 environment->ClearHistory(); 198 return instr; 199 } 200 201 202 void HBasicBlock::Finish(HControlInstruction* end, HSourcePosition position) { 203 DCHECK(!IsFinished()); 204 AddInstruction(end, position); 205 end_ = end; 206 for (HSuccessorIterator it(end); !it.Done(); it.Advance()) { 207 it.Current()->RegisterPredecessor(this); 208 } 209 } 210 211 212 void HBasicBlock::Goto(HBasicBlock* block, 213 HSourcePosition position, 214 FunctionState* state, 215 bool add_simulate) { 216 bool drop_extra = state != NULL && 217 state->inlining_kind() == NORMAL_RETURN; 218 219 if (block->IsInlineReturnTarget()) { 220 HEnvironment* env = last_environment(); 221 int argument_count = env->arguments_environment()->parameter_count(); 222 AddInstruction(new(zone()) 223 HLeaveInlined(state->entry(), argument_count), 224 position); 225 UpdateEnvironment(last_environment()->DiscardInlined(drop_extra)); 226 } 227 228 if (add_simulate) AddNewSimulate(BailoutId::None(), position); 229 HGoto* instr = new(zone()) HGoto(block); 230 Finish(instr, position); 231 } 232 233 234 void HBasicBlock::AddLeaveInlined(HValue* return_value, 235 FunctionState* state, 236 HSourcePosition position) { 237 HBasicBlock* target = state->function_return(); 238 bool drop_extra = state->inlining_kind() == NORMAL_RETURN; 239 240 DCHECK(target->IsInlineReturnTarget()); 241 DCHECK(return_value != NULL); 242 HEnvironment* env = last_environment(); 243 int argument_count = env->arguments_environment()->parameter_count(); 244 AddInstruction(new(zone()) HLeaveInlined(state->entry(), argument_count), 245 position); 246 UpdateEnvironment(last_environment()->DiscardInlined(drop_extra)); 247 last_environment()->Push(return_value); 248 AddNewSimulate(BailoutId::None(), position); 249 HGoto* instr = new(zone()) HGoto(target); 250 Finish(instr, position); 251 } 252 253 254 void HBasicBlock::SetInitialEnvironment(HEnvironment* env) { 255 DCHECK(!HasEnvironment()); 256 DCHECK(first() == NULL); 257 UpdateEnvironment(env); 258 } 259 260 261 void HBasicBlock::UpdateEnvironment(HEnvironment* env) { 262 last_environment_ = env; 263 graph()->update_maximum_environment_size(env->first_expression_index()); 264 } 265 266 267 void HBasicBlock::SetJoinId(BailoutId ast_id) { 268 int length = predecessors_.length(); 269 DCHECK(length > 0); 270 for (int i = 0; i < length; i++) { 271 HBasicBlock* predecessor = predecessors_[i]; 272 DCHECK(predecessor->end()->IsGoto()); 273 HSimulate* simulate = HSimulate::cast(predecessor->end()->previous()); 274 DCHECK(i != 0 || 275 (predecessor->last_environment()->closure().is_null() || 276 predecessor->last_environment()->closure()->shared() 277 ->VerifyBailoutId(ast_id))); 278 simulate->set_ast_id(ast_id); 279 predecessor->last_environment()->set_ast_id(ast_id); 280 } 281 } 282 283 284 bool HBasicBlock::Dominates(HBasicBlock* other) const { 285 HBasicBlock* current = other->dominator(); 286 while (current != NULL) { 287 if (current == this) return true; 288 current = current->dominator(); 289 } 290 return false; 291 } 292 293 294 bool HBasicBlock::EqualToOrDominates(HBasicBlock* other) const { 295 if (this == other) return true; 296 return Dominates(other); 297 } 298 299 300 int HBasicBlock::LoopNestingDepth() const { 301 const HBasicBlock* current = this; 302 int result = (current->IsLoopHeader()) ? 1 : 0; 303 while (current->parent_loop_header() != NULL) { 304 current = current->parent_loop_header(); 305 result++; 306 } 307 return result; 308 } 309 310 311 void HBasicBlock::PostProcessLoopHeader(IterationStatement* stmt) { 312 DCHECK(IsLoopHeader()); 313 314 SetJoinId(stmt->EntryId()); 315 if (predecessors()->length() == 1) { 316 // This is a degenerated loop. 317 DetachLoopInformation(); 318 return; 319 } 320 321 // Only the first entry into the loop is from outside the loop. All other 322 // entries must be back edges. 323 for (int i = 1; i < predecessors()->length(); ++i) { 324 loop_information()->RegisterBackEdge(predecessors()->at(i)); 325 } 326 } 327 328 329 void HBasicBlock::MarkSuccEdgeUnreachable(int succ) { 330 DCHECK(IsFinished()); 331 HBasicBlock* succ_block = end()->SuccessorAt(succ); 332 333 DCHECK(succ_block->predecessors()->length() == 1); 334 succ_block->MarkUnreachable(); 335 } 336 337 338 void HBasicBlock::RegisterPredecessor(HBasicBlock* pred) { 339 if (HasPredecessor()) { 340 // Only loop header blocks can have a predecessor added after 341 // instructions have been added to the block (they have phis for all 342 // values in the environment, these phis may be eliminated later). 343 DCHECK(IsLoopHeader() || first_ == NULL); 344 HEnvironment* incoming_env = pred->last_environment(); 345 if (IsLoopHeader()) { 346 DCHECK(phis()->length() == incoming_env->length()); 347 for (int i = 0; i < phis_.length(); ++i) { 348 phis_[i]->AddInput(incoming_env->values()->at(i)); 349 } 350 } else { 351 last_environment()->AddIncomingEdge(this, pred->last_environment()); 352 } 353 } else if (!HasEnvironment() && !IsFinished()) { 354 DCHECK(!IsLoopHeader()); 355 SetInitialEnvironment(pred->last_environment()->Copy()); 356 } 357 358 predecessors_.Add(pred, zone()); 359 } 360 361 362 void HBasicBlock::AddDominatedBlock(HBasicBlock* block) { 363 DCHECK(!dominated_blocks_.Contains(block)); 364 // Keep the list of dominated blocks sorted such that if there is two 365 // succeeding block in this list, the predecessor is before the successor. 366 int index = 0; 367 while (index < dominated_blocks_.length() && 368 dominated_blocks_[index]->block_id() < block->block_id()) { 369 ++index; 370 } 371 dominated_blocks_.InsertAt(index, block, zone()); 372 } 373 374 375 void HBasicBlock::AssignCommonDominator(HBasicBlock* other) { 376 if (dominator_ == NULL) { 377 dominator_ = other; 378 other->AddDominatedBlock(this); 379 } else if (other->dominator() != NULL) { 380 HBasicBlock* first = dominator_; 381 HBasicBlock* second = other; 382 383 while (first != second) { 384 if (first->block_id() > second->block_id()) { 385 first = first->dominator(); 386 } else { 387 second = second->dominator(); 388 } 389 DCHECK(first != NULL && second != NULL); 390 } 391 392 if (dominator_ != first) { 393 DCHECK(dominator_->dominated_blocks_.Contains(this)); 394 dominator_->dominated_blocks_.RemoveElement(this); 395 dominator_ = first; 396 first->AddDominatedBlock(this); 397 } 398 } 399 } 400 401 402 void HBasicBlock::AssignLoopSuccessorDominators() { 403 // Mark blocks that dominate all subsequent reachable blocks inside their 404 // loop. Exploit the fact that blocks are sorted in reverse post order. When 405 // the loop is visited in increasing block id order, if the number of 406 // non-loop-exiting successor edges at the dominator_candidate block doesn't 407 // exceed the number of previously encountered predecessor edges, there is no 408 // path from the loop header to any block with higher id that doesn't go 409 // through the dominator_candidate block. In this case, the 410 // dominator_candidate block is guaranteed to dominate all blocks reachable 411 // from it with higher ids. 412 HBasicBlock* last = loop_information()->GetLastBackEdge(); 413 int outstanding_successors = 1; // one edge from the pre-header 414 // Header always dominates everything. 415 MarkAsLoopSuccessorDominator(); 416 for (int j = block_id(); j <= last->block_id(); ++j) { 417 HBasicBlock* dominator_candidate = graph_->blocks()->at(j); 418 for (HPredecessorIterator it(dominator_candidate); !it.Done(); 419 it.Advance()) { 420 HBasicBlock* predecessor = it.Current(); 421 // Don't count back edges. 422 if (predecessor->block_id() < dominator_candidate->block_id()) { 423 outstanding_successors--; 424 } 425 } 426 427 // If more successors than predecessors have been seen in the loop up to 428 // now, it's not possible to guarantee that the current block dominates 429 // all of the blocks with higher IDs. In this case, assume conservatively 430 // that those paths through loop that don't go through the current block 431 // contain all of the loop's dependencies. Also be careful to record 432 // dominator information about the current loop that's being processed, 433 // and not nested loops, which will be processed when 434 // AssignLoopSuccessorDominators gets called on their header. 435 DCHECK(outstanding_successors >= 0); 436 HBasicBlock* parent_loop_header = dominator_candidate->parent_loop_header(); 437 if (outstanding_successors == 0 && 438 (parent_loop_header == this && !dominator_candidate->IsLoopHeader())) { 439 dominator_candidate->MarkAsLoopSuccessorDominator(); 440 } 441 HControlInstruction* end = dominator_candidate->end(); 442 for (HSuccessorIterator it(end); !it.Done(); it.Advance()) { 443 HBasicBlock* successor = it.Current(); 444 // Only count successors that remain inside the loop and don't loop back 445 // to a loop header. 446 if (successor->block_id() > dominator_candidate->block_id() && 447 successor->block_id() <= last->block_id()) { 448 // Backwards edges must land on loop headers. 449 DCHECK(successor->block_id() > dominator_candidate->block_id() || 450 successor->IsLoopHeader()); 451 outstanding_successors++; 452 } 453 } 454 } 455 } 456 457 458 int HBasicBlock::PredecessorIndexOf(HBasicBlock* predecessor) const { 459 for (int i = 0; i < predecessors_.length(); ++i) { 460 if (predecessors_[i] == predecessor) return i; 461 } 462 UNREACHABLE(); 463 return -1; 464 } 465 466 467 #ifdef DEBUG 468 void HBasicBlock::Verify() { 469 // Check that every block is finished. 470 DCHECK(IsFinished()); 471 DCHECK(block_id() >= 0); 472 473 // Check that the incoming edges are in edge split form. 474 if (predecessors_.length() > 1) { 475 for (int i = 0; i < predecessors_.length(); ++i) { 476 DCHECK(predecessors_[i]->end()->SecondSuccessor() == NULL); 477 } 478 } 479 } 480 #endif 481 482 483 void HLoopInformation::RegisterBackEdge(HBasicBlock* block) { 484 this->back_edges_.Add(block, block->zone()); 485 AddBlock(block); 486 } 487 488 489 HBasicBlock* HLoopInformation::GetLastBackEdge() const { 490 int max_id = -1; 491 HBasicBlock* result = NULL; 492 for (int i = 0; i < back_edges_.length(); ++i) { 493 HBasicBlock* cur = back_edges_[i]; 494 if (cur->block_id() > max_id) { 495 max_id = cur->block_id(); 496 result = cur; 497 } 498 } 499 return result; 500 } 501 502 503 void HLoopInformation::AddBlock(HBasicBlock* block) { 504 if (block == loop_header()) return; 505 if (block->parent_loop_header() == loop_header()) return; 506 if (block->parent_loop_header() != NULL) { 507 AddBlock(block->parent_loop_header()); 508 } else { 509 block->set_parent_loop_header(loop_header()); 510 blocks_.Add(block, block->zone()); 511 for (int i = 0; i < block->predecessors()->length(); ++i) { 512 AddBlock(block->predecessors()->at(i)); 513 } 514 } 515 } 516 517 518 #ifdef DEBUG 519 520 // Checks reachability of the blocks in this graph and stores a bit in 521 // the BitVector "reachable()" for every block that can be reached 522 // from the start block of the graph. If "dont_visit" is non-null, the given 523 // block is treated as if it would not be part of the graph. "visited_count()" 524 // returns the number of reachable blocks. 525 class ReachabilityAnalyzer BASE_EMBEDDED { 526 public: 527 ReachabilityAnalyzer(HBasicBlock* entry_block, 528 int block_count, 529 HBasicBlock* dont_visit) 530 : visited_count_(0), 531 stack_(16, entry_block->zone()), 532 reachable_(block_count, entry_block->zone()), 533 dont_visit_(dont_visit) { 534 PushBlock(entry_block); 535 Analyze(); 536 } 537 538 int visited_count() const { return visited_count_; } 539 const BitVector* reachable() const { return &reachable_; } 540 541 private: 542 void PushBlock(HBasicBlock* block) { 543 if (block != NULL && block != dont_visit_ && 544 !reachable_.Contains(block->block_id())) { 545 reachable_.Add(block->block_id()); 546 stack_.Add(block, block->zone()); 547 visited_count_++; 548 } 549 } 550 551 void Analyze() { 552 while (!stack_.is_empty()) { 553 HControlInstruction* end = stack_.RemoveLast()->end(); 554 for (HSuccessorIterator it(end); !it.Done(); it.Advance()) { 555 PushBlock(it.Current()); 556 } 557 } 558 } 559 560 int visited_count_; 561 ZoneList<HBasicBlock*> stack_; 562 BitVector reachable_; 563 HBasicBlock* dont_visit_; 564 }; 565 566 567 void HGraph::Verify(bool do_full_verify) const { 568 Heap::RelocationLock relocation_lock(isolate()->heap()); 569 AllowHandleDereference allow_deref; 570 AllowDeferredHandleDereference allow_deferred_deref; 571 for (int i = 0; i < blocks_.length(); i++) { 572 HBasicBlock* block = blocks_.at(i); 573 574 block->Verify(); 575 576 // Check that every block contains at least one node and that only the last 577 // node is a control instruction. 578 HInstruction* current = block->first(); 579 DCHECK(current != NULL && current->IsBlockEntry()); 580 while (current != NULL) { 581 DCHECK((current->next() == NULL) == current->IsControlInstruction()); 582 DCHECK(current->block() == block); 583 current->Verify(); 584 current = current->next(); 585 } 586 587 // Check that successors are correctly set. 588 HBasicBlock* first = block->end()->FirstSuccessor(); 589 HBasicBlock* second = block->end()->SecondSuccessor(); 590 DCHECK(second == NULL || first != NULL); 591 592 // Check that the predecessor array is correct. 593 if (first != NULL) { 594 DCHECK(first->predecessors()->Contains(block)); 595 if (second != NULL) { 596 DCHECK(second->predecessors()->Contains(block)); 597 } 598 } 599 600 // Check that phis have correct arguments. 601 for (int j = 0; j < block->phis()->length(); j++) { 602 HPhi* phi = block->phis()->at(j); 603 phi->Verify(); 604 } 605 606 // Check that all join blocks have predecessors that end with an 607 // unconditional goto and agree on their environment node id. 608 if (block->predecessors()->length() >= 2) { 609 BailoutId id = 610 block->predecessors()->first()->last_environment()->ast_id(); 611 for (int k = 0; k < block->predecessors()->length(); k++) { 612 HBasicBlock* predecessor = block->predecessors()->at(k); 613 DCHECK(predecessor->end()->IsGoto() || 614 predecessor->end()->IsDeoptimize()); 615 DCHECK(predecessor->last_environment()->ast_id() == id); 616 } 617 } 618 } 619 620 // Check special property of first block to have no predecessors. 621 DCHECK(blocks_.at(0)->predecessors()->is_empty()); 622 623 if (do_full_verify) { 624 // Check that the graph is fully connected. 625 ReachabilityAnalyzer analyzer(entry_block_, blocks_.length(), NULL); 626 DCHECK(analyzer.visited_count() == blocks_.length()); 627 628 // Check that entry block dominator is NULL. 629 DCHECK(entry_block_->dominator() == NULL); 630 631 // Check dominators. 632 for (int i = 0; i < blocks_.length(); ++i) { 633 HBasicBlock* block = blocks_.at(i); 634 if (block->dominator() == NULL) { 635 // Only start block may have no dominator assigned to. 636 DCHECK(i == 0); 637 } else { 638 // Assert that block is unreachable if dominator must not be visited. 639 ReachabilityAnalyzer dominator_analyzer(entry_block_, 640 blocks_.length(), 641 block->dominator()); 642 DCHECK(!dominator_analyzer.reachable()->Contains(block->block_id())); 643 } 644 } 645 } 646 } 647 648 #endif 649 650 651 HConstant* HGraph::GetConstant(SetOncePointer<HConstant>* pointer, 652 int32_t value) { 653 if (!pointer->is_set()) { 654 // Can't pass GetInvalidContext() to HConstant::New, because that will 655 // recursively call GetConstant 656 HConstant* constant = HConstant::New(zone(), NULL, value); 657 constant->InsertAfter(entry_block()->first()); 658 pointer->set(constant); 659 return constant; 660 } 661 return ReinsertConstantIfNecessary(pointer->get()); 662 } 663 664 665 HConstant* HGraph::ReinsertConstantIfNecessary(HConstant* constant) { 666 if (!constant->IsLinked()) { 667 // The constant was removed from the graph. Reinsert. 668 constant->ClearFlag(HValue::kIsDead); 669 constant->InsertAfter(entry_block()->first()); 670 } 671 return constant; 672 } 673 674 675 HConstant* HGraph::GetConstant0() { 676 return GetConstant(&constant_0_, 0); 677 } 678 679 680 HConstant* HGraph::GetConstant1() { 681 return GetConstant(&constant_1_, 1); 682 } 683 684 685 HConstant* HGraph::GetConstantMinus1() { 686 return GetConstant(&constant_minus1_, -1); 687 } 688 689 690 #define DEFINE_GET_CONSTANT(Name, name, type, htype, boolean_value) \ 691 HConstant* HGraph::GetConstant##Name() { \ 692 if (!constant_##name##_.is_set()) { \ 693 HConstant* constant = new(zone()) HConstant( \ 694 Unique<Object>::CreateImmovable(isolate()->factory()->name##_value()), \ 695 Unique<Map>::CreateImmovable(isolate()->factory()->type##_map()), \ 696 false, \ 697 Representation::Tagged(), \ 698 htype, \ 699 true, \ 700 boolean_value, \ 701 false, \ 702 ODDBALL_TYPE); \ 703 constant->InsertAfter(entry_block()->first()); \ 704 constant_##name##_.set(constant); \ 705 } \ 706 return ReinsertConstantIfNecessary(constant_##name##_.get()); \ 707 } 708 709 710 DEFINE_GET_CONSTANT(Undefined, undefined, undefined, HType::Undefined(), false) 711 DEFINE_GET_CONSTANT(True, true, boolean, HType::Boolean(), true) 712 DEFINE_GET_CONSTANT(False, false, boolean, HType::Boolean(), false) 713 DEFINE_GET_CONSTANT(Hole, the_hole, the_hole, HType::None(), false) 714 DEFINE_GET_CONSTANT(Null, null, null, HType::Null(), false) 715 716 717 #undef DEFINE_GET_CONSTANT 718 719 #define DEFINE_IS_CONSTANT(Name, name) \ 720 bool HGraph::IsConstant##Name(HConstant* constant) { \ 721 return constant_##name##_.is_set() && constant == constant_##name##_.get(); \ 722 } 723 DEFINE_IS_CONSTANT(Undefined, undefined) 724 DEFINE_IS_CONSTANT(0, 0) 725 DEFINE_IS_CONSTANT(1, 1) 726 DEFINE_IS_CONSTANT(Minus1, minus1) 727 DEFINE_IS_CONSTANT(True, true) 728 DEFINE_IS_CONSTANT(False, false) 729 DEFINE_IS_CONSTANT(Hole, the_hole) 730 DEFINE_IS_CONSTANT(Null, null) 731 732 #undef DEFINE_IS_CONSTANT 733 734 735 HConstant* HGraph::GetInvalidContext() { 736 return GetConstant(&constant_invalid_context_, 0xFFFFC0C7); 737 } 738 739 740 bool HGraph::IsStandardConstant(HConstant* constant) { 741 if (IsConstantUndefined(constant)) return true; 742 if (IsConstant0(constant)) return true; 743 if (IsConstant1(constant)) return true; 744 if (IsConstantMinus1(constant)) return true; 745 if (IsConstantTrue(constant)) return true; 746 if (IsConstantFalse(constant)) return true; 747 if (IsConstantHole(constant)) return true; 748 if (IsConstantNull(constant)) return true; 749 return false; 750 } 751 752 753 HGraphBuilder::IfBuilder::IfBuilder() : builder_(NULL), needs_compare_(true) {} 754 755 756 HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder) 757 : needs_compare_(true) { 758 Initialize(builder); 759 } 760 761 762 HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder, 763 HIfContinuation* continuation) 764 : needs_compare_(false), first_true_block_(NULL), first_false_block_(NULL) { 765 InitializeDontCreateBlocks(builder); 766 continuation->Continue(&first_true_block_, &first_false_block_); 767 } 768 769 770 void HGraphBuilder::IfBuilder::InitializeDontCreateBlocks( 771 HGraphBuilder* builder) { 772 builder_ = builder; 773 finished_ = false; 774 did_then_ = false; 775 did_else_ = false; 776 did_else_if_ = false; 777 did_and_ = false; 778 did_or_ = false; 779 captured_ = false; 780 pending_merge_block_ = false; 781 split_edge_merge_block_ = NULL; 782 merge_at_join_blocks_ = NULL; 783 normal_merge_at_join_block_count_ = 0; 784 deopt_merge_at_join_block_count_ = 0; 785 } 786 787 788 void HGraphBuilder::IfBuilder::Initialize(HGraphBuilder* builder) { 789 InitializeDontCreateBlocks(builder); 790 HEnvironment* env = builder->environment(); 791 first_true_block_ = builder->CreateBasicBlock(env->Copy()); 792 first_false_block_ = builder->CreateBasicBlock(env->Copy()); 793 } 794 795 796 HControlInstruction* HGraphBuilder::IfBuilder::AddCompare( 797 HControlInstruction* compare) { 798 DCHECK(did_then_ == did_else_); 799 if (did_else_) { 800 // Handle if-then-elseif 801 did_else_if_ = true; 802 did_else_ = false; 803 did_then_ = false; 804 did_and_ = false; 805 did_or_ = false; 806 pending_merge_block_ = false; 807 split_edge_merge_block_ = NULL; 808 HEnvironment* env = builder()->environment(); 809 first_true_block_ = builder()->CreateBasicBlock(env->Copy()); 810 first_false_block_ = builder()->CreateBasicBlock(env->Copy()); 811 } 812 if (split_edge_merge_block_ != NULL) { 813 HEnvironment* env = first_false_block_->last_environment(); 814 HBasicBlock* split_edge = builder()->CreateBasicBlock(env->Copy()); 815 if (did_or_) { 816 compare->SetSuccessorAt(0, split_edge); 817 compare->SetSuccessorAt(1, first_false_block_); 818 } else { 819 compare->SetSuccessorAt(0, first_true_block_); 820 compare->SetSuccessorAt(1, split_edge); 821 } 822 builder()->GotoNoSimulate(split_edge, split_edge_merge_block_); 823 } else { 824 compare->SetSuccessorAt(0, first_true_block_); 825 compare->SetSuccessorAt(1, first_false_block_); 826 } 827 builder()->FinishCurrentBlock(compare); 828 needs_compare_ = false; 829 return compare; 830 } 831 832 833 void HGraphBuilder::IfBuilder::Or() { 834 DCHECK(!needs_compare_); 835 DCHECK(!did_and_); 836 did_or_ = true; 837 HEnvironment* env = first_false_block_->last_environment(); 838 if (split_edge_merge_block_ == NULL) { 839 split_edge_merge_block_ = builder()->CreateBasicBlock(env->Copy()); 840 builder()->GotoNoSimulate(first_true_block_, split_edge_merge_block_); 841 first_true_block_ = split_edge_merge_block_; 842 } 843 builder()->set_current_block(first_false_block_); 844 first_false_block_ = builder()->CreateBasicBlock(env->Copy()); 845 } 846 847 848 void HGraphBuilder::IfBuilder::And() { 849 DCHECK(!needs_compare_); 850 DCHECK(!did_or_); 851 did_and_ = true; 852 HEnvironment* env = first_false_block_->last_environment(); 853 if (split_edge_merge_block_ == NULL) { 854 split_edge_merge_block_ = builder()->CreateBasicBlock(env->Copy()); 855 builder()->GotoNoSimulate(first_false_block_, split_edge_merge_block_); 856 first_false_block_ = split_edge_merge_block_; 857 } 858 builder()->set_current_block(first_true_block_); 859 first_true_block_ = builder()->CreateBasicBlock(env->Copy()); 860 } 861 862 863 void HGraphBuilder::IfBuilder::CaptureContinuation( 864 HIfContinuation* continuation) { 865 DCHECK(!did_else_if_); 866 DCHECK(!finished_); 867 DCHECK(!captured_); 868 869 HBasicBlock* true_block = NULL; 870 HBasicBlock* false_block = NULL; 871 Finish(&true_block, &false_block); 872 DCHECK(true_block != NULL); 873 DCHECK(false_block != NULL); 874 continuation->Capture(true_block, false_block); 875 captured_ = true; 876 builder()->set_current_block(NULL); 877 End(); 878 } 879 880 881 void HGraphBuilder::IfBuilder::JoinContinuation(HIfContinuation* continuation) { 882 DCHECK(!did_else_if_); 883 DCHECK(!finished_); 884 DCHECK(!captured_); 885 HBasicBlock* true_block = NULL; 886 HBasicBlock* false_block = NULL; 887 Finish(&true_block, &false_block); 888 merge_at_join_blocks_ = NULL; 889 if (true_block != NULL && !true_block->IsFinished()) { 890 DCHECK(continuation->IsTrueReachable()); 891 builder()->GotoNoSimulate(true_block, continuation->true_branch()); 892 } 893 if (false_block != NULL && !false_block->IsFinished()) { 894 DCHECK(continuation->IsFalseReachable()); 895 builder()->GotoNoSimulate(false_block, continuation->false_branch()); 896 } 897 captured_ = true; 898 End(); 899 } 900 901 902 void HGraphBuilder::IfBuilder::Then() { 903 DCHECK(!captured_); 904 DCHECK(!finished_); 905 did_then_ = true; 906 if (needs_compare_) { 907 // Handle if's without any expressions, they jump directly to the "else" 908 // branch. However, we must pretend that the "then" branch is reachable, 909 // so that the graph builder visits it and sees any live range extending 910 // constructs within it. 911 HConstant* constant_false = builder()->graph()->GetConstantFalse(); 912 ToBooleanStub::Types boolean_type = ToBooleanStub::Types(); 913 boolean_type.Add(ToBooleanStub::BOOLEAN); 914 HBranch* branch = builder()->New<HBranch>( 915 constant_false, boolean_type, first_true_block_, first_false_block_); 916 builder()->FinishCurrentBlock(branch); 917 } 918 builder()->set_current_block(first_true_block_); 919 pending_merge_block_ = true; 920 } 921 922 923 void HGraphBuilder::IfBuilder::Else() { 924 DCHECK(did_then_); 925 DCHECK(!captured_); 926 DCHECK(!finished_); 927 AddMergeAtJoinBlock(false); 928 builder()->set_current_block(first_false_block_); 929 pending_merge_block_ = true; 930 did_else_ = true; 931 } 932 933 934 void HGraphBuilder::IfBuilder::Deopt(const char* reason) { 935 DCHECK(did_then_); 936 builder()->Add<HDeoptimize>(reason, Deoptimizer::EAGER); 937 AddMergeAtJoinBlock(true); 938 } 939 940 941 void HGraphBuilder::IfBuilder::Return(HValue* value) { 942 HValue* parameter_count = builder()->graph()->GetConstantMinus1(); 943 builder()->FinishExitCurrentBlock( 944 builder()->New<HReturn>(value, parameter_count)); 945 AddMergeAtJoinBlock(false); 946 } 947 948 949 void HGraphBuilder::IfBuilder::AddMergeAtJoinBlock(bool deopt) { 950 if (!pending_merge_block_) return; 951 HBasicBlock* block = builder()->current_block(); 952 DCHECK(block == NULL || !block->IsFinished()); 953 MergeAtJoinBlock* record = new (builder()->zone()) 954 MergeAtJoinBlock(block, deopt, merge_at_join_blocks_); 955 merge_at_join_blocks_ = record; 956 if (block != NULL) { 957 DCHECK(block->end() == NULL); 958 if (deopt) { 959 normal_merge_at_join_block_count_++; 960 } else { 961 deopt_merge_at_join_block_count_++; 962 } 963 } 964 builder()->set_current_block(NULL); 965 pending_merge_block_ = false; 966 } 967 968 969 void HGraphBuilder::IfBuilder::Finish() { 970 DCHECK(!finished_); 971 if (!did_then_) { 972 Then(); 973 } 974 AddMergeAtJoinBlock(false); 975 if (!did_else_) { 976 Else(); 977 AddMergeAtJoinBlock(false); 978 } 979 finished_ = true; 980 } 981 982 983 void HGraphBuilder::IfBuilder::Finish(HBasicBlock** then_continuation, 984 HBasicBlock** else_continuation) { 985 Finish(); 986 987 MergeAtJoinBlock* else_record = merge_at_join_blocks_; 988 if (else_continuation != NULL) { 989 *else_continuation = else_record->block_; 990 } 991 MergeAtJoinBlock* then_record = else_record->next_; 992 if (then_continuation != NULL) { 993 *then_continuation = then_record->block_; 994 } 995 DCHECK(then_record->next_ == NULL); 996 } 997 998 999 void HGraphBuilder::IfBuilder::End() { 1000 if (captured_) return; 1001 Finish(); 1002 1003 int total_merged_blocks = normal_merge_at_join_block_count_ + 1004 deopt_merge_at_join_block_count_; 1005 DCHECK(total_merged_blocks >= 1); 1006 HBasicBlock* merge_block = 1007 total_merged_blocks == 1 ? NULL : builder()->graph()->CreateBasicBlock(); 1008 1009 // Merge non-deopt blocks first to ensure environment has right size for 1010 // padding. 1011 MergeAtJoinBlock* current = merge_at_join_blocks_; 1012 while (current != NULL) { 1013 if (!current->deopt_ && current->block_ != NULL) { 1014 // If there is only one block that makes it through to the end of the 1015 // if, then just set it as the current block and continue rather then 1016 // creating an unnecessary merge block. 1017 if (total_merged_blocks == 1) { 1018 builder()->set_current_block(current->block_); 1019 return; 1020 } 1021 builder()->GotoNoSimulate(current->block_, merge_block); 1022 } 1023 current = current->next_; 1024 } 1025 1026 // Merge deopt blocks, padding when necessary. 1027 current = merge_at_join_blocks_; 1028 while (current != NULL) { 1029 if (current->deopt_ && current->block_ != NULL) { 1030 current->block_->FinishExit(HAbnormalExit::New(builder()->zone(), NULL), 1031 HSourcePosition::Unknown()); 1032 } 1033 current = current->next_; 1034 } 1035 builder()->set_current_block(merge_block); 1036 } 1037 1038 1039 HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder) { 1040 Initialize(builder, NULL, kWhileTrue, NULL); 1041 } 1042 1043 1044 HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder, HValue* context, 1045 LoopBuilder::Direction direction) { 1046 Initialize(builder, context, direction, builder->graph()->GetConstant1()); 1047 } 1048 1049 1050 HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder, HValue* context, 1051 LoopBuilder::Direction direction, 1052 HValue* increment_amount) { 1053 Initialize(builder, context, direction, increment_amount); 1054 increment_amount_ = increment_amount; 1055 } 1056 1057 1058 void HGraphBuilder::LoopBuilder::Initialize(HGraphBuilder* builder, 1059 HValue* context, 1060 Direction direction, 1061 HValue* increment_amount) { 1062 builder_ = builder; 1063 context_ = context; 1064 direction_ = direction; 1065 increment_amount_ = increment_amount; 1066 1067 finished_ = false; 1068 header_block_ = builder->CreateLoopHeaderBlock(); 1069 body_block_ = NULL; 1070 exit_block_ = NULL; 1071 exit_trampoline_block_ = NULL; 1072 } 1073 1074 1075 HValue* HGraphBuilder::LoopBuilder::BeginBody( 1076 HValue* initial, 1077 HValue* terminating, 1078 Token::Value token) { 1079 DCHECK(direction_ != kWhileTrue); 1080 HEnvironment* env = builder_->environment(); 1081 phi_ = header_block_->AddNewPhi(env->values()->length()); 1082 phi_->AddInput(initial); 1083 env->Push(initial); 1084 builder_->GotoNoSimulate(header_block_); 1085 1086 HEnvironment* body_env = env->Copy(); 1087 HEnvironment* exit_env = env->Copy(); 1088 // Remove the phi from the expression stack 1089 body_env->Pop(); 1090 exit_env->Pop(); 1091 body_block_ = builder_->CreateBasicBlock(body_env); 1092 exit_block_ = builder_->CreateBasicBlock(exit_env); 1093 1094 builder_->set_current_block(header_block_); 1095 env->Pop(); 1096 builder_->FinishCurrentBlock(builder_->New<HCompareNumericAndBranch>( 1097 phi_, terminating, token, body_block_, exit_block_)); 1098 1099 builder_->set_current_block(body_block_); 1100 if (direction_ == kPreIncrement || direction_ == kPreDecrement) { 1101 HValue* one = builder_->graph()->GetConstant1(); 1102 if (direction_ == kPreIncrement) { 1103 increment_ = HAdd::New(zone(), context_, phi_, one); 1104 } else { 1105 increment_ = HSub::New(zone(), context_, phi_, one); 1106 } 1107 increment_->ClearFlag(HValue::kCanOverflow); 1108 builder_->AddInstruction(increment_); 1109 return increment_; 1110 } else { 1111 return phi_; 1112 } 1113 } 1114 1115 1116 void HGraphBuilder::LoopBuilder::BeginBody(int drop_count) { 1117 DCHECK(direction_ == kWhileTrue); 1118 HEnvironment* env = builder_->environment(); 1119 builder_->GotoNoSimulate(header_block_); 1120 builder_->set_current_block(header_block_); 1121 env->Drop(drop_count); 1122 } 1123 1124 1125 void HGraphBuilder::LoopBuilder::Break() { 1126 if (exit_trampoline_block_ == NULL) { 1127 // Its the first time we saw a break. 1128 if (direction_ == kWhileTrue) { 1129 HEnvironment* env = builder_->environment()->Copy(); 1130 exit_trampoline_block_ = builder_->CreateBasicBlock(env); 1131 } else { 1132 HEnvironment* env = exit_block_->last_environment()->Copy(); 1133 exit_trampoline_block_ = builder_->CreateBasicBlock(env); 1134 builder_->GotoNoSimulate(exit_block_, exit_trampoline_block_); 1135 } 1136 } 1137 1138 builder_->GotoNoSimulate(exit_trampoline_block_); 1139 builder_->set_current_block(NULL); 1140 } 1141 1142 1143 void HGraphBuilder::LoopBuilder::EndBody() { 1144 DCHECK(!finished_); 1145 1146 if (direction_ == kPostIncrement || direction_ == kPostDecrement) { 1147 if (direction_ == kPostIncrement) { 1148 increment_ = HAdd::New(zone(), context_, phi_, increment_amount_); 1149 } else { 1150 increment_ = HSub::New(zone(), context_, phi_, increment_amount_); 1151 } 1152 increment_->ClearFlag(HValue::kCanOverflow); 1153 builder_->AddInstruction(increment_); 1154 } 1155 1156 if (direction_ != kWhileTrue) { 1157 // Push the new increment value on the expression stack to merge into 1158 // the phi. 1159 builder_->environment()->Push(increment_); 1160 } 1161 HBasicBlock* last_block = builder_->current_block(); 1162 builder_->GotoNoSimulate(last_block, header_block_); 1163 header_block_->loop_information()->RegisterBackEdge(last_block); 1164 1165 if (exit_trampoline_block_ != NULL) { 1166 builder_->set_current_block(exit_trampoline_block_); 1167 } else { 1168 builder_->set_current_block(exit_block_); 1169 } 1170 finished_ = true; 1171 } 1172 1173 1174 HGraph* HGraphBuilder::CreateGraph() { 1175 graph_ = new(zone()) HGraph(info_); 1176 if (FLAG_hydrogen_stats) isolate()->GetHStatistics()->Initialize(info_); 1177 CompilationPhase phase("H_Block building", info_); 1178 set_current_block(graph()->entry_block()); 1179 if (!BuildGraph()) return NULL; 1180 graph()->FinalizeUniqueness(); 1181 return graph_; 1182 } 1183 1184 1185 HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) { 1186 DCHECK(current_block() != NULL); 1187 DCHECK(!FLAG_hydrogen_track_positions || 1188 !position_.IsUnknown() || 1189 !info_->IsOptimizing()); 1190 current_block()->AddInstruction(instr, source_position()); 1191 if (graph()->IsInsideNoSideEffectsScope()) { 1192 instr->SetFlag(HValue::kHasNoObservableSideEffects); 1193 } 1194 return instr; 1195 } 1196 1197 1198 void HGraphBuilder::FinishCurrentBlock(HControlInstruction* last) { 1199 DCHECK(!FLAG_hydrogen_track_positions || 1200 !info_->IsOptimizing() || 1201 !position_.IsUnknown()); 1202 current_block()->Finish(last, source_position()); 1203 if (last->IsReturn() || last->IsAbnormalExit()) { 1204 set_current_block(NULL); 1205 } 1206 } 1207 1208 1209 void HGraphBuilder::FinishExitCurrentBlock(HControlInstruction* instruction) { 1210 DCHECK(!FLAG_hydrogen_track_positions || !info_->IsOptimizing() || 1211 !position_.IsUnknown()); 1212 current_block()->FinishExit(instruction, source_position()); 1213 if (instruction->IsReturn() || instruction->IsAbnormalExit()) { 1214 set_current_block(NULL); 1215 } 1216 } 1217 1218 1219 void HGraphBuilder::AddIncrementCounter(StatsCounter* counter) { 1220 if (FLAG_native_code_counters && counter->Enabled()) { 1221 HValue* reference = Add<HConstant>(ExternalReference(counter)); 1222 HValue* old_value = Add<HLoadNamedField>( 1223 reference, static_cast<HValue*>(NULL), HObjectAccess::ForCounter()); 1224 HValue* new_value = AddUncasted<HAdd>(old_value, graph()->GetConstant1()); 1225 new_value->ClearFlag(HValue::kCanOverflow); // Ignore counter overflow 1226 Add<HStoreNamedField>(reference, HObjectAccess::ForCounter(), 1227 new_value, STORE_TO_INITIALIZED_ENTRY); 1228 } 1229 } 1230 1231 1232 void HGraphBuilder::AddSimulate(BailoutId id, 1233 RemovableSimulate removable) { 1234 DCHECK(current_block() != NULL); 1235 DCHECK(!graph()->IsInsideNoSideEffectsScope()); 1236 current_block()->AddNewSimulate(id, source_position(), removable); 1237 } 1238 1239 1240 HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) { 1241 HBasicBlock* b = graph()->CreateBasicBlock(); 1242 b->SetInitialEnvironment(env); 1243 return b; 1244 } 1245 1246 1247 HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() { 1248 HBasicBlock* header = graph()->CreateBasicBlock(); 1249 HEnvironment* entry_env = environment()->CopyAsLoopHeader(header); 1250 header->SetInitialEnvironment(entry_env); 1251 header->AttachLoopInformation(); 1252 return header; 1253 } 1254 1255 1256 HValue* HGraphBuilder::BuildGetElementsKind(HValue* object) { 1257 HValue* map = Add<HLoadNamedField>(object, static_cast<HValue*>(NULL), 1258 HObjectAccess::ForMap()); 1259 1260 HValue* bit_field2 = Add<HLoadNamedField>(map, static_cast<HValue*>(NULL), 1261 HObjectAccess::ForMapBitField2()); 1262 return BuildDecodeField<Map::ElementsKindBits>(bit_field2); 1263 } 1264 1265 1266 HValue* HGraphBuilder::BuildCheckHeapObject(HValue* obj) { 1267 if (obj->type().IsHeapObject()) return obj; 1268 return Add<HCheckHeapObject>(obj); 1269 } 1270 1271 1272 void HGraphBuilder::FinishExitWithHardDeoptimization(const char* reason) { 1273 Add<HDeoptimize>(reason, Deoptimizer::EAGER); 1274 FinishExitCurrentBlock(New<HAbnormalExit>()); 1275 } 1276 1277 1278 HValue* HGraphBuilder::BuildCheckString(HValue* string) { 1279 if (!string->type().IsString()) { 1280 DCHECK(!string->IsConstant() || 1281 !HConstant::cast(string)->HasStringValue()); 1282 BuildCheckHeapObject(string); 1283 return Add<HCheckInstanceType>(string, HCheckInstanceType::IS_STRING); 1284 } 1285 return string; 1286 } 1287 1288 1289 HValue* HGraphBuilder::BuildWrapReceiver(HValue* object, HValue* function) { 1290 if (object->type().IsJSObject()) return object; 1291 if (function->IsConstant() && 1292 HConstant::cast(function)->handle(isolate())->IsJSFunction()) { 1293 Handle<JSFunction> f = Handle<JSFunction>::cast( 1294 HConstant::cast(function)->handle(isolate())); 1295 SharedFunctionInfo* shared = f->shared(); 1296 if (shared->strict_mode() == STRICT || shared->native()) return object; 1297 } 1298 return Add<HWrapReceiver>(object, function); 1299 } 1300 1301 1302 HValue* HGraphBuilder::BuildCheckForCapacityGrow( 1303 HValue* object, 1304 HValue* elements, 1305 ElementsKind kind, 1306 HValue* length, 1307 HValue* key, 1308 bool is_js_array, 1309 PropertyAccessType access_type) { 1310 IfBuilder length_checker(this); 1311 1312 Token::Value token = IsHoleyElementsKind(kind) ? Token::GTE : Token::EQ; 1313 length_checker.If<HCompareNumericAndBranch>(key, length, token); 1314 1315 length_checker.Then(); 1316 1317 HValue* current_capacity = AddLoadFixedArrayLength(elements); 1318 1319 IfBuilder capacity_checker(this); 1320 1321 capacity_checker.If<HCompareNumericAndBranch>(key, current_capacity, 1322 Token::GTE); 1323 capacity_checker.Then(); 1324 1325 HValue* max_gap = Add<HConstant>(static_cast<int32_t>(JSObject::kMaxGap)); 1326 HValue* max_capacity = AddUncasted<HAdd>(current_capacity, max_gap); 1327 1328 Add<HBoundsCheck>(key, max_capacity); 1329 1330 HValue* new_capacity = BuildNewElementsCapacity(key); 1331 HValue* new_elements = BuildGrowElementsCapacity(object, elements, 1332 kind, kind, length, 1333 new_capacity); 1334 1335 environment()->Push(new_elements); 1336 capacity_checker.Else(); 1337 1338 environment()->Push(elements); 1339 capacity_checker.End(); 1340 1341 if (is_js_array) { 1342 HValue* new_length = AddUncasted<HAdd>(key, graph_->GetConstant1()); 1343 new_length->ClearFlag(HValue::kCanOverflow); 1344 1345 Add<HStoreNamedField>(object, HObjectAccess::ForArrayLength(kind), 1346 new_length); 1347 } 1348 1349 if (access_type == STORE && kind == FAST_SMI_ELEMENTS) { 1350 HValue* checked_elements = environment()->Top(); 1351 1352 // Write zero to ensure that the new element is initialized with some smi. 1353 Add<HStoreKeyed>(checked_elements, key, graph()->GetConstant0(), kind); 1354 } 1355 1356 length_checker.Else(); 1357 Add<HBoundsCheck>(key, length); 1358 1359 environment()->Push(elements); 1360 length_checker.End(); 1361 1362 return environment()->Pop(); 1363 } 1364 1365 1366 HValue* HGraphBuilder::BuildCopyElementsOnWrite(HValue* object, 1367 HValue* elements, 1368 ElementsKind kind, 1369 HValue* length) { 1370 Factory* factory = isolate()->factory(); 1371 1372 IfBuilder cow_checker(this); 1373 1374 cow_checker.If<HCompareMap>(elements, factory->fixed_cow_array_map()); 1375 cow_checker.Then(); 1376 1377 HValue* capacity = AddLoadFixedArrayLength(elements); 1378 1379 HValue* new_elements = BuildGrowElementsCapacity(object, elements, kind, 1380 kind, length, capacity); 1381 1382 environment()->Push(new_elements); 1383 1384 cow_checker.Else(); 1385 1386 environment()->Push(elements); 1387 1388 cow_checker.End(); 1389 1390 return environment()->Pop(); 1391 } 1392 1393 1394 void HGraphBuilder::BuildTransitionElementsKind(HValue* object, 1395 HValue* map, 1396 ElementsKind from_kind, 1397 ElementsKind to_kind, 1398 bool is_jsarray) { 1399 DCHECK(!IsFastHoleyElementsKind(from_kind) || 1400 IsFastHoleyElementsKind(to_kind)); 1401 1402 if (AllocationSite::GetMode(from_kind, to_kind) == TRACK_ALLOCATION_SITE) { 1403 Add<HTrapAllocationMemento>(object); 1404 } 1405 1406 if (!IsSimpleMapChangeTransition(from_kind, to_kind)) { 1407 HInstruction* elements = AddLoadElements(object); 1408 1409 HInstruction* empty_fixed_array = Add<HConstant>( 1410 isolate()->factory()->empty_fixed_array()); 1411 1412 IfBuilder if_builder(this); 1413 1414 if_builder.IfNot<HCompareObjectEqAndBranch>(elements, empty_fixed_array); 1415 1416 if_builder.Then(); 1417 1418 HInstruction* elements_length = AddLoadFixedArrayLength(elements); 1419 1420 HInstruction* array_length = is_jsarray 1421 ? Add<HLoadNamedField>(object, static_cast<HValue*>(NULL), 1422 HObjectAccess::ForArrayLength(from_kind)) 1423 : elements_length; 1424 1425 BuildGrowElementsCapacity(object, elements, from_kind, to_kind, 1426 array_length, elements_length); 1427 1428 if_builder.End(); 1429 } 1430 1431 Add<HStoreNamedField>(object, HObjectAccess::ForMap(), map); 1432 } 1433 1434 1435 void HGraphBuilder::BuildJSObjectCheck(HValue* receiver, 1436 int bit_field_mask) { 1437 // Check that the object isn't a smi. 1438 Add<HCheckHeapObject>(receiver); 1439 1440 // Get the map of the receiver. 1441 HValue* map = Add<HLoadNamedField>(receiver, static_cast<HValue*>(NULL), 1442 HObjectAccess::ForMap()); 1443 1444 // Check the instance type and if an access check is needed, this can be 1445 // done with a single load, since both bytes are adjacent in the map. 1446 HObjectAccess access(HObjectAccess::ForMapInstanceTypeAndBitField()); 1447 HValue* instance_type_and_bit_field = 1448 Add<HLoadNamedField>(map, static_cast<HValue*>(NULL), access); 1449 1450 HValue* mask = Add<HConstant>(0x00FF | (bit_field_mask << 8)); 1451 HValue* and_result = AddUncasted<HBitwise>(Token::BIT_AND, 1452 instance_type_and_bit_field, 1453 mask); 1454 HValue* sub_result = AddUncasted<HSub>(and_result, 1455 Add<HConstant>(JS_OBJECT_TYPE)); 1456 Add<HBoundsCheck>(sub_result, 1457 Add<HConstant>(LAST_JS_OBJECT_TYPE + 1 - JS_OBJECT_TYPE)); 1458 } 1459 1460 1461 void HGraphBuilder::BuildKeyedIndexCheck(HValue* key, 1462 HIfContinuation* join_continuation) { 1463 // The sometimes unintuitively backward ordering of the ifs below is 1464 // convoluted, but necessary. All of the paths must guarantee that the 1465 // if-true of the continuation returns a smi element index and the if-false of 1466 // the continuation returns either a symbol or a unique string key. All other 1467 // object types cause a deopt to fall back to the runtime. 1468 1469 IfBuilder key_smi_if(this); 1470 key_smi_if.If<HIsSmiAndBranch>(key); 1471 key_smi_if.Then(); 1472 { 1473 Push(key); // Nothing to do, just continue to true of continuation. 1474 } 1475 key_smi_if.Else(); 1476 { 1477 HValue* map = Add<HLoadNamedField>(key, static_cast<HValue*>(NULL), 1478 HObjectAccess::ForMap()); 1479 HValue* instance_type = 1480 Add<HLoadNamedField>(map, static_cast<HValue*>(NULL), 1481 HObjectAccess::ForMapInstanceType()); 1482 1483 // Non-unique string, check for a string with a hash code that is actually 1484 // an index. 1485 STATIC_ASSERT(LAST_UNIQUE_NAME_TYPE == FIRST_NONSTRING_TYPE); 1486 IfBuilder not_string_or_name_if(this); 1487 not_string_or_name_if.If<HCompareNumericAndBranch>( 1488 instance_type, 1489 Add<HConstant>(LAST_UNIQUE_NAME_TYPE), 1490 Token::GT); 1491 1492 not_string_or_name_if.Then(); 1493 { 1494 // Non-smi, non-Name, non-String: Try to convert to smi in case of 1495 // HeapNumber. 1496 // TODO(danno): This could call some variant of ToString 1497 Push(AddUncasted<HForceRepresentation>(key, Representation::Smi())); 1498 } 1499 not_string_or_name_if.Else(); 1500 { 1501 // String or Name: check explicitly for Name, they can short-circuit 1502 // directly to unique non-index key path. 1503 IfBuilder not_symbol_if(this); 1504 not_symbol_if.If<HCompareNumericAndBranch>( 1505 instance_type, 1506 Add<HConstant>(SYMBOL_TYPE), 1507 Token::NE); 1508 1509 not_symbol_if.Then(); 1510 { 1511 // String: check whether the String is a String of an index. If it is, 1512 // extract the index value from the hash. 1513 HValue* hash = 1514 Add<HLoadNamedField>(key, static_cast<HValue*>(NULL), 1515 HObjectAccess::ForNameHashField()); 1516 HValue* not_index_mask = Add<HConstant>(static_cast<int>( 1517 String::kContainsCachedArrayIndexMask)); 1518 1519 HValue* not_index_test = AddUncasted<HBitwise>( 1520 Token::BIT_AND, hash, not_index_mask); 1521 1522 IfBuilder string_index_if(this); 1523 string_index_if.If<HCompareNumericAndBranch>(not_index_test, 1524 graph()->GetConstant0(), 1525 Token::EQ); 1526 string_index_if.Then(); 1527 { 1528 // String with index in hash: extract string and merge to index path. 1529 Push(BuildDecodeField<String::ArrayIndexValueBits>(hash)); 1530 } 1531 string_index_if.Else(); 1532 { 1533 // Key is a non-index String, check for uniqueness/internalization. 1534 // If it's not internalized yet, internalize it now. 1535 HValue* not_internalized_bit = AddUncasted<HBitwise>( 1536 Token::BIT_AND, 1537 instance_type, 1538 Add<HConstant>(static_cast<int>(kIsNotInternalizedMask))); 1539 1540 IfBuilder internalized(this); 1541 internalized.If<HCompareNumericAndBranch>(not_internalized_bit, 1542 graph()->GetConstant0(), 1543 Token::EQ); 1544 internalized.Then(); 1545 Push(key); 1546 1547 internalized.Else(); 1548 Add<HPushArguments>(key); 1549 HValue* intern_key = Add<HCallRuntime>( 1550 isolate()->factory()->empty_string(), 1551 Runtime::FunctionForId(Runtime::kInternalizeString), 1); 1552 Push(intern_key); 1553 1554 internalized.End(); 1555 // Key guaranteed to be a unique string 1556 } 1557 string_index_if.JoinContinuation(join_continuation); 1558 } 1559 not_symbol_if.Else(); 1560 { 1561 Push(key); // Key is symbol 1562 } 1563 not_symbol_if.JoinContinuation(join_continuation); 1564 } 1565 not_string_or_name_if.JoinContinuation(join_continuation); 1566 } 1567 key_smi_if.JoinContinuation(join_continuation); 1568 } 1569 1570 1571 void HGraphBuilder::BuildNonGlobalObjectCheck(HValue* receiver) { 1572 // Get the the instance type of the receiver, and make sure that it is 1573 // not one of the global object types. 1574 HValue* map = Add<HLoadNamedField>(receiver, static_cast<HValue*>(NULL), 1575 HObjectAccess::ForMap()); 1576 HValue* instance_type = 1577 Add<HLoadNamedField>(map, static_cast<HValue*>(NULL), 1578 HObjectAccess::ForMapInstanceType()); 1579 STATIC_ASSERT(JS_BUILTINS_OBJECT_TYPE == JS_GLOBAL_OBJECT_TYPE + 1); 1580 HValue* min_global_type = Add<HConstant>(JS_GLOBAL_OBJECT_TYPE); 1581 HValue* max_global_type = Add<HConstant>(JS_BUILTINS_OBJECT_TYPE); 1582 1583 IfBuilder if_global_object(this); 1584 if_global_object.If<HCompareNumericAndBranch>(instance_type, 1585 max_global_type, 1586 Token::LTE); 1587 if_global_object.And(); 1588 if_global_object.If<HCompareNumericAndBranch>(instance_type, 1589 min_global_type, 1590 Token::GTE); 1591 if_global_object.ThenDeopt("receiver was a global object"); 1592 if_global_object.End(); 1593 } 1594 1595 1596 void HGraphBuilder::BuildTestForDictionaryProperties( 1597 HValue* object, 1598 HIfContinuation* continuation) { 1599 HValue* properties = Add<HLoadNamedField>( 1600 object, static_cast<HValue*>(NULL), 1601 HObjectAccess::ForPropertiesPointer()); 1602 HValue* properties_map = 1603 Add<HLoadNamedField>(properties, static_cast<HValue*>(NULL), 1604 HObjectAccess::ForMap()); 1605 HValue* hash_map = Add<HLoadRoot>(Heap::kHashTableMapRootIndex); 1606 IfBuilder builder(this); 1607 builder.If<HCompareObjectEqAndBranch>(properties_map, hash_map); 1608 builder.CaptureContinuation(continuation); 1609 } 1610 1611 1612 HValue* HGraphBuilder::BuildKeyedLookupCacheHash(HValue* object, 1613 HValue* key) { 1614 // Load the map of the receiver, compute the keyed lookup cache hash 1615 // based on 32 bits of the map pointer and the string hash. 1616 HValue* object_map = 1617 Add<HLoadNamedField>(object, static_cast<HValue*>(NULL), 1618 HObjectAccess::ForMapAsInteger32()); 1619 HValue* shifted_map = AddUncasted<HShr>( 1620 object_map, Add<HConstant>(KeyedLookupCache::kMapHashShift)); 1621 HValue* string_hash = 1622 Add<HLoadNamedField>(key, static_cast<HValue*>(NULL), 1623 HObjectAccess::ForStringHashField()); 1624 HValue* shifted_hash = AddUncasted<HShr>( 1625 string_hash, Add<HConstant>(String::kHashShift)); 1626 HValue* xor_result = AddUncasted<HBitwise>(Token::BIT_XOR, shifted_map, 1627 shifted_hash); 1628 int mask = (KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask); 1629 return AddUncasted<HBitwise>(Token::BIT_AND, xor_result, 1630 Add<HConstant>(mask)); 1631 } 1632 1633 1634 HValue* HGraphBuilder::BuildElementIndexHash(HValue* index) { 1635 int32_t seed_value = static_cast<uint32_t>(isolate()->heap()->HashSeed()); 1636 HValue* seed = Add<HConstant>(seed_value); 1637 HValue* hash = AddUncasted<HBitwise>(Token::BIT_XOR, index, seed); 1638 1639 // hash = ~hash + (hash << 15); 1640 HValue* shifted_hash = AddUncasted<HShl>(hash, Add<HConstant>(15)); 1641 HValue* not_hash = AddUncasted<HBitwise>(Token::BIT_XOR, hash, 1642 graph()->GetConstantMinus1()); 1643 hash = AddUncasted<HAdd>(shifted_hash, not_hash); 1644 1645 // hash = hash ^ (hash >> 12); 1646 shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(12)); 1647 hash = AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash); 1648 1649 // hash = hash + (hash << 2); 1650 shifted_hash = AddUncasted<HShl>(hash, Add<HConstant>(2)); 1651 hash = AddUncasted<HAdd>(hash, shifted_hash); 1652 1653 // hash = hash ^ (hash >> 4); 1654 shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(4)); 1655 hash = AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash); 1656 1657 // hash = hash * 2057; 1658 hash = AddUncasted<HMul>(hash, Add<HConstant>(2057)); 1659 hash->ClearFlag(HValue::kCanOverflow); 1660 1661 // hash = hash ^ (hash >> 16); 1662 shifted_hash = AddUncasted<HShr>(hash, Add<HConstant>(16)); 1663 return AddUncasted<HBitwise>(Token::BIT_XOR, hash, shifted_hash); 1664 } 1665 1666 1667 HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoad(HValue* receiver, 1668 HValue* elements, 1669 HValue* key, 1670 HValue* hash) { 1671 HValue* capacity = Add<HLoadKeyed>( 1672 elements, 1673 Add<HConstant>(NameDictionary::kCapacityIndex), 1674 static_cast<HValue*>(NULL), 1675 FAST_ELEMENTS); 1676 1677 HValue* mask = AddUncasted<HSub>(capacity, graph()->GetConstant1()); 1678 mask->ChangeRepresentation(Representation::Integer32()); 1679 mask->ClearFlag(HValue::kCanOverflow); 1680 1681 HValue* entry = hash; 1682 HValue* count = graph()->GetConstant1(); 1683 Push(entry); 1684 Push(count); 1685 1686 HIfContinuation return_or_loop_continuation(graph()->CreateBasicBlock(), 1687 graph()->CreateBasicBlock()); 1688 HIfContinuation found_key_match_continuation(graph()->CreateBasicBlock(), 1689 graph()->CreateBasicBlock()); 1690 LoopBuilder probe_loop(this); 1691 probe_loop.BeginBody(2); // Drop entry, count from last environment to 1692 // appease live range building without simulates. 1693 1694 count = Pop(); 1695 entry = Pop(); 1696 entry = AddUncasted<HBitwise>(Token::BIT_AND, entry, mask); 1697 int entry_size = SeededNumberDictionary::kEntrySize; 1698 HValue* base_index = AddUncasted<HMul>(entry, Add<HConstant>(entry_size)); 1699 base_index->ClearFlag(HValue::kCanOverflow); 1700 int start_offset = SeededNumberDictionary::kElementsStartIndex; 1701 HValue* key_index = 1702 AddUncasted<HAdd>(base_index, Add<HConstant>(start_offset)); 1703 key_index->ClearFlag(HValue::kCanOverflow); 1704 1705 HValue* candidate_key = Add<HLoadKeyed>( 1706 elements, key_index, static_cast<HValue*>(NULL), FAST_ELEMENTS); 1707 IfBuilder if_undefined(this); 1708 if_undefined.If<HCompareObjectEqAndBranch>(candidate_key, 1709 graph()->GetConstantUndefined()); 1710 if_undefined.Then(); 1711 { 1712 // element == undefined means "not found". Call the runtime. 1713 // TODO(jkummerow): walk the prototype chain instead. 1714 Add<HPushArguments>(receiver, key); 1715 Push(Add<HCallRuntime>(isolate()->factory()->empty_string(), 1716 Runtime::FunctionForId(Runtime::kKeyedGetProperty), 1717 2)); 1718 } 1719 if_undefined.Else(); 1720 { 1721 IfBuilder if_match(this); 1722 if_match.If<HCompareObjectEqAndBranch>(candidate_key, key); 1723 if_match.Then(); 1724 if_match.Else(); 1725 1726 // Update non-internalized string in the dictionary with internalized key? 1727 IfBuilder if_update_with_internalized(this); 1728 HValue* smi_check = 1729 if_update_with_internalized.IfNot<HIsSmiAndBranch>(candidate_key); 1730 if_update_with_internalized.And(); 1731 HValue* map = AddLoadMap(candidate_key, smi_check); 1732 HValue* instance_type = Add<HLoadNamedField>( 1733 map, static_cast<HValue*>(NULL), HObjectAccess::ForMapInstanceType()); 1734 HValue* not_internalized_bit = AddUncasted<HBitwise>( 1735 Token::BIT_AND, instance_type, 1736 Add<HConstant>(static_cast<int>(kIsNotInternalizedMask))); 1737 if_update_with_internalized.If<HCompareNumericAndBranch>( 1738 not_internalized_bit, graph()->GetConstant0(), Token::NE); 1739 if_update_with_internalized.And(); 1740 if_update_with_internalized.IfNot<HCompareObjectEqAndBranch>( 1741 candidate_key, graph()->GetConstantHole()); 1742 if_update_with_internalized.AndIf<HStringCompareAndBranch>(candidate_key, 1743 key, Token::EQ); 1744 if_update_with_internalized.Then(); 1745 // Replace a key that is a non-internalized string by the equivalent 1746 // internalized string for faster further lookups. 1747 Add<HStoreKeyed>(elements, key_index, key, FAST_ELEMENTS); 1748 if_update_with_internalized.Else(); 1749 1750 if_update_with_internalized.JoinContinuation(&found_key_match_continuation); 1751 if_match.JoinContinuation(&found_key_match_continuation); 1752 1753 IfBuilder found_key_match(this, &found_key_match_continuation); 1754 found_key_match.Then(); 1755 // Key at current probe matches. Relevant bits in the |details| field must 1756 // be zero, otherwise the dictionary element requires special handling. 1757 HValue* details_index = 1758 AddUncasted<HAdd>(base_index, Add<HConstant>(start_offset + 2)); 1759 details_index->ClearFlag(HValue::kCanOverflow); 1760 HValue* details = Add<HLoadKeyed>( 1761 elements, details_index, static_cast<HValue*>(NULL), FAST_ELEMENTS); 1762 int details_mask = PropertyDetails::TypeField::kMask | 1763 PropertyDetails::DeletedField::kMask; 1764 details = AddUncasted<HBitwise>(Token::BIT_AND, details, 1765 Add<HConstant>(details_mask)); 1766 IfBuilder details_compare(this); 1767 details_compare.If<HCompareNumericAndBranch>( 1768 details, graph()->GetConstant0(), Token::EQ); 1769 details_compare.Then(); 1770 HValue* result_index = 1771 AddUncasted<HAdd>(base_index, Add<HConstant>(start_offset + 1)); 1772 result_index->ClearFlag(HValue::kCanOverflow); 1773 Push(Add<HLoadKeyed>(elements, result_index, static_cast<HValue*>(NULL), 1774 FAST_ELEMENTS)); 1775 details_compare.Else(); 1776 Add<HPushArguments>(receiver, key); 1777 Push(Add<HCallRuntime>(isolate()->factory()->empty_string(), 1778 Runtime::FunctionForId(Runtime::kKeyedGetProperty), 1779 2)); 1780 details_compare.End(); 1781 1782 found_key_match.Else(); 1783 found_key_match.JoinContinuation(&return_or_loop_continuation); 1784 } 1785 if_undefined.JoinContinuation(&return_or_loop_continuation); 1786 1787 IfBuilder return_or_loop(this, &return_or_loop_continuation); 1788 return_or_loop.Then(); 1789 probe_loop.Break(); 1790 1791 return_or_loop.Else(); 1792 entry = AddUncasted<HAdd>(entry, count); 1793 entry->ClearFlag(HValue::kCanOverflow); 1794 count = AddUncasted<HAdd>(count, graph()->GetConstant1()); 1795 count->ClearFlag(HValue::kCanOverflow); 1796 Push(entry); 1797 Push(count); 1798 1799 probe_loop.EndBody(); 1800 1801 return_or_loop.End(); 1802 1803 return Pop(); 1804 } 1805 1806 1807 HValue* HGraphBuilder::BuildRegExpConstructResult(HValue* length, 1808 HValue* index, 1809 HValue* input) { 1810 NoObservableSideEffectsScope scope(this); 1811 HConstant* max_length = Add<HConstant>(JSObject::kInitialMaxFastElementArray); 1812 Add<HBoundsCheck>(length, max_length); 1813 1814 // Generate size calculation code here in order to make it dominate 1815 // the JSRegExpResult allocation. 1816 ElementsKind elements_kind = FAST_ELEMENTS; 1817 HValue* size = BuildCalculateElementsSize(elements_kind, length); 1818 1819 // Allocate the JSRegExpResult and the FixedArray in one step. 1820 HValue* result = Add<HAllocate>( 1821 Add<HConstant>(JSRegExpResult::kSize), HType::JSArray(), 1822 NOT_TENURED, JS_ARRAY_TYPE); 1823 1824 // Initialize the JSRegExpResult header. 1825 HValue* global_object = Add<HLoadNamedField>( 1826 context(), static_cast<HValue*>(NULL), 1827 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); 1828 HValue* native_context = Add<HLoadNamedField>( 1829 global_object, static_cast<HValue*>(NULL), 1830 HObjectAccess::ForGlobalObjectNativeContext()); 1831 Add<HStoreNamedField>( 1832 result, HObjectAccess::ForMap(), 1833 Add<HLoadNamedField>( 1834 native_context, static_cast<HValue*>(NULL), 1835 HObjectAccess::ForContextSlot(Context::REGEXP_RESULT_MAP_INDEX))); 1836 HConstant* empty_fixed_array = 1837 Add<HConstant>(isolate()->factory()->empty_fixed_array()); 1838 Add<HStoreNamedField>( 1839 result, HObjectAccess::ForJSArrayOffset(JSArray::kPropertiesOffset), 1840 empty_fixed_array); 1841 Add<HStoreNamedField>( 1842 result, HObjectAccess::ForJSArrayOffset(JSArray::kElementsOffset), 1843 empty_fixed_array); 1844 Add<HStoreNamedField>( 1845 result, HObjectAccess::ForJSArrayOffset(JSArray::kLengthOffset), length); 1846 1847 // Initialize the additional fields. 1848 Add<HStoreNamedField>( 1849 result, HObjectAccess::ForJSArrayOffset(JSRegExpResult::kIndexOffset), 1850 index); 1851 Add<HStoreNamedField>( 1852 result, HObjectAccess::ForJSArrayOffset(JSRegExpResult::kInputOffset), 1853 input); 1854 1855 // Allocate and initialize the elements header. 1856 HAllocate* elements = BuildAllocateElements(elements_kind, size); 1857 BuildInitializeElementsHeader(elements, elements_kind, length); 1858 1859 if (!elements->has_size_upper_bound()) { 1860 HConstant* size_in_bytes_upper_bound = EstablishElementsAllocationSize( 1861 elements_kind, max_length->Integer32Value()); 1862 elements->set_size_upper_bound(size_in_bytes_upper_bound); 1863 } 1864 1865 Add<HStoreNamedField>( 1866 result, HObjectAccess::ForJSArrayOffset(JSArray::kElementsOffset), 1867 elements); 1868 1869 // Initialize the elements contents with undefined. 1870 BuildFillElementsWithValue( 1871 elements, elements_kind, graph()->GetConstant0(), length, 1872 graph()->GetConstantUndefined()); 1873 1874 return result; 1875 } 1876 1877 1878 HValue* HGraphBuilder::BuildNumberToString(HValue* object, Type* type) { 1879 NoObservableSideEffectsScope scope(this); 1880 1881 // Convert constant numbers at compile time. 1882 if (object->IsConstant() && HConstant::cast(object)->HasNumberValue()) { 1883 Handle<Object> number = HConstant::cast(object)->handle(isolate()); 1884 Handle<String> result = isolate()->factory()->NumberToString(number); 1885 return Add<HConstant>(result); 1886 } 1887 1888 // Create a joinable continuation. 1889 HIfContinuation found(graph()->CreateBasicBlock(), 1890 graph()->CreateBasicBlock()); 1891 1892 // Load the number string cache. 1893 HValue* number_string_cache = 1894 Add<HLoadRoot>(Heap::kNumberStringCacheRootIndex); 1895 1896 // Make the hash mask from the length of the number string cache. It 1897 // contains two elements (number and string) for each cache entry. 1898 HValue* mask = AddLoadFixedArrayLength(number_string_cache); 1899 mask->set_type(HType::Smi()); 1900 mask = AddUncasted<HSar>(mask, graph()->GetConstant1()); 1901 mask = AddUncasted<HSub>(mask, graph()->GetConstant1()); 1902 1903 // Check whether object is a smi. 1904 IfBuilder if_objectissmi(this); 1905 if_objectissmi.If<HIsSmiAndBranch>(object); 1906 if_objectissmi.Then(); 1907 { 1908 // Compute hash for smi similar to smi_get_hash(). 1909 HValue* hash = AddUncasted<HBitwise>(Token::BIT_AND, object, mask); 1910 1911 // Load the key. 1912 HValue* key_index = AddUncasted<HShl>(hash, graph()->GetConstant1()); 1913 HValue* key = Add<HLoadKeyed>(number_string_cache, key_index, 1914 static_cast<HValue*>(NULL), 1915 FAST_ELEMENTS, ALLOW_RETURN_HOLE); 1916 1917 // Check if object == key. 1918 IfBuilder if_objectiskey(this); 1919 if_objectiskey.If<HCompareObjectEqAndBranch>(object, key); 1920 if_objectiskey.Then(); 1921 { 1922 // Make the key_index available. 1923 Push(key_index); 1924 } 1925 if_objectiskey.JoinContinuation(&found); 1926 } 1927 if_objectissmi.Else(); 1928 { 1929 if (type->Is(Type::SignedSmall())) { 1930 if_objectissmi.Deopt("Expected smi"); 1931 } else { 1932 // Check if the object is a heap number. 1933 IfBuilder if_objectisnumber(this); 1934 HValue* objectisnumber = if_objectisnumber.If<HCompareMap>( 1935 object, isolate()->factory()->heap_number_map()); 1936 if_objectisnumber.Then(); 1937 { 1938 // Compute hash for heap number similar to double_get_hash(). 1939 HValue* low = Add<HLoadNamedField>( 1940 object, objectisnumber, 1941 HObjectAccess::ForHeapNumberValueLowestBits()); 1942 HValue* high = Add<HLoadNamedField>( 1943 object, objectisnumber, 1944 HObjectAccess::ForHeapNumberValueHighestBits()); 1945 HValue* hash = AddUncasted<HBitwise>(Token::BIT_XOR, low, high); 1946 hash = AddUncasted<HBitwise>(Token::BIT_AND, hash, mask); 1947 1948 // Load the key. 1949 HValue* key_index = AddUncasted<HShl>(hash, graph()->GetConstant1()); 1950 HValue* key = Add<HLoadKeyed>(number_string_cache, key_index, 1951 static_cast<HValue*>(NULL), 1952 FAST_ELEMENTS, ALLOW_RETURN_HOLE); 1953 1954 // Check if the key is a heap number and compare it with the object. 1955 IfBuilder if_keyisnotsmi(this); 1956 HValue* keyisnotsmi = if_keyisnotsmi.IfNot<HIsSmiAndBranch>(key); 1957 if_keyisnotsmi.Then(); 1958 { 1959 IfBuilder if_keyisheapnumber(this); 1960 if_keyisheapnumber.If<HCompareMap>( 1961 key, isolate()->factory()->heap_number_map()); 1962 if_keyisheapnumber.Then(); 1963 { 1964 // Check if values of key and object match. 1965 IfBuilder if_keyeqobject(this); 1966 if_keyeqobject.If<HCompareNumericAndBranch>( 1967 Add<HLoadNamedField>(key, keyisnotsmi, 1968 HObjectAccess::ForHeapNumberValue()), 1969 Add<HLoadNamedField>(object, objectisnumber, 1970 HObjectAccess::ForHeapNumberValue()), 1971 Token::EQ); 1972 if_keyeqobject.Then(); 1973 { 1974 // Make the key_index available. 1975 Push(key_index); 1976 } 1977 if_keyeqobject.JoinContinuation(&found); 1978 } 1979 if_keyisheapnumber.JoinContinuation(&found); 1980 } 1981 if_keyisnotsmi.JoinContinuation(&found); 1982 } 1983 if_objectisnumber.Else(); 1984 { 1985 if (type->Is(Type::Number())) { 1986 if_objectisnumber.Deopt("Expected heap number"); 1987 } 1988 } 1989 if_objectisnumber.JoinContinuation(&found); 1990 } 1991 } 1992 if_objectissmi.JoinContinuation(&found); 1993 1994 // Check for cache hit. 1995 IfBuilder if_found(this, &found); 1996 if_found.Then(); 1997 { 1998 // Count number to string operation in native code. 1999 AddIncrementCounter(isolate()->counters()->number_to_string_native()); 2000 2001 // Load the value in case of cache hit. 2002 HValue* key_index = Pop(); 2003 HValue* value_index = AddUncasted<HAdd>(key_index, graph()->GetConstant1()); 2004 Push(Add<HLoadKeyed>(number_string_cache, value_index, 2005 static_cast<HValue*>(NULL), 2006 FAST_ELEMENTS, ALLOW_RETURN_HOLE)); 2007 } 2008 if_found.Else(); 2009 { 2010 // Cache miss, fallback to runtime. 2011 Add<HPushArguments>(object); 2012 Push(Add<HCallRuntime>( 2013 isolate()->factory()->empty_string(), 2014 Runtime::FunctionForId(Runtime::kNumberToStringSkipCache), 2015 1)); 2016 } 2017 if_found.End(); 2018 2019 return Pop(); 2020 } 2021 2022 2023 HAllocate* HGraphBuilder::BuildAllocate( 2024 HValue* object_size, 2025 HType type, 2026 InstanceType instance_type, 2027 HAllocationMode allocation_mode) { 2028 // Compute the effective allocation size. 2029 HValue* size = object_size; 2030 if (allocation_mode.CreateAllocationMementos()) { 2031 size = AddUncasted<HAdd>(size, Add<HConstant>(AllocationMemento::kSize)); 2032 size->ClearFlag(HValue::kCanOverflow); 2033 } 2034 2035 // Perform the actual allocation. 2036 HAllocate* object = Add<HAllocate>( 2037 size, type, allocation_mode.GetPretenureMode(), 2038 instance_type, allocation_mode.feedback_site()); 2039 2040 // Setup the allocation memento. 2041 if (allocation_mode.CreateAllocationMementos()) { 2042 BuildCreateAllocationMemento( 2043 object, object_size, allocation_mode.current_site()); 2044 } 2045 2046 return object; 2047 } 2048 2049 2050 HValue* HGraphBuilder::BuildAddStringLengths(HValue* left_length, 2051 HValue* right_length) { 2052 // Compute the combined string length and check against max string length. 2053 HValue* length = AddUncasted<HAdd>(left_length, right_length); 2054 // Check that length <= kMaxLength <=> length < MaxLength + 1. 2055 HValue* max_length = Add<HConstant>(String::kMaxLength + 1); 2056 Add<HBoundsCheck>(length, max_length); 2057 return length; 2058 } 2059 2060 2061 HValue* HGraphBuilder::BuildCreateConsString( 2062 HValue* length, 2063 HValue* left, 2064 HValue* right, 2065 HAllocationMode allocation_mode) { 2066 // Determine the string instance types. 2067 HInstruction* left_instance_type = AddLoadStringInstanceType(left); 2068 HInstruction* right_instance_type = AddLoadStringInstanceType(right); 2069 2070 // Allocate the cons string object. HAllocate does not care whether we 2071 // pass CONS_STRING_TYPE or CONS_ONE_BYTE_STRING_TYPE here, so we just use 2072 // CONS_STRING_TYPE here. Below we decide whether the cons string is 2073 // one-byte or two-byte and set the appropriate map. 2074 DCHECK(HAllocate::CompatibleInstanceTypes(CONS_STRING_TYPE, 2075 CONS_ONE_BYTE_STRING_TYPE)); 2076 HAllocate* result = BuildAllocate(Add<HConstant>(ConsString::kSize), 2077 HType::String(), CONS_STRING_TYPE, 2078 allocation_mode); 2079 2080 // Compute intersection and difference of instance types. 2081 HValue* anded_instance_types = AddUncasted<HBitwise>( 2082 Token::BIT_AND, left_instance_type, right_instance_type); 2083 HValue* xored_instance_types = AddUncasted<HBitwise>( 2084 Token::BIT_XOR, left_instance_type, right_instance_type); 2085 2086 // We create a one-byte cons string if 2087 // 1. both strings are one-byte, or 2088 // 2. at least one of the strings is two-byte, but happens to contain only 2089 // one-byte characters. 2090 // To do this, we check 2091 // 1. if both strings are one-byte, or if the one-byte data hint is set in 2092 // both strings, or 2093 // 2. if one of the strings has the one-byte data hint set and the other 2094 // string is one-byte. 2095 IfBuilder if_onebyte(this); 2096 STATIC_ASSERT(kOneByteStringTag != 0); 2097 STATIC_ASSERT(kOneByteDataHintMask != 0); 2098 if_onebyte.If<HCompareNumericAndBranch>( 2099 AddUncasted<HBitwise>( 2100 Token::BIT_AND, anded_instance_types, 2101 Add<HConstant>(static_cast<int32_t>( 2102 kStringEncodingMask | kOneByteDataHintMask))), 2103 graph()->GetConstant0(), Token::NE); 2104 if_onebyte.Or(); 2105 STATIC_ASSERT(kOneByteStringTag != 0 && 2106 kOneByteDataHintTag != 0 && 2107 kOneByteDataHintTag != kOneByteStringTag); 2108 if_onebyte.If<HCompareNumericAndBranch>( 2109 AddUncasted<HBitwise>( 2110 Token::BIT_AND, xored_instance_types, 2111 Add<HConstant>(static_cast<int32_t>( 2112 kOneByteStringTag | kOneByteDataHintTag))), 2113 Add<HConstant>(static_cast<int32_t>( 2114 kOneByteStringTag | kOneByteDataHintTag)), Token::EQ); 2115 if_onebyte.Then(); 2116 { 2117 // We can safely skip the write barrier for storing the map here. 2118 Add<HStoreNamedField>( 2119 result, HObjectAccess::ForMap(), 2120 Add<HConstant>(isolate()->factory()->cons_one_byte_string_map())); 2121 } 2122 if_onebyte.Else(); 2123 { 2124 // We can safely skip the write barrier for storing the map here. 2125 Add<HStoreNamedField>( 2126 result, HObjectAccess::ForMap(), 2127 Add<HConstant>(isolate()->factory()->cons_string_map())); 2128 } 2129 if_onebyte.End(); 2130 2131 // Initialize the cons string fields. 2132 Add<HStoreNamedField>(result, HObjectAccess::ForStringHashField(), 2133 Add<HConstant>(String::kEmptyHashField)); 2134 Add<HStoreNamedField>(result, HObjectAccess::ForStringLength(), length); 2135 Add<HStoreNamedField>(result, HObjectAccess::ForConsStringFirst(), left); 2136 Add<HStoreNamedField>(result, HObjectAccess::ForConsStringSecond(), right); 2137 2138 // Count the native string addition. 2139 AddIncrementCounter(isolate()->counters()->string_add_native()); 2140 2141 return result; 2142 } 2143 2144 2145 void HGraphBuilder::BuildCopySeqStringChars(HValue* src, 2146 HValue* src_offset, 2147 String::Encoding src_encoding, 2148 HValue* dst, 2149 HValue* dst_offset, 2150 String::Encoding dst_encoding, 2151 HValue* length) { 2152 DCHECK(dst_encoding != String::ONE_BYTE_ENCODING || 2153 src_encoding == String::ONE_BYTE_ENCODING); 2154 LoopBuilder loop(this, context(), LoopBuilder::kPostIncrement); 2155 HValue* index = loop.BeginBody(graph()->GetConstant0(), length, Token::LT); 2156 { 2157 HValue* src_index = AddUncasted<HAdd>(src_offset, index); 2158 HValue* value = 2159 AddUncasted<HSeqStringGetChar>(src_encoding, src, src_index); 2160 HValue* dst_index = AddUncasted<HAdd>(dst_offset, index); 2161 Add<HSeqStringSetChar>(dst_encoding, dst, dst_index, value); 2162 } 2163 loop.EndBody(); 2164 } 2165 2166 2167 HValue* HGraphBuilder::BuildObjectSizeAlignment( 2168 HValue* unaligned_size, int header_size) { 2169 DCHECK((header_size & kObjectAlignmentMask) == 0); 2170 HValue* size = AddUncasted<HAdd>( 2171 unaligned_size, Add<HConstant>(static_cast<int32_t>( 2172 header_size + kObjectAlignmentMask))); 2173 size->ClearFlag(HValue::kCanOverflow); 2174 return AddUncasted<HBitwise>( 2175 Token::BIT_AND, size, Add<HConstant>(static_cast<int32_t>( 2176 ~kObjectAlignmentMask))); 2177 } 2178 2179 2180 HValue* HGraphBuilder::BuildUncheckedStringAdd( 2181 HValue* left, 2182 HValue* right, 2183 HAllocationMode allocation_mode) { 2184 // Determine the string lengths. 2185 HValue* left_length = AddLoadStringLength(left); 2186 HValue* right_length = AddLoadStringLength(right); 2187 2188 // Compute the combined string length. 2189 HValue* length = BuildAddStringLengths(left_length, right_length); 2190 2191 // Do some manual constant folding here. 2192 if (left_length->IsConstant()) { 2193 HConstant* c_left_length = HConstant::cast(left_length); 2194 DCHECK_NE(0, c_left_length->Integer32Value()); 2195 if (c_left_length->Integer32Value() + 1 >= ConsString::kMinLength) { 2196 // The right string contains at least one character. 2197 return BuildCreateConsString(length, left, right, allocation_mode); 2198 } 2199 } else if (right_length->IsConstant()) { 2200 HConstant* c_right_length = HConstant::cast(right_length); 2201 DCHECK_NE(0, c_right_length->Integer32Value()); 2202 if (c_right_length->Integer32Value() + 1 >= ConsString::kMinLength) { 2203 // The left string contains at least one character. 2204 return BuildCreateConsString(length, left, right, allocation_mode); 2205 } 2206 } 2207 2208 // Check if we should create a cons string. 2209 IfBuilder if_createcons(this); 2210 if_createcons.If<HCompareNumericAndBranch>( 2211 length, Add<HConstant>(ConsString::kMinLength), Token::GTE); 2212 if_createcons.Then(); 2213 { 2214 // Create a cons string. 2215 Push(BuildCreateConsString(length, left, right, allocation_mode)); 2216 } 2217 if_createcons.Else(); 2218 { 2219 // Determine the string instance types. 2220 HValue* left_instance_type = AddLoadStringInstanceType(left); 2221 HValue* right_instance_type = AddLoadStringInstanceType(right); 2222 2223 // Compute union and difference of instance types. 2224 HValue* ored_instance_types = AddUncasted<HBitwise>( 2225 Token::BIT_OR, left_instance_type, right_instance_type); 2226 HValue* xored_instance_types = AddUncasted<HBitwise>( 2227 Token::BIT_XOR, left_instance_type, right_instance_type); 2228 2229 // Check if both strings have the same encoding and both are 2230 // sequential. 2231 IfBuilder if_sameencodingandsequential(this); 2232 if_sameencodingandsequential.If<HCompareNumericAndBranch>( 2233 AddUncasted<HBitwise>( 2234 Token::BIT_AND, xored_instance_types, 2235 Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))), 2236 graph()->GetConstant0(), Token::EQ); 2237 if_sameencodingandsequential.And(); 2238 STATIC_ASSERT(kSeqStringTag == 0); 2239 if_sameencodingandsequential.If<HCompareNumericAndBranch>( 2240 AddUncasted<HBitwise>( 2241 Token::BIT_AND, ored_instance_types, 2242 Add<HConstant>(static_cast<int32_t>(kStringRepresentationMask))), 2243 graph()->GetConstant0(), Token::EQ); 2244 if_sameencodingandsequential.Then(); 2245 { 2246 HConstant* string_map = 2247 Add<HConstant>(isolate()->factory()->string_map()); 2248 HConstant* one_byte_string_map = 2249 Add<HConstant>(isolate()->factory()->one_byte_string_map()); 2250 2251 // Determine map and size depending on whether result is one-byte string. 2252 IfBuilder if_onebyte(this); 2253 STATIC_ASSERT(kOneByteStringTag != 0); 2254 if_onebyte.If<HCompareNumericAndBranch>( 2255 AddUncasted<HBitwise>( 2256 Token::BIT_AND, ored_instance_types, 2257 Add<HConstant>(static_cast<int32_t>(kStringEncodingMask))), 2258 graph()->GetConstant0(), Token::NE); 2259 if_onebyte.Then(); 2260 { 2261 // Allocate sequential one-byte string object. 2262 Push(length); 2263 Push(one_byte_string_map); 2264 } 2265 if_onebyte.Else(); 2266 { 2267 // Allocate sequential two-byte string object. 2268 HValue* size = AddUncasted<HShl>(length, graph()->GetConstant1()); 2269 size->ClearFlag(HValue::kCanOverflow); 2270 size->SetFlag(HValue::kUint32); 2271 Push(size); 2272 Push(string_map); 2273 } 2274 if_onebyte.End(); 2275 HValue* map = Pop(); 2276 2277 // Calculate the number of bytes needed for the characters in the 2278 // string while observing object alignment. 2279 STATIC_ASSERT((SeqString::kHeaderSize & kObjectAlignmentMask) == 0); 2280 HValue* size = BuildObjectSizeAlignment(Pop(), SeqString::kHeaderSize); 2281 2282 // Allocate the string object. HAllocate does not care whether we pass 2283 // STRING_TYPE or ONE_BYTE_STRING_TYPE here, so we just use STRING_TYPE. 2284 HAllocate* result = BuildAllocate( 2285 size, HType::String(), STRING_TYPE, allocation_mode); 2286 Add<HStoreNamedField>(result, HObjectAccess::ForMap(), map); 2287 2288 // Initialize the string fields. 2289 Add<HStoreNamedField>(result, HObjectAccess::ForStringHashField(), 2290 Add<HConstant>(String::kEmptyHashField)); 2291 Add<HStoreNamedField>(result, HObjectAccess::ForStringLength(), length); 2292 2293 // Copy characters to the result string. 2294 IfBuilder if_twobyte(this); 2295 if_twobyte.If<HCompareObjectEqAndBranch>(map, string_map); 2296 if_twobyte.Then(); 2297 { 2298 // Copy characters from the left string. 2299 BuildCopySeqStringChars( 2300 left, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, 2301 result, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, 2302 left_length); 2303 2304 // Copy characters from the right string. 2305 BuildCopySeqStringChars( 2306 right, graph()->GetConstant0(), String::TWO_BYTE_ENCODING, 2307 result, left_length, String::TWO_BYTE_ENCODING, 2308 right_length); 2309 } 2310 if_twobyte.Else(); 2311 { 2312 // Copy characters from the left string. 2313 BuildCopySeqStringChars( 2314 left, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, 2315 result, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, 2316 left_length); 2317 2318 // Copy characters from the right string. 2319 BuildCopySeqStringChars( 2320 right, graph()->GetConstant0(), String::ONE_BYTE_ENCODING, 2321 result, left_length, String::ONE_BYTE_ENCODING, 2322 right_length); 2323 } 2324 if_twobyte.End(); 2325 2326 // Count the native string addition. 2327 AddIncrementCounter(isolate()->counters()->string_add_native()); 2328 2329 // Return the sequential string. 2330 Push(result); 2331 } 2332 if_sameencodingandsequential.Else(); 2333 { 2334 // Fallback to the runtime to add the two strings. 2335 Add<HPushArguments>(left, right); 2336 Push(Add<HCallRuntime>( 2337 isolate()->factory()->empty_string(), 2338 Runtime::FunctionForId(Runtime::kStringAdd), 2339 2)); 2340 } 2341 if_sameencodingandsequential.End(); 2342 } 2343 if_createcons.End(); 2344 2345 return Pop(); 2346 } 2347 2348 2349 HValue* HGraphBuilder::BuildStringAdd( 2350 HValue* left, 2351 HValue* right, 2352 HAllocationMode allocation_mode) { 2353 NoObservableSideEffectsScope no_effects(this); 2354 2355 // Determine string lengths. 2356 HValue* left_length = AddLoadStringLength(left); 2357 HValue* right_length = AddLoadStringLength(right); 2358 2359 // Check if left string is empty. 2360 IfBuilder if_leftempty(this); 2361 if_leftempty.If<HCompareNumericAndBranch>( 2362 left_length, graph()->GetConstant0(), Token::EQ); 2363 if_leftempty.Then(); 2364 { 2365 // Count the native string addition. 2366 AddIncrementCounter(isolate()->counters()->string_add_native()); 2367 2368 // Just return the right string. 2369 Push(right); 2370 } 2371 if_leftempty.Else(); 2372 { 2373 // Check if right string is empty. 2374 IfBuilder if_rightempty(this); 2375 if_rightempty.If<HCompareNumericAndBranch>( 2376 right_length, graph()->GetConstant0(), Token::EQ); 2377 if_rightempty.Then(); 2378 { 2379 // Count the native string addition. 2380 AddIncrementCounter(isolate()->counters()->string_add_native()); 2381 2382 // Just return the left string. 2383 Push(left); 2384 } 2385 if_rightempty.Else(); 2386 { 2387 // Add the two non-empty strings. 2388 Push(BuildUncheckedStringAdd(left, right, allocation_mode)); 2389 } 2390 if_rightempty.End(); 2391 } 2392 if_leftempty.End(); 2393 2394 return Pop(); 2395 } 2396 2397 2398 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( 2399 HValue* checked_object, 2400 HValue* key, 2401 HValue* val, 2402 bool is_js_array, 2403 ElementsKind elements_kind, 2404 PropertyAccessType access_type, 2405 LoadKeyedHoleMode load_mode, 2406 KeyedAccessStoreMode store_mode) { 2407 DCHECK((!IsExternalArrayElementsKind(elements_kind) && 2408 !IsFixedTypedArrayElementsKind(elements_kind)) || 2409 !is_js_array); 2410 // No GVNFlag is necessary for ElementsKind if there is an explicit dependency 2411 // on a HElementsTransition instruction. The flag can also be removed if the 2412 // map to check has FAST_HOLEY_ELEMENTS, since there can be no further 2413 // ElementsKind transitions. Finally, the dependency can be removed for stores 2414 // for FAST_ELEMENTS, since a transition to HOLEY elements won't change the 2415 // generated store code. 2416 if ((elements_kind == FAST_HOLEY_ELEMENTS) || 2417 (elements_kind == FAST_ELEMENTS && access_type == STORE)) { 2418 checked_object->ClearDependsOnFlag(kElementsKind); 2419 } 2420 2421 bool fast_smi_only_elements = IsFastSmiElementsKind(elements_kind); 2422 bool fast_elements = IsFastObjectElementsKind(elements_kind); 2423 HValue* elements = AddLoadElements(checked_object); 2424 if (access_type == STORE && (fast_elements || fast_smi_only_elements) && 2425 store_mode != STORE_NO_TRANSITION_HANDLE_COW) { 2426 HCheckMaps* check_cow_map = Add<HCheckMaps>( 2427 elements, isolate()->factory()->fixed_array_map()); 2428 check_cow_map->ClearDependsOnFlag(kElementsKind); 2429 } 2430 HInstruction* length = NULL; 2431 if (is_js_array) { 2432 length = Add<HLoadNamedField>( 2433 checked_object->ActualValue(), checked_object, 2434 HObjectAccess::ForArrayLength(elements_kind)); 2435 } else { 2436 length = AddLoadFixedArrayLength(elements); 2437 } 2438 length->set_type(HType::Smi()); 2439 HValue* checked_key = NULL; 2440 if (IsExternalArrayElementsKind(elements_kind) || 2441 IsFixedTypedArrayElementsKind(elements_kind)) { 2442 HValue* backing_store; 2443 if (IsExternalArrayElementsKind(elements_kind)) { 2444 backing_store = Add<HLoadNamedField>( 2445 elements, static_cast<HValue*>(NULL), 2446 HObjectAccess::ForExternalArrayExternalPointer()); 2447 } else { 2448 backing_store = elements; 2449 } 2450 if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) { 2451 NoObservableSideEffectsScope no_effects(this); 2452 IfBuilder length_checker(this); 2453 length_checker.If<HCompareNumericAndBranch>(key, length, Token::LT); 2454 length_checker.Then(); 2455 IfBuilder negative_checker(this); 2456 HValue* bounds_check = negative_checker.If<HCompareNumericAndBranch>( 2457 key, graph()->GetConstant0(), Token::GTE); 2458 negative_checker.Then(); 2459 HInstruction* result = AddElementAccess( 2460 backing_store, key, val, bounds_check, elements_kind, access_type); 2461 negative_checker.ElseDeopt("Negative key encountered"); 2462 negative_checker.End(); 2463 length_checker.End(); 2464 return result; 2465 } else { 2466 DCHECK(store_mode == STANDARD_STORE); 2467 checked_key = Add<HBoundsCheck>(key, length); 2468 return AddElementAccess( 2469 backing_store, checked_key, val, 2470 checked_object, elements_kind, access_type); 2471 } 2472 } 2473 DCHECK(fast_smi_only_elements || 2474 fast_elements || 2475 IsFastDoubleElementsKind(elements_kind)); 2476 2477 // In case val is stored into a fast smi array, assure that the value is a smi 2478 // before manipulating the backing store. Otherwise the actual store may 2479 // deopt, leaving the backing store in an invalid state. 2480 if (access_type == STORE && IsFastSmiElementsKind(elements_kind) && 2481 !val->type().IsSmi()) { 2482 val = AddUncasted<HForceRepresentation>(val, Representation::Smi()); 2483 } 2484 2485 if (IsGrowStoreMode(store_mode)) { 2486 NoObservableSideEffectsScope no_effects(this); 2487 Representation representation = HStoreKeyed::RequiredValueRepresentation( 2488 elements_kind, STORE_TO_INITIALIZED_ENTRY); 2489 val = AddUncasted<HForceRepresentation>(val, representation); 2490 elements = BuildCheckForCapacityGrow(checked_object, elements, 2491 elements_kind, length, key, 2492 is_js_array, access_type); 2493 checked_key = key; 2494 } else { 2495 checked_key = Add<HBoundsCheck>(key, length); 2496 2497 if (access_type == STORE && (fast_elements || fast_smi_only_elements)) { 2498 if (store_mode == STORE_NO_TRANSITION_HANDLE_COW) { 2499 NoObservableSideEffectsScope no_effects(this); 2500 elements = BuildCopyElementsOnWrite(checked_object, elements, 2501 elements_kind, length); 2502 } else { 2503 HCheckMaps* check_cow_map = Add<HCheckMaps>( 2504 elements, isolate()->factory()->fixed_array_map()); 2505 check_cow_map->ClearDependsOnFlag(kElementsKind); 2506 } 2507 } 2508 } 2509 return AddElementAccess(elements, checked_key, val, checked_object, 2510 elements_kind, access_type, load_mode); 2511 } 2512 2513 2514 HValue* HGraphBuilder::BuildAllocateArrayFromLength( 2515 JSArrayBuilder* array_builder, 2516 HValue* length_argument) { 2517 if (length_argument->IsConstant() && 2518 HConstant::cast(length_argument)->HasSmiValue()) { 2519 int array_length = HConstant::cast(length_argument)->Integer32Value(); 2520 if (array_length == 0) { 2521 return array_builder->AllocateEmptyArray(); 2522 } else { 2523 return array_builder->AllocateArray(length_argument, 2524 array_length, 2525 length_argument); 2526 } 2527 } 2528 2529 HValue* constant_zero = graph()->GetConstant0(); 2530 HConstant* max_alloc_length = 2531 Add<HConstant>(JSObject::kInitialMaxFastElementArray); 2532 HInstruction* checked_length = Add<HBoundsCheck>(length_argument, 2533 max_alloc_length); 2534 IfBuilder if_builder(this); 2535 if_builder.If<HCompareNumericAndBranch>(checked_length, constant_zero, 2536 Token::EQ); 2537 if_builder.Then(); 2538 const int initial_capacity = JSArray::kPreallocatedArrayElements; 2539 HConstant* initial_capacity_node = Add<HConstant>(initial_capacity); 2540 Push(initial_capacity_node); // capacity 2541 Push(constant_zero); // length 2542 if_builder.Else(); 2543 if (!(top_info()->IsStub()) && 2544 IsFastPackedElementsKind(array_builder->kind())) { 2545 // We'll come back later with better (holey) feedback. 2546 if_builder.Deopt("Holey array despite packed elements_kind feedback"); 2547 } else { 2548 Push(checked_length); // capacity 2549 Push(checked_length); // length 2550 } 2551 if_builder.End(); 2552 2553 // Figure out total size 2554 HValue* length = Pop(); 2555 HValue* capacity = Pop(); 2556 return array_builder->AllocateArray(capacity, max_alloc_length, length); 2557 } 2558 2559 2560 HValue* HGraphBuilder::BuildCalculateElementsSize(ElementsKind kind, 2561 HValue* capacity) { 2562 int elements_size = IsFastDoubleElementsKind(kind) 2563 ? kDoubleSize 2564 : kPointerSize; 2565 2566 HConstant* elements_size_value = Add<HConstant>(elements_size); 2567 HInstruction* mul = HMul::NewImul(zone(), context(), 2568 capacity->ActualValue(), 2569 elements_size_value); 2570 AddInstruction(mul); 2571 mul->ClearFlag(HValue::kCanOverflow); 2572 2573 STATIC_ASSERT(FixedDoubleArray::kHeaderSize == FixedArray::kHeaderSize); 2574 2575 HConstant* header_size = Add<HConstant>(FixedArray::kHeaderSize); 2576 HValue* total_size = AddUncasted<HAdd>(mul, header_size); 2577 total_size->ClearFlag(HValue::kCanOverflow); 2578 return total_size; 2579 } 2580 2581 2582 HAllocate* HGraphBuilder::AllocateJSArrayObject(AllocationSiteMode mode) { 2583 int base_size = JSArray::kSize; 2584 if (mode == TRACK_ALLOCATION_SITE) { 2585 base_size += AllocationMemento::kSize; 2586 } 2587 HConstant* size_in_bytes = Add<HConstant>(base_size); 2588 return Add<HAllocate>( 2589 size_in_bytes, HType::JSArray(), NOT_TENURED, JS_OBJECT_TYPE); 2590 } 2591 2592 2593 HConstant* HGraphBuilder::EstablishElementsAllocationSize( 2594 ElementsKind kind, 2595 int capacity) { 2596 int base_size = IsFastDoubleElementsKind(kind) 2597 ? FixedDoubleArray::SizeFor(capacity) 2598 : FixedArray::SizeFor(capacity); 2599 2600 return Add<HConstant>(base_size); 2601 } 2602 2603 2604 HAllocate* HGraphBuilder::BuildAllocateElements(ElementsKind kind, 2605 HValue* size_in_bytes) { 2606 InstanceType instance_type = IsFastDoubleElementsKind(kind) 2607 ? FIXED_DOUBLE_ARRAY_TYPE 2608 : FIXED_ARRAY_TYPE; 2609 2610 return Add<HAllocate>(size_in_bytes, HType::HeapObject(), NOT_TENURED, 2611 instance_type); 2612 } 2613 2614 2615 void HGraphBuilder::BuildInitializeElementsHeader(HValue* elements, 2616 ElementsKind kind, 2617 HValue* capacity) { 2618 Factory* factory = isolate()->factory(); 2619 Handle<Map> map = IsFastDoubleElementsKind(kind) 2620 ? factory->fixed_double_array_map() 2621 : factory->fixed_array_map(); 2622 2623 Add<HStoreNamedField>(elements, HObjectAccess::ForMap(), Add<HConstant>(map)); 2624 Add<HStoreNamedField>(elements, HObjectAccess::ForFixedArrayLength(), 2625 capacity); 2626 } 2627 2628 2629 HValue* HGraphBuilder::BuildAllocateElementsAndInitializeElementsHeader( 2630 ElementsKind kind, 2631 HValue* capacity) { 2632 // The HForceRepresentation is to prevent possible deopt on int-smi 2633 // conversion after allocation but before the new object fields are set. 2634 capacity = AddUncasted<HForceRepresentation>(capacity, Representation::Smi()); 2635 HValue* size_in_bytes = BuildCalculateElementsSize(kind, capacity); 2636 HValue* new_elements = BuildAllocateElements(kind, size_in_bytes); 2637 BuildInitializeElementsHeader(new_elements, kind, capacity); 2638 return new_elements; 2639 } 2640 2641 2642 void HGraphBuilder::BuildJSArrayHeader(HValue* array, 2643 HValue* array_map, 2644 HValue* elements, 2645 AllocationSiteMode mode, 2646 ElementsKind elements_kind, 2647 HValue* allocation_site_payload, 2648 HValue* length_field) { 2649 Add<HStoreNamedField>(array, HObjectAccess::ForMap(), array_map); 2650 2651 HConstant* empty_fixed_array = 2652 Add<HConstant>(isolate()->factory()->empty_fixed_array()); 2653 2654 Add<HStoreNamedField>( 2655 array, HObjectAccess::ForPropertiesPointer(), empty_fixed_array); 2656 2657 Add<HStoreNamedField>( 2658 array, HObjectAccess::ForElementsPointer(), 2659 elements != NULL ? elements : empty_fixed_array); 2660 2661 Add<HStoreNamedField>( 2662 array, HObjectAccess::ForArrayLength(elements_kind), length_field); 2663 2664 if (mode == TRACK_ALLOCATION_SITE) { 2665 BuildCreateAllocationMemento( 2666 array, Add<HConstant>(JSArray::kSize), allocation_site_payload); 2667 } 2668 } 2669 2670 2671 HInstruction* HGraphBuilder::AddElementAccess( 2672 HValue* elements, 2673 HValue* checked_key, 2674 HValue* val, 2675 HValue* dependency, 2676 ElementsKind elements_kind, 2677 PropertyAccessType access_type, 2678 LoadKeyedHoleMode load_mode) { 2679 if (access_type == STORE) { 2680 DCHECK(val != NULL); 2681 if (elements_kind == EXTERNAL_UINT8_CLAMPED_ELEMENTS || 2682 elements_kind == UINT8_CLAMPED_ELEMENTS) { 2683 val = Add<HClampToUint8>(val); 2684 } 2685 return Add<HStoreKeyed>(elements, checked_key, val, elements_kind, 2686 STORE_TO_INITIALIZED_ENTRY); 2687 } 2688 2689 DCHECK(access_type == LOAD); 2690 DCHECK(val == NULL); 2691 HLoadKeyed* load = Add<HLoadKeyed>( 2692 elements, checked_key, dependency, elements_kind, load_mode); 2693 if (FLAG_opt_safe_uint32_operations && 2694 (elements_kind == EXTERNAL_UINT32_ELEMENTS || 2695 elements_kind == UINT32_ELEMENTS)) { 2696 graph()->RecordUint32Instruction(load); 2697 } 2698 return load; 2699 } 2700 2701 2702 HLoadNamedField* HGraphBuilder::AddLoadMap(HValue* object, 2703 HValue* dependency) { 2704 return Add<HLoadNamedField>(object, dependency, HObjectAccess::ForMap()); 2705 } 2706 2707 2708 HLoadNamedField* HGraphBuilder::AddLoadElements(HValue* object, 2709 HValue* dependency) { 2710 return Add<HLoadNamedField>( 2711 object, dependency, HObjectAccess::ForElementsPointer()); 2712 } 2713 2714 2715 HLoadNamedField* HGraphBuilder::AddLoadFixedArrayLength( 2716 HValue* array, 2717 HValue* dependency) { 2718 return Add<HLoadNamedField>( 2719 array, dependency, HObjectAccess::ForFixedArrayLength()); 2720 } 2721 2722 2723 HLoadNamedField* HGraphBuilder::AddLoadArrayLength(HValue* array, 2724 ElementsKind kind, 2725 HValue* dependency) { 2726 return Add<HLoadNamedField>( 2727 array, dependency, HObjectAccess::ForArrayLength(kind)); 2728 } 2729 2730 2731 HValue* HGraphBuilder::BuildNewElementsCapacity(HValue* old_capacity) { 2732 HValue* half_old_capacity = AddUncasted<HShr>(old_capacity, 2733 graph_->GetConstant1()); 2734 2735 HValue* new_capacity = AddUncasted<HAdd>(half_old_capacity, old_capacity); 2736 new_capacity->ClearFlag(HValue::kCanOverflow); 2737 2738 HValue* min_growth = Add<HConstant>(16); 2739 2740 new_capacity = AddUncasted<HAdd>(new_capacity, min_growth); 2741 new_capacity->ClearFlag(HValue::kCanOverflow); 2742 2743 return new_capacity; 2744 } 2745 2746 2747 HValue* HGraphBuilder::BuildGrowElementsCapacity(HValue* object, 2748 HValue* elements, 2749 ElementsKind kind, 2750 ElementsKind new_kind, 2751 HValue* length, 2752 HValue* new_capacity) { 2753 Add<HBoundsCheck>(new_capacity, Add<HConstant>( 2754 (Page::kMaxRegularHeapObjectSize - FixedArray::kHeaderSize) >> 2755 ElementsKindToShiftSize(new_kind))); 2756 2757 HValue* new_elements = BuildAllocateElementsAndInitializeElementsHeader( 2758 new_kind, new_capacity); 2759 2760 BuildCopyElements(elements, kind, new_elements, 2761 new_kind, length, new_capacity); 2762 2763 Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(), 2764 new_elements); 2765 2766 return new_elements; 2767 } 2768 2769 2770 void HGraphBuilder::BuildFillElementsWithValue(HValue* elements, 2771 ElementsKind elements_kind, 2772 HValue* from, 2773 HValue* to, 2774 HValue* value) { 2775 if (to == NULL) { 2776 to = AddLoadFixedArrayLength(elements); 2777 } 2778 2779 // Special loop unfolding case 2780 STATIC_ASSERT(JSArray::kPreallocatedArrayElements <= 2781 kElementLoopUnrollThreshold); 2782 int initial_capacity = -1; 2783 if (from->IsInteger32Constant() && to->IsInteger32Constant()) { 2784 int constant_from = from->GetInteger32Constant(); 2785 int constant_to = to->GetInteger32Constant(); 2786 2787 if (constant_from == 0 && constant_to <= kElementLoopUnrollThreshold) { 2788 initial_capacity = constant_to; 2789 } 2790 } 2791 2792 // Since we're about to store a hole value, the store instruction below must 2793 // assume an elements kind that supports heap object values. 2794 if (IsFastSmiOrObjectElementsKind(elements_kind)) { 2795 elements_kind = FAST_HOLEY_ELEMENTS; 2796 } 2797 2798 if (initial_capacity >= 0) { 2799 for (int i = 0; i < initial_capacity; i++) { 2800 HInstruction* key = Add<HConstant>(i); 2801 Add<HStoreKeyed>(elements, key, value, elements_kind); 2802 } 2803 } else { 2804 // Carefully loop backwards so that the "from" remains live through the loop 2805 // rather than the to. This often corresponds to keeping length live rather 2806 // then capacity, which helps register allocation, since length is used more 2807 // other than capacity after filling with holes. 2808 LoopBuilder builder(this, context(), LoopBuilder::kPostDecrement); 2809 2810 HValue* key = builder.BeginBody(to, from, Token::GT); 2811 2812 HValue* adjusted_key = AddUncasted<HSub>(key, graph()->GetConstant1()); 2813 adjusted_key->ClearFlag(HValue::kCanOverflow); 2814 2815 Add<HStoreKeyed>(elements, adjusted_key, value, elements_kind); 2816 2817 builder.EndBody(); 2818 } 2819 } 2820 2821 2822 void HGraphBuilder::BuildFillElementsWithHole(HValue* elements, 2823 ElementsKind elements_kind, 2824 HValue* from, 2825 HValue* to) { 2826 // Fast elements kinds need to be initialized in case statements below cause a 2827 // garbage collection. 2828 Factory* factory = isolate()->factory(); 2829 2830 double nan_double = FixedDoubleArray::hole_nan_as_double(); 2831 HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind) 2832 ? Add<HConstant>(factory->the_hole_value()) 2833 : Add<HConstant>(nan_double); 2834 2835 BuildFillElementsWithValue(elements, elements_kind, from, to, hole); 2836 } 2837 2838 2839 void HGraphBuilder::BuildCopyElements(HValue* from_elements, 2840 ElementsKind from_elements_kind, 2841 HValue* to_elements, 2842 ElementsKind to_elements_kind, 2843 HValue* length, 2844 HValue* capacity) { 2845 int constant_capacity = -1; 2846 if (capacity != NULL && 2847 capacity->IsConstant() && 2848 HConstant::cast(capacity)->HasInteger32Value()) { 2849 int constant_candidate = HConstant::cast(capacity)->Integer32Value(); 2850 if (constant_candidate <= kElementLoopUnrollThreshold) { 2851 constant_capacity = constant_candidate; 2852 } 2853 } 2854 2855 bool pre_fill_with_holes = 2856 IsFastDoubleElementsKind(from_elements_kind) && 2857 IsFastObjectElementsKind(to_elements_kind); 2858 if (pre_fill_with_holes) { 2859 // If the copy might trigger a GC, make sure that the FixedArray is 2860 // pre-initialized with holes to make sure that it's always in a 2861 // consistent state. 2862 BuildFillElementsWithHole(to_elements, to_elements_kind, 2863 graph()->GetConstant0(), NULL); 2864 } 2865 2866 if (constant_capacity != -1) { 2867 // Unroll the loop for small elements kinds. 2868 for (int i = 0; i < constant_capacity; i++) { 2869 HValue* key_constant = Add<HConstant>(i); 2870 HInstruction* value = Add<HLoadKeyed>(from_elements, key_constant, 2871 static_cast<HValue*>(NULL), 2872 from_elements_kind); 2873 Add<HStoreKeyed>(to_elements, key_constant, value, to_elements_kind); 2874 } 2875 } else { 2876 if (!pre_fill_with_holes && 2877 (capacity == NULL || !length->Equals(capacity))) { 2878 BuildFillElementsWithHole(to_elements, to_elements_kind, 2879 length, NULL); 2880 } 2881 2882 if (capacity == NULL) { 2883 capacity = AddLoadFixedArrayLength(to_elements); 2884 } 2885 2886 LoopBuilder builder(this, context(), LoopBuilder::kPostDecrement); 2887 2888 HValue* key = builder.BeginBody(length, graph()->GetConstant0(), 2889 Token::GT); 2890 2891 key = AddUncasted<HSub>(key, graph()->GetConstant1()); 2892 key->ClearFlag(HValue::kCanOverflow); 2893 2894 HValue* element = Add<HLoadKeyed>(from_elements, key, 2895 static_cast<HValue*>(NULL), 2896 from_elements_kind, 2897 ALLOW_RETURN_HOLE); 2898 2899 ElementsKind kind = (IsHoleyElementsKind(from_elements_kind) && 2900 IsFastSmiElementsKind(to_elements_kind)) 2901 ? FAST_HOLEY_ELEMENTS : to_elements_kind; 2902 2903 if (IsHoleyElementsKind(from_elements_kind) && 2904 from_elements_kind != to_elements_kind) { 2905 IfBuilder if_hole(this); 2906 if_hole.If<HCompareHoleAndBranch>(element); 2907 if_hole.Then(); 2908 HConstant* hole_constant = IsFastDoubleElementsKind(to_elements_kind) 2909 ? Add<HConstant>(FixedDoubleArray::hole_nan_as_double()) 2910 : graph()->GetConstantHole(); 2911 Add<HStoreKeyed>(to_elements, key, hole_constant, kind); 2912 if_hole.Else(); 2913 HStoreKeyed* store = Add<HStoreKeyed>(to_elements, key, element, kind); 2914 store->SetFlag(HValue::kAllowUndefinedAsNaN); 2915 if_hole.End(); 2916 } else { 2917 HStoreKeyed* store = Add<HStoreKeyed>(to_elements, key, element, kind); 2918 store->SetFlag(HValue::kAllowUndefinedAsNaN); 2919 } 2920 2921 builder.EndBody(); 2922 } 2923 2924 Counters* counters = isolate()->counters(); 2925 AddIncrementCounter(counters->inlined_copied_elements()); 2926 } 2927 2928 2929 HValue* HGraphBuilder::BuildCloneShallowArrayCow(HValue* boilerplate, 2930 HValue* allocation_site, 2931 AllocationSiteMode mode, 2932 ElementsKind kind) { 2933 HAllocate* array = AllocateJSArrayObject(mode); 2934 2935 HValue* map = AddLoadMap(boilerplate); 2936 HValue* elements = AddLoadElements(boilerplate); 2937 HValue* length = AddLoadArrayLength(boilerplate, kind); 2938 2939 BuildJSArrayHeader(array, 2940 map, 2941 elements, 2942 mode, 2943 FAST_ELEMENTS, 2944 allocation_site, 2945 length); 2946 return array; 2947 } 2948 2949 2950 HValue* HGraphBuilder::BuildCloneShallowArrayEmpty(HValue* boilerplate, 2951 HValue* allocation_site, 2952 AllocationSiteMode mode) { 2953 HAllocate* array = AllocateJSArrayObject(mode); 2954 2955 HValue* map = AddLoadMap(boilerplate); 2956 2957 BuildJSArrayHeader(array, 2958 map, 2959 NULL, // set elements to empty fixed array 2960 mode, 2961 FAST_ELEMENTS, 2962 allocation_site, 2963 graph()->GetConstant0()); 2964 return array; 2965 } 2966 2967 2968 HValue* HGraphBuilder::BuildCloneShallowArrayNonEmpty(HValue* boilerplate, 2969 HValue* allocation_site, 2970 AllocationSiteMode mode, 2971 ElementsKind kind) { 2972 HValue* boilerplate_elements = AddLoadElements(boilerplate); 2973 HValue* capacity = AddLoadFixedArrayLength(boilerplate_elements); 2974 2975 // Generate size calculation code here in order to make it dominate 2976 // the JSArray allocation. 2977 HValue* elements_size = BuildCalculateElementsSize(kind, capacity); 2978 2979 // Create empty JSArray object for now, store elimination should remove 2980 // redundant initialization of elements and length fields and at the same 2981 // time the object will be fully prepared for GC if it happens during 2982 // elements allocation. 2983 HValue* result = BuildCloneShallowArrayEmpty( 2984 boilerplate, allocation_site, mode); 2985 2986 HAllocate* elements = BuildAllocateElements(kind, elements_size); 2987 2988 // This function implicitly relies on the fact that the 2989 // FastCloneShallowArrayStub is called only for literals shorter than 2990 // JSObject::kInitialMaxFastElementArray. 2991 // Can't add HBoundsCheck here because otherwise the stub will eager a frame. 2992 HConstant* size_upper_bound = EstablishElementsAllocationSize( 2993 kind, JSObject::kInitialMaxFastElementArray); 2994 elements->set_size_upper_bound(size_upper_bound); 2995 2996 Add<HStoreNamedField>(result, HObjectAccess::ForElementsPointer(), elements); 2997 2998 // The allocation for the cloned array above causes register pressure on 2999 // machines with low register counts. Force a reload of the boilerplate 3000 // elements here to free up a register for the allocation to avoid unnecessary 3001 // spillage. 3002 boilerplate_elements = AddLoadElements(boilerplate); 3003 boilerplate_elements->SetFlag(HValue::kCantBeReplaced); 3004 3005 // Copy the elements array header. 3006 for (int i = 0; i < FixedArrayBase::kHeaderSize; i += kPointerSize) { 3007 HObjectAccess access = HObjectAccess::ForFixedArrayHeader(i); 3008 Add<HStoreNamedField>(elements, access, 3009 Add<HLoadNamedField>(boilerplate_elements, 3010 static_cast<HValue*>(NULL), access)); 3011 } 3012 3013 // And the result of the length 3014 HValue* length = AddLoadArrayLength(boilerplate, kind); 3015 Add<HStoreNamedField>(result, HObjectAccess::ForArrayLength(kind), length); 3016 3017 BuildCopyElements(boilerplate_elements, kind, elements, 3018 kind, length, NULL); 3019 return result; 3020 } 3021 3022 3023 void HGraphBuilder::BuildCompareNil( 3024 HValue* value, 3025 Type* type, 3026 HIfContinuation* continuation) { 3027 IfBuilder if_nil(this); 3028 bool some_case_handled = false; 3029 bool some_case_missing = false; 3030 3031 if (type->Maybe(Type::Null())) { 3032 if (some_case_handled) if_nil.Or(); 3033 if_nil.If<HCompareObjectEqAndBranch>(value, graph()->GetConstantNull()); 3034 some_case_handled = true; 3035 } else { 3036 some_case_missing = true; 3037 } 3038 3039 if (type->Maybe(Type::Undefined())) { 3040 if (some_case_handled) if_nil.Or(); 3041 if_nil.If<HCompareObjectEqAndBranch>(value, 3042 graph()->GetConstantUndefined()); 3043 some_case_handled = true; 3044 } else { 3045 some_case_missing = true; 3046 } 3047 3048 if (type->Maybe(Type::Undetectable())) { 3049 if (some_case_handled) if_nil.Or(); 3050 if_nil.If<HIsUndetectableAndBranch>(value); 3051 some_case_handled = true; 3052 } else { 3053 some_case_missing = true; 3054 } 3055 3056 if (some_case_missing) { 3057 if_nil.Then(); 3058 if_nil.Else(); 3059 if (type->NumClasses() == 1) { 3060 BuildCheckHeapObject(value); 3061 // For ICs, the map checked below is a sentinel map that gets replaced by 3062 // the monomorphic map when the code is used as a template to generate a 3063 // new IC. For optimized functions, there is no sentinel map, the map 3064 // emitted below is the actual monomorphic map. 3065 Add<HCheckMaps>(value, type->Classes().Current()); 3066 } else { 3067 if_nil.Deopt("Too many undetectable types"); 3068 } 3069 } 3070 3071 if_nil.CaptureContinuation(continuation); 3072 } 3073 3074 3075 void HGraphBuilder::BuildCreateAllocationMemento( 3076 HValue* previous_object, 3077 HValue* previous_object_size, 3078 HValue* allocation_site) { 3079 DCHECK(allocation_site != NULL); 3080 HInnerAllocatedObject* allocation_memento = Add<HInnerAllocatedObject>( 3081 previous_object, previous_object_size, HType::HeapObject()); 3082 AddStoreMapConstant( 3083 allocation_memento, isolate()->factory()->allocation_memento_map()); 3084 Add<HStoreNamedField>( 3085 allocation_memento, 3086 HObjectAccess::ForAllocationMementoSite(), 3087 allocation_site); 3088 if (FLAG_allocation_site_pretenuring) { 3089 HValue* memento_create_count = Add<HLoadNamedField>( 3090 allocation_site, static_cast<HValue*>(NULL), 3091 HObjectAccess::ForAllocationSiteOffset( 3092 AllocationSite::kPretenureCreateCountOffset)); 3093 memento_create_count = AddUncasted<HAdd>( 3094 memento_create_count, graph()->GetConstant1()); 3095 // This smi value is reset to zero after every gc, overflow isn't a problem 3096 // since the counter is bounded by the new space size. 3097 memento_create_count->ClearFlag(HValue::kCanOverflow); 3098 Add<HStoreNamedField>( 3099 allocation_site, HObjectAccess::ForAllocationSiteOffset( 3100 AllocationSite::kPretenureCreateCountOffset), memento_create_count); 3101 } 3102 } 3103 3104 3105 HInstruction* HGraphBuilder::BuildGetNativeContext(HValue* closure) { 3106 // Get the global context, then the native context 3107 HInstruction* context = 3108 Add<HLoadNamedField>(closure, static_cast<HValue*>(NULL), 3109 HObjectAccess::ForFunctionContextPointer()); 3110 HInstruction* global_object = Add<HLoadNamedField>( 3111 context, static_cast<HValue*>(NULL), 3112 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); 3113 HObjectAccess access = HObjectAccess::ForObservableJSObjectOffset( 3114 GlobalObject::kNativeContextOffset); 3115 return Add<HLoadNamedField>( 3116 global_object, static_cast<HValue*>(NULL), access); 3117 } 3118 3119 3120 HInstruction* HGraphBuilder::BuildGetNativeContext() { 3121 // Get the global context, then the native context 3122 HValue* global_object = Add<HLoadNamedField>( 3123 context(), static_cast<HValue*>(NULL), 3124 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); 3125 return Add<HLoadNamedField>( 3126 global_object, static_cast<HValue*>(NULL), 3127 HObjectAccess::ForObservableJSObjectOffset( 3128 GlobalObject::kNativeContextOffset)); 3129 } 3130 3131 3132 HInstruction* HGraphBuilder::BuildGetArrayFunction() { 3133 HInstruction* native_context = BuildGetNativeContext(); 3134 HInstruction* index = 3135 Add<HConstant>(static_cast<int32_t>(Context::ARRAY_FUNCTION_INDEX)); 3136 return Add<HLoadKeyed>( 3137 native_context, index, static_cast<HValue*>(NULL), FAST_ELEMENTS); 3138 } 3139 3140 3141 HGraphBuilder::JSArrayBuilder::JSArrayBuilder(HGraphBuilder* builder, 3142 ElementsKind kind, 3143 HValue* allocation_site_payload, 3144 HValue* constructor_function, 3145 AllocationSiteOverrideMode override_mode) : 3146 builder_(builder), 3147 kind_(kind), 3148 allocation_site_payload_(allocation_site_payload), 3149 constructor_function_(constructor_function) { 3150 DCHECK(!allocation_site_payload->IsConstant() || 3151 HConstant::cast(allocation_site_payload)->handle( 3152 builder_->isolate())->IsAllocationSite()); 3153 mode_ = override_mode == DISABLE_ALLOCATION_SITES 3154 ? DONT_TRACK_ALLOCATION_SITE 3155 : AllocationSite::GetMode(kind); 3156 } 3157 3158 3159 HGraphBuilder::JSArrayBuilder::JSArrayBuilder(HGraphBuilder* builder, 3160 ElementsKind kind, 3161 HValue* constructor_function) : 3162 builder_(builder), 3163 kind_(kind), 3164 mode_(DONT_TRACK_ALLOCATION_SITE), 3165 allocation_site_payload_(NULL), 3166 constructor_function_(constructor_function) { 3167 } 3168 3169 3170 HValue* HGraphBuilder::JSArrayBuilder::EmitMapCode() { 3171 if (!builder()->top_info()->IsStub()) { 3172 // A constant map is fine. 3173 Handle<Map> map(builder()->isolate()->get_initial_js_array_map(kind_), 3174 builder()->isolate()); 3175 return builder()->Add<HConstant>(map); 3176 } 3177 3178 if (constructor_function_ != NULL && kind_ == GetInitialFastElementsKind()) { 3179 // No need for a context lookup if the kind_ matches the initial 3180 // map, because we can just load the map in that case. 3181 HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap(); 3182 return builder()->Add<HLoadNamedField>( 3183 constructor_function_, static_cast<HValue*>(NULL), access); 3184 } 3185 3186 // TODO(mvstanton): we should always have a constructor function if we 3187 // are creating a stub. 3188 HInstruction* native_context = constructor_function_ != NULL 3189 ? builder()->BuildGetNativeContext(constructor_function_) 3190 : builder()->BuildGetNativeContext(); 3191 3192 HInstruction* index = builder()->Add<HConstant>( 3193 static_cast<int32_t>(Context::JS_ARRAY_MAPS_INDEX)); 3194 3195 HInstruction* map_array = builder()->Add<HLoadKeyed>( 3196 native_context, index, static_cast<HValue*>(NULL), FAST_ELEMENTS); 3197 3198 HInstruction* kind_index = builder()->Add<HConstant>(kind_); 3199 3200 return builder()->Add<HLoadKeyed>( 3201 map_array, kind_index, static_cast<HValue*>(NULL), FAST_ELEMENTS); 3202 } 3203 3204 3205 HValue* HGraphBuilder::JSArrayBuilder::EmitInternalMapCode() { 3206 // Find the map near the constructor function 3207 HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap(); 3208 return builder()->Add<HLoadNamedField>( 3209 constructor_function_, static_cast<HValue*>(NULL), access); 3210 } 3211 3212 3213 HAllocate* HGraphBuilder::JSArrayBuilder::AllocateEmptyArray() { 3214 HConstant* capacity = builder()->Add<HConstant>(initial_capacity()); 3215 return AllocateArray(capacity, 3216 capacity, 3217 builder()->graph()->GetConstant0()); 3218 } 3219 3220 3221 HAllocate* HGraphBuilder::JSArrayBuilder::AllocateArray( 3222 HValue* capacity, 3223 HConstant* capacity_upper_bound, 3224 HValue* length_field, 3225 FillMode fill_mode) { 3226 return AllocateArray(capacity, 3227 capacity_upper_bound->GetInteger32Constant(), 3228 length_field, 3229 fill_mode); 3230 } 3231 3232 3233 HAllocate* HGraphBuilder::JSArrayBuilder::AllocateArray( 3234 HValue* capacity, 3235 int capacity_upper_bound, 3236 HValue* length_field, 3237 FillMode fill_mode) { 3238 HConstant* elememts_size_upper_bound = capacity->IsInteger32Constant() 3239 ? HConstant::cast(capacity) 3240 : builder()->EstablishElementsAllocationSize(kind_, capacity_upper_bound); 3241 3242 HAllocate* array = AllocateArray(capacity, length_field, fill_mode); 3243 if (!elements_location_->has_size_upper_bound()) { 3244 elements_location_->set_size_upper_bound(elememts_size_upper_bound); 3245 } 3246 return array; 3247 } 3248 3249 3250 HAllocate* HGraphBuilder::JSArrayBuilder::AllocateArray( 3251 HValue* capacity, 3252 HValue* length_field, 3253 FillMode fill_mode) { 3254 // These HForceRepresentations are because we store these as fields in the 3255 // objects we construct, and an int32-to-smi HChange could deopt. Accept 3256 // the deopt possibility now, before allocation occurs. 3257 capacity = 3258 builder()->AddUncasted<HForceRepresentation>(capacity, 3259 Representation::Smi()); 3260 length_field = 3261 builder()->AddUncasted<HForceRepresentation>(length_field, 3262 Representation::Smi()); 3263 3264 // Generate size calculation code here in order to make it dominate 3265 // the JSArray allocation. 3266 HValue* elements_size = 3267 builder()->BuildCalculateElementsSize(kind_, capacity); 3268 3269 // Allocate (dealing with failure appropriately) 3270 HAllocate* array_object = builder()->AllocateJSArrayObject(mode_); 3271 3272 // Fill in the fields: map, properties, length 3273 HValue* map; 3274 if (allocation_site_payload_ == NULL) { 3275 map = EmitInternalMapCode(); 3276 } else { 3277 map = EmitMapCode(); 3278 } 3279 3280 builder()->BuildJSArrayHeader(array_object, 3281 map, 3282 NULL, // set elements to empty fixed array 3283 mode_, 3284 kind_, 3285 allocation_site_payload_, 3286 length_field); 3287 3288 // Allocate and initialize the elements 3289 elements_location_ = builder()->BuildAllocateElements(kind_, elements_size); 3290 3291 builder()->BuildInitializeElementsHeader(elements_location_, kind_, capacity); 3292 3293 // Set the elements 3294 builder()->Add<HStoreNamedField>( 3295 array_object, HObjectAccess::ForElementsPointer(), elements_location_); 3296 3297 if (fill_mode == FILL_WITH_HOLE) { 3298 builder()->BuildFillElementsWithHole(elements_location_, kind_, 3299 graph()->GetConstant0(), capacity); 3300 } 3301 3302 return array_object; 3303 } 3304 3305 3306 HValue* HGraphBuilder::AddLoadJSBuiltin(Builtins::JavaScript builtin) { 3307 HValue* global_object = Add<HLoadNamedField>( 3308 context(), static_cast<HValue*>(NULL), 3309 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); 3310 HObjectAccess access = HObjectAccess::ForObservableJSObjectOffset( 3311 GlobalObject::kBuiltinsOffset); 3312 HValue* builtins = Add<HLoadNamedField>( 3313 global_object, static_cast<HValue*>(NULL), access); 3314 HObjectAccess function_access = HObjectAccess::ForObservableJSObjectOffset( 3315 JSBuiltinsObject::OffsetOfFunctionWithId(builtin)); 3316 return Add<HLoadNamedField>( 3317 builtins, static_cast<HValue*>(NULL), function_access); 3318 } 3319 3320 3321 HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info) 3322 : HGraphBuilder(info), 3323 function_state_(NULL), 3324 initial_function_state_(this, info, NORMAL_RETURN, 0), 3325 ast_context_(NULL), 3326 break_scope_(NULL), 3327 inlined_count_(0), 3328 globals_(10, info->zone()), 3329 osr_(new(info->zone()) HOsrBuilder(this)) { 3330 // This is not initialized in the initializer list because the 3331 // constructor for the initial state relies on function_state_ == NULL 3332 // to know it's the initial state. 3333 function_state_= &initial_function_state_; 3334 InitializeAstVisitor(info->zone()); 3335 if (FLAG_hydrogen_track_positions) { 3336 SetSourcePosition(info->shared_info()->start_position()); 3337 } 3338 } 3339 3340 3341 HBasicBlock* HOptimizedGraphBuilder::CreateJoin(HBasicBlock* first, 3342 HBasicBlock* second, 3343 BailoutId join_id) { 3344 if (first == NULL) { 3345 return second; 3346 } else if (second == NULL) { 3347 return first; 3348 } else { 3349 HBasicBlock* join_block = graph()->CreateBasicBlock(); 3350 Goto(first, join_block); 3351 Goto(second, join_block); 3352 join_block->SetJoinId(join_id); 3353 return join_block; 3354 } 3355 } 3356 3357 3358 HBasicBlock* HOptimizedGraphBuilder::JoinContinue(IterationStatement* statement, 3359 HBasicBlock* exit_block, 3360 HBasicBlock* continue_block) { 3361 if (continue_block != NULL) { 3362 if (exit_block != NULL) Goto(exit_block, continue_block); 3363 continue_block->SetJoinId(statement->ContinueId()); 3364 return continue_block; 3365 } 3366 return exit_block; 3367 } 3368 3369 3370 HBasicBlock* HOptimizedGraphBuilder::CreateLoop(IterationStatement* statement, 3371 HBasicBlock* loop_entry, 3372 HBasicBlock* body_exit, 3373 HBasicBlock* loop_successor, 3374 HBasicBlock* break_block) { 3375 if (body_exit != NULL) Goto(body_exit, loop_entry); 3376 loop_entry->PostProcessLoopHeader(statement); 3377 if (break_block != NULL) { 3378 if (loop_successor != NULL) Goto(loop_successor, break_block); 3379 break_block->SetJoinId(statement->ExitId()); 3380 return break_block; 3381 } 3382 return loop_successor; 3383 } 3384 3385 3386 // Build a new loop header block and set it as the current block. 3387 HBasicBlock* HOptimizedGraphBuilder::BuildLoopEntry() { 3388 HBasicBlock* loop_entry = CreateLoopHeaderBlock(); 3389 Goto(loop_entry); 3390 set_current_block(loop_entry); 3391 return loop_entry; 3392 } 3393 3394 3395 HBasicBlock* HOptimizedGraphBuilder::BuildLoopEntry( 3396 IterationStatement* statement) { 3397 HBasicBlock* loop_entry = osr()->HasOsrEntryAt(statement) 3398 ? osr()->BuildOsrLoopEntry(statement) 3399 : BuildLoopEntry(); 3400 return loop_entry; 3401 } 3402 3403 3404 void HBasicBlock::FinishExit(HControlInstruction* instruction, 3405 HSourcePosition position) { 3406 Finish(instruction, position); 3407 ClearEnvironment(); 3408 } 3409 3410 3411 OStream& operator<<(OStream& os, const HBasicBlock& b) { 3412 return os << "B" << b.block_id(); 3413 } 3414 3415 3416 HGraph::HGraph(CompilationInfo* info) 3417 : isolate_(info->isolate()), 3418 next_block_id_(0), 3419 entry_block_(NULL), 3420 blocks_(8, info->zone()), 3421 values_(16, info->zone()), 3422 phi_list_(NULL), 3423 uint32_instructions_(NULL), 3424 osr_(NULL), 3425 info_(info), 3426 zone_(info->zone()), 3427 is_recursive_(false), 3428 use_optimistic_licm_(false), 3429 depends_on_empty_array_proto_elements_(false), 3430 type_change_checksum_(0), 3431 maximum_environment_size_(0), 3432 no_side_effects_scope_count_(0), 3433 disallow_adding_new_values_(false), 3434 next_inline_id_(0), 3435 inlined_functions_(5, info->zone()) { 3436 if (info->IsStub()) { 3437 CallInterfaceDescriptor descriptor = 3438 info->code_stub()->GetCallInterfaceDescriptor(); 3439 start_environment_ = new (zone_) 3440 HEnvironment(zone_, descriptor.GetEnvironmentParameterCount()); 3441 } else { 3442 TraceInlinedFunction(info->shared_info(), HSourcePosition::Unknown()); 3443 start_environment_ = 3444 new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_); 3445 } 3446 start_environment_->set_ast_id(BailoutId::FunctionEntry()); 3447 entry_block_ = CreateBasicBlock(); 3448 entry_block_->SetInitialEnvironment(start_environment_); 3449 } 3450 3451 3452 HBasicBlock* HGraph::CreateBasicBlock() { 3453 HBasicBlock* result = new(zone()) HBasicBlock(this); 3454 blocks_.Add(result, zone()); 3455 return result; 3456 } 3457 3458 3459 void HGraph::FinalizeUniqueness() { 3460 DisallowHeapAllocation no_gc; 3461 DCHECK(!OptimizingCompilerThread::IsOptimizerThread(isolate())); 3462 for (int i = 0; i < blocks()->length(); ++i) { 3463 for (HInstructionIterator it(blocks()->at(i)); !it.Done(); it.Advance()) { 3464 it.Current()->FinalizeUniqueness(); 3465 } 3466 } 3467 } 3468 3469 3470 int HGraph::TraceInlinedFunction( 3471 Handle<SharedFunctionInfo> shared, 3472 HSourcePosition position) { 3473 if (!FLAG_hydrogen_track_positions) { 3474 return 0; 3475 } 3476 3477 int id = 0; 3478 for (; id < inlined_functions_.length(); id++) { 3479 if (inlined_functions_[id].shared().is_identical_to(shared)) { 3480 break; 3481 } 3482 } 3483 3484 if (id == inlined_functions_.length()) { 3485 inlined_functions_.Add(InlinedFunctionInfo(shared), zone()); 3486 3487 if (!shared->script()->IsUndefined()) { 3488 Handle<Script> script(Script::cast(shared->script())); 3489 if (!script->source()->IsUndefined()) { 3490 CodeTracer::Scope tracing_scopex(isolate()->GetCodeTracer()); 3491 OFStream os(tracing_scopex.file()); 3492 os << "--- FUNCTION SOURCE (" << shared->DebugName()->ToCString().get() 3493 << ") id{" << info()->optimization_id() << "," << id << "} ---\n"; 3494 { 3495 ConsStringIteratorOp op; 3496 StringCharacterStream stream(String::cast(script->source()), 3497 &op, 3498 shared->start_position()); 3499 // fun->end_position() points to the last character in the stream. We 3500 // need to compensate by adding one to calculate the length. 3501 int source_len = 3502 shared->end_position() - shared->start_position() + 1; 3503 for (int i = 0; i < source_len; i++) { 3504 if (stream.HasMore()) { 3505 os << AsReversiblyEscapedUC16(stream.GetNext()); 3506 } 3507 } 3508 } 3509 3510 os << "\n--- END ---\n"; 3511 } 3512 } 3513 } 3514 3515 int inline_id = next_inline_id_++; 3516 3517 if (inline_id != 0) { 3518 CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer()); 3519 OFStream os(tracing_scope.file()); 3520 os << "INLINE (" << shared->DebugName()->ToCString().get() << ") id{" 3521 << info()->optimization_id() << "," << id << "} AS " << inline_id 3522 << " AT " << position << endl; 3523 } 3524 3525 return inline_id; 3526 } 3527 3528 3529 int HGraph::SourcePositionToScriptPosition(HSourcePosition pos) { 3530 if (!FLAG_hydrogen_track_positions || pos.IsUnknown()) { 3531 return pos.raw(); 3532 } 3533 3534 return inlined_functions_[pos.inlining_id()].start_position() + 3535 pos.position(); 3536 } 3537 3538 3539 // Block ordering was implemented with two mutually recursive methods, 3540 // HGraph::Postorder and HGraph::PostorderLoopBlocks. 3541 // The recursion could lead to stack overflow so the algorithm has been 3542 // implemented iteratively. 3543 // At a high level the algorithm looks like this: 3544 // 3545 // Postorder(block, loop_header) : { 3546 // if (block has already been visited or is of another loop) return; 3547 // mark block as visited; 3548 // if (block is a loop header) { 3549 // VisitLoopMembers(block, loop_header); 3550 // VisitSuccessorsOfLoopHeader(block); 3551 // } else { 3552 // VisitSuccessors(block) 3553 // } 3554 // put block in result list; 3555 // } 3556 // 3557 // VisitLoopMembers(block, outer_loop_header) { 3558 // foreach (block b in block loop members) { 3559 // VisitSuccessorsOfLoopMember(b, outer_loop_header); 3560 // if (b is loop header) VisitLoopMembers(b); 3561 // } 3562 // } 3563 // 3564 // VisitSuccessorsOfLoopMember(block, outer_loop_header) { 3565 // foreach (block b in block successors) Postorder(b, outer_loop_header) 3566 // } 3567 // 3568 // VisitSuccessorsOfLoopHeader(block) { 3569 // foreach (block b in block successors) Postorder(b, block) 3570 // } 3571 // 3572 // VisitSuccessors(block, loop_header) { 3573 // foreach (block b in block successors) Postorder(b, loop_header) 3574 // } 3575 // 3576 // The ordering is started calling Postorder(entry, NULL). 3577 // 3578 // Each instance of PostorderProcessor represents the "stack frame" of the 3579 // recursion, and particularly keeps the state of the loop (iteration) of the 3580 // "Visit..." function it represents. 3581 // To recycle memory we keep all the frames in a double linked list but 3582 // this means that we cannot use constructors to initialize the frames. 3583 // 3584 class PostorderProcessor : public ZoneObject { 3585 public: 3586 // Back link (towards the stack bottom). 3587 PostorderProcessor* parent() {return father_; } 3588 // Forward link (towards the stack top). 3589 PostorderProcessor* child() {return child_; } 3590 HBasicBlock* block() { return block_; } 3591 HLoopInformation* loop() { return loop_; } 3592 HBasicBlock* loop_header() { return loop_header_; } 3593 3594 static PostorderProcessor* CreateEntryProcessor(Zone* zone, 3595 HBasicBlock* block) { 3596 PostorderProcessor* result = new(zone) PostorderProcessor(NULL); 3597 return result->SetupSuccessors(zone, block, NULL); 3598 } 3599 3600 PostorderProcessor* PerformStep(Zone* zone, 3601 ZoneList<HBasicBlock*>* order) { 3602 PostorderProcessor* next = 3603 PerformNonBacktrackingStep(zone, order); 3604 if (next != NULL) { 3605 return next; 3606 } else { 3607 return Backtrack(zone, order); 3608 } 3609 } 3610 3611 private: 3612 explicit PostorderProcessor(PostorderProcessor* father) 3613 : father_(father), child_(NULL), successor_iterator(NULL) { } 3614 3615 // Each enum value states the cycle whose state is kept by this instance. 3616 enum LoopKind { 3617 NONE, 3618 SUCCESSORS, 3619 SUCCESSORS_OF_LOOP_HEADER, 3620 LOOP_MEMBERS, 3621 SUCCESSORS_OF_LOOP_MEMBER 3622 }; 3623 3624 // Each "Setup..." method is like a constructor for a cycle state. 3625 PostorderProcessor* SetupSuccessors(Zone* zone, 3626 HBasicBlock* block, 3627 HBasicBlock* loop_header) { 3628 if (block == NULL || block->IsOrdered() || 3629 block->parent_loop_header() != loop_header) { 3630 kind_ = NONE; 3631 block_ = NULL; 3632 loop_ = NULL; 3633 loop_header_ = NULL; 3634 return this; 3635 } else { 3636 block_ = block; 3637 loop_ = NULL; 3638 block->MarkAsOrdered(); 3639 3640 if (block->IsLoopHeader()) { 3641 kind_ = SUCCESSORS_OF_LOOP_HEADER; 3642 loop_header_ = block; 3643 InitializeSuccessors(); 3644 PostorderProcessor* result = Push(zone); 3645 return result->SetupLoopMembers(zone, block, block->loop_information(), 3646 loop_header); 3647 } else { 3648 DCHECK(block->IsFinished()); 3649 kind_ = SUCCESSORS; 3650 loop_header_ = loop_header; 3651 InitializeSuccessors(); 3652 return this; 3653 } 3654 } 3655 } 3656 3657 PostorderProcessor* SetupLoopMembers(Zone* zone, 3658 HBasicBlock* block, 3659 HLoopInformation* loop, 3660 HBasicBlock* loop_header) { 3661 kind_ = LOOP_MEMBERS; 3662 block_ = block; 3663 loop_ = loop; 3664 loop_header_ = loop_header; 3665 InitializeLoopMembers(); 3666 return this; 3667 } 3668 3669 PostorderProcessor* SetupSuccessorsOfLoopMember( 3670 HBasicBlock* block, 3671 HLoopInformation* loop, 3672 HBasicBlock* loop_header) { 3673 kind_ = SUCCESSORS_OF_LOOP_MEMBER; 3674 block_ = block; 3675 loop_ = loop; 3676 loop_header_ = loop_header; 3677 InitializeSuccessors(); 3678 return this; 3679 } 3680 3681 // This method "allocates" a new stack frame. 3682 PostorderProcessor* Push(Zone* zone) { 3683 if (child_ == NULL) { 3684 child_ = new(zone) PostorderProcessor(this); 3685 } 3686 return child_; 3687 } 3688 3689 void ClosePostorder(ZoneList<HBasicBlock*>* order, Zone* zone) { 3690 DCHECK(block_->end()->FirstSuccessor() == NULL || 3691 order->Contains(block_->end()->FirstSuccessor()) || 3692 block_->end()->FirstSuccessor()->IsLoopHeader()); 3693 DCHECK(block_->end()->SecondSuccessor() == NULL || 3694 order->Contains(block_->end()->SecondSuccessor()) || 3695 block_->end()->SecondSuccessor()->IsLoopHeader()); 3696 order->Add(block_, zone); 3697 } 3698 3699 // This method is the basic block to walk up the stack. 3700 PostorderProcessor* Pop(Zone* zone, 3701 ZoneList<HBasicBlock*>* order) { 3702 switch (kind_) { 3703 case SUCCESSORS: 3704 case SUCCESSORS_OF_LOOP_HEADER: 3705 ClosePostorder(order, zone); 3706 return father_; 3707 case LOOP_MEMBERS: 3708 return father_; 3709 case SUCCESSORS_OF_LOOP_MEMBER: 3710 if (block()->IsLoopHeader() && block() != loop_->loop_header()) { 3711 // In this case we need to perform a LOOP_MEMBERS cycle so we 3712 // initialize it and return this instead of father. 3713 return SetupLoopMembers(zone, block(), 3714 block()->loop_information(), loop_header_); 3715 } else { 3716 return father_; 3717 } 3718 case NONE: 3719 return father_; 3720 } 3721 UNREACHABLE(); 3722 return NULL; 3723 } 3724 3725 // Walks up the stack. 3726 PostorderProcessor* Backtrack(Zone* zone, 3727 ZoneList<HBasicBlock*>* order) { 3728 PostorderProcessor* parent = Pop(zone, order); 3729 while (parent != NULL) { 3730 PostorderProcessor* next = 3731 parent->PerformNonBacktrackingStep(zone, order); 3732 if (next != NULL) { 3733 return next; 3734 } else { 3735 parent = parent->Pop(zone, order); 3736 } 3737 } 3738 return NULL; 3739 } 3740 3741 PostorderProcessor* PerformNonBacktrackingStep( 3742 Zone* zone, 3743 ZoneList<HBasicBlock*>* order) { 3744 HBasicBlock* next_block; 3745 switch (kind_) { 3746 case SUCCESSORS: 3747 next_block = AdvanceSuccessors(); 3748 if (next_block != NULL) { 3749 PostorderProcessor* result = Push(zone); 3750 return result->SetupSuccessors(zone, next_block, loop_header_); 3751 } 3752 break; 3753 case SUCCESSORS_OF_LOOP_HEADER: 3754 next_block = AdvanceSuccessors(); 3755 if (next_block != NULL) { 3756 PostorderProcessor* result = Push(zone); 3757 return result->SetupSuccessors(zone, next_block, block()); 3758 } 3759 break; 3760 case LOOP_MEMBERS: 3761 next_block = AdvanceLoopMembers(); 3762 if (next_block != NULL) { 3763 PostorderProcessor* result = Push(zone); 3764 return result->SetupSuccessorsOfLoopMember(next_block, 3765 loop_, loop_header_); 3766 } 3767 break; 3768 case SUCCESSORS_OF_LOOP_MEMBER: 3769 next_block = AdvanceSuccessors(); 3770 if (next_block != NULL) { 3771 PostorderProcessor* result = Push(zone); 3772 return result->SetupSuccessors(zone, next_block, loop_header_); 3773 } 3774 break; 3775 case NONE: 3776 return NULL; 3777 } 3778 return NULL; 3779 } 3780 3781 // The following two methods implement a "foreach b in successors" cycle. 3782 void InitializeSuccessors() { 3783 loop_index = 0; 3784 loop_length = 0; 3785 successor_iterator = HSuccessorIterator(block_->end()); 3786 } 3787 3788 HBasicBlock* AdvanceSuccessors() { 3789 if (!successor_iterator.Done()) { 3790 HBasicBlock* result = successor_iterator.Current(); 3791 successor_iterator.Advance(); 3792 return result; 3793 } 3794 return NULL; 3795 } 3796 3797 // The following two methods implement a "foreach b in loop members" cycle. 3798 void InitializeLoopMembers() { 3799 loop_index = 0; 3800 loop_length = loop_->blocks()->length(); 3801 } 3802 3803 HBasicBlock* AdvanceLoopMembers() { 3804 if (loop_index < loop_length) { 3805 HBasicBlock* result = loop_->blocks()->at(loop_index); 3806 loop_index++; 3807 return result; 3808 } else { 3809 return NULL; 3810 } 3811 } 3812 3813 LoopKind kind_; 3814 PostorderProcessor* father_; 3815 PostorderProcessor* child_; 3816 HLoopInformation* loop_; 3817 HBasicBlock* block_; 3818 HBasicBlock* loop_header_; 3819 int loop_index; 3820 int loop_length; 3821 HSuccessorIterator successor_iterator; 3822 }; 3823 3824 3825 void HGraph::OrderBlocks() { 3826 CompilationPhase phase("H_Block ordering", info()); 3827 3828 #ifdef DEBUG 3829 // Initially the blocks must not be ordered. 3830 for (int i = 0; i < blocks_.length(); ++i) { 3831 DCHECK(!blocks_[i]->IsOrdered()); 3832 } 3833 #endif 3834 3835 PostorderProcessor* postorder = 3836 PostorderProcessor::CreateEntryProcessor(zone(), blocks_[0]); 3837 blocks_.Rewind(0); 3838 while (postorder) { 3839 postorder = postorder->PerformStep(zone(), &blocks_); 3840 } 3841 3842 #ifdef DEBUG 3843 // Now all blocks must be marked as ordered. 3844 for (int i = 0; i < blocks_.length(); ++i) { 3845 DCHECK(blocks_[i]->IsOrdered()); 3846 } 3847 #endif 3848 3849 // Reverse block list and assign block IDs. 3850 for (int i = 0, j = blocks_.length(); --j >= i; ++i) { 3851 HBasicBlock* bi = blocks_[i]; 3852 HBasicBlock* bj = blocks_[j]; 3853 bi->set_block_id(j); 3854 bj->set_block_id(i); 3855 blocks_[i] = bj; 3856 blocks_[j] = bi; 3857 } 3858 } 3859 3860 3861 void HGraph::AssignDominators() { 3862 HPhase phase("H_Assign dominators", this); 3863 for (int i = 0; i < blocks_.length(); ++i) { 3864 HBasicBlock* block = blocks_[i]; 3865 if (block->IsLoopHeader()) { 3866 // Only the first predecessor of a loop header is from outside the loop. 3867 // All others are back edges, and thus cannot dominate the loop header. 3868 block->AssignCommonDominator(block->predecessors()->first()); 3869 block->AssignLoopSuccessorDominators(); 3870 } else { 3871 for (int j = blocks_[i]->predecessors()->length() - 1; j >= 0; --j) { 3872 blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->at(j)); 3873 } 3874 } 3875 } 3876 } 3877 3878 3879 bool HGraph::CheckArgumentsPhiUses() { 3880 int block_count = blocks_.length(); 3881 for (int i = 0; i < block_count; ++i) { 3882 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) { 3883 HPhi* phi = blocks_[i]->phis()->at(j); 3884 // We don't support phi uses of arguments for now. 3885 if (phi->CheckFlag(HValue::kIsArguments)) return false; 3886 } 3887 } 3888 return true; 3889 } 3890 3891 3892 bool HGraph::CheckConstPhiUses() { 3893 int block_count = blocks_.length(); 3894 for (int i = 0; i < block_count; ++i) { 3895 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) { 3896 HPhi* phi = blocks_[i]->phis()->at(j); 3897 // Check for the hole value (from an uninitialized const). 3898 for (int k = 0; k < phi->OperandCount(); k++) { 3899 if (phi->OperandAt(k) == GetConstantHole()) return false; 3900 } 3901 } 3902 } 3903 return true; 3904 } 3905 3906 3907 void HGraph::CollectPhis() { 3908 int block_count = blocks_.length(); 3909 phi_list_ = new(zone()) ZoneList<HPhi*>(block_count, zone()); 3910 for (int i = 0; i < block_count; ++i) { 3911 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) { 3912 HPhi* phi = blocks_[i]->phis()->at(j); 3913 phi_list_->Add(phi, zone()); 3914 } 3915 } 3916 } 3917 3918 3919 // Implementation of utility class to encapsulate the translation state for 3920 // a (possibly inlined) function. 3921 FunctionState::FunctionState(HOptimizedGraphBuilder* owner, 3922 CompilationInfo* info, 3923 InliningKind inlining_kind, 3924 int inlining_id) 3925 : owner_(owner), 3926 compilation_info_(info), 3927 call_context_(NULL), 3928 inlining_kind_(inlining_kind), 3929 function_return_(NULL), 3930 test_context_(NULL), 3931 entry_(NULL), 3932 arguments_object_(NULL), 3933 arguments_elements_(NULL), 3934 inlining_id_(inlining_id), 3935 outer_source_position_(HSourcePosition::Unknown()), 3936 outer_(owner->function_state()) { 3937 if (outer_ != NULL) { 3938 // State for an inline function. 3939 if (owner->ast_context()->IsTest()) { 3940 HBasicBlock* if_true = owner->graph()->CreateBasicBlock(); 3941 HBasicBlock* if_false = owner->graph()->CreateBasicBlock(); 3942 if_true->MarkAsInlineReturnTarget(owner->current_block()); 3943 if_false->MarkAsInlineReturnTarget(owner->current_block()); 3944 TestContext* outer_test_context = TestContext::cast(owner->ast_context()); 3945 Expression* cond = outer_test_context->condition(); 3946 // The AstContext constructor pushed on the context stack. This newed 3947 // instance is the reason that AstContext can't be BASE_EMBEDDED. 3948 test_context_ = new TestContext(owner, cond, if_true, if_false); 3949 } else { 3950 function_return_ = owner->graph()->CreateBasicBlock(); 3951 function_return()->MarkAsInlineReturnTarget(owner->current_block()); 3952 } 3953 // Set this after possibly allocating a new TestContext above. 3954 call_context_ = owner->ast_context(); 3955 } 3956 3957 // Push on the state stack. 3958 owner->set_function_state(this); 3959 3960 if (FLAG_hydrogen_track_positions) { 3961 outer_source_position_ = owner->source_position(); 3962 owner->EnterInlinedSource( 3963 info->shared_info()->start_position(), 3964 inlining_id); 3965 owner->SetSourcePosition(info->shared_info()->start_position()); 3966 } 3967 } 3968 3969 3970 FunctionState::~FunctionState() { 3971 delete test_context_; 3972 owner_->set_function_state(outer_); 3973 3974 if (FLAG_hydrogen_track_positions) { 3975 owner_->set_source_position(outer_source_position_); 3976 owner_->EnterInlinedSource( 3977 outer_->compilation_info()->shared_info()->start_position(), 3978 outer_->inlining_id()); 3979 } 3980 } 3981 3982 3983 // Implementation of utility classes to represent an expression's context in 3984 // the AST. 3985 AstContext::AstContext(HOptimizedGraphBuilder* owner, Expression::Context kind) 3986 : owner_(owner), 3987 kind_(kind), 3988 outer_(owner->ast_context()), 3989 for_typeof_(false) { 3990 owner->set_ast_context(this); // Push. 3991 #ifdef DEBUG 3992 DCHECK(owner->environment()->frame_type() == JS_FUNCTION); 3993 original_length_ = owner->environment()->length(); 3994 #endif 3995 } 3996 3997 3998 AstContext::~AstContext() { 3999 owner_->set_ast_context(outer_); // Pop. 4000 } 4001 4002 4003 EffectContext::~EffectContext() { 4004 DCHECK(owner()->HasStackOverflow() || 4005 owner()->current_block() == NULL || 4006 (owner()->environment()->length() == original_length_ && 4007 owner()->environment()->frame_type() == JS_FUNCTION)); 4008 } 4009 4010 4011 ValueContext::~ValueContext() { 4012 DCHECK(owner()->HasStackOverflow() || 4013 owner()->current_block() == NULL || 4014 (owner()->environment()->length() == original_length_ + 1 && 4015 owner()->environment()->frame_type() == JS_FUNCTION)); 4016 } 4017 4018 4019 void EffectContext::ReturnValue(HValue* value) { 4020 // The value is simply ignored. 4021 } 4022 4023 4024 void ValueContext::ReturnValue(HValue* value) { 4025 // The value is tracked in the bailout environment, and communicated 4026 // through the environment as the result of the expression. 4027 if (!arguments_allowed() && value->CheckFlag(HValue::kIsArguments)) { 4028 owner()->Bailout(kBadValueContextForArgumentsValue); 4029 } 4030 owner()->Push(value); 4031 } 4032 4033 4034 void TestContext::ReturnValue(HValue* value) { 4035 BuildBranch(value); 4036 } 4037 4038 4039 void EffectContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) { 4040 DCHECK(!instr->IsControlInstruction()); 4041 owner()->AddInstruction(instr); 4042 if (instr->HasObservableSideEffects()) { 4043 owner()->Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); 4044 } 4045 } 4046 4047 4048 void EffectContext::ReturnControl(HControlInstruction* instr, 4049 BailoutId ast_id) { 4050 DCHECK(!instr->HasObservableSideEffects()); 4051 HBasicBlock* empty_true = owner()->graph()->CreateBasicBlock(); 4052 HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock(); 4053 instr->SetSuccessorAt(0, empty_true); 4054 instr->SetSuccessorAt(1, empty_false); 4055 owner()->FinishCurrentBlock(instr); 4056 HBasicBlock* join = owner()->CreateJoin(empty_true, empty_false, ast_id); 4057 owner()->set_current_block(join); 4058 } 4059 4060 4061 void EffectContext::ReturnContinuation(HIfContinuation* continuation, 4062 BailoutId ast_id) { 4063 HBasicBlock* true_branch = NULL; 4064 HBasicBlock* false_branch = NULL; 4065 continuation->Continue(&true_branch, &false_branch); 4066 if (!continuation->IsTrueReachable()) { 4067 owner()->set_current_block(false_branch); 4068 } else if (!continuation->IsFalseReachable()) { 4069 owner()->set_current_block(true_branch); 4070 } else { 4071 HBasicBlock* join = owner()->CreateJoin(true_branch, false_branch, ast_id); 4072 owner()->set_current_block(join); 4073 } 4074 } 4075 4076 4077 void ValueContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) { 4078 DCHECK(!instr->IsControlInstruction()); 4079 if (!arguments_allowed() && instr->CheckFlag(HValue::kIsArguments)) { 4080 return owner()->Bailout(kBadValueContextForArgumentsObjectValue); 4081 } 4082 owner()->AddInstruction(instr); 4083 owner()->Push(instr); 4084 if (instr->HasObservableSideEffects()) { 4085 owner()->Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); 4086 } 4087 } 4088 4089 4090 void ValueContext::ReturnControl(HControlInstruction* instr, BailoutId ast_id) { 4091 DCHECK(!instr->HasObservableSideEffects()); 4092 if (!arguments_allowed() && instr->CheckFlag(HValue::kIsArguments)) { 4093 return owner()->Bailout(kBadValueContextForArgumentsObjectValue); 4094 } 4095 HBasicBlock* materialize_false = owner()->graph()->CreateBasicBlock(); 4096 HBasicBlock* materialize_true = owner()->graph()->CreateBasicBlock(); 4097 instr->SetSuccessorAt(0, materialize_true); 4098 instr->SetSuccessorAt(1, materialize_false); 4099 owner()->FinishCurrentBlock(instr); 4100 owner()->set_current_block(materialize_true); 4101 owner()->Push(owner()->graph()->GetConstantTrue()); 4102 owner()->set_current_block(materialize_false); 4103 owner()->Push(owner()->graph()->GetConstantFalse()); 4104 HBasicBlock* join = 4105 owner()->CreateJoin(materialize_true, materialize_false, ast_id); 4106 owner()->set_current_block(join); 4107 } 4108 4109 4110 void ValueContext::ReturnContinuation(HIfContinuation* continuation, 4111 BailoutId ast_id) { 4112 HBasicBlock* materialize_true = NULL; 4113 HBasicBlock* materialize_false = NULL; 4114 continuation->Continue(&materialize_true, &materialize_false); 4115 if (continuation->IsTrueReachable()) { 4116 owner()->set_current_block(materialize_true); 4117 owner()->Push(owner()->graph()->GetConstantTrue()); 4118 owner()->set_current_block(materialize_true); 4119 } 4120 if (continuation->IsFalseReachable()) { 4121 owner()->set_current_block(materialize_false); 4122 owner()->Push(owner()->graph()->GetConstantFalse()); 4123 owner()->set_current_block(materialize_false); 4124 } 4125 if (continuation->TrueAndFalseReachable()) { 4126 HBasicBlock* join = 4127 owner()->CreateJoin(materialize_true, materialize_false, ast_id); 4128 owner()->set_current_block(join); 4129 } 4130 } 4131 4132 4133 void TestContext::ReturnInstruction(HInstruction* instr, BailoutId ast_id) { 4134 DCHECK(!instr->IsControlInstruction()); 4135 HOptimizedGraphBuilder* builder = owner(); 4136 builder->AddInstruction(instr); 4137 // We expect a simulate after every expression with side effects, though 4138 // this one isn't actually needed (and wouldn't work if it were targeted). 4139 if (instr->HasObservableSideEffects()) { 4140 builder->Push(instr); 4141 builder->Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); 4142 builder->Pop(); 4143 } 4144 BuildBranch(instr); 4145 } 4146 4147 4148 void TestContext::ReturnControl(HControlInstruction* instr, BailoutId ast_id) { 4149 DCHECK(!instr->HasObservableSideEffects()); 4150 HBasicBlock* empty_true = owner()->graph()->CreateBasicBlock(); 4151 HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock(); 4152 instr->SetSuccessorAt(0, empty_true); 4153 instr->SetSuccessorAt(1, empty_false); 4154 owner()->FinishCurrentBlock(instr); 4155 owner()->Goto(empty_true, if_true(), owner()->function_state()); 4156 owner()->Goto(empty_false, if_false(), owner()->function_state()); 4157 owner()->set_current_block(NULL); 4158 } 4159 4160 4161 void TestContext::ReturnContinuation(HIfContinuation* continuation, 4162 BailoutId ast_id) { 4163 HBasicBlock* true_branch = NULL; 4164 HBasicBlock* false_branch = NULL; 4165 continuation->Continue(&true_branch, &false_branch); 4166 if (continuation->IsTrueReachable()) { 4167 owner()->Goto(true_branch, if_true(), owner()->function_state()); 4168 } 4169 if (continuation->IsFalseReachable()) { 4170 owner()->Goto(false_branch, if_false(), owner()->function_state()); 4171 } 4172 owner()->set_current_block(NULL); 4173 } 4174 4175 4176 void TestContext::BuildBranch(HValue* value) { 4177 // We expect the graph to be in edge-split form: there is no edge that 4178 // connects a branch node to a join node. We conservatively ensure that 4179 // property by always adding an empty block on the outgoing edges of this 4180 // branch. 4181 HOptimizedGraphBuilder* builder = owner(); 4182 if (value != NULL && value->CheckFlag(HValue::kIsArguments)) { 4183 builder->Bailout(kArgumentsObjectValueInATestContext); 4184 } 4185 ToBooleanStub::Types expected(condition()->to_boolean_types()); 4186 ReturnControl(owner()->New<HBranch>(value, expected), BailoutId::None()); 4187 } 4188 4189 4190 // HOptimizedGraphBuilder infrastructure for bailing out and checking bailouts. 4191 #define CHECK_BAILOUT(call) \ 4192 do { \ 4193 call; \ 4194 if (HasStackOverflow()) return; \ 4195 } while (false) 4196 4197 4198 #define CHECK_ALIVE(call) \ 4199 do { \ 4200 call; \ 4201 if (HasStackOverflow() || current_block() == NULL) return; \ 4202 } while (false) 4203 4204 4205 #define CHECK_ALIVE_OR_RETURN(call, value) \ 4206 do { \ 4207 call; \ 4208 if (HasStackOverflow() || current_block() == NULL) return value; \ 4209 } while (false) 4210 4211 4212 void HOptimizedGraphBuilder::Bailout(BailoutReason reason) { 4213 current_info()->AbortOptimization(reason); 4214 SetStackOverflow(); 4215 } 4216 4217 4218 void HOptimizedGraphBuilder::VisitForEffect(Expression* expr) { 4219 EffectContext for_effect(this); 4220 Visit(expr); 4221 } 4222 4223 4224 void HOptimizedGraphBuilder::VisitForValue(Expression* expr, 4225 ArgumentsAllowedFlag flag) { 4226 ValueContext for_value(this, flag); 4227 Visit(expr); 4228 } 4229 4230 4231 void HOptimizedGraphBuilder::VisitForTypeOf(Expression* expr) { 4232 ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED); 4233 for_value.set_for_typeof(true); 4234 Visit(expr); 4235 } 4236 4237 4238 void HOptimizedGraphBuilder::VisitForControl(Expression* expr, 4239 HBasicBlock* true_block, 4240 HBasicBlock* false_block) { 4241 TestContext for_test(this, expr, true_block, false_block); 4242 Visit(expr); 4243 } 4244 4245 4246 void HOptimizedGraphBuilder::VisitExpressions( 4247 ZoneList<Expression*>* exprs) { 4248 for (int i = 0; i < exprs->length(); ++i) { 4249 CHECK_ALIVE(VisitForValue(exprs->at(i))); 4250 } 4251 } 4252 4253 4254 bool HOptimizedGraphBuilder::BuildGraph() { 4255 if (current_info()->function()->is_generator()) { 4256 Bailout(kFunctionIsAGenerator); 4257 return false; 4258 } 4259 Scope* scope = current_info()->scope(); 4260 if (scope->HasIllegalRedeclaration()) { 4261 Bailout(kFunctionWithIllegalRedeclaration); 4262 return false; 4263 } 4264 if (scope->calls_eval()) { 4265 Bailout(kFunctionCallsEval); 4266 return false; 4267 } 4268 SetUpScope(scope); 4269 4270 // Add an edge to the body entry. This is warty: the graph's start 4271 // environment will be used by the Lithium translation as the initial 4272 // environment on graph entry, but it has now been mutated by the 4273 // Hydrogen translation of the instructions in the start block. This 4274 // environment uses values which have not been defined yet. These 4275 // Hydrogen instructions will then be replayed by the Lithium 4276 // translation, so they cannot have an environment effect. The edge to 4277 // the body's entry block (along with some special logic for the start 4278 // block in HInstruction::InsertAfter) seals the start block from 4279 // getting unwanted instructions inserted. 4280 // 4281 // TODO(kmillikin): Fix this. Stop mutating the initial environment. 4282 // Make the Hydrogen instructions in the initial block into Hydrogen 4283 // values (but not instructions), present in the initial environment and 4284 // not replayed by the Lithium translation. 4285 HEnvironment* initial_env = environment()->CopyWithoutHistory(); 4286 HBasicBlock* body_entry = CreateBasicBlock(initial_env); 4287 Goto(body_entry); 4288 body_entry->SetJoinId(BailoutId::FunctionEntry()); 4289 set_current_block(body_entry); 4290 4291 // Handle implicit declaration of the function name in named function 4292 // expressions before other declarations. 4293 if (scope->is_function_scope() && scope->function() != NULL) { 4294 VisitVariableDeclaration(scope->function()); 4295 } 4296 VisitDeclarations(scope->declarations()); 4297 Add<HSimulate>(BailoutId::Declarations()); 4298 4299 Add<HStackCheck>(HStackCheck::kFunctionEntry); 4300 4301 VisitStatements(current_info()->function()->body()); 4302 if (HasStackOverflow()) return false; 4303 4304 if (current_block() != NULL) { 4305 Add<HReturn>(graph()->GetConstantUndefined()); 4306 set_current_block(NULL); 4307 } 4308 4309 // If the checksum of the number of type info changes is the same as the 4310 // last time this function was compiled, then this recompile is likely not 4311 // due to missing/inadequate type feedback, but rather too aggressive 4312 // optimization. Disable optimistic LICM in that case. 4313 Handle<Code> unoptimized_code(current_info()->shared_info()->code()); 4314 DCHECK(unoptimized_code->kind() == Code::FUNCTION); 4315 Handle<TypeFeedbackInfo> type_info( 4316 TypeFeedbackInfo::cast(unoptimized_code->type_feedback_info())); 4317 int checksum = type_info->own_type_change_checksum(); 4318 int composite_checksum = graph()->update_type_change_checksum(checksum); 4319 graph()->set_use_optimistic_licm( 4320 !type_info->matches_inlined_type_change_checksum(composite_checksum)); 4321 type_info->set_inlined_type_change_checksum(composite_checksum); 4322 4323 // Perform any necessary OSR-specific cleanups or changes to the graph. 4324 osr()->FinishGraph(); 4325 4326 return true; 4327 } 4328 4329 4330 bool HGraph::Optimize(BailoutReason* bailout_reason) { 4331 OrderBlocks(); 4332 AssignDominators(); 4333 4334 // We need to create a HConstant "zero" now so that GVN will fold every 4335 // zero-valued constant in the graph together. 4336 // The constant is needed to make idef-based bounds check work: the pass 4337 // evaluates relations with "zero" and that zero cannot be created after GVN. 4338 GetConstant0(); 4339 4340 #ifdef DEBUG 4341 // Do a full verify after building the graph and computing dominators. 4342 Verify(true); 4343 #endif 4344 4345 if (FLAG_analyze_environment_liveness && maximum_environment_size() != 0) { 4346 Run<HEnvironmentLivenessAnalysisPhase>(); 4347 } 4348 4349 if (!CheckConstPhiUses()) { 4350 *bailout_reason = kUnsupportedPhiUseOfConstVariable; 4351 return false; 4352 } 4353 Run<HRedundantPhiEliminationPhase>(); 4354 if (!CheckArgumentsPhiUses()) { 4355 *bailout_reason = kUnsupportedPhiUseOfArguments; 4356 return false; 4357 } 4358 4359 // Find and mark unreachable code to simplify optimizations, especially gvn, 4360 // where unreachable code could unnecessarily defeat LICM. 4361 Run<HMarkUnreachableBlocksPhase>(); 4362 4363 if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>(); 4364 if (FLAG_use_escape_analysis) Run<HEscapeAnalysisPhase>(); 4365 4366 if (FLAG_load_elimination) Run<HLoadEliminationPhase>(); 4367 4368 CollectPhis(); 4369 4370 if (has_osr()) osr()->FinishOsrValues(); 4371 4372 Run<HInferRepresentationPhase>(); 4373 4374 // Remove HSimulate instructions that have turned out not to be needed 4375 // after all by folding them into the following HSimulate. 4376 // This must happen after inferring representations. 4377 Run<HMergeRemovableSimulatesPhase>(); 4378 4379 Run<HMarkDeoptimizeOnUndefinedPhase>(); 4380 Run<HRepresentationChangesPhase>(); 4381 4382 Run<HInferTypesPhase>(); 4383 4384 // Must be performed before canonicalization to ensure that Canonicalize 4385 // will not remove semantically meaningful ToInt32 operations e.g. BIT_OR with 4386 // zero. 4387 if (FLAG_opt_safe_uint32_operations) Run<HUint32AnalysisPhase>(); 4388 4389 if (FLAG_use_canonicalizing) Run<HCanonicalizePhase>(); 4390 4391 if (FLAG_use_gvn) Run<HGlobalValueNumberingPhase>(); 4392 4393 if (FLAG_check_elimination) Run<HCheckEliminationPhase>(); 4394 4395 if (FLAG_store_elimination) Run<HStoreEliminationPhase>(); 4396 4397 Run<HRangeAnalysisPhase>(); 4398 4399 Run<HComputeChangeUndefinedToNaN>(); 4400 4401 // Eliminate redundant stack checks on backwards branches. 4402 Run<HStackCheckEliminationPhase>(); 4403 4404 if (FLAG_array_bounds_checks_elimination) Run<HBoundsCheckEliminationPhase>(); 4405 if (FLAG_array_bounds_checks_hoisting) Run<HBoundsCheckHoistingPhase>(); 4406 if (FLAG_array_index_dehoisting) Run<HDehoistIndexComputationsPhase>(); 4407 if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>(); 4408 4409 RestoreActualValues(); 4410 4411 // Find unreachable code a second time, GVN and other optimizations may have 4412 // made blocks unreachable that were previously reachable. 4413 Run<HMarkUnreachableBlocksPhase>(); 4414 4415 return true; 4416 } 4417 4418 4419 void HGraph::RestoreActualValues() { 4420 HPhase phase("H_Restore actual values", this); 4421 4422 for (int block_index = 0; block_index < blocks()->length(); block_index++) { 4423 HBasicBlock* block = blocks()->at(block_index); 4424 4425 #ifdef DEBUG 4426 for (int i = 0; i < block->phis()->length(); i++) { 4427 HPhi* phi = block->phis()->at(i); 4428 DCHECK(phi->ActualValue() == phi); 4429 } 4430 #endif 4431 4432 for (HInstructionIterator it(block); !it.Done(); it.Advance()) { 4433 HInstruction* instruction = it.Current(); 4434 if (instruction->ActualValue() == instruction) continue; 4435 if (instruction->CheckFlag(HValue::kIsDead)) { 4436 // The instruction was marked as deleted but left in the graph 4437 // as a control flow dependency point for subsequent 4438 // instructions. 4439 instruction->DeleteAndReplaceWith(instruction->ActualValue()); 4440 } else { 4441 DCHECK(instruction->IsInformativeDefinition()); 4442 if (instruction->IsPurelyInformativeDefinition()) { 4443 instruction->DeleteAndReplaceWith(instruction->RedefinedOperand()); 4444 } else { 4445 instruction->ReplaceAllUsesWith(instruction->ActualValue()); 4446 } 4447 } 4448 } 4449 } 4450 } 4451 4452 4453 void HOptimizedGraphBuilder::PushArgumentsFromEnvironment(int count) { 4454 ZoneList<HValue*> arguments(count, zone()); 4455 for (int i = 0; i < count; ++i) { 4456 arguments.Add(Pop(), zone()); 4457 } 4458 4459 HPushArguments* push_args = New<HPushArguments>(); 4460 while (!arguments.is_empty()) { 4461 push_args->AddInput(arguments.RemoveLast()); 4462 } 4463 AddInstruction(push_args); 4464 } 4465 4466 4467 template <class Instruction> 4468 HInstruction* HOptimizedGraphBuilder::PreProcessCall(Instruction* call) { 4469 PushArgumentsFromEnvironment(call->argument_count()); 4470 return call; 4471 } 4472 4473 4474 void HOptimizedGraphBuilder::SetUpScope(Scope* scope) { 4475 // First special is HContext. 4476 HInstruction* context = Add<HContext>(); 4477 environment()->BindContext(context); 4478 4479 // Create an arguments object containing the initial parameters. Set the 4480 // initial values of parameters including "this" having parameter index 0. 4481 DCHECK_EQ(scope->num_parameters() + 1, environment()->parameter_count()); 4482 HArgumentsObject* arguments_object = 4483 New<HArgumentsObject>(environment()->parameter_count()); 4484 for (int i = 0; i < environment()->parameter_count(); ++i) { 4485 HInstruction* parameter = Add<HParameter>(i); 4486 arguments_object->AddArgument(parameter, zone()); 4487 environment()->Bind(i, parameter); 4488 } 4489 AddInstruction(arguments_object); 4490 graph()->SetArgumentsObject(arguments_object); 4491 4492 HConstant* undefined_constant = graph()->GetConstantUndefined(); 4493 // Initialize specials and locals to undefined. 4494 for (int i = environment()->parameter_count() + 1; 4495 i < environment()->length(); 4496 ++i) { 4497 environment()->Bind(i, undefined_constant); 4498 } 4499 4500 // Handle the arguments and arguments shadow variables specially (they do 4501 // not have declarations). 4502 if (scope->arguments() != NULL) { 4503 if (!scope->arguments()->IsStackAllocated()) { 4504 return Bailout(kContextAllocatedArguments); 4505 } 4506 4507 environment()->Bind(scope->arguments(), 4508 graph()->GetArgumentsObject()); 4509 } 4510 } 4511 4512 4513 Type* HOptimizedGraphBuilder::ToType(Handle<Map> map) { 4514 return IC::MapToType<Type>(map, zone()); 4515 } 4516 4517 4518 void HOptimizedGraphBuilder::VisitStatements(ZoneList<Statement*>* statements) { 4519 for (int i = 0; i < statements->length(); i++) { 4520 Statement* stmt = statements->at(i); 4521 CHECK_ALIVE(Visit(stmt)); 4522 if (stmt->IsJump()) break; 4523 } 4524 } 4525 4526 4527 void HOptimizedGraphBuilder::VisitBlock(Block* stmt) { 4528 DCHECK(!HasStackOverflow()); 4529 DCHECK(current_block() != NULL); 4530 DCHECK(current_block()->HasPredecessor()); 4531 4532 Scope* outer_scope = scope(); 4533 Scope* scope = stmt->scope(); 4534 BreakAndContinueInfo break_info(stmt, outer_scope); 4535 4536 { BreakAndContinueScope push(&break_info, this); 4537 if (scope != NULL) { 4538 // Load the function object. 4539 Scope* declaration_scope = scope->DeclarationScope(); 4540 HInstruction* function; 4541 HValue* outer_context = environment()->context(); 4542 if (declaration_scope->is_global_scope() || 4543 declaration_scope->is_eval_scope()) { 4544 function = new(zone()) HLoadContextSlot( 4545 outer_context, Context::CLOSURE_INDEX, HLoadContextSlot::kNoCheck); 4546 } else { 4547 function = New<HThisFunction>(); 4548 } 4549 AddInstruction(function); 4550 // Allocate a block context and store it to the stack frame. 4551 HInstruction* inner_context = Add<HAllocateBlockContext>( 4552 outer_context, function, scope->GetScopeInfo()); 4553 HInstruction* instr = Add<HStoreFrameContext>(inner_context); 4554 if (instr->HasObservableSideEffects()) { 4555 AddSimulate(stmt->EntryId(), REMOVABLE_SIMULATE); 4556 } 4557 set_scope(scope); 4558 environment()->BindContext(inner_context); 4559 VisitDeclarations(scope->declarations()); 4560 AddSimulate(stmt->DeclsId(), REMOVABLE_SIMULATE); 4561 } 4562 CHECK_BAILOUT(VisitStatements(stmt->statements())); 4563 } 4564 set_scope(outer_scope); 4565 if (scope != NULL && current_block() != NULL) { 4566 HValue* inner_context = environment()->context(); 4567 HValue* outer_context = Add<HLoadNamedField>( 4568 inner_context, static_cast<HValue*>(NULL), 4569 HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX)); 4570 4571 HInstruction* instr = Add<HStoreFrameContext>(outer_context); 4572 if (instr->HasObservableSideEffects()) { 4573 AddSimulate(stmt->ExitId(), REMOVABLE_SIMULATE); 4574 } 4575 environment()->BindContext(outer_context); 4576 } 4577 HBasicBlock* break_block = break_info.break_block(); 4578 if (break_block != NULL) { 4579 if (current_block() != NULL) Goto(break_block); 4580 break_block->SetJoinId(stmt->ExitId()); 4581 set_current_block(break_block); 4582 } 4583 } 4584 4585 4586 void HOptimizedGraphBuilder::VisitExpressionStatement( 4587 ExpressionStatement* stmt) { 4588 DCHECK(!HasStackOverflow()); 4589 DCHECK(current_block() != NULL); 4590 DCHECK(current_block()->HasPredecessor()); 4591 VisitForEffect(stmt->expression()); 4592 } 4593 4594 4595 void HOptimizedGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) { 4596 DCHECK(!HasStackOverflow()); 4597 DCHECK(current_block() != NULL); 4598 DCHECK(current_block()->HasPredecessor()); 4599 } 4600 4601 4602 void HOptimizedGraphBuilder::VisitIfStatement(IfStatement* stmt) { 4603 DCHECK(!HasStackOverflow()); 4604 DCHECK(current_block() != NULL); 4605 DCHECK(current_block()->HasPredecessor()); 4606 if (stmt->condition()->ToBooleanIsTrue()) { 4607 Add<HSimulate>(stmt->ThenId()); 4608 Visit(stmt->then_statement()); 4609 } else if (stmt->condition()->ToBooleanIsFalse()) { 4610 Add<HSimulate>(stmt->ElseId()); 4611 Visit(stmt->else_statement()); 4612 } else { 4613 HBasicBlock* cond_true = graph()->CreateBasicBlock(); 4614 HBasicBlock* cond_false = graph()->CreateBasicBlock(); 4615 CHECK_BAILOUT(VisitForControl(stmt->condition(), cond_true, cond_false)); 4616 4617 if (cond_true->HasPredecessor()) { 4618 cond_true->SetJoinId(stmt->ThenId()); 4619 set_current_block(cond_true); 4620 CHECK_BAILOUT(Visit(stmt->then_statement())); 4621 cond_true = current_block(); 4622 } else { 4623 cond_true = NULL; 4624 } 4625 4626 if (cond_false->HasPredecessor()) { 4627 cond_false->SetJoinId(stmt->ElseId()); 4628 set_current_block(cond_false); 4629 CHECK_BAILOUT(Visit(stmt->else_statement())); 4630 cond_false = current_block(); 4631 } else { 4632 cond_false = NULL; 4633 } 4634 4635 HBasicBlock* join = CreateJoin(cond_true, cond_false, stmt->IfId()); 4636 set_current_block(join); 4637 } 4638 } 4639 4640 4641 HBasicBlock* HOptimizedGraphBuilder::BreakAndContinueScope::Get( 4642 BreakableStatement* stmt, 4643 BreakType type, 4644 Scope** scope, 4645 int* drop_extra) { 4646 *drop_extra = 0; 4647 BreakAndContinueScope* current = this; 4648 while (current != NULL && current->info()->target() != stmt) { 4649 *drop_extra += current->info()->drop_extra(); 4650 current = current->next(); 4651 } 4652 DCHECK(current != NULL); // Always found (unless stack is malformed). 4653 *scope = current->info()->scope(); 4654 4655 if (type == BREAK) { 4656 *drop_extra += current->info()->drop_extra(); 4657 } 4658 4659 HBasicBlock* block = NULL; 4660 switch (type) { 4661 case BREAK: 4662 block = current->info()->break_block(); 4663 if (block == NULL) { 4664 block = current->owner()->graph()->CreateBasicBlock(); 4665 current->info()->set_break_block(block); 4666 } 4667 break; 4668 4669 case CONTINUE: 4670 block = current->info()->continue_block(); 4671 if (block == NULL) { 4672 block = current->owner()->graph()->CreateBasicBlock(); 4673 current->info()->set_continue_block(block); 4674 } 4675 break; 4676 } 4677 4678 return block; 4679 } 4680 4681 4682 void HOptimizedGraphBuilder::VisitContinueStatement( 4683 ContinueStatement* stmt) { 4684 DCHECK(!HasStackOverflow()); 4685 DCHECK(current_block() != NULL); 4686 DCHECK(current_block()->HasPredecessor()); 4687 Scope* outer_scope = NULL; 4688 Scope* inner_scope = scope(); 4689 int drop_extra = 0; 4690 HBasicBlock* continue_block = break_scope()->Get( 4691 stmt->target(), BreakAndContinueScope::CONTINUE, 4692 &outer_scope, &drop_extra); 4693 HValue* context = environment()->context(); 4694 Drop(drop_extra); 4695 int context_pop_count = inner_scope->ContextChainLength(outer_scope); 4696 if (context_pop_count > 0) { 4697 while (context_pop_count-- > 0) { 4698 HInstruction* context_instruction = Add<HLoadNamedField>( 4699 context, static_cast<HValue*>(NULL), 4700 HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX)); 4701 context = context_instruction; 4702 } 4703 HInstruction* instr = Add<HStoreFrameContext>(context); 4704 if (instr->HasObservableSideEffects()) { 4705 AddSimulate(stmt->target()->EntryId(), REMOVABLE_SIMULATE); 4706 } 4707 environment()->BindContext(context); 4708 } 4709 4710 Goto(continue_block); 4711 set_current_block(NULL); 4712 } 4713 4714 4715 void HOptimizedGraphBuilder::VisitBreakStatement(BreakStatement* stmt) { 4716 DCHECK(!HasStackOverflow()); 4717 DCHECK(current_block() != NULL); 4718 DCHECK(current_block()->HasPredecessor()); 4719 Scope* outer_scope = NULL; 4720 Scope* inner_scope = scope(); 4721 int drop_extra = 0; 4722 HBasicBlock* break_block = break_scope()->Get( 4723 stmt->target(), BreakAndContinueScope::BREAK, 4724 &outer_scope, &drop_extra); 4725 HValue* context = environment()->context(); 4726 Drop(drop_extra); 4727 int context_pop_count = inner_scope->ContextChainLength(outer_scope); 4728 if (context_pop_count > 0) { 4729 while (context_pop_count-- > 0) { 4730 HInstruction* context_instruction = Add<HLoadNamedField>( 4731 context, static_cast<HValue*>(NULL), 4732 HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX)); 4733 context = context_instruction; 4734 } 4735 HInstruction* instr = Add<HStoreFrameContext>(context); 4736 if (instr->HasObservableSideEffects()) { 4737 AddSimulate(stmt->target()->ExitId(), REMOVABLE_SIMULATE); 4738 } 4739 environment()->BindContext(context); 4740 } 4741 Goto(break_block); 4742 set_current_block(NULL); 4743 } 4744 4745 4746 void HOptimizedGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { 4747 DCHECK(!HasStackOverflow()); 4748 DCHECK(current_block() != NULL); 4749 DCHECK(current_block()->HasPredecessor()); 4750 FunctionState* state = function_state(); 4751 AstContext* context = call_context(); 4752 if (context == NULL) { 4753 // Not an inlined return, so an actual one. 4754 CHECK_ALIVE(VisitForValue(stmt->expression())); 4755 HValue* result = environment()->Pop(); 4756 Add<HReturn>(result); 4757 } else if (state->inlining_kind() == CONSTRUCT_CALL_RETURN) { 4758 // Return from an inlined construct call. In a test context the return value 4759 // will always evaluate to true, in a value context the return value needs 4760 // to be a JSObject. 4761 if (context->IsTest()) { 4762 TestContext* test = TestContext::cast(context); 4763 CHECK_ALIVE(VisitForEffect(stmt->expression())); 4764 Goto(test->if_true(), state); 4765 } else if (context->IsEffect()) { 4766 CHECK_ALIVE(VisitForEffect(stmt->expression())); 4767 Goto(function_return(), state); 4768 } else { 4769 DCHECK(context->IsValue()); 4770 CHECK_ALIVE(VisitForValue(stmt->expression())); 4771 HValue* return_value = Pop(); 4772 HValue* receiver = environment()->arguments_environment()->Lookup(0); 4773 HHasInstanceTypeAndBranch* typecheck = 4774 New<HHasInstanceTypeAndBranch>(return_value, 4775 FIRST_SPEC_OBJECT_TYPE, 4776 LAST_SPEC_OBJECT_TYPE); 4777 HBasicBlock* if_spec_object = graph()->CreateBasicBlock(); 4778 HBasicBlock* not_spec_object = graph()->CreateBasicBlock(); 4779 typecheck->SetSuccessorAt(0, if_spec_object); 4780 typecheck->SetSuccessorAt(1, not_spec_object); 4781 FinishCurrentBlock(typecheck); 4782 AddLeaveInlined(if_spec_object, return_value, state); 4783 AddLeaveInlined(not_spec_object, receiver, state); 4784 } 4785 } else if (state->inlining_kind() == SETTER_CALL_RETURN) { 4786 // Return from an inlined setter call. The returned value is never used, the 4787 // value of an assignment is always the value of the RHS of the assignment. 4788 CHECK_ALIVE(VisitForEffect(stmt->expression())); 4789 if (context->IsTest()) { 4790 HValue* rhs = environment()->arguments_environment()->Lookup(1); 4791 context->ReturnValue(rhs); 4792 } else if (context->IsEffect()) { 4793 Goto(function_return(), state); 4794 } else { 4795 DCHECK(context->IsValue()); 4796 HValue* rhs = environment()->arguments_environment()->Lookup(1); 4797 AddLeaveInlined(rhs, state); 4798 } 4799 } else { 4800 // Return from a normal inlined function. Visit the subexpression in the 4801 // expression context of the call. 4802 if (context->IsTest()) { 4803 TestContext* test = TestContext::cast(context); 4804 VisitForControl(stmt->expression(), test->if_true(), test->if_false()); 4805 } else if (context->IsEffect()) { 4806 // Visit in value context and ignore the result. This is needed to keep 4807 // environment in sync with full-codegen since some visitors (e.g. 4808 // VisitCountOperation) use the operand stack differently depending on 4809 // context. 4810 CHECK_ALIVE(VisitForValue(stmt->expression())); 4811 Pop(); 4812 Goto(function_return(), state); 4813 } else { 4814 DCHECK(context->IsValue()); 4815 CHECK_ALIVE(VisitForValue(stmt->expression())); 4816 AddLeaveInlined(Pop(), state); 4817 } 4818 } 4819 set_current_block(NULL); 4820 } 4821 4822 4823 void HOptimizedGraphBuilder::VisitWithStatement(WithStatement* stmt) { 4824 DCHECK(!HasStackOverflow()); 4825 DCHECK(current_block() != NULL); 4826 DCHECK(current_block()->HasPredecessor()); 4827 return Bailout(kWithStatement); 4828 } 4829 4830 4831 void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { 4832 DCHECK(!HasStackOverflow()); 4833 DCHECK(current_block() != NULL); 4834 DCHECK(current_block()->HasPredecessor()); 4835 4836 ZoneList<CaseClause*>* clauses = stmt->cases(); 4837 int clause_count = clauses->length(); 4838 ZoneList<HBasicBlock*> body_blocks(clause_count, zone()); 4839 4840 CHECK_ALIVE(VisitForValue(stmt->tag())); 4841 Add<HSimulate>(stmt->EntryId()); 4842 HValue* tag_value = Top(); 4843 Type* tag_type = stmt->tag()->bounds().lower; 4844 4845 // 1. Build all the tests, with dangling true branches 4846 BailoutId default_id = BailoutId::None(); 4847 for (int i = 0; i < clause_count; ++i) { 4848 CaseClause* clause = clauses->at(i); 4849 if (clause->is_default()) { 4850 body_blocks.Add(NULL, zone()); 4851 if (default_id.IsNone()) default_id = clause->EntryId(); 4852 continue; 4853 } 4854 4855 // Generate a compare and branch. 4856 CHECK_ALIVE(VisitForValue(clause->label())); 4857 HValue* label_value = Pop(); 4858 4859 Type* label_type = clause->label()->bounds().lower; 4860 Type* combined_type = clause->compare_type(); 4861 HControlInstruction* compare = BuildCompareInstruction( 4862 Token::EQ_STRICT, tag_value, label_value, tag_type, label_type, 4863 combined_type, 4864 ScriptPositionToSourcePosition(stmt->tag()->position()), 4865 ScriptPositionToSourcePosition(clause->label()->position()), 4866 PUSH_BEFORE_SIMULATE, clause->id()); 4867 4868 HBasicBlock* next_test_block = graph()->CreateBasicBlock(); 4869 HBasicBlock* body_block = graph()->CreateBasicBlock(); 4870 body_blocks.Add(body_block, zone()); 4871 compare->SetSuccessorAt(0, body_block); 4872 compare->SetSuccessorAt(1, next_test_block); 4873 FinishCurrentBlock(compare); 4874 4875 set_current_block(body_block); 4876 Drop(1); // tag_value 4877 4878 set_current_block(next_test_block); 4879 } 4880 4881 // Save the current block to use for the default or to join with the 4882 // exit. 4883 HBasicBlock* last_block = current_block(); 4884 Drop(1); // tag_value 4885 4886 // 2. Loop over the clauses and the linked list of tests in lockstep, 4887 // translating the clause bodies. 4888 HBasicBlock* fall_through_block = NULL; 4889 4890 BreakAndContinueInfo break_info(stmt, scope()); 4891 { BreakAndContinueScope push(&break_info, this); 4892 for (int i = 0; i < clause_count; ++i) { 4893 CaseClause* clause = clauses->at(i); 4894 4895 // Identify the block where normal (non-fall-through) control flow 4896 // goes to. 4897 HBasicBlock* normal_block = NULL; 4898 if (clause->is_default()) { 4899 if (last_block == NULL) continue; 4900 normal_block = last_block; 4901 last_block = NULL; // Cleared to indicate we've handled it. 4902 } else { 4903 normal_block = body_blocks[i]; 4904 } 4905 4906 if (fall_through_block == NULL) { 4907 set_current_block(normal_block); 4908 } else { 4909 HBasicBlock* join = CreateJoin(fall_through_block, 4910 normal_block, 4911 clause->EntryId()); 4912 set_current_block(join); 4913 } 4914 4915 CHECK_BAILOUT(VisitStatements(clause->statements())); 4916 fall_through_block = current_block(); 4917 } 4918 } 4919 4920 // Create an up-to-3-way join. Use the break block if it exists since 4921 // it's already a join block. 4922 HBasicBlock* break_block = break_info.break_block(); 4923 if (break_block == NULL) { 4924 set_current_block(CreateJoin(fall_through_block, 4925 last_block, 4926 stmt->ExitId())); 4927 } else { 4928 if (fall_through_block != NULL) Goto(fall_through_block, break_block); 4929 if (last_block != NULL) Goto(last_block, break_block); 4930 break_block->SetJoinId(stmt->ExitId()); 4931 set_current_block(break_block); 4932 } 4933 } 4934 4935 4936 void HOptimizedGraphBuilder::VisitLoopBody(IterationStatement* stmt, 4937 HBasicBlock* loop_entry) { 4938 Add<HSimulate>(stmt->StackCheckId()); 4939 HStackCheck* stack_check = 4940 HStackCheck::cast(Add<HStackCheck>(HStackCheck::kBackwardsBranch)); 4941 DCHECK(loop_entry->IsLoopHeader()); 4942 loop_entry->loop_information()->set_stack_check(stack_check); 4943 CHECK_BAILOUT(Visit(stmt->body())); 4944 } 4945 4946 4947 void HOptimizedGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) { 4948 DCHECK(!HasStackOverflow()); 4949 DCHECK(current_block() != NULL); 4950 DCHECK(current_block()->HasPredecessor()); 4951 DCHECK(current_block() != NULL); 4952 HBasicBlock* loop_entry = BuildLoopEntry(stmt); 4953 4954 BreakAndContinueInfo break_info(stmt, scope()); 4955 { 4956 BreakAndContinueScope push(&break_info, this); 4957 CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry)); 4958 } 4959 HBasicBlock* body_exit = 4960 JoinContinue(stmt, current_block(), break_info.continue_block()); 4961 HBasicBlock* loop_successor = NULL; 4962 if (body_exit != NULL && !stmt->cond()->ToBooleanIsTrue()) { 4963 set_current_block(body_exit); 4964 loop_successor = graph()->CreateBasicBlock(); 4965 if (stmt->cond()->ToBooleanIsFalse()) { 4966 loop_entry->loop_information()->stack_check()->Eliminate(); 4967 Goto(loop_successor); 4968 body_exit = NULL; 4969 } else { 4970 // The block for a true condition, the actual predecessor block of the 4971 // back edge. 4972 body_exit = graph()->CreateBasicBlock(); 4973 CHECK_BAILOUT(VisitForControl(stmt->cond(), body_exit, loop_successor)); 4974 } 4975 if (body_exit != NULL && body_exit->HasPredecessor()) { 4976 body_exit->SetJoinId(stmt->BackEdgeId()); 4977 } else { 4978 body_exit = NULL; 4979 } 4980 if (loop_successor->HasPredecessor()) { 4981 loop_successor->SetJoinId(stmt->ExitId()); 4982 } else { 4983 loop_successor = NULL; 4984 } 4985 } 4986 HBasicBlock* loop_exit = CreateLoop(stmt, 4987 loop_entry, 4988 body_exit, 4989 loop_successor, 4990 break_info.break_block()); 4991 set_current_block(loop_exit); 4992 } 4993 4994 4995 void HOptimizedGraphBuilder::VisitWhileStatement(WhileStatement* stmt) { 4996 DCHECK(!HasStackOverflow()); 4997 DCHECK(current_block() != NULL); 4998 DCHECK(current_block()->HasPredecessor()); 4999 DCHECK(current_block() != NULL); 5000 HBasicBlock* loop_entry = BuildLoopEntry(stmt); 5001 5002 // If the condition is constant true, do not generate a branch. 5003 HBasicBlock* loop_successor = NULL; 5004 if (!stmt->cond()->ToBooleanIsTrue()) { 5005 HBasicBlock* body_entry = graph()->CreateBasicBlock(); 5006 loop_successor = graph()->CreateBasicBlock(); 5007 CHECK_BAILOUT(VisitForControl(stmt->cond(), body_entry, loop_successor)); 5008 if (body_entry->HasPredecessor()) { 5009 body_entry->SetJoinId(stmt->BodyId()); 5010 set_current_block(body_entry); 5011 } 5012 if (loop_successor->HasPredecessor()) { 5013 loop_successor->SetJoinId(stmt->ExitId()); 5014 } else { 5015 loop_successor = NULL; 5016 } 5017 } 5018 5019 BreakAndContinueInfo break_info(stmt, scope()); 5020 if (current_block() != NULL) { 5021 BreakAndContinueScope push(&break_info, this); 5022 CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry)); 5023 } 5024 HBasicBlock* body_exit = 5025 JoinContinue(stmt, current_block(), break_info.continue_block()); 5026 HBasicBlock* loop_exit = CreateLoop(stmt, 5027 loop_entry, 5028 body_exit, 5029 loop_successor, 5030 break_info.break_block()); 5031 set_current_block(loop_exit); 5032 } 5033 5034 5035 void HOptimizedGraphBuilder::VisitForStatement(ForStatement* stmt) { 5036 DCHECK(!HasStackOverflow()); 5037 DCHECK(current_block() != NULL); 5038 DCHECK(current_block()->HasPredecessor()); 5039 if (stmt->init() != NULL) { 5040 CHECK_ALIVE(Visit(stmt->init())); 5041 } 5042 DCHECK(current_block() != NULL); 5043 HBasicBlock* loop_entry = BuildLoopEntry(stmt); 5044 5045 HBasicBlock* loop_successor = NULL; 5046 if (stmt->cond() != NULL) { 5047 HBasicBlock* body_entry = graph()->CreateBasicBlock(); 5048 loop_successor = graph()->CreateBasicBlock(); 5049 CHECK_BAILOUT(VisitForControl(stmt->cond(), body_entry, loop_successor)); 5050 if (body_entry->HasPredecessor()) { 5051 body_entry->SetJoinId(stmt->BodyId()); 5052 set_current_block(body_entry); 5053 } 5054 if (loop_successor->HasPredecessor()) { 5055 loop_successor->SetJoinId(stmt->ExitId()); 5056 } else { 5057 loop_successor = NULL; 5058 } 5059 } 5060 5061 BreakAndContinueInfo break_info(stmt, scope()); 5062 if (current_block() != NULL) { 5063 BreakAndContinueScope push(&break_info, this); 5064 CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry)); 5065 } 5066 HBasicBlock* body_exit = 5067 JoinContinue(stmt, current_block(), break_info.continue_block()); 5068 5069 if (stmt->next() != NULL && body_exit != NULL) { 5070 set_current_block(body_exit); 5071 CHECK_BAILOUT(Visit(stmt->next())); 5072 body_exit = current_block(); 5073 } 5074 5075 HBasicBlock* loop_exit = CreateLoop(stmt, 5076 loop_entry, 5077 body_exit, 5078 loop_successor, 5079 break_info.break_block()); 5080 set_current_block(loop_exit); 5081 } 5082 5083 5084 void HOptimizedGraphBuilder::VisitForInStatement(ForInStatement* stmt) { 5085 DCHECK(!HasStackOverflow()); 5086 DCHECK(current_block() != NULL); 5087 DCHECK(current_block()->HasPredecessor()); 5088 5089 if (!FLAG_optimize_for_in) { 5090 return Bailout(kForInStatementOptimizationIsDisabled); 5091 } 5092 5093 if (stmt->for_in_type() != ForInStatement::FAST_FOR_IN) { 5094 return Bailout(kForInStatementIsNotFastCase); 5095 } 5096 5097 if (!stmt->each()->IsVariableProxy() || 5098 !stmt->each()->AsVariableProxy()->var()->IsStackLocal()) { 5099 return Bailout(kForInStatementWithNonLocalEachVariable); 5100 } 5101 5102 Variable* each_var = stmt->each()->AsVariableProxy()->var(); 5103 5104 CHECK_ALIVE(VisitForValue(stmt->enumerable())); 5105 HValue* enumerable = Top(); // Leave enumerable at the top. 5106 5107 HInstruction* map = Add<HForInPrepareMap>(enumerable); 5108 Add<HSimulate>(stmt->PrepareId()); 5109 5110 HInstruction* array = Add<HForInCacheArray>( 5111 enumerable, map, DescriptorArray::kEnumCacheBridgeCacheIndex); 5112 5113 HInstruction* enum_length = Add<HMapEnumLength>(map); 5114 5115 HInstruction* start_index = Add<HConstant>(0); 5116 5117 Push(map); 5118 Push(array); 5119 Push(enum_length); 5120 Push(start_index); 5121 5122 HInstruction* index_cache = Add<HForInCacheArray>( 5123 enumerable, map, DescriptorArray::kEnumCacheBridgeIndicesCacheIndex); 5124 HForInCacheArray::cast(array)->set_index_cache( 5125 HForInCacheArray::cast(index_cache)); 5126 5127 HBasicBlock* loop_entry = BuildLoopEntry(stmt); 5128 5129 HValue* index = environment()->ExpressionStackAt(0); 5130 HValue* limit = environment()->ExpressionStackAt(1); 5131 5132 // Check that we still have more keys. 5133 HCompareNumericAndBranch* compare_index = 5134 New<HCompareNumericAndBranch>(index, limit, Token::LT); 5135 compare_index->set_observed_input_representation( 5136 Representation::Smi(), Representation::Smi()); 5137 5138 HBasicBlock* loop_body = graph()->CreateBasicBlock(); 5139 HBasicBlock* loop_successor = graph()->CreateBasicBlock(); 5140 5141 compare_index->SetSuccessorAt(0, loop_body); 5142 compare_index->SetSuccessorAt(1, loop_successor); 5143 FinishCurrentBlock(compare_index); 5144 5145 set_current_block(loop_successor); 5146 Drop(5); 5147 5148 set_current_block(loop_body); 5149 5150 HValue* key = Add<HLoadKeyed>( 5151 environment()->ExpressionStackAt(2), // Enum cache. 5152 environment()->ExpressionStackAt(0), // Iteration index. 5153 environment()->ExpressionStackAt(0), 5154 FAST_ELEMENTS); 5155 5156 // Check if the expected map still matches that of the enumerable. 5157 // If not just deoptimize. 5158 Add<HCheckMapValue>(environment()->ExpressionStackAt(4), 5159 environment()->ExpressionStackAt(3)); 5160 5161 Bind(each_var, key); 5162 5163 BreakAndContinueInfo break_info(stmt, scope(), 5); 5164 { 5165 BreakAndContinueScope push(&break_info, this); 5166 CHECK_BAILOUT(VisitLoopBody(stmt, loop_entry)); 5167 } 5168 5169 HBasicBlock* body_exit = 5170 JoinContinue(stmt, current_block(), break_info.continue_block()); 5171 5172 if (body_exit != NULL) { 5173 set_current_block(body_exit); 5174 5175 HValue* current_index = Pop(); 5176 Push(AddUncasted<HAdd>(current_index, graph()->GetConstant1())); 5177 body_exit = current_block(); 5178 } 5179 5180 HBasicBlock* loop_exit = CreateLoop(stmt, 5181 loop_entry, 5182 body_exit, 5183 loop_successor, 5184 break_info.break_block()); 5185 5186 set_current_block(loop_exit); 5187 } 5188 5189 5190 void HOptimizedGraphBuilder::VisitForOfStatement(ForOfStatement* stmt) { 5191 DCHECK(!HasStackOverflow()); 5192 DCHECK(current_block() != NULL); 5193 DCHECK(current_block()->HasPredecessor()); 5194 return Bailout(kForOfStatement); 5195 } 5196 5197 5198 void HOptimizedGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) { 5199 DCHECK(!HasStackOverflow()); 5200 DCHECK(current_block() != NULL); 5201 DCHECK(current_block()->HasPredecessor()); 5202 return Bailout(kTryCatchStatement); 5203 } 5204 5205 5206 void HOptimizedGraphBuilder::VisitTryFinallyStatement( 5207 TryFinallyStatement* stmt) { 5208 DCHECK(!HasStackOverflow()); 5209 DCHECK(current_block() != NULL); 5210 DCHECK(current_block()->HasPredecessor()); 5211 return Bailout(kTryFinallyStatement); 5212 } 5213 5214 5215 void HOptimizedGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) { 5216 DCHECK(!HasStackOverflow()); 5217 DCHECK(current_block() != NULL); 5218 DCHECK(current_block()->HasPredecessor()); 5219 return Bailout(kDebuggerStatement); 5220 } 5221 5222 5223 void HOptimizedGraphBuilder::VisitCaseClause(CaseClause* clause) { 5224 UNREACHABLE(); 5225 } 5226 5227 5228 void HOptimizedGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { 5229 DCHECK(!HasStackOverflow()); 5230 DCHECK(current_block() != NULL); 5231 DCHECK(current_block()->HasPredecessor()); 5232 Handle<SharedFunctionInfo> shared_info = expr->shared_info(); 5233 if (shared_info.is_null()) { 5234 shared_info = 5235 Compiler::BuildFunctionInfo(expr, current_info()->script(), top_info()); 5236 } 5237 // We also have a stack overflow if the recursive compilation did. 5238 if (HasStackOverflow()) return; 5239 HFunctionLiteral* instr = 5240 New<HFunctionLiteral>(shared_info, expr->pretenure()); 5241 return ast_context()->ReturnInstruction(instr, expr->id()); 5242 } 5243 5244 5245 void HOptimizedGraphBuilder::VisitClassLiteral(ClassLiteral* lit) { 5246 DCHECK(!HasStackOverflow()); 5247 DCHECK(current_block() != NULL); 5248 DCHECK(current_block()->HasPredecessor()); 5249 return Bailout(kClassLiteral); 5250 } 5251 5252 5253 void HOptimizedGraphBuilder::VisitNativeFunctionLiteral( 5254 NativeFunctionLiteral* expr) { 5255 DCHECK(!HasStackOverflow()); 5256 DCHECK(current_block() != NULL); 5257 DCHECK(current_block()->HasPredecessor()); 5258 return Bailout(kNativeFunctionLiteral); 5259 } 5260 5261 5262 void HOptimizedGraphBuilder::VisitConditional(Conditional* expr) { 5263 DCHECK(!HasStackOverflow()); 5264 DCHECK(current_block() != NULL); 5265 DCHECK(current_block()->HasPredecessor()); 5266 HBasicBlock* cond_true = graph()->CreateBasicBlock(); 5267 HBasicBlock* cond_false = graph()->CreateBasicBlock(); 5268 CHECK_BAILOUT(VisitForControl(expr->condition(), cond_true, cond_false)); 5269 5270 // Visit the true and false subexpressions in the same AST context as the 5271 // whole expression. 5272 if (cond_true->HasPredecessor()) { 5273 cond_true->SetJoinId(expr->ThenId()); 5274 set_current_block(cond_true); 5275 CHECK_BAILOUT(Visit(expr->then_expression())); 5276 cond_true = current_block(); 5277 } else { 5278 cond_true = NULL; 5279 } 5280 5281 if (cond_false->HasPredecessor()) { 5282 cond_false->SetJoinId(expr->ElseId()); 5283 set_current_block(cond_false); 5284 CHECK_BAILOUT(Visit(expr->else_expression())); 5285 cond_false = current_block(); 5286 } else { 5287 cond_false = NULL; 5288 } 5289 5290 if (!ast_context()->IsTest()) { 5291 HBasicBlock* join = CreateJoin(cond_true, cond_false, expr->id()); 5292 set_current_block(join); 5293 if (join != NULL && !ast_context()->IsEffect()) { 5294 return ast_context()->ReturnValue(Pop()); 5295 } 5296 } 5297 } 5298 5299 5300 HOptimizedGraphBuilder::GlobalPropertyAccess 5301 HOptimizedGraphBuilder::LookupGlobalProperty(Variable* var, LookupIterator* it, 5302 PropertyAccessType access_type) { 5303 if (var->is_this() || !current_info()->has_global_object()) { 5304 return kUseGeneric; 5305 } 5306 5307 switch (it->state()) { 5308 case LookupIterator::ACCESSOR: 5309 case LookupIterator::ACCESS_CHECK: 5310 case LookupIterator::INTERCEPTOR: 5311 case LookupIterator::NOT_FOUND: 5312 return kUseGeneric; 5313 case LookupIterator::DATA: 5314 if (access_type == STORE && it->IsReadOnly()) return kUseGeneric; 5315 return kUseCell; 5316 case LookupIterator::JSPROXY: 5317 case LookupIterator::TRANSITION: 5318 UNREACHABLE(); 5319 } 5320 UNREACHABLE(); 5321 return kUseGeneric; 5322 } 5323 5324 5325 HValue* HOptimizedGraphBuilder::BuildContextChainWalk(Variable* var) { 5326 DCHECK(var->IsContextSlot()); 5327 HValue* context = environment()->context(); 5328 int length = scope()->ContextChainLength(var->scope()); 5329 while (length-- > 0) { 5330 context = Add<HLoadNamedField>( 5331 context, static_cast<HValue*>(NULL), 5332 HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX)); 5333 } 5334 return context; 5335 } 5336 5337 5338 void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) { 5339 if (expr->is_this()) { 5340 current_info()->set_this_has_uses(true); 5341 } 5342 5343 DCHECK(!HasStackOverflow()); 5344 DCHECK(current_block() != NULL); 5345 DCHECK(current_block()->HasPredecessor()); 5346 Variable* variable = expr->var(); 5347 switch (variable->location()) { 5348 case Variable::UNALLOCATED: { 5349 if (IsLexicalVariableMode(variable->mode())) { 5350 // TODO(rossberg): should this be an DCHECK? 5351 return Bailout(kReferenceToGlobalLexicalVariable); 5352 } 5353 // Handle known global constants like 'undefined' specially to avoid a 5354 // load from a global cell for them. 5355 Handle<Object> constant_value = 5356 isolate()->factory()->GlobalConstantFor(variable->name()); 5357 if (!constant_value.is_null()) { 5358 HConstant* instr = New<HConstant>(constant_value); 5359 return ast_context()->ReturnInstruction(instr, expr->id()); 5360 } 5361 5362 Handle<GlobalObject> global(current_info()->global_object()); 5363 LookupIterator it(global, variable->name(), 5364 LookupIterator::OWN_SKIP_INTERCEPTOR); 5365 GlobalPropertyAccess type = LookupGlobalProperty(variable, &it, LOAD); 5366 5367 if (type == kUseCell) { 5368 Handle<PropertyCell> cell = it.GetPropertyCell(); 5369 if (cell->type()->IsConstant()) { 5370 PropertyCell::AddDependentCompilationInfo(cell, top_info()); 5371 Handle<Object> constant_object = cell->type()->AsConstant()->Value(); 5372 if (constant_object->IsConsString()) { 5373 constant_object = 5374 String::Flatten(Handle<String>::cast(constant_object)); 5375 } 5376 HConstant* constant = New<HConstant>(constant_object); 5377 return ast_context()->ReturnInstruction(constant, expr->id()); 5378 } else { 5379 HLoadGlobalCell* instr = 5380 New<HLoadGlobalCell>(cell, it.property_details()); 5381 return ast_context()->ReturnInstruction(instr, expr->id()); 5382 } 5383 } else { 5384 HValue* global_object = Add<HLoadNamedField>( 5385 context(), static_cast<HValue*>(NULL), 5386 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); 5387 HLoadGlobalGeneric* instr = 5388 New<HLoadGlobalGeneric>(global_object, 5389 variable->name(), 5390 ast_context()->is_for_typeof()); 5391 if (FLAG_vector_ics) { 5392 Handle<SharedFunctionInfo> current_shared = 5393 function_state()->compilation_info()->shared_info(); 5394 instr->SetVectorAndSlot( 5395 handle(current_shared->feedback_vector(), isolate()), 5396 expr->VariableFeedbackSlot()); 5397 } 5398 return ast_context()->ReturnInstruction(instr, expr->id()); 5399 } 5400 } 5401 5402 case Variable::PARAMETER: 5403 case Variable::LOCAL: { 5404 HValue* value = LookupAndMakeLive(variable); 5405 if (value == graph()->GetConstantHole()) { 5406 DCHECK(IsDeclaredVariableMode(variable->mode()) && 5407 variable->mode() != VAR); 5408 return Bailout(kReferenceToUninitializedVariable); 5409 } 5410 return ast_context()->ReturnValue(value); 5411 } 5412 5413 case Variable::CONTEXT: { 5414 HValue* context = BuildContextChainWalk(variable); 5415 HLoadContextSlot::Mode mode; 5416 switch (variable->mode()) { 5417 case LET: 5418 case CONST: 5419 mode = HLoadContextSlot::kCheckDeoptimize; 5420 break; 5421 case CONST_LEGACY: 5422 mode = HLoadContextSlot::kCheckReturnUndefined; 5423 break; 5424 default: 5425 mode = HLoadContextSlot::kNoCheck; 5426 break; 5427 } 5428 HLoadContextSlot* instr = 5429 new(zone()) HLoadContextSlot(context, variable->index(), mode); 5430 return ast_context()->ReturnInstruction(instr, expr->id()); 5431 } 5432 5433 case Variable::LOOKUP: 5434 return Bailout(kReferenceToAVariableWhichRequiresDynamicLookup); 5435 } 5436 } 5437 5438 5439 void HOptimizedGraphBuilder::VisitLiteral(Literal* expr) { 5440 DCHECK(!HasStackOverflow()); 5441 DCHECK(current_block() != NULL); 5442 DCHECK(current_block()->HasPredecessor()); 5443 HConstant* instr = New<HConstant>(expr->value()); 5444 return ast_context()->ReturnInstruction(instr, expr->id()); 5445 } 5446 5447 5448 void HOptimizedGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { 5449 DCHECK(!HasStackOverflow()); 5450 DCHECK(current_block() != NULL); 5451 DCHECK(current_block()->HasPredecessor()); 5452 Handle<JSFunction> closure = function_state()->compilation_info()->closure(); 5453 Handle<FixedArray> literals(closure->literals()); 5454 HRegExpLiteral* instr = New<HRegExpLiteral>(literals, 5455 expr->pattern(), 5456 expr->flags(), 5457 expr->literal_index()); 5458 return ast_context()->ReturnInstruction(instr, expr->id()); 5459 } 5460 5461 5462 static bool CanInlinePropertyAccess(Type* type) { 5463 if (type->Is(Type::NumberOrString())) return true; 5464 if (!type->IsClass()) return false; 5465 Handle<Map> map = type->AsClass()->Map(); 5466 return map->IsJSObjectMap() && 5467 !map->is_dictionary_map() && 5468 !map->has_named_interceptor(); 5469 } 5470 5471 5472 // Determines whether the given array or object literal boilerplate satisfies 5473 // all limits to be considered for fast deep-copying and computes the total 5474 // size of all objects that are part of the graph. 5475 static bool IsFastLiteral(Handle<JSObject> boilerplate, 5476 int max_depth, 5477 int* max_properties) { 5478 if (boilerplate->map()->is_deprecated() && 5479 !JSObject::TryMigrateInstance(boilerplate)) { 5480 return false; 5481 } 5482 5483 DCHECK(max_depth >= 0 && *max_properties >= 0); 5484 if (max_depth == 0) return false; 5485 5486 Isolate* isolate = boilerplate->GetIsolate(); 5487 Handle<FixedArrayBase> elements(boilerplate->elements()); 5488 if (elements->length() > 0 && 5489 elements->map() != isolate->heap()->fixed_cow_array_map()) { 5490 if (boilerplate->HasFastObjectElements()) { 5491 Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements); 5492 int length = elements->length(); 5493 for (int i = 0; i < length; i++) { 5494 if ((*max_properties)-- == 0) return false; 5495 Handle<Object> value(fast_elements->get(i), isolate); 5496 if (value->IsJSObject()) { 5497 Handle<JSObject> value_object = Handle<JSObject>::cast(value); 5498 if (!IsFastLiteral(value_object, 5499 max_depth - 1, 5500 max_properties)) { 5501 return false; 5502 } 5503 } 5504 } 5505 } else if (!boilerplate->HasFastDoubleElements()) { 5506 return false; 5507 } 5508 } 5509 5510 Handle<FixedArray> properties(boilerplate->properties()); 5511 if (properties->length() > 0) { 5512 return false; 5513 } else { 5514 Handle<DescriptorArray> descriptors( 5515 boilerplate->map()->instance_descriptors()); 5516 int limit = boilerplate->map()->NumberOfOwnDescriptors(); 5517 for (int i = 0; i < limit; i++) { 5518 PropertyDetails details = descriptors->GetDetails(i); 5519 if (details.type() != FIELD) continue; 5520 int index = descriptors->GetFieldIndex(i); 5521 if ((*max_properties)-- == 0) return false; 5522 Handle<Object> value(boilerplate->InObjectPropertyAt(index), isolate); 5523 if (value->IsJSObject()) { 5524 Handle<JSObject> value_object = Handle<JSObject>::cast(value); 5525 if (!IsFastLiteral(value_object, 5526 max_depth - 1, 5527 max_properties)) { 5528 return false; 5529 } 5530 } 5531 } 5532 } 5533 return true; 5534 } 5535 5536 5537 void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { 5538 DCHECK(!HasStackOverflow()); 5539 DCHECK(current_block() != NULL); 5540 DCHECK(current_block()->HasPredecessor()); 5541 expr->BuildConstantProperties(isolate()); 5542 Handle<JSFunction> closure = function_state()->compilation_info()->closure(); 5543 HInstruction* literal; 5544 5545 // Check whether to use fast or slow deep-copying for boilerplate. 5546 int max_properties = kMaxFastLiteralProperties; 5547 Handle<Object> literals_cell(closure->literals()->get(expr->literal_index()), 5548 isolate()); 5549 Handle<AllocationSite> site; 5550 Handle<JSObject> boilerplate; 5551 if (!literals_cell->IsUndefined()) { 5552 // Retrieve the boilerplate 5553 site = Handle<AllocationSite>::cast(literals_cell); 5554 boilerplate = Handle<JSObject>(JSObject::cast(site->transition_info()), 5555 isolate()); 5556 } 5557 5558 if (!boilerplate.is_null() && 5559 IsFastLiteral(boilerplate, kMaxFastLiteralDepth, &max_properties)) { 5560 AllocationSiteUsageContext usage_context(isolate(), site, false); 5561 usage_context.EnterNewScope(); 5562 literal = BuildFastLiteral(boilerplate, &usage_context); 5563 usage_context.ExitScope(site, boilerplate); 5564 } else { 5565 NoObservableSideEffectsScope no_effects(this); 5566 Handle<FixedArray> closure_literals(closure->literals(), isolate()); 5567 Handle<FixedArray> constant_properties = expr->constant_properties(); 5568 int literal_index = expr->literal_index(); 5569 int flags = expr->fast_elements() 5570 ? ObjectLiteral::kFastElements : ObjectLiteral::kNoFlags; 5571 flags |= expr->has_function() 5572 ? ObjectLiteral::kHasFunction : ObjectLiteral::kNoFlags; 5573 5574 Add<HPushArguments>(Add<HConstant>(closure_literals), 5575 Add<HConstant>(literal_index), 5576 Add<HConstant>(constant_properties), 5577 Add<HConstant>(flags)); 5578 5579 // TODO(mvstanton): Add a flag to turn off creation of any 5580 // AllocationMementos for this call: we are in crankshaft and should have 5581 // learned enough about transition behavior to stop emitting mementos. 5582 Runtime::FunctionId function_id = Runtime::kCreateObjectLiteral; 5583 literal = Add<HCallRuntime>(isolate()->factory()->empty_string(), 5584 Runtime::FunctionForId(function_id), 5585 4); 5586 } 5587 5588 // The object is expected in the bailout environment during computation 5589 // of the property values and is the value of the entire expression. 5590 Push(literal); 5591 5592 expr->CalculateEmitStore(zone()); 5593 5594 for (int i = 0; i < expr->properties()->length(); i++) { 5595 ObjectLiteral::Property* property = expr->properties()->at(i); 5596 if (property->IsCompileTimeValue()) continue; 5597 5598 Literal* key = property->key(); 5599 Expression* value = property->value(); 5600 5601 switch (property->kind()) { 5602 case ObjectLiteral::Property::MATERIALIZED_LITERAL: 5603 DCHECK(!CompileTimeValue::IsCompileTimeValue(value)); 5604 // Fall through. 5605 case ObjectLiteral::Property::COMPUTED: 5606 if (key->value()->IsInternalizedString()) { 5607 if (property->emit_store()) { 5608 CHECK_ALIVE(VisitForValue(value)); 5609 HValue* value = Pop(); 5610 Handle<Map> map = property->GetReceiverType(); 5611 Handle<String> name = property->key()->AsPropertyName(); 5612 HInstruction* store; 5613 if (map.is_null()) { 5614 // If we don't know the monomorphic type, do a generic store. 5615 CHECK_ALIVE(store = BuildNamedGeneric( 5616 STORE, NULL, literal, name, value)); 5617 } else { 5618 PropertyAccessInfo info(this, STORE, ToType(map), name); 5619 if (info.CanAccessMonomorphic()) { 5620 HValue* checked_literal = Add<HCheckMaps>(literal, map); 5621 DCHECK(!info.IsAccessor()); 5622 store = BuildMonomorphicAccess( 5623 &info, literal, checked_literal, value, 5624 BailoutId::None(), BailoutId::None()); 5625 } else { 5626 CHECK_ALIVE(store = BuildNamedGeneric( 5627 STORE, NULL, literal, name, value)); 5628 } 5629 } 5630 AddInstruction(store); 5631 if (store->HasObservableSideEffects()) { 5632 Add<HSimulate>(key->id(), REMOVABLE_SIMULATE); 5633 } 5634 } else { 5635 CHECK_ALIVE(VisitForEffect(value)); 5636 } 5637 break; 5638 } 5639 // Fall through. 5640 case ObjectLiteral::Property::PROTOTYPE: 5641 case ObjectLiteral::Property::SETTER: 5642 case ObjectLiteral::Property::GETTER: 5643 return Bailout(kObjectLiteralWithComplexProperty); 5644 default: UNREACHABLE(); 5645 } 5646 } 5647 5648 if (expr->has_function()) { 5649 // Return the result of the transformation to fast properties 5650 // instead of the original since this operation changes the map 5651 // of the object. This makes sure that the original object won't 5652 // be used by other optimized code before it is transformed 5653 // (e.g. because of code motion). 5654 HToFastProperties* result = Add<HToFastProperties>(Pop()); 5655 return ast_context()->ReturnValue(result); 5656 } else { 5657 return ast_context()->ReturnValue(Pop()); 5658 } 5659 } 5660 5661 5662 void HOptimizedGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { 5663 DCHECK(!HasStackOverflow()); 5664 DCHECK(current_block() != NULL); 5665 DCHECK(current_block()->HasPredecessor()); 5666 expr->BuildConstantElements(isolate()); 5667 ZoneList<Expression*>* subexprs = expr->values(); 5668 int length = subexprs->length(); 5669 HInstruction* literal; 5670 5671 Handle<AllocationSite> site; 5672 Handle<FixedArray> literals(environment()->closure()->literals(), isolate()); 5673 bool uninitialized = false; 5674 Handle<Object> literals_cell(literals->get(expr->literal_index()), 5675 isolate()); 5676 Handle<JSObject> boilerplate_object; 5677 if (literals_cell->IsUndefined()) { 5678 uninitialized = true; 5679 Handle<Object> raw_boilerplate; 5680 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 5681 isolate(), raw_boilerplate, 5682 Runtime::CreateArrayLiteralBoilerplate( 5683 isolate(), literals, expr->constant_elements()), 5684 Bailout(kArrayBoilerplateCreationFailed)); 5685 5686 boilerplate_object = Handle<JSObject>::cast(raw_boilerplate); 5687 AllocationSiteCreationContext creation_context(isolate()); 5688 site = creation_context.EnterNewScope(); 5689 if (JSObject::DeepWalk(boilerplate_object, &creation_context).is_null()) { 5690 return Bailout(kArrayBoilerplateCreationFailed); 5691 } 5692 creation_context.ExitScope(site, boilerplate_object); 5693 literals->set(expr->literal_index(), *site); 5694 5695 if (boilerplate_object->elements()->map() == 5696 isolate()->heap()->fixed_cow_array_map()) { 5697 isolate()->counters()->cow_arrays_created_runtime()->Increment(); 5698 } 5699 } else { 5700 DCHECK(literals_cell->IsAllocationSite()); 5701 site = Handle<AllocationSite>::cast(literals_cell); 5702 boilerplate_object = Handle<JSObject>( 5703 JSObject::cast(site->transition_info()), isolate()); 5704 } 5705 5706 DCHECK(!boilerplate_object.is_null()); 5707 DCHECK(site->SitePointsToLiteral()); 5708 5709 ElementsKind boilerplate_elements_kind = 5710 boilerplate_object->GetElementsKind(); 5711 5712 // Check whether to use fast or slow deep-copying for boilerplate. 5713 int max_properties = kMaxFastLiteralProperties; 5714 if (IsFastLiteral(boilerplate_object, 5715 kMaxFastLiteralDepth, 5716 &max_properties)) { 5717 AllocationSiteUsageContext usage_context(isolate(), site, false); 5718 usage_context.EnterNewScope(); 5719 literal = BuildFastLiteral(boilerplate_object, &usage_context); 5720 usage_context.ExitScope(site, boilerplate_object); 5721 } else { 5722 NoObservableSideEffectsScope no_effects(this); 5723 // Boilerplate already exists and constant elements are never accessed, 5724 // pass an empty fixed array to the runtime function instead. 5725 Handle<FixedArray> constants = isolate()->factory()->empty_fixed_array(); 5726 int literal_index = expr->literal_index(); 5727 int flags = expr->depth() == 1 5728 ? ArrayLiteral::kShallowElements 5729 : ArrayLiteral::kNoFlags; 5730 flags |= ArrayLiteral::kDisableMementos; 5731 5732 Add<HPushArguments>(Add<HConstant>(literals), 5733 Add<HConstant>(literal_index), 5734 Add<HConstant>(constants), 5735 Add<HConstant>(flags)); 5736 5737 // TODO(mvstanton): Consider a flag to turn off creation of any 5738 // AllocationMementos for this call: we are in crankshaft and should have 5739 // learned enough about transition behavior to stop emitting mementos. 5740 Runtime::FunctionId function_id = Runtime::kCreateArrayLiteral; 5741 literal = Add<HCallRuntime>(isolate()->factory()->empty_string(), 5742 Runtime::FunctionForId(function_id), 5743 4); 5744 5745 // De-opt if elements kind changed from boilerplate_elements_kind. 5746 Handle<Map> map = Handle<Map>(boilerplate_object->map(), isolate()); 5747 literal = Add<HCheckMaps>(literal, map); 5748 } 5749 5750 // The array is expected in the bailout environment during computation 5751 // of the property values and is the value of the entire expression. 5752 Push(literal); 5753 // The literal index is on the stack, too. 5754 Push(Add<HConstant>(expr->literal_index())); 5755 5756 HInstruction* elements = NULL; 5757 5758 for (int i = 0; i < length; i++) { 5759 Expression* subexpr = subexprs->at(i); 5760 // If the subexpression is a literal or a simple materialized literal it 5761 // is already set in the cloned array. 5762 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; 5763 5764 CHECK_ALIVE(VisitForValue(subexpr)); 5765 HValue* value = Pop(); 5766 if (!Smi::IsValid(i)) return Bailout(kNonSmiKeyInArrayLiteral); 5767 5768 elements = AddLoadElements(literal); 5769 5770 HValue* key = Add<HConstant>(i); 5771 5772 switch (boilerplate_elements_kind) { 5773 case FAST_SMI_ELEMENTS: 5774 case FAST_HOLEY_SMI_ELEMENTS: 5775 case FAST_ELEMENTS: 5776 case FAST_HOLEY_ELEMENTS: 5777 case FAST_DOUBLE_ELEMENTS: 5778 case FAST_HOLEY_DOUBLE_ELEMENTS: { 5779 HStoreKeyed* instr = Add<HStoreKeyed>(elements, key, value, 5780 boilerplate_elements_kind); 5781 instr->SetUninitialized(uninitialized); 5782 break; 5783 } 5784 default: 5785 UNREACHABLE(); 5786 break; 5787 } 5788 5789 Add<HSimulate>(expr->GetIdForElement(i)); 5790 } 5791 5792 Drop(1); // array literal index 5793 return ast_context()->ReturnValue(Pop()); 5794 } 5795 5796 5797 HCheckMaps* HOptimizedGraphBuilder::AddCheckMap(HValue* object, 5798 Handle<Map> map) { 5799 BuildCheckHeapObject(object); 5800 return Add<HCheckMaps>(object, map); 5801 } 5802 5803 5804 HInstruction* HOptimizedGraphBuilder::BuildLoadNamedField( 5805 PropertyAccessInfo* info, 5806 HValue* checked_object) { 5807 // See if this is a load for an immutable property 5808 if (checked_object->ActualValue()->IsConstant()) { 5809 Handle<Object> object( 5810 HConstant::cast(checked_object->ActualValue())->handle(isolate())); 5811 5812 if (object->IsJSObject()) { 5813 LookupIterator it(object, info->name(), 5814 LookupIterator::OWN_SKIP_INTERCEPTOR); 5815 Handle<Object> value = JSObject::GetDataProperty(&it); 5816 if (it.IsFound() && it.IsReadOnly() && !it.IsConfigurable()) { 5817 return New<HConstant>(value); 5818 } 5819 } 5820 } 5821 5822 HObjectAccess access = info->access(); 5823 if (access.representation().IsDouble()) { 5824 // Load the heap number. 5825 checked_object = Add<HLoadNamedField>( 5826 checked_object, static_cast<HValue*>(NULL), 5827 access.WithRepresentation(Representation::Tagged())); 5828 // Load the double value from it. 5829 access = HObjectAccess::ForHeapNumberValue(); 5830 } 5831 5832 SmallMapList* map_list = info->field_maps(); 5833 if (map_list->length() == 0) { 5834 return New<HLoadNamedField>(checked_object, checked_object, access); 5835 } 5836 5837 UniqueSet<Map>* maps = new(zone()) UniqueSet<Map>(map_list->length(), zone()); 5838 for (int i = 0; i < map_list->length(); ++i) { 5839 maps->Add(Unique<Map>::CreateImmovable(map_list->at(i)), zone()); 5840 } 5841 return New<HLoadNamedField>( 5842 checked_object, checked_object, access, maps, info->field_type()); 5843 } 5844 5845 5846 HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField( 5847 PropertyAccessInfo* info, 5848 HValue* checked_object, 5849 HValue* value) { 5850 bool transition_to_field = info->IsTransition(); 5851 // TODO(verwaest): Move this logic into PropertyAccessInfo. 5852 HObjectAccess field_access = info->access(); 5853 5854 HStoreNamedField *instr; 5855 if (field_access.representation().IsDouble()) { 5856 HObjectAccess heap_number_access = 5857 field_access.WithRepresentation(Representation::Tagged()); 5858 if (transition_to_field) { 5859 // The store requires a mutable HeapNumber to be allocated. 5860 NoObservableSideEffectsScope no_side_effects(this); 5861 HInstruction* heap_number_size = Add<HConstant>(HeapNumber::kSize); 5862 5863 // TODO(hpayer): Allocation site pretenuring support. 5864 HInstruction* heap_number = Add<HAllocate>(heap_number_size, 5865 HType::HeapObject(), 5866 NOT_TENURED, 5867 MUTABLE_HEAP_NUMBER_TYPE); 5868 AddStoreMapConstant( 5869 heap_number, isolate()->factory()->mutable_heap_number_map()); 5870 Add<HStoreNamedField>(heap_number, HObjectAccess::ForHeapNumberValue(), 5871 value); 5872 instr = New<HStoreNamedField>(checked_object->ActualValue(), 5873 heap_number_access, 5874 heap_number); 5875 } else { 5876 // Already holds a HeapNumber; load the box and write its value field. 5877 HInstruction* heap_number = Add<HLoadNamedField>( 5878 checked_object, static_cast<HValue*>(NULL), heap_number_access); 5879 instr = New<HStoreNamedField>(heap_number, 5880 HObjectAccess::ForHeapNumberValue(), 5881 value, STORE_TO_INITIALIZED_ENTRY); 5882 } 5883 } else { 5884 if (field_access.representation().IsHeapObject()) { 5885 BuildCheckHeapObject(value); 5886 } 5887 5888 if (!info->field_maps()->is_empty()) { 5889 DCHECK(field_access.representation().IsHeapObject()); 5890 value = Add<HCheckMaps>(value, info->field_maps()); 5891 } 5892 5893 // This is a normal store. 5894 instr = New<HStoreNamedField>( 5895 checked_object->ActualValue(), field_access, value, 5896 transition_to_field ? INITIALIZING_STORE : STORE_TO_INITIALIZED_ENTRY); 5897 } 5898 5899 if (transition_to_field) { 5900 Handle<Map> transition(info->transition()); 5901 DCHECK(!transition->is_deprecated()); 5902 instr->SetTransition(Add<HConstant>(transition)); 5903 } 5904 return instr; 5905 } 5906 5907 5908 bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatible( 5909 PropertyAccessInfo* info) { 5910 if (!CanInlinePropertyAccess(type_)) return false; 5911 5912 // Currently only handle Type::Number as a polymorphic case. 5913 // TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber 5914 // instruction. 5915 if (type_->Is(Type::Number())) return false; 5916 5917 // Values are only compatible for monomorphic load if they all behave the same 5918 // regarding value wrappers. 5919 if (type_->Is(Type::NumberOrString())) { 5920 if (!info->type_->Is(Type::NumberOrString())) return false; 5921 } else { 5922 if (info->type_->Is(Type::NumberOrString())) return false; 5923 } 5924 5925 if (!LookupDescriptor()) return false; 5926 5927 if (!IsFound()) { 5928 return (!info->IsFound() || info->has_holder()) && 5929 map()->prototype() == info->map()->prototype(); 5930 } 5931 5932 // Mismatch if the other access info found the property in the prototype 5933 // chain. 5934 if (info->has_holder()) return false; 5935 5936 if (IsAccessor()) { 5937 return accessor_.is_identical_to(info->accessor_) && 5938 api_holder_.is_identical_to(info->api_holder_); 5939 } 5940 5941 if (IsConstant()) { 5942 return constant_.is_identical_to(info->constant_); 5943 } 5944 5945 DCHECK(IsField()); 5946 if (!info->IsField()) return false; 5947 5948 Representation r = access_.representation(); 5949 if (IsLoad()) { 5950 if (!info->access_.representation().IsCompatibleForLoad(r)) return false; 5951 } else { 5952 if (!info->access_.representation().IsCompatibleForStore(r)) return false; 5953 } 5954 if (info->access_.offset() != access_.offset()) return false; 5955 if (info->access_.IsInobject() != access_.IsInobject()) return false; 5956 if (IsLoad()) { 5957 if (field_maps_.is_empty()) { 5958 info->field_maps_.Clear(); 5959 } else if (!info->field_maps_.is_empty()) { 5960 for (int i = 0; i < field_maps_.length(); ++i) { 5961 info->field_maps_.AddMapIfMissing(field_maps_.at(i), info->zone()); 5962 } 5963 info->field_maps_.Sort(); 5964 } 5965 } else { 5966 // We can only merge stores that agree on their field maps. The comparison 5967 // below is safe, since we keep the field maps sorted. 5968 if (field_maps_.length() != info->field_maps_.length()) return false; 5969 for (int i = 0; i < field_maps_.length(); ++i) { 5970 if (!field_maps_.at(i).is_identical_to(info->field_maps_.at(i))) { 5971 return false; 5972 } 5973 } 5974 } 5975 info->GeneralizeRepresentation(r); 5976 info->field_type_ = info->field_type_.Combine(field_type_); 5977 return true; 5978 } 5979 5980 5981 bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupDescriptor() { 5982 if (!type_->IsClass()) return true; 5983 map()->LookupDescriptor(NULL, *name_, &lookup_); 5984 return LoadResult(map()); 5985 } 5986 5987 5988 bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadResult(Handle<Map> map) { 5989 if (!IsLoad() && IsProperty() && IsReadOnly()) { 5990 return false; 5991 } 5992 5993 if (IsField()) { 5994 // Construct the object field access. 5995 int index = GetLocalFieldIndexFromMap(map); 5996 access_ = HObjectAccess::ForField(map, index, representation(), name_); 5997 5998 // Load field map for heap objects. 5999 LoadFieldMaps(map); 6000 } else if (IsAccessor()) { 6001 Handle<Object> accessors = GetAccessorsFromMap(map); 6002 if (!accessors->IsAccessorPair()) return false; 6003 Object* raw_accessor = 6004 IsLoad() ? Handle<AccessorPair>::cast(accessors)->getter() 6005 : Handle<AccessorPair>::cast(accessors)->setter(); 6006 if (!raw_accessor->IsJSFunction()) return false; 6007 Handle<JSFunction> accessor = handle(JSFunction::cast(raw_accessor)); 6008 if (accessor->shared()->IsApiFunction()) { 6009 CallOptimization call_optimization(accessor); 6010 if (call_optimization.is_simple_api_call()) { 6011 CallOptimization::HolderLookup holder_lookup; 6012 Handle<Map> receiver_map = this->map(); 6013 api_holder_ = call_optimization.LookupHolderOfExpectedType( 6014 receiver_map, &holder_lookup); 6015 } 6016 } 6017 accessor_ = accessor; 6018 } else if (IsConstant()) { 6019 constant_ = GetConstantFromMap(map); 6020 } 6021 6022 return true; 6023 } 6024 6025 6026 void HOptimizedGraphBuilder::PropertyAccessInfo::LoadFieldMaps( 6027 Handle<Map> map) { 6028 // Clear any previously collected field maps/type. 6029 field_maps_.Clear(); 6030 field_type_ = HType::Tagged(); 6031 6032 // Figure out the field type from the accessor map. 6033 Handle<HeapType> field_type = GetFieldTypeFromMap(map); 6034 6035 // Collect the (stable) maps from the field type. 6036 int num_field_maps = field_type->NumClasses(); 6037 if (num_field_maps == 0) return; 6038 DCHECK(access_.representation().IsHeapObject()); 6039 field_maps_.Reserve(num_field_maps, zone()); 6040 HeapType::Iterator<Map> it = field_type->Classes(); 6041 while (!it.Done()) { 6042 Handle<Map> field_map = it.Current(); 6043 if (!field_map->is_stable()) { 6044 field_maps_.Clear(); 6045 return; 6046 } 6047 field_maps_.Add(field_map, zone()); 6048 it.Advance(); 6049 } 6050 field_maps_.Sort(); 6051 DCHECK_EQ(num_field_maps, field_maps_.length()); 6052 6053 // Determine field HType from field HeapType. 6054 field_type_ = HType::FromType<HeapType>(field_type); 6055 DCHECK(field_type_.IsHeapObject()); 6056 6057 // Add dependency on the map that introduced the field. 6058 Map::AddDependentCompilationInfo(GetFieldOwnerFromMap(map), 6059 DependentCode::kFieldTypeGroup, top_info()); 6060 } 6061 6062 6063 bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() { 6064 Handle<Map> map = this->map(); 6065 6066 while (map->prototype()->IsJSObject()) { 6067 holder_ = handle(JSObject::cast(map->prototype())); 6068 if (holder_->map()->is_deprecated()) { 6069 JSObject::TryMigrateInstance(holder_); 6070 } 6071 map = Handle<Map>(holder_->map()); 6072 if (!CanInlinePropertyAccess(ToType(map))) { 6073 lookup_.NotFound(); 6074 return false; 6075 } 6076 map->LookupDescriptor(*holder_, *name_, &lookup_); 6077 if (IsFound()) return LoadResult(map); 6078 } 6079 lookup_.NotFound(); 6080 return true; 6081 } 6082 6083 6084 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() { 6085 if (!CanInlinePropertyAccess(type_)) return false; 6086 if (IsJSObjectFieldAccessor()) return IsLoad(); 6087 if (this->map()->function_with_prototype() && 6088 !this->map()->has_non_instance_prototype() && 6089 name_.is_identical_to(isolate()->factory()->prototype_string())) { 6090 return IsLoad(); 6091 } 6092 if (!LookupDescriptor()) return false; 6093 if (IsFound()) return IsLoad() || !IsReadOnly(); 6094 if (!LookupInPrototypes()) return false; 6095 if (IsLoad()) return true; 6096 6097 if (IsAccessor()) return true; 6098 Handle<Map> map = this->map(); 6099 map->LookupTransition(NULL, *name_, &lookup_); 6100 if (lookup_.IsTransitionToField() && map->unused_property_fields() > 0) { 6101 // Construct the object field access. 6102 int descriptor = transition()->LastAdded(); 6103 int index = 6104 transition()->instance_descriptors()->GetFieldIndex(descriptor) - 6105 map->inobject_properties(); 6106 PropertyDetails details = 6107 transition()->instance_descriptors()->GetDetails(descriptor); 6108 Representation representation = details.representation(); 6109 access_ = HObjectAccess::ForField(map, index, representation, name_); 6110 6111 // Load field map for heap objects. 6112 LoadFieldMaps(transition()); 6113 return true; 6114 } 6115 return false; 6116 } 6117 6118 6119 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessAsMonomorphic( 6120 SmallMapList* types) { 6121 DCHECK(type_->Is(ToType(types->first()))); 6122 if (!CanAccessMonomorphic()) return false; 6123 STATIC_ASSERT(kMaxLoadPolymorphism == kMaxStorePolymorphism); 6124 if (types->length() > kMaxLoadPolymorphism) return false; 6125 6126 HObjectAccess access = HObjectAccess::ForMap(); // bogus default 6127 if (GetJSObjectFieldAccess(&access)) { 6128 for (int i = 1; i < types->length(); ++i) { 6129 PropertyAccessInfo test_info( 6130 builder_, access_type_, ToType(types->at(i)), name_); 6131 HObjectAccess test_access = HObjectAccess::ForMap(); // bogus default 6132 if (!test_info.GetJSObjectFieldAccess(&test_access)) return false; 6133 if (!access.Equals(test_access)) return false; 6134 } 6135 return true; 6136 } 6137 6138 // Currently only handle Type::Number as a polymorphic case. 6139 // TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber 6140 // instruction. 6141 if (type_->Is(Type::Number())) return false; 6142 6143 // Multiple maps cannot transition to the same target map. 6144 DCHECK(!IsLoad() || !IsTransition()); 6145 if (IsTransition() && types->length() > 1) return false; 6146 6147 for (int i = 1; i < types->length(); ++i) { 6148 PropertyAccessInfo test_info( 6149 builder_, access_type_, ToType(types->at(i)), name_); 6150 if (!test_info.IsCompatible(this)) return false; 6151 } 6152 6153 return true; 6154 } 6155 6156 6157 Handle<Map> HOptimizedGraphBuilder::PropertyAccessInfo::map() { 6158 JSFunction* ctor = IC::GetRootConstructor( 6159 type_, current_info()->closure()->context()->native_context()); 6160 if (ctor != NULL) return handle(ctor->initial_map()); 6161 return type_->AsClass()->Map(); 6162 } 6163 6164 6165 static bool NeedsWrappingFor(Type* type, Handle<JSFunction> target) { 6166 return type->Is(Type::NumberOrString()) && 6167 target->shared()->strict_mode() == SLOPPY && 6168 !target->shared()->native(); 6169 } 6170 6171 6172 HInstruction* HOptimizedGraphBuilder::BuildMonomorphicAccess( 6173 PropertyAccessInfo* info, 6174 HValue* object, 6175 HValue* checked_object, 6176 HValue* value, 6177 BailoutId ast_id, 6178 BailoutId return_id, 6179 bool can_inline_accessor) { 6180 6181 HObjectAccess access = HObjectAccess::ForMap(); // bogus default 6182 if (info->GetJSObjectFieldAccess(&access)) { 6183 DCHECK(info->IsLoad()); 6184 return New<HLoadNamedField>(object, checked_object, access); 6185 } 6186 6187 if (info->name().is_identical_to(isolate()->factory()->prototype_string()) && 6188 info->map()->function_with_prototype()) { 6189 DCHECK(!info->map()->has_non_instance_prototype()); 6190 return New<HLoadFunctionPrototype>(checked_object); 6191 } 6192 6193 HValue* checked_holder = checked_object; 6194 if (info->has_holder()) { 6195 Handle<JSObject> prototype(JSObject::cast(info->map()->prototype())); 6196 checked_holder = BuildCheckPrototypeMaps(prototype, info->holder()); 6197 } 6198 6199 if (!info->IsFound()) { 6200 DCHECK(info->IsLoad()); 6201 return graph()->GetConstantUndefined(); 6202 } 6203 6204 if (info->IsField()) { 6205 if (info->IsLoad()) { 6206 return BuildLoadNamedField(info, checked_holder); 6207 } else { 6208 return BuildStoreNamedField(info, checked_object, value); 6209 } 6210 } 6211 6212 if (info->IsTransition()) { 6213 DCHECK(!info->IsLoad()); 6214 return BuildStoreNamedField(info, checked_object, value); 6215 } 6216 6217 if (info->IsAccessor()) { 6218 Push(checked_object); 6219 int argument_count = 1; 6220 if (!info->IsLoad()) { 6221 argument_count = 2; 6222 Push(value); 6223 } 6224 6225 if (NeedsWrappingFor(info->type(), info->accessor())) { 6226 HValue* function = Add<HConstant>(info->accessor()); 6227 PushArgumentsFromEnvironment(argument_count); 6228 return New<HCallFunction>(function, argument_count, WRAP_AND_CALL); 6229 } else if (FLAG_inline_accessors && can_inline_accessor) { 6230 bool success = info->IsLoad() 6231 ? TryInlineGetter(info->accessor(), info->map(), ast_id, return_id) 6232 : TryInlineSetter( 6233 info->accessor(), info->map(), ast_id, return_id, value); 6234 if (success || HasStackOverflow()) return NULL; 6235 } 6236 6237 PushArgumentsFromEnvironment(argument_count); 6238 return BuildCallConstantFunction(info->accessor(), argument_count); 6239 } 6240 6241 DCHECK(info->IsConstant()); 6242 if (info->IsLoad()) { 6243 return New<HConstant>(info->constant()); 6244 } else { 6245 return New<HCheckValue>(value, Handle<JSFunction>::cast(info->constant())); 6246 } 6247 } 6248 6249 6250 void HOptimizedGraphBuilder::HandlePolymorphicNamedFieldAccess( 6251 PropertyAccessType access_type, 6252 Expression* expr, 6253 BailoutId ast_id, 6254 BailoutId return_id, 6255 HValue* object, 6256 HValue* value, 6257 SmallMapList* types, 6258 Handle<String> name) { 6259 // Something did not match; must use a polymorphic load. 6260 int count = 0; 6261 HBasicBlock* join = NULL; 6262 HBasicBlock* number_block = NULL; 6263 bool handled_string = false; 6264 6265 bool handle_smi = false; 6266 STATIC_ASSERT(kMaxLoadPolymorphism == kMaxStorePolymorphism); 6267 int i; 6268 for (i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { 6269 PropertyAccessInfo info(this, access_type, ToType(types->at(i)), name); 6270 if (info.type()->Is(Type::String())) { 6271 if (handled_string) continue; 6272 handled_string = true; 6273 } 6274 if (info.CanAccessMonomorphic()) { 6275 count++; 6276 if (info.type()->Is(Type::Number())) { 6277 handle_smi = true; 6278 break; 6279 } 6280 } 6281 } 6282 6283 if (i < types->length()) { 6284 count = -1; 6285 types->Clear(); 6286 } else { 6287 count = 0; 6288 } 6289 HControlInstruction* smi_check = NULL; 6290 handled_string = false; 6291 6292 for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { 6293 PropertyAccessInfo info(this, access_type, ToType(types->at(i)), name); 6294 if (info.type()->Is(Type::String())) { 6295 if (handled_string) continue; 6296 handled_string = true; 6297 } 6298 if (!info.CanAccessMonomorphic()) continue; 6299 6300 if (count == 0) { 6301 join = graph()->CreateBasicBlock(); 6302 if (handle_smi) { 6303 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); 6304 HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); 6305 number_block = graph()->CreateBasicBlock(); 6306 smi_check = New<HIsSmiAndBranch>( 6307 object, empty_smi_block, not_smi_block); 6308 FinishCurrentBlock(smi_check); 6309 GotoNoSimulate(empty_smi_block, number_block); 6310 set_current_block(not_smi_block); 6311 } else { 6312 BuildCheckHeapObject(object); 6313 } 6314 } 6315 ++count; 6316 HBasicBlock* if_true = graph()->CreateBasicBlock(); 6317 HBasicBlock* if_false = graph()->CreateBasicBlock(); 6318 HUnaryControlInstruction* compare; 6319 6320 HValue* dependency; 6321 if (info.type()->Is(Type::Number())) { 6322 Handle<Map> heap_number_map = isolate()->factory()->heap_number_map(); 6323 compare = New<HCompareMap>(object, heap_number_map, if_true, if_false); 6324 dependency = smi_check; 6325 } else if (info.type()->Is(Type::String())) { 6326 compare = New<HIsStringAndBranch>(object, if_true, if_false); 6327 dependency = compare; 6328 } else { 6329 compare = New<HCompareMap>(object, info.map(), if_true, if_false); 6330 dependency = compare; 6331 } 6332 FinishCurrentBlock(compare); 6333 6334 if (info.type()->Is(Type::Number())) { 6335 GotoNoSimulate(if_true, number_block); 6336 if_true = number_block; 6337 } 6338 6339 set_current_block(if_true); 6340 6341 HInstruction* access = BuildMonomorphicAccess( 6342 &info, object, dependency, value, ast_id, 6343 return_id, FLAG_polymorphic_inlining); 6344 6345 HValue* result = NULL; 6346 switch (access_type) { 6347 case LOAD: 6348 result = access; 6349 break; 6350 case STORE: 6351 result = value; 6352 break; 6353 } 6354 6355 if (access == NULL) { 6356 if (HasStackOverflow()) return; 6357 } else { 6358 if (!access->IsLinked()) AddInstruction(access); 6359 if (!ast_context()->IsEffect()) Push(result); 6360 } 6361 6362 if (current_block() != NULL) Goto(join); 6363 set_current_block(if_false); 6364 } 6365 6366 // Finish up. Unconditionally deoptimize if we've handled all the maps we 6367 // know about and do not want to handle ones we've never seen. Otherwise 6368 // use a generic IC. 6369 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { 6370 FinishExitWithHardDeoptimization("Uknown map in polymorphic access"); 6371 } else { 6372 HInstruction* instr = BuildNamedGeneric(access_type, expr, object, name, 6373 value); 6374 AddInstruction(instr); 6375 if (!ast_context()->IsEffect()) Push(access_type == LOAD ? instr : value); 6376 6377 if (join != NULL) { 6378 Goto(join); 6379 } else { 6380 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); 6381 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); 6382 return; 6383 } 6384 } 6385 6386 DCHECK(join != NULL); 6387 if (join->HasPredecessor()) { 6388 join->SetJoinId(ast_id); 6389 set_current_block(join); 6390 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); 6391 } else { 6392 set_current_block(NULL); 6393 } 6394 } 6395 6396 6397 static bool ComputeReceiverTypes(Expression* expr, 6398 HValue* receiver, 6399 SmallMapList** t, 6400 Zone* zone) { 6401 SmallMapList* types = expr->GetReceiverTypes(); 6402 *t = types; 6403 bool monomorphic = expr->IsMonomorphic(); 6404 if (types != NULL && receiver->HasMonomorphicJSObjectType()) { 6405 Map* root_map = receiver->GetMonomorphicJSObjectMap()->FindRootMap(); 6406 types->FilterForPossibleTransitions(root_map); 6407 monomorphic = types->length() == 1; 6408 } 6409 return monomorphic && 6410 CanInlinePropertyAccess(IC::MapToType<Type>(types->first(), zone)); 6411 } 6412 6413 6414 static bool AreStringTypes(SmallMapList* types) { 6415 for (int i = 0; i < types->length(); i++) { 6416 if (types->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false; 6417 } 6418 return true; 6419 } 6420 6421 6422 void HOptimizedGraphBuilder::BuildStore(Expression* expr, 6423 Property* prop, 6424 BailoutId ast_id, 6425 BailoutId return_id, 6426 bool is_uninitialized) { 6427 if (!prop->key()->IsPropertyName()) { 6428 // Keyed store. 6429 HValue* value = Pop(); 6430 HValue* key = Pop(); 6431 HValue* object = Pop(); 6432 bool has_side_effects = false; 6433 HValue* result = HandleKeyedElementAccess( 6434 object, key, value, expr, ast_id, return_id, STORE, &has_side_effects); 6435 if (has_side_effects) { 6436 if (!ast_context()->IsEffect()) Push(value); 6437 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); 6438 if (!ast_context()->IsEffect()) Drop(1); 6439 } 6440 if (result == NULL) return; 6441 return ast_context()->ReturnValue(value); 6442 } 6443 6444 // Named store. 6445 HValue* value = Pop(); 6446 HValue* object = Pop(); 6447 6448 Literal* key = prop->key()->AsLiteral(); 6449 Handle<String> name = Handle<String>::cast(key->value()); 6450 DCHECK(!name.is_null()); 6451 6452 HInstruction* instr = BuildNamedAccess(STORE, ast_id, return_id, expr, 6453 object, name, value, is_uninitialized); 6454 if (instr == NULL) return; 6455 6456 if (!ast_context()->IsEffect()) Push(value); 6457 AddInstruction(instr); 6458 if (instr->HasObservableSideEffects()) { 6459 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); 6460 } 6461 if (!ast_context()->IsEffect()) Drop(1); 6462 return ast_context()->ReturnValue(value); 6463 } 6464 6465 6466 void HOptimizedGraphBuilder::HandlePropertyAssignment(Assignment* expr) { 6467 Property* prop = expr->target()->AsProperty(); 6468 DCHECK(prop != NULL); 6469 CHECK_ALIVE(VisitForValue(prop->obj())); 6470 if (!prop->key()->IsPropertyName()) { 6471 CHECK_ALIVE(VisitForValue(prop->key())); 6472 } 6473 CHECK_ALIVE(VisitForValue(expr->value())); 6474 BuildStore(expr, prop, expr->id(), 6475 expr->AssignmentId(), expr->IsUninitialized()); 6476 } 6477 6478 6479 // Because not every expression has a position and there is not common 6480 // superclass of Assignment and CountOperation, we cannot just pass the 6481 // owning expression instead of position and ast_id separately. 6482 void HOptimizedGraphBuilder::HandleGlobalVariableAssignment( 6483 Variable* var, 6484 HValue* value, 6485 BailoutId ast_id) { 6486 Handle<GlobalObject> global(current_info()->global_object()); 6487 LookupIterator it(global, var->name(), LookupIterator::OWN_SKIP_INTERCEPTOR); 6488 GlobalPropertyAccess type = LookupGlobalProperty(var, &it, STORE); 6489 if (type == kUseCell) { 6490 Handle<PropertyCell> cell = it.GetPropertyCell(); 6491 if (cell->type()->IsConstant()) { 6492 Handle<Object> constant = cell->type()->AsConstant()->Value(); 6493 if (value->IsConstant()) { 6494 HConstant* c_value = HConstant::cast(value); 6495 if (!constant.is_identical_to(c_value->handle(isolate()))) { 6496 Add<HDeoptimize>("Constant global variable assignment", 6497 Deoptimizer::EAGER); 6498 } 6499 } else { 6500 HValue* c_constant = Add<HConstant>(constant); 6501 IfBuilder builder(this); 6502 if (constant->IsNumber()) { 6503 builder.If<HCompareNumericAndBranch>(value, c_constant, Token::EQ); 6504 } else { 6505 builder.If<HCompareObjectEqAndBranch>(value, c_constant); 6506 } 6507 builder.Then(); 6508 builder.Else(); 6509 Add<HDeoptimize>("Constant global variable assignment", 6510 Deoptimizer::EAGER); 6511 builder.End(); 6512 } 6513 } 6514 HInstruction* instr = 6515 Add<HStoreGlobalCell>(value, cell, it.property_details()); 6516 if (instr->HasObservableSideEffects()) { 6517 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); 6518 } 6519 } else { 6520 HValue* global_object = Add<HLoadNamedField>( 6521 context(), static_cast<HValue*>(NULL), 6522 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); 6523 HStoreNamedGeneric* instr = 6524 Add<HStoreNamedGeneric>(global_object, var->name(), 6525 value, function_strict_mode()); 6526 USE(instr); 6527 DCHECK(instr->HasObservableSideEffects()); 6528 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); 6529 } 6530 } 6531 6532 6533 void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) { 6534 Expression* target = expr->target(); 6535 VariableProxy* proxy = target->AsVariableProxy(); 6536 Property* prop = target->AsProperty(); 6537 DCHECK(proxy == NULL || prop == NULL); 6538 6539 // We have a second position recorded in the FullCodeGenerator to have 6540 // type feedback for the binary operation. 6541 BinaryOperation* operation = expr->binary_operation(); 6542 6543 if (proxy != NULL) { 6544 Variable* var = proxy->var(); 6545 if (var->mode() == LET) { 6546 return Bailout(kUnsupportedLetCompoundAssignment); 6547 } 6548 6549 CHECK_ALIVE(VisitForValue(operation)); 6550 6551 switch (var->location()) { 6552 case Variable::UNALLOCATED: 6553 HandleGlobalVariableAssignment(var, 6554 Top(), 6555 expr->AssignmentId()); 6556 break; 6557 6558 case Variable::PARAMETER: 6559 case Variable::LOCAL: 6560 if (var->mode() == CONST_LEGACY) { 6561 return Bailout(kUnsupportedConstCompoundAssignment); 6562 } 6563 BindIfLive(var, Top()); 6564 break; 6565 6566 case Variable::CONTEXT: { 6567 // Bail out if we try to mutate a parameter value in a function 6568 // using the arguments object. We do not (yet) correctly handle the 6569 // arguments property of the function. 6570 if (current_info()->scope()->arguments() != NULL) { 6571 // Parameters will be allocated to context slots. We have no 6572 // direct way to detect that the variable is a parameter so we do 6573 // a linear search of the parameter variables. 6574 int count = current_info()->scope()->num_parameters(); 6575 for (int i = 0; i < count; ++i) { 6576 if (var == current_info()->scope()->parameter(i)) { 6577 Bailout(kAssignmentToParameterFunctionUsesArgumentsObject); 6578 } 6579 } 6580 } 6581 6582 HStoreContextSlot::Mode mode; 6583 6584 switch (var->mode()) { 6585 case LET: 6586 mode = HStoreContextSlot::kCheckDeoptimize; 6587 break; 6588 case CONST: 6589 // This case is checked statically so no need to 6590 // perform checks here 6591 UNREACHABLE(); 6592 case CONST_LEGACY: 6593 return ast_context()->ReturnValue(Pop()); 6594 default: 6595 mode = HStoreContextSlot::kNoCheck; 6596 } 6597 6598 HValue* context = BuildContextChainWalk(var); 6599 HStoreContextSlot* instr = Add<HStoreContextSlot>( 6600 context, var->index(), mode, Top()); 6601 if (instr->HasObservableSideEffects()) { 6602 Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE); 6603 } 6604 break; 6605 } 6606 6607 case Variable::LOOKUP: 6608 return Bailout(kCompoundAssignmentToLookupSlot); 6609 } 6610 return ast_context()->ReturnValue(Pop()); 6611 6612 } else if (prop != NULL) { 6613 CHECK_ALIVE(VisitForValue(prop->obj())); 6614 HValue* object = Top(); 6615 HValue* key = NULL; 6616 if (!prop->key()->IsPropertyName() || prop->IsStringAccess()) { 6617 CHECK_ALIVE(VisitForValue(prop->key())); 6618 key = Top(); 6619 } 6620 6621 CHECK_ALIVE(PushLoad(prop, object, key)); 6622 6623 CHECK_ALIVE(VisitForValue(expr->value())); 6624 HValue* right = Pop(); 6625 HValue* left = Pop(); 6626 6627 Push(BuildBinaryOperation(operation, left, right, PUSH_BEFORE_SIMULATE)); 6628 6629 BuildStore(expr, prop, expr->id(), 6630 expr->AssignmentId(), expr->IsUninitialized()); 6631 } else { 6632 return Bailout(kInvalidLhsInCompoundAssignment); 6633 } 6634 } 6635 6636 6637 void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) { 6638 DCHECK(!HasStackOverflow()); 6639 DCHECK(current_block() != NULL); 6640 DCHECK(current_block()->HasPredecessor()); 6641 VariableProxy* proxy = expr->target()->AsVariableProxy(); 6642 Property* prop = expr->target()->AsProperty(); 6643 DCHECK(proxy == NULL || prop == NULL); 6644 6645 if (expr->is_compound()) { 6646 HandleCompoundAssignment(expr); 6647 return; 6648 } 6649 6650 if (prop != NULL) { 6651 HandlePropertyAssignment(expr); 6652 } else if (proxy != NULL) { 6653 Variable* var = proxy->var(); 6654 6655 if (var->mode() == CONST) { 6656 if (expr->op() != Token::INIT_CONST) { 6657 return Bailout(kNonInitializerAssignmentToConst); 6658 } 6659 } else if (var->mode() == CONST_LEGACY) { 6660 if (expr->op() != Token::INIT_CONST_LEGACY) { 6661 CHECK_ALIVE(VisitForValue(expr->value())); 6662 return ast_context()->ReturnValue(Pop()); 6663 } 6664 6665 if (var->IsStackAllocated()) { 6666 // We insert a use of the old value to detect unsupported uses of const 6667 // variables (e.g. initialization inside a loop). 6668 HValue* old_value = environment()->Lookup(var); 6669 Add<HUseConst>(old_value); 6670 } 6671 } 6672 6673 if (proxy->IsArguments()) return Bailout(kAssignmentToArguments); 6674 6675 // Handle the assignment. 6676 switch (var->location()) { 6677 case Variable::UNALLOCATED: 6678 CHECK_ALIVE(VisitForValue(expr->value())); 6679 HandleGlobalVariableAssignment(var, 6680 Top(), 6681 expr->AssignmentId()); 6682 return ast_context()->ReturnValue(Pop()); 6683 6684 case Variable::PARAMETER: 6685 case Variable::LOCAL: { 6686 // Perform an initialization check for let declared variables 6687 // or parameters. 6688 if (var->mode() == LET && expr->op() == Token::ASSIGN) { 6689 HValue* env_value = environment()->Lookup(var); 6690 if (env_value == graph()->GetConstantHole()) { 6691 return Bailout(kAssignmentToLetVariableBeforeInitialization); 6692 } 6693 } 6694 // We do not allow the arguments object to occur in a context where it 6695 // may escape, but assignments to stack-allocated locals are 6696 // permitted. 6697 CHECK_ALIVE(VisitForValue(expr->value(), ARGUMENTS_ALLOWED)); 6698 HValue* value = Pop(); 6699 BindIfLive(var, value); 6700 return ast_context()->ReturnValue(value); 6701 } 6702 6703 case Variable::CONTEXT: { 6704 // Bail out if we try to mutate a parameter value in a function using 6705 // the arguments object. We do not (yet) correctly handle the 6706 // arguments property of the function. 6707 if (current_info()->scope()->arguments() != NULL) { 6708 // Parameters will rewrite to context slots. We have no direct way 6709 // to detect that the variable is a parameter. 6710 int count = current_info()->scope()->num_parameters(); 6711 for (int i = 0; i < count; ++i) { 6712 if (var == current_info()->scope()->parameter(i)) { 6713 return Bailout(kAssignmentToParameterInArgumentsObject); 6714 } 6715 } 6716 } 6717 6718 CHECK_ALIVE(VisitForValue(expr->value())); 6719 HStoreContextSlot::Mode mode; 6720 if (expr->op() == Token::ASSIGN) { 6721 switch (var->mode()) { 6722 case LET: 6723 mode = HStoreContextSlot::kCheckDeoptimize; 6724 break; 6725 case CONST: 6726 // This case is checked statically so no need to 6727 // perform checks here 6728 UNREACHABLE(); 6729 case CONST_LEGACY: 6730 return ast_context()->ReturnValue(Pop()); 6731 default: 6732 mode = HStoreContextSlot::kNoCheck; 6733 } 6734 } else if (expr->op() == Token::INIT_VAR || 6735 expr->op() == Token::INIT_LET || 6736 expr->op() == Token::INIT_CONST) { 6737 mode = HStoreContextSlot::kNoCheck; 6738 } else { 6739 DCHECK(expr->op() == Token::INIT_CONST_LEGACY); 6740 6741 mode = HStoreContextSlot::kCheckIgnoreAssignment; 6742 } 6743 6744 HValue* context = BuildContextChainWalk(var); 6745 HStoreContextSlot* instr = Add<HStoreContextSlot>( 6746 context, var->index(), mode, Top()); 6747 if (instr->HasObservableSideEffects()) { 6748 Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE); 6749 } 6750 return ast_context()->ReturnValue(Pop()); 6751 } 6752 6753 case Variable::LOOKUP: 6754 return Bailout(kAssignmentToLOOKUPVariable); 6755 } 6756 } else { 6757 return Bailout(kInvalidLeftHandSideInAssignment); 6758 } 6759 } 6760 6761 6762 void HOptimizedGraphBuilder::VisitYield(Yield* expr) { 6763 // Generators are not optimized, so we should never get here. 6764 UNREACHABLE(); 6765 } 6766 6767 6768 void HOptimizedGraphBuilder::VisitThrow(Throw* expr) { 6769 DCHECK(!HasStackOverflow()); 6770 DCHECK(current_block() != NULL); 6771 DCHECK(current_block()->HasPredecessor()); 6772 if (!ast_context()->IsEffect()) { 6773 // The parser turns invalid left-hand sides in assignments into throw 6774 // statements, which may not be in effect contexts. We might still try 6775 // to optimize such functions; bail out now if we do. 6776 return Bailout(kInvalidLeftHandSideInAssignment); 6777 } 6778 CHECK_ALIVE(VisitForValue(expr->exception())); 6779 6780 HValue* value = environment()->Pop(); 6781 if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position()); 6782 Add<HPushArguments>(value); 6783 Add<HCallRuntime>(isolate()->factory()->empty_string(), 6784 Runtime::FunctionForId(Runtime::kThrow), 1); 6785 Add<HSimulate>(expr->id()); 6786 6787 // If the throw definitely exits the function, we can finish with a dummy 6788 // control flow at this point. This is not the case if the throw is inside 6789 // an inlined function which may be replaced. 6790 if (call_context() == NULL) { 6791 FinishExitCurrentBlock(New<HAbnormalExit>()); 6792 } 6793 } 6794 6795 6796 HInstruction* HGraphBuilder::AddLoadStringInstanceType(HValue* string) { 6797 if (string->IsConstant()) { 6798 HConstant* c_string = HConstant::cast(string); 6799 if (c_string->HasStringValue()) { 6800 return Add<HConstant>(c_string->StringValue()->map()->instance_type()); 6801 } 6802 } 6803 return Add<HLoadNamedField>( 6804 Add<HLoadNamedField>(string, static_cast<HValue*>(NULL), 6805 HObjectAccess::ForMap()), 6806 static_cast<HValue*>(NULL), HObjectAccess::ForMapInstanceType()); 6807 } 6808 6809 6810 HInstruction* HGraphBuilder::AddLoadStringLength(HValue* string) { 6811 if (string->IsConstant()) { 6812 HConstant* c_string = HConstant::cast(string); 6813 if (c_string->HasStringValue()) { 6814 return Add<HConstant>(c_string->StringValue()->length()); 6815 } 6816 } 6817 return Add<HLoadNamedField>(string, static_cast<HValue*>(NULL), 6818 HObjectAccess::ForStringLength()); 6819 } 6820 6821 6822 HInstruction* HOptimizedGraphBuilder::BuildNamedGeneric( 6823 PropertyAccessType access_type, 6824 Expression* expr, 6825 HValue* object, 6826 Handle<String> name, 6827 HValue* value, 6828 bool is_uninitialized) { 6829 if (is_uninitialized) { 6830 Add<HDeoptimize>("Insufficient type feedback for generic named access", 6831 Deoptimizer::SOFT); 6832 } 6833 if (access_type == LOAD) { 6834 HLoadNamedGeneric* result = New<HLoadNamedGeneric>(object, name); 6835 if (FLAG_vector_ics) { 6836 Handle<SharedFunctionInfo> current_shared = 6837 function_state()->compilation_info()->shared_info(); 6838 result->SetVectorAndSlot( 6839 handle(current_shared->feedback_vector(), isolate()), 6840 expr->AsProperty()->PropertyFeedbackSlot()); 6841 } 6842 return result; 6843 } else { 6844 return New<HStoreNamedGeneric>(object, name, value, function_strict_mode()); 6845 } 6846 } 6847 6848 6849 6850 HInstruction* HOptimizedGraphBuilder::BuildKeyedGeneric( 6851 PropertyAccessType access_type, 6852 Expression* expr, 6853 HValue* object, 6854 HValue* key, 6855 HValue* value) { 6856 if (access_type == LOAD) { 6857 HLoadKeyedGeneric* result = New<HLoadKeyedGeneric>(object, key); 6858 if (FLAG_vector_ics) { 6859 Handle<SharedFunctionInfo> current_shared = 6860 function_state()->compilation_info()->shared_info(); 6861 result->SetVectorAndSlot( 6862 handle(current_shared->feedback_vector(), isolate()), 6863 expr->AsProperty()->PropertyFeedbackSlot()); 6864 } 6865 return result; 6866 } else { 6867 return New<HStoreKeyedGeneric>(object, key, value, function_strict_mode()); 6868 } 6869 } 6870 6871 6872 LoadKeyedHoleMode HOptimizedGraphBuilder::BuildKeyedHoleMode(Handle<Map> map) { 6873 // Loads from a "stock" fast holey double arrays can elide the hole check. 6874 LoadKeyedHoleMode load_mode = NEVER_RETURN_HOLE; 6875 if (*map == isolate()->get_initial_js_array_map(FAST_HOLEY_DOUBLE_ELEMENTS) && 6876 isolate()->IsFastArrayConstructorPrototypeChainIntact()) { 6877 Handle<JSObject> prototype(JSObject::cast(map->prototype()), isolate()); 6878 Handle<JSObject> object_prototype = isolate()->initial_object_prototype(); 6879 BuildCheckPrototypeMaps(prototype, object_prototype); 6880 load_mode = ALLOW_RETURN_HOLE; 6881 graph()->MarkDependsOnEmptyArrayProtoElements(); 6882 } 6883 6884 return load_mode; 6885 } 6886 6887 6888 HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess( 6889 HValue* object, 6890 HValue* key, 6891 HValue* val, 6892 HValue* dependency, 6893 Handle<Map> map, 6894 PropertyAccessType access_type, 6895 KeyedAccessStoreMode store_mode) { 6896 HCheckMaps* checked_object = Add<HCheckMaps>(object, map, dependency); 6897 if (dependency) { 6898 checked_object->ClearDependsOnFlag(kElementsKind); 6899 } 6900 6901 if (access_type == STORE && map->prototype()->IsJSObject()) { 6902 // monomorphic stores need a prototype chain check because shape 6903 // changes could allow callbacks on elements in the chain that 6904 // aren't compatible with monomorphic keyed stores. 6905 PrototypeIterator iter(map); 6906 JSObject* holder = NULL; 6907 while (!iter.IsAtEnd()) { 6908 holder = JSObject::cast(*PrototypeIterator::GetCurrent(iter)); 6909 iter.Advance(); 6910 } 6911 DCHECK(holder && holder->IsJSObject()); 6912 6913 BuildCheckPrototypeMaps(handle(JSObject::cast(map->prototype())), 6914 Handle<JSObject>(holder)); 6915 } 6916 6917 LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map); 6918 return BuildUncheckedMonomorphicElementAccess( 6919 checked_object, key, val, 6920 map->instance_type() == JS_ARRAY_TYPE, 6921 map->elements_kind(), access_type, 6922 load_mode, store_mode); 6923 } 6924 6925 6926 HInstruction* HOptimizedGraphBuilder::TryBuildConsolidatedElementLoad( 6927 HValue* object, 6928 HValue* key, 6929 HValue* val, 6930 SmallMapList* maps) { 6931 // For polymorphic loads of similar elements kinds (i.e. all tagged or all 6932 // double), always use the "worst case" code without a transition. This is 6933 // much faster than transitioning the elements to the worst case, trading a 6934 // HTransitionElements for a HCheckMaps, and avoiding mutation of the array. 6935 bool has_double_maps = false; 6936 bool has_smi_or_object_maps = false; 6937 bool has_js_array_access = false; 6938 bool has_non_js_array_access = false; 6939 bool has_seen_holey_elements = false; 6940 Handle<Map> most_general_consolidated_map; 6941 for (int i = 0; i < maps->length(); ++i) { 6942 Handle<Map> map = maps->at(i); 6943 if (!map->IsJSObjectMap()) return NULL; 6944 // Don't allow mixing of JSArrays with JSObjects. 6945 if (map->instance_type() == JS_ARRAY_TYPE) { 6946 if (has_non_js_array_access) return NULL; 6947 has_js_array_access = true; 6948 } else if (has_js_array_access) { 6949 return NULL; 6950 } else { 6951 has_non_js_array_access = true; 6952 } 6953 // Don't allow mixed, incompatible elements kinds. 6954 if (map->has_fast_double_elements()) { 6955 if (has_smi_or_object_maps) return NULL; 6956 has_double_maps = true; 6957 } else if (map->has_fast_smi_or_object_elements()) { 6958 if (has_double_maps) return NULL; 6959 has_smi_or_object_maps = true; 6960 } else { 6961 return NULL; 6962 } 6963 // Remember if we've ever seen holey elements. 6964 if (IsHoleyElementsKind(map->elements_kind())) { 6965 has_seen_holey_elements = true; 6966 } 6967 // Remember the most general elements kind, the code for its load will 6968 // properly handle all of the more specific cases. 6969 if ((i == 0) || IsMoreGeneralElementsKindTransition( 6970 most_general_consolidated_map->elements_kind(), 6971 map->elements_kind())) { 6972 most_general_consolidated_map = map; 6973 } 6974 } 6975 if (!has_double_maps && !has_smi_or_object_maps) return NULL; 6976 6977 HCheckMaps* checked_object = Add<HCheckMaps>(object, maps); 6978 // FAST_ELEMENTS is considered more general than FAST_HOLEY_SMI_ELEMENTS. 6979 // If we've seen both, the consolidated load must use FAST_HOLEY_ELEMENTS. 6980 ElementsKind consolidated_elements_kind = has_seen_holey_elements 6981 ? GetHoleyElementsKind(most_general_consolidated_map->elements_kind()) 6982 : most_general_consolidated_map->elements_kind(); 6983 HInstruction* instr = BuildUncheckedMonomorphicElementAccess( 6984 checked_object, key, val, 6985 most_general_consolidated_map->instance_type() == JS_ARRAY_TYPE, 6986 consolidated_elements_kind, 6987 LOAD, NEVER_RETURN_HOLE, STANDARD_STORE); 6988 return instr; 6989 } 6990 6991 6992 HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( 6993 Expression* expr, 6994 HValue* object, 6995 HValue* key, 6996 HValue* val, 6997 SmallMapList* maps, 6998 PropertyAccessType access_type, 6999 KeyedAccessStoreMode store_mode, 7000 bool* has_side_effects) { 7001 *has_side_effects = false; 7002 BuildCheckHeapObject(object); 7003 7004 if (access_type == LOAD) { 7005 HInstruction* consolidated_load = 7006 TryBuildConsolidatedElementLoad(object, key, val, maps); 7007 if (consolidated_load != NULL) { 7008 *has_side_effects |= consolidated_load->HasObservableSideEffects(); 7009 return consolidated_load; 7010 } 7011 } 7012 7013 // Elements_kind transition support. 7014 MapHandleList transition_target(maps->length()); 7015 // Collect possible transition targets. 7016 MapHandleList possible_transitioned_maps(maps->length()); 7017 for (int i = 0; i < maps->length(); ++i) { 7018 Handle<Map> map = maps->at(i); 7019 ElementsKind elements_kind = map->elements_kind(); 7020 if (IsFastElementsKind(elements_kind) && 7021 elements_kind != GetInitialFastElementsKind()) { 7022 possible_transitioned_maps.Add(map); 7023 } 7024 if (elements_kind == SLOPPY_ARGUMENTS_ELEMENTS) { 7025 HInstruction* result = BuildKeyedGeneric(access_type, expr, object, key, 7026 val); 7027 *has_side_effects = result->HasObservableSideEffects(); 7028 return AddInstruction(result); 7029 } 7030 } 7031 // Get transition target for each map (NULL == no transition). 7032 for (int i = 0; i < maps->length(); ++i) { 7033 Handle<Map> map = maps->at(i); 7034 Handle<Map> transitioned_map = 7035 map->FindTransitionedMap(&possible_transitioned_maps); 7036 transition_target.Add(transitioned_map); 7037 } 7038 7039 MapHandleList untransitionable_maps(maps->length()); 7040 HTransitionElementsKind* transition = NULL; 7041 for (int i = 0; i < maps->length(); ++i) { 7042 Handle<Map> map = maps->at(i); 7043 DCHECK(map->IsMap()); 7044 if (!transition_target.at(i).is_null()) { 7045 DCHECK(Map::IsValidElementsTransition( 7046 map->elements_kind(), 7047 transition_target.at(i)->elements_kind())); 7048 transition = Add<HTransitionElementsKind>(object, map, 7049 transition_target.at(i)); 7050 } else { 7051 untransitionable_maps.Add(map); 7052 } 7053 } 7054 7055 // If only one map is left after transitioning, handle this case 7056 // monomorphically. 7057 DCHECK(untransitionable_maps.length() >= 1); 7058 if (untransitionable_maps.length() == 1) { 7059 Handle<Map> untransitionable_map = untransitionable_maps[0]; 7060 HInstruction* instr = NULL; 7061 if (untransitionable_map->has_slow_elements_kind() || 7062 !untransitionable_map->IsJSObjectMap()) { 7063 instr = AddInstruction(BuildKeyedGeneric(access_type, expr, object, key, 7064 val)); 7065 } else { 7066 instr = BuildMonomorphicElementAccess( 7067 object, key, val, transition, untransitionable_map, access_type, 7068 store_mode); 7069 } 7070 *has_side_effects |= instr->HasObservableSideEffects(); 7071 return access_type == STORE ? val : instr; 7072 } 7073 7074 HBasicBlock* join = graph()->CreateBasicBlock(); 7075 7076 for (int i = 0; i < untransitionable_maps.length(); ++i) { 7077 Handle<Map> map = untransitionable_maps[i]; 7078 if (!map->IsJSObjectMap()) continue; 7079 ElementsKind elements_kind = map->elements_kind(); 7080 HBasicBlock* this_map = graph()->CreateBasicBlock(); 7081 HBasicBlock* other_map = graph()->CreateBasicBlock(); 7082 HCompareMap* mapcompare = 7083 New<HCompareMap>(object, map, this_map, other_map); 7084 FinishCurrentBlock(mapcompare); 7085 7086 set_current_block(this_map); 7087 HInstruction* access = NULL; 7088 if (IsDictionaryElementsKind(elements_kind)) { 7089 access = AddInstruction(BuildKeyedGeneric(access_type, expr, object, key, 7090 val)); 7091 } else { 7092 DCHECK(IsFastElementsKind(elements_kind) || 7093 IsExternalArrayElementsKind(elements_kind) || 7094 IsFixedTypedArrayElementsKind(elements_kind)); 7095 LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map); 7096 // Happily, mapcompare is a checked object. 7097 access = BuildUncheckedMonomorphicElementAccess( 7098 mapcompare, key, val, 7099 map->instance_type() == JS_ARRAY_TYPE, 7100 elements_kind, access_type, 7101 load_mode, 7102 store_mode); 7103 } 7104 *has_side_effects |= access->HasObservableSideEffects(); 7105 // The caller will use has_side_effects and add a correct Simulate. 7106 access->SetFlag(HValue::kHasNoObservableSideEffects); 7107 if (access_type == LOAD) { 7108 Push(access); 7109 } 7110 NoObservableSideEffectsScope scope(this); 7111 GotoNoSimulate(join); 7112 set_current_block(other_map); 7113 } 7114 7115 // Ensure that we visited at least one map above that goes to join. This is 7116 // necessary because FinishExitWithHardDeoptimization does an AbnormalExit 7117 // rather than joining the join block. If this becomes an issue, insert a 7118 // generic access in the case length() == 0. 7119 DCHECK(join->predecessors()->length() > 0); 7120 // Deopt if none of the cases matched. 7121 NoObservableSideEffectsScope scope(this); 7122 FinishExitWithHardDeoptimization("Unknown map in polymorphic element access"); 7123 set_current_block(join); 7124 return access_type == STORE ? val : Pop(); 7125 } 7126 7127 7128 HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess( 7129 HValue* obj, HValue* key, HValue* val, Expression* expr, BailoutId ast_id, 7130 BailoutId return_id, PropertyAccessType access_type, 7131 bool* has_side_effects) { 7132 if (key->ActualValue()->IsConstant()) { 7133 Handle<Object> constant = 7134 HConstant::cast(key->ActualValue())->handle(isolate()); 7135 uint32_t array_index; 7136 if (constant->IsString() && 7137 !Handle<String>::cast(constant)->AsArrayIndex(&array_index)) { 7138 if (!constant->IsUniqueName()) { 7139 constant = isolate()->factory()->InternalizeString( 7140 Handle<String>::cast(constant)); 7141 } 7142 HInstruction* instr = 7143 BuildNamedAccess(access_type, ast_id, return_id, expr, obj, 7144 Handle<String>::cast(constant), val, false); 7145 if (instr == NULL || instr->IsLinked()) { 7146 *has_side_effects = false; 7147 } else { 7148 AddInstruction(instr); 7149 *has_side_effects = instr->HasObservableSideEffects(); 7150 } 7151 return instr; 7152 } 7153 } 7154 7155 DCHECK(!expr->IsPropertyName()); 7156 HInstruction* instr = NULL; 7157 7158 SmallMapList* types; 7159 bool monomorphic = ComputeReceiverTypes(expr, obj, &types, zone()); 7160 7161 bool force_generic = false; 7162 if (access_type == STORE && 7163 (monomorphic || (types != NULL && !types->is_empty()))) { 7164 // Stores can't be mono/polymorphic if their prototype chain has dictionary 7165 // elements. However a receiver map that has dictionary elements itself 7166 // should be left to normal mono/poly behavior (the other maps may benefit 7167 // from highly optimized stores). 7168 for (int i = 0; i < types->length(); i++) { 7169 Handle<Map> current_map = types->at(i); 7170 if (current_map->DictionaryElementsInPrototypeChainOnly()) { 7171 force_generic = true; 7172 monomorphic = false; 7173 break; 7174 } 7175 } 7176 } 7177 7178 if (monomorphic) { 7179 Handle<Map> map = types->first(); 7180 if (map->has_slow_elements_kind() || !map->IsJSObjectMap()) { 7181 instr = AddInstruction(BuildKeyedGeneric(access_type, expr, obj, key, 7182 val)); 7183 } else { 7184 BuildCheckHeapObject(obj); 7185 instr = BuildMonomorphicElementAccess( 7186 obj, key, val, NULL, map, access_type, expr->GetStoreMode()); 7187 } 7188 } else if (!force_generic && (types != NULL && !types->is_empty())) { 7189 return HandlePolymorphicElementAccess( 7190 expr, obj, key, val, types, access_type, 7191 expr->GetStoreMode(), has_side_effects); 7192 } else { 7193 if (access_type == STORE) { 7194 if (expr->IsAssignment() && 7195 expr->AsAssignment()->HasNoTypeInformation()) { 7196 Add<HDeoptimize>("Insufficient type feedback for keyed store", 7197 Deoptimizer::SOFT); 7198 } 7199 } else { 7200 if (expr->AsProperty()->HasNoTypeInformation()) { 7201 Add<HDeoptimize>("Insufficient type feedback for keyed load", 7202 Deoptimizer::SOFT); 7203 } 7204 } 7205 instr = AddInstruction(BuildKeyedGeneric(access_type, expr, obj, key, val)); 7206 } 7207 *has_side_effects = instr->HasObservableSideEffects(); 7208 return instr; 7209 } 7210 7211 7212 void HOptimizedGraphBuilder::EnsureArgumentsArePushedForAccess() { 7213 // Outermost function already has arguments on the stack. 7214 if (function_state()->outer() == NULL) return; 7215 7216 if (function_state()->arguments_pushed()) return; 7217 7218 // Push arguments when entering inlined function. 7219 HEnterInlined* entry = function_state()->entry(); 7220 entry->set_arguments_pushed(); 7221 7222 HArgumentsObject* arguments = entry->arguments_object(); 7223 const ZoneList<HValue*>* arguments_values = arguments->arguments_values(); 7224 7225 HInstruction* insert_after = entry; 7226 for (int i = 0; i < arguments_values->length(); i++) { 7227 HValue* argument = arguments_values->at(i); 7228 HInstruction* push_argument = New<HPushArguments>(argument); 7229 push_argument->InsertAfter(insert_after); 7230 insert_after = push_argument; 7231 } 7232 7233 HArgumentsElements* arguments_elements = New<HArgumentsElements>(true); 7234 arguments_elements->ClearFlag(HValue::kUseGVN); 7235 arguments_elements->InsertAfter(insert_after); 7236 function_state()->set_arguments_elements(arguments_elements); 7237 } 7238 7239 7240 bool HOptimizedGraphBuilder::TryArgumentsAccess(Property* expr) { 7241 VariableProxy* proxy = expr->obj()->AsVariableProxy(); 7242 if (proxy == NULL) return false; 7243 if (!proxy->var()->IsStackAllocated()) return false; 7244 if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) { 7245 return false; 7246 } 7247 7248 HInstruction* result = NULL; 7249 if (expr->key()->IsPropertyName()) { 7250 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); 7251 if (!String::Equals(name, isolate()->factory()->length_string())) { 7252 return false; 7253 } 7254 7255 if (function_state()->outer() == NULL) { 7256 HInstruction* elements = Add<HArgumentsElements>(false); 7257 result = New<HArgumentsLength>(elements); 7258 } else { 7259 // Number of arguments without receiver. 7260 int argument_count = environment()-> 7261 arguments_environment()->parameter_count() - 1; 7262 result = New<HConstant>(argument_count); 7263 } 7264 } else { 7265 Push(graph()->GetArgumentsObject()); 7266 CHECK_ALIVE_OR_RETURN(VisitForValue(expr->key()), true); 7267 HValue* key = Pop(); 7268 Drop(1); // Arguments object. 7269 if (function_state()->outer() == NULL) { 7270 HInstruction* elements = Add<HArgumentsElements>(false); 7271 HInstruction* length = Add<HArgumentsLength>(elements); 7272 HInstruction* checked_key = Add<HBoundsCheck>(key, length); 7273 result = New<HAccessArgumentsAt>(elements, length, checked_key); 7274 } else { 7275 EnsureArgumentsArePushedForAccess(); 7276 7277 // Number of arguments without receiver. 7278 HInstruction* elements = function_state()->arguments_elements(); 7279 int argument_count = environment()-> 7280 arguments_environment()->parameter_count() - 1; 7281 HInstruction* length = Add<HConstant>(argument_count); 7282 HInstruction* checked_key = Add<HBoundsCheck>(key, length); 7283 result = New<HAccessArgumentsAt>(elements, length, checked_key); 7284 } 7285 } 7286 ast_context()->ReturnInstruction(result, expr->id()); 7287 return true; 7288 } 7289 7290 7291 HInstruction* HOptimizedGraphBuilder::BuildNamedAccess( 7292 PropertyAccessType access, 7293 BailoutId ast_id, 7294 BailoutId return_id, 7295 Expression* expr, 7296 HValue* object, 7297 Handle<String> name, 7298 HValue* value, 7299 bool is_uninitialized) { 7300 SmallMapList* types; 7301 ComputeReceiverTypes(expr, object, &types, zone()); 7302 DCHECK(types != NULL); 7303 7304 if (types->length() > 0) { 7305 PropertyAccessInfo info(this, access, ToType(types->first()), name); 7306 if (!info.CanAccessAsMonomorphic(types)) { 7307 HandlePolymorphicNamedFieldAccess( 7308 access, expr, ast_id, return_id, object, value, types, name); 7309 return NULL; 7310 } 7311 7312 HValue* checked_object; 7313 // Type::Number() is only supported by polymorphic load/call handling. 7314 DCHECK(!info.type()->Is(Type::Number())); 7315 BuildCheckHeapObject(object); 7316 if (AreStringTypes(types)) { 7317 checked_object = 7318 Add<HCheckInstanceType>(object, HCheckInstanceType::IS_STRING); 7319 } else { 7320 checked_object = Add<HCheckMaps>(object, types); 7321 } 7322 return BuildMonomorphicAccess( 7323 &info, object, checked_object, value, ast_id, return_id); 7324 } 7325 7326 return BuildNamedGeneric(access, expr, object, name, value, is_uninitialized); 7327 } 7328 7329 7330 void HOptimizedGraphBuilder::PushLoad(Property* expr, 7331 HValue* object, 7332 HValue* key) { 7333 ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED); 7334 Push(object); 7335 if (key != NULL) Push(key); 7336 BuildLoad(expr, expr->LoadId()); 7337 } 7338 7339 7340 void HOptimizedGraphBuilder::BuildLoad(Property* expr, 7341 BailoutId ast_id) { 7342 HInstruction* instr = NULL; 7343 if (expr->IsStringAccess()) { 7344 HValue* index = Pop(); 7345 HValue* string = Pop(); 7346 HInstruction* char_code = BuildStringCharCodeAt(string, index); 7347 AddInstruction(char_code); 7348 instr = NewUncasted<HStringCharFromCode>(char_code); 7349 7350 } else if (expr->key()->IsPropertyName()) { 7351 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); 7352 HValue* object = Pop(); 7353 7354 instr = BuildNamedAccess(LOAD, ast_id, expr->LoadId(), expr, 7355 object, name, NULL, expr->IsUninitialized()); 7356 if (instr == NULL) return; 7357 if (instr->IsLinked()) return ast_context()->ReturnValue(instr); 7358 7359 } else { 7360 HValue* key = Pop(); 7361 HValue* obj = Pop(); 7362 7363 bool has_side_effects = false; 7364 HValue* load = HandleKeyedElementAccess( 7365 obj, key, NULL, expr, ast_id, expr->LoadId(), LOAD, &has_side_effects); 7366 if (has_side_effects) { 7367 if (ast_context()->IsEffect()) { 7368 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); 7369 } else { 7370 Push(load); 7371 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); 7372 Drop(1); 7373 } 7374 } 7375 if (load == NULL) return; 7376 return ast_context()->ReturnValue(load); 7377 } 7378 return ast_context()->ReturnInstruction(instr, ast_id); 7379 } 7380 7381 7382 void HOptimizedGraphBuilder::VisitProperty(Property* expr) { 7383 DCHECK(!HasStackOverflow()); 7384 DCHECK(current_block() != NULL); 7385 DCHECK(current_block()->HasPredecessor()); 7386 7387 if (TryArgumentsAccess(expr)) return; 7388 7389 CHECK_ALIVE(VisitForValue(expr->obj())); 7390 if (!expr->key()->IsPropertyName() || expr->IsStringAccess()) { 7391 CHECK_ALIVE(VisitForValue(expr->key())); 7392 } 7393 7394 BuildLoad(expr, expr->id()); 7395 } 7396 7397 7398 HInstruction* HGraphBuilder::BuildConstantMapCheck(Handle<JSObject> constant) { 7399 HCheckMaps* check = Add<HCheckMaps>( 7400 Add<HConstant>(constant), handle(constant->map())); 7401 check->ClearDependsOnFlag(kElementsKind); 7402 return check; 7403 } 7404 7405 7406 HInstruction* HGraphBuilder::BuildCheckPrototypeMaps(Handle<JSObject> prototype, 7407 Handle<JSObject> holder) { 7408 PrototypeIterator iter(isolate(), prototype, 7409 PrototypeIterator::START_AT_RECEIVER); 7410 while (holder.is_null() || 7411 !PrototypeIterator::GetCurrent(iter).is_identical_to(holder)) { 7412 BuildConstantMapCheck( 7413 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter))); 7414 iter.Advance(); 7415 if (iter.IsAtEnd()) { 7416 return NULL; 7417 } 7418 } 7419 return BuildConstantMapCheck( 7420 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter))); 7421 } 7422 7423 7424 void HOptimizedGraphBuilder::AddCheckPrototypeMaps(Handle<JSObject> holder, 7425 Handle<Map> receiver_map) { 7426 if (!holder.is_null()) { 7427 Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype())); 7428 BuildCheckPrototypeMaps(prototype, holder); 7429 } 7430 } 7431 7432 7433 HInstruction* HOptimizedGraphBuilder::NewPlainFunctionCall( 7434 HValue* fun, int argument_count, bool pass_argument_count) { 7435 return New<HCallJSFunction>( 7436 fun, argument_count, pass_argument_count); 7437 } 7438 7439 7440 HInstruction* HOptimizedGraphBuilder::NewArgumentAdaptorCall( 7441 HValue* fun, HValue* context, 7442 int argument_count, HValue* expected_param_count) { 7443 ArgumentAdaptorDescriptor descriptor(isolate()); 7444 HValue* arity = Add<HConstant>(argument_count - 1); 7445 7446 HValue* op_vals[] = { context, fun, arity, expected_param_count }; 7447 7448 Handle<Code> adaptor = 7449 isolate()->builtins()->ArgumentsAdaptorTrampoline(); 7450 HConstant* adaptor_value = Add<HConstant>(adaptor); 7451 7452 return New<HCallWithDescriptor>( 7453 adaptor_value, argument_count, descriptor, 7454 Vector<HValue*>(op_vals, descriptor.GetEnvironmentLength())); 7455 } 7456 7457 7458 HInstruction* HOptimizedGraphBuilder::BuildCallConstantFunction( 7459 Handle<JSFunction> jsfun, int argument_count) { 7460 HValue* target = Add<HConstant>(jsfun); 7461 // For constant functions, we try to avoid calling the 7462 // argument adaptor and instead call the function directly 7463 int formal_parameter_count = jsfun->shared()->formal_parameter_count(); 7464 bool dont_adapt_arguments = 7465 (formal_parameter_count == 7466 SharedFunctionInfo::kDontAdaptArgumentsSentinel); 7467 int arity = argument_count - 1; 7468 bool can_invoke_directly = 7469 dont_adapt_arguments || formal_parameter_count == arity; 7470 if (can_invoke_directly) { 7471 if (jsfun.is_identical_to(current_info()->closure())) { 7472 graph()->MarkRecursive(); 7473 } 7474 return NewPlainFunctionCall(target, argument_count, dont_adapt_arguments); 7475 } else { 7476 HValue* param_count_value = Add<HConstant>(formal_parameter_count); 7477 HValue* context = Add<HLoadNamedField>( 7478 target, static_cast<HValue*>(NULL), 7479 HObjectAccess::ForFunctionContextPointer()); 7480 return NewArgumentAdaptorCall(target, context, 7481 argument_count, param_count_value); 7482 } 7483 UNREACHABLE(); 7484 return NULL; 7485 } 7486 7487 7488 class FunctionSorter { 7489 public: 7490 explicit FunctionSorter(int index = 0, int ticks = 0, int size = 0) 7491 : index_(index), ticks_(ticks), size_(size) {} 7492 7493 int index() const { return index_; } 7494 int ticks() const { return ticks_; } 7495 int size() const { return size_; } 7496 7497 private: 7498 int index_; 7499 int ticks_; 7500 int size_; 7501 }; 7502 7503 7504 inline bool operator<(const FunctionSorter& lhs, const FunctionSorter& rhs) { 7505 int diff = lhs.ticks() - rhs.ticks(); 7506 if (diff != 0) return diff > 0; 7507 return lhs.size() < rhs.size(); 7508 } 7509 7510 7511 void HOptimizedGraphBuilder::HandlePolymorphicCallNamed( 7512 Call* expr, 7513 HValue* receiver, 7514 SmallMapList* types, 7515 Handle<String> name) { 7516 int argument_count = expr->arguments()->length() + 1; // Includes receiver. 7517 FunctionSorter order[kMaxCallPolymorphism]; 7518 7519 bool handle_smi = false; 7520 bool handled_string = false; 7521 int ordered_functions = 0; 7522 7523 int i; 7524 for (i = 0; i < types->length() && ordered_functions < kMaxCallPolymorphism; 7525 ++i) { 7526 PropertyAccessInfo info(this, LOAD, ToType(types->at(i)), name); 7527 if (info.CanAccessMonomorphic() && info.IsConstant() && 7528 info.constant()->IsJSFunction()) { 7529 if (info.type()->Is(Type::String())) { 7530 if (handled_string) continue; 7531 handled_string = true; 7532 } 7533 Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant()); 7534 if (info.type()->Is(Type::Number())) { 7535 handle_smi = true; 7536 } 7537 expr->set_target(target); 7538 order[ordered_functions++] = FunctionSorter( 7539 i, target->shared()->profiler_ticks(), InliningAstSize(target)); 7540 } 7541 } 7542 7543 std::sort(order, order + ordered_functions); 7544 7545 if (i < types->length()) { 7546 types->Clear(); 7547 ordered_functions = -1; 7548 } 7549 7550 HBasicBlock* number_block = NULL; 7551 HBasicBlock* join = NULL; 7552 handled_string = false; 7553 int count = 0; 7554 7555 for (int fn = 0; fn < ordered_functions; ++fn) { 7556 int i = order[fn].index(); 7557 PropertyAccessInfo info(this, LOAD, ToType(types->at(i)), name); 7558 if (info.type()->Is(Type::String())) { 7559 if (handled_string) continue; 7560 handled_string = true; 7561 } 7562 // Reloads the target. 7563 info.CanAccessMonomorphic(); 7564 Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant()); 7565 7566 expr->set_target(target); 7567 if (count == 0) { 7568 // Only needed once. 7569 join = graph()->CreateBasicBlock(); 7570 if (handle_smi) { 7571 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); 7572 HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); 7573 number_block = graph()->CreateBasicBlock(); 7574 FinishCurrentBlock(New<HIsSmiAndBranch>( 7575 receiver, empty_smi_block, not_smi_block)); 7576 GotoNoSimulate(empty_smi_block, number_block); 7577 set_current_block(not_smi_block); 7578 } else { 7579 BuildCheckHeapObject(receiver); 7580 } 7581 } 7582 ++count; 7583 HBasicBlock* if_true = graph()->CreateBasicBlock(); 7584 HBasicBlock* if_false = graph()->CreateBasicBlock(); 7585 HUnaryControlInstruction* compare; 7586 7587 Handle<Map> map = info.map(); 7588 if (info.type()->Is(Type::Number())) { 7589 Handle<Map> heap_number_map = isolate()->factory()->heap_number_map(); 7590 compare = New<HCompareMap>(receiver, heap_number_map, if_true, if_false); 7591 } else if (info.type()->Is(Type::String())) { 7592 compare = New<HIsStringAndBranch>(receiver, if_true, if_false); 7593 } else { 7594 compare = New<HCompareMap>(receiver, map, if_true, if_false); 7595 } 7596 FinishCurrentBlock(compare); 7597 7598 if (info.type()->Is(Type::Number())) { 7599 GotoNoSimulate(if_true, number_block); 7600 if_true = number_block; 7601 } 7602 7603 set_current_block(if_true); 7604 7605 AddCheckPrototypeMaps(info.holder(), map); 7606 7607 HValue* function = Add<HConstant>(expr->target()); 7608 environment()->SetExpressionStackAt(0, function); 7609 Push(receiver); 7610 CHECK_ALIVE(VisitExpressions(expr->arguments())); 7611 bool needs_wrapping = NeedsWrappingFor(info.type(), target); 7612 bool try_inline = FLAG_polymorphic_inlining && !needs_wrapping; 7613 if (FLAG_trace_inlining && try_inline) { 7614 Handle<JSFunction> caller = current_info()->closure(); 7615 SmartArrayPointer<char> caller_name = 7616 caller->shared()->DebugName()->ToCString(); 7617 PrintF("Trying to inline the polymorphic call to %s from %s\n", 7618 name->ToCString().get(), 7619 caller_name.get()); 7620 } 7621 if (try_inline && TryInlineCall(expr)) { 7622 // Trying to inline will signal that we should bailout from the 7623 // entire compilation by setting stack overflow on the visitor. 7624 if (HasStackOverflow()) return; 7625 } else { 7626 // Since HWrapReceiver currently cannot actually wrap numbers and strings, 7627 // use the regular CallFunctionStub for method calls to wrap the receiver. 7628 // TODO(verwaest): Support creation of value wrappers directly in 7629 // HWrapReceiver. 7630 HInstruction* call = needs_wrapping 7631 ? NewUncasted<HCallFunction>( 7632 function, argument_count, WRAP_AND_CALL) 7633 : BuildCallConstantFunction(target, argument_count); 7634 PushArgumentsFromEnvironment(argument_count); 7635 AddInstruction(call); 7636 Drop(1); // Drop the function. 7637 if (!ast_context()->IsEffect()) Push(call); 7638 } 7639 7640 if (current_block() != NULL) Goto(join); 7641 set_current_block(if_false); 7642 } 7643 7644 // Finish up. Unconditionally deoptimize if we've handled all the maps we 7645 // know about and do not want to handle ones we've never seen. Otherwise 7646 // use a generic IC. 7647 if (ordered_functions == types->length() && FLAG_deoptimize_uncommon_cases) { 7648 FinishExitWithHardDeoptimization("Unknown map in polymorphic call"); 7649 } else { 7650 Property* prop = expr->expression()->AsProperty(); 7651 HInstruction* function = BuildNamedGeneric( 7652 LOAD, prop, receiver, name, NULL, prop->IsUninitialized()); 7653 AddInstruction(function); 7654 Push(function); 7655 AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE); 7656 7657 environment()->SetExpressionStackAt(1, function); 7658 environment()->SetExpressionStackAt(0, receiver); 7659 CHECK_ALIVE(VisitExpressions(expr->arguments())); 7660 7661 CallFunctionFlags flags = receiver->type().IsJSObject() 7662 ? NO_CALL_FUNCTION_FLAGS : CALL_AS_METHOD; 7663 HInstruction* call = New<HCallFunction>( 7664 function, argument_count, flags); 7665 7666 PushArgumentsFromEnvironment(argument_count); 7667 7668 Drop(1); // Function. 7669 7670 if (join != NULL) { 7671 AddInstruction(call); 7672 if (!ast_context()->IsEffect()) Push(call); 7673 Goto(join); 7674 } else { 7675 return ast_context()->ReturnInstruction(call, expr->id()); 7676 } 7677 } 7678 7679 // We assume that control flow is always live after an expression. So 7680 // even without predecessors to the join block, we set it as the exit 7681 // block and continue by adding instructions there. 7682 DCHECK(join != NULL); 7683 if (join->HasPredecessor()) { 7684 set_current_block(join); 7685 join->SetJoinId(expr->id()); 7686 if (!ast_context()->IsEffect()) return ast_context()->ReturnValue(Pop()); 7687 } else { 7688 set_current_block(NULL); 7689 } 7690 } 7691 7692 7693 void HOptimizedGraphBuilder::TraceInline(Handle<JSFunction> target, 7694 Handle<JSFunction> caller, 7695 const char* reason) { 7696 if (FLAG_trace_inlining) { 7697 SmartArrayPointer<char> target_name = 7698 target->shared()->DebugName()->ToCString(); 7699 SmartArrayPointer<char> caller_name = 7700 caller->shared()->DebugName()->ToCString(); 7701 if (reason == NULL) { 7702 PrintF("Inlined %s called from %s.\n", target_name.get(), 7703 caller_name.get()); 7704 } else { 7705 PrintF("Did not inline %s called from %s (%s).\n", 7706 target_name.get(), caller_name.get(), reason); 7707 } 7708 } 7709 } 7710 7711 7712 static const int kNotInlinable = 1000000000; 7713 7714 7715 int HOptimizedGraphBuilder::InliningAstSize(Handle<JSFunction> target) { 7716 if (!FLAG_use_inlining) return kNotInlinable; 7717 7718 // Precondition: call is monomorphic and we have found a target with the 7719 // appropriate arity. 7720 Handle<JSFunction> caller = current_info()->closure(); 7721 Handle<SharedFunctionInfo> target_shared(target->shared()); 7722 7723 // Always inline builtins marked for inlining. 7724 if (target->IsBuiltin()) { 7725 return target_shared->inline_builtin() ? 0 : kNotInlinable; 7726 } 7727 7728 if (target_shared->IsApiFunction()) { 7729 TraceInline(target, caller, "target is api function"); 7730 return kNotInlinable; 7731 } 7732 7733 // Do a quick check on source code length to avoid parsing large 7734 // inlining candidates. 7735 if (target_shared->SourceSize() > 7736 Min(FLAG_max_inlined_source_size, kUnlimitedMaxInlinedSourceSize)) { 7737 TraceInline(target, caller, "target text too big"); 7738 return kNotInlinable; 7739 } 7740 7741 // Target must be inlineable. 7742 if (!target_shared->IsInlineable()) { 7743 TraceInline(target, caller, "target not inlineable"); 7744 return kNotInlinable; 7745 } 7746 if (target_shared->DisableOptimizationReason() != kNoReason) { 7747 TraceInline(target, caller, "target contains unsupported syntax [early]"); 7748 return kNotInlinable; 7749 } 7750 7751 int nodes_added = target_shared->ast_node_count(); 7752 return nodes_added; 7753 } 7754 7755 7756 bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target, 7757 int arguments_count, 7758 HValue* implicit_return_value, 7759 BailoutId ast_id, 7760 BailoutId return_id, 7761 InliningKind inlining_kind, 7762 HSourcePosition position) { 7763 int nodes_added = InliningAstSize(target); 7764 if (nodes_added == kNotInlinable) return false; 7765 7766 Handle<JSFunction> caller = current_info()->closure(); 7767 7768 if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) { 7769 TraceInline(target, caller, "target AST is too large [early]"); 7770 return false; 7771 } 7772 7773 // Don't inline deeper than the maximum number of inlining levels. 7774 HEnvironment* env = environment(); 7775 int current_level = 1; 7776 while (env->outer() != NULL) { 7777 if (current_level == FLAG_max_inlining_levels) { 7778 TraceInline(target, caller, "inline depth limit reached"); 7779 return false; 7780 } 7781 if (env->outer()->frame_type() == JS_FUNCTION) { 7782 current_level++; 7783 } 7784 env = env->outer(); 7785 } 7786 7787 // Don't inline recursive functions. 7788 for (FunctionState* state = function_state(); 7789 state != NULL; 7790 state = state->outer()) { 7791 if (*state->compilation_info()->closure() == *target) { 7792 TraceInline(target, caller, "target is recursive"); 7793 return false; 7794 } 7795 } 7796 7797 // We don't want to add more than a certain number of nodes from inlining. 7798 if (inlined_count_ > Min(FLAG_max_inlined_nodes_cumulative, 7799 kUnlimitedMaxInlinedNodesCumulative)) { 7800 TraceInline(target, caller, "cumulative AST node limit reached"); 7801 return false; 7802 } 7803 7804 // Parse and allocate variables. 7805 CompilationInfo target_info(target, zone()); 7806 // Use the same AstValueFactory for creating strings in the sub-compilation 7807 // step, but don't transfer ownership to target_info. 7808 target_info.SetAstValueFactory(top_info()->ast_value_factory(), false); 7809 Handle<SharedFunctionInfo> target_shared(target->shared()); 7810 if (!Parser::Parse(&target_info) || !Scope::Analyze(&target_info)) { 7811 if (target_info.isolate()->has_pending_exception()) { 7812 // Parse or scope error, never optimize this function. 7813 SetStackOverflow(); 7814 target_shared->DisableOptimization(kParseScopeError); 7815 } 7816 TraceInline(target, caller, "parse failure"); 7817 return false; 7818 } 7819 7820 if (target_info.scope()->num_heap_slots() > 0) { 7821 TraceInline(target, caller, "target has context-allocated variables"); 7822 return false; 7823 } 7824 FunctionLiteral* function = target_info.function(); 7825 7826 // The following conditions must be checked again after re-parsing, because 7827 // earlier the information might not have been complete due to lazy parsing. 7828 nodes_added = function->ast_node_count(); 7829 if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) { 7830 TraceInline(target, caller, "target AST is too large [late]"); 7831 return false; 7832 } 7833 if (function->dont_optimize()) { 7834 TraceInline(target, caller, "target contains unsupported syntax [late]"); 7835 return false; 7836 } 7837 7838 // If the function uses the arguments object check that inlining of functions 7839 // with arguments object is enabled and the arguments-variable is 7840 // stack allocated. 7841 if (function->scope()->arguments() != NULL) { 7842 if (!FLAG_inline_arguments) { 7843 TraceInline(target, caller, "target uses arguments object"); 7844 return false; 7845 } 7846 7847 if (!function->scope()->arguments()->IsStackAllocated()) { 7848 TraceInline(target, 7849 caller, 7850 "target uses non-stackallocated arguments object"); 7851 return false; 7852 } 7853 } 7854 7855 // All declarations must be inlineable. 7856 ZoneList<Declaration*>* decls = target_info.scope()->declarations(); 7857 int decl_count = decls->length(); 7858 for (int i = 0; i < decl_count; ++i) { 7859 if (!decls->at(i)->IsInlineable()) { 7860 TraceInline(target, caller, "target has non-trivial declaration"); 7861 return false; 7862 } 7863 } 7864 7865 // Generate the deoptimization data for the unoptimized version of 7866 // the target function if we don't already have it. 7867 if (!Compiler::EnsureDeoptimizationSupport(&target_info)) { 7868 TraceInline(target, caller, "could not generate deoptimization info"); 7869 return false; 7870 } 7871 7872 // ---------------------------------------------------------------- 7873 // After this point, we've made a decision to inline this function (so 7874 // TryInline should always return true). 7875 7876 // Type-check the inlined function. 7877 DCHECK(target_shared->has_deoptimization_support()); 7878 AstTyper::Run(&target_info); 7879 7880 int function_id = graph()->TraceInlinedFunction(target_shared, position); 7881 7882 // Save the pending call context. Set up new one for the inlined function. 7883 // The function state is new-allocated because we need to delete it 7884 // in two different places. 7885 FunctionState* target_state = new FunctionState( 7886 this, &target_info, inlining_kind, function_id); 7887 7888 HConstant* undefined = graph()->GetConstantUndefined(); 7889 7890 HEnvironment* inner_env = 7891 environment()->CopyForInlining(target, 7892 arguments_count, 7893 function, 7894 undefined, 7895 function_state()->inlining_kind()); 7896 7897 HConstant* context = Add<HConstant>(Handle<Context>(target->context())); 7898 inner_env->BindContext(context); 7899 7900 // Create a dematerialized arguments object for the function, also copy the 7901 // current arguments values to use them for materialization. 7902 HEnvironment* arguments_env = inner_env->arguments_environment(); 7903 int parameter_count = arguments_env->parameter_count(); 7904 HArgumentsObject* arguments_object = Add<HArgumentsObject>(parameter_count); 7905 for (int i = 0; i < parameter_count; i++) { 7906 arguments_object->AddArgument(arguments_env->Lookup(i), zone()); 7907 } 7908 7909 // If the function uses arguments object then bind bind one. 7910 if (function->scope()->arguments() != NULL) { 7911 DCHECK(function->scope()->arguments()->IsStackAllocated()); 7912 inner_env->Bind(function->scope()->arguments(), arguments_object); 7913 } 7914 7915 // Capture the state before invoking the inlined function for deopt in the 7916 // inlined function. This simulate has no bailout-id since it's not directly 7917 // reachable for deopt, and is only used to capture the state. If the simulate 7918 // becomes reachable by merging, the ast id of the simulate merged into it is 7919 // adopted. 7920 Add<HSimulate>(BailoutId::None()); 7921 7922 current_block()->UpdateEnvironment(inner_env); 7923 Scope* saved_scope = scope(); 7924 set_scope(target_info.scope()); 7925 HEnterInlined* enter_inlined = 7926 Add<HEnterInlined>(return_id, target, context, arguments_count, function, 7927 function_state()->inlining_kind(), 7928 function->scope()->arguments(), arguments_object); 7929 function_state()->set_entry(enter_inlined); 7930 7931 VisitDeclarations(target_info.scope()->declarations()); 7932 VisitStatements(function->body()); 7933 set_scope(saved_scope); 7934 if (HasStackOverflow()) { 7935 // Bail out if the inline function did, as we cannot residualize a call 7936 // instead, but do not disable optimization for the outer function. 7937 TraceInline(target, caller, "inline graph construction failed"); 7938 target_shared->DisableOptimization(kInliningBailedOut); 7939 current_info()->RetryOptimization(kInliningBailedOut); 7940 delete target_state; 7941 return true; 7942 } 7943 7944 // Update inlined nodes count. 7945 inlined_count_ += nodes_added; 7946 7947 Handle<Code> unoptimized_code(target_shared->code()); 7948 DCHECK(unoptimized_code->kind() == Code::FUNCTION); 7949 Handle<TypeFeedbackInfo> type_info( 7950 TypeFeedbackInfo::cast(unoptimized_code->type_feedback_info())); 7951 graph()->update_type_change_checksum(type_info->own_type_change_checksum()); 7952 7953 TraceInline(target, caller, NULL); 7954 7955 if (current_block() != NULL) { 7956 FunctionState* state = function_state(); 7957 if (state->inlining_kind() == CONSTRUCT_CALL_RETURN) { 7958 // Falling off the end of an inlined construct call. In a test context the 7959 // return value will always evaluate to true, in a value context the 7960 // return value is the newly allocated receiver. 7961 if (call_context()->IsTest()) { 7962 Goto(inlined_test_context()->if_true(), state); 7963 } else if (call_context()->IsEffect()) { 7964 Goto(function_return(), state); 7965 } else { 7966 DCHECK(call_context()->IsValue()); 7967 AddLeaveInlined(implicit_return_value, state); 7968 } 7969 } else if (state->inlining_kind() == SETTER_CALL_RETURN) { 7970 // Falling off the end of an inlined setter call. The returned value is 7971 // never used, the value of an assignment is always the value of the RHS 7972 // of the assignment. 7973 if (call_context()->IsTest()) { 7974 inlined_test_context()->ReturnValue(implicit_return_value); 7975 } else if (call_context()->IsEffect()) { 7976 Goto(function_return(), state); 7977 } else { 7978 DCHECK(call_context()->IsValue()); 7979 AddLeaveInlined(implicit_return_value, state); 7980 } 7981 } else { 7982 // Falling off the end of a normal inlined function. This basically means 7983 // returning undefined. 7984 if (call_context()->IsTest()) { 7985 Goto(inlined_test_context()->if_false(), state); 7986 } else if (call_context()->IsEffect()) { 7987 Goto(function_return(), state); 7988 } else { 7989 DCHECK(call_context()->IsValue()); 7990 AddLeaveInlined(undefined, state); 7991 } 7992 } 7993 } 7994 7995 // Fix up the function exits. 7996 if (inlined_test_context() != NULL) { 7997 HBasicBlock* if_true = inlined_test_context()->if_true(); 7998 HBasicBlock* if_false = inlined_test_context()->if_false(); 7999 8000 HEnterInlined* entry = function_state()->entry(); 8001 8002 // Pop the return test context from the expression context stack. 8003 DCHECK(ast_context() == inlined_test_context()); 8004 ClearInlinedTestContext(); 8005 delete target_state; 8006 8007 // Forward to the real test context. 8008 if (if_true->HasPredecessor()) { 8009 entry->RegisterReturnTarget(if_true, zone()); 8010 if_true->SetJoinId(ast_id); 8011 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); 8012 Goto(if_true, true_target, function_state()); 8013 } 8014 if (if_false->HasPredecessor()) { 8015 entry->RegisterReturnTarget(if_false, zone()); 8016 if_false->SetJoinId(ast_id); 8017 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); 8018 Goto(if_false, false_target, function_state()); 8019 } 8020 set_current_block(NULL); 8021 return true; 8022 8023 } else if (function_return()->HasPredecessor()) { 8024 function_state()->entry()->RegisterReturnTarget(function_return(), zone()); 8025 function_return()->SetJoinId(ast_id); 8026 set_current_block(function_return()); 8027 } else { 8028 set_current_block(NULL); 8029 } 8030 delete target_state; 8031 return true; 8032 } 8033 8034 8035 bool HOptimizedGraphBuilder::TryInlineCall(Call* expr) { 8036 return TryInline(expr->target(), 8037 expr->arguments()->length(), 8038 NULL, 8039 expr->id(), 8040 expr->ReturnId(), 8041 NORMAL_RETURN, 8042 ScriptPositionToSourcePosition(expr->position())); 8043 } 8044 8045 8046 bool HOptimizedGraphBuilder::TryInlineConstruct(CallNew* expr, 8047 HValue* implicit_return_value) { 8048 return TryInline(expr->target(), 8049 expr->arguments()->length(), 8050 implicit_return_value, 8051 expr->id(), 8052 expr->ReturnId(), 8053 CONSTRUCT_CALL_RETURN, 8054 ScriptPositionToSourcePosition(expr->position())); 8055 } 8056 8057 8058 bool HOptimizedGraphBuilder::TryInlineGetter(Handle<JSFunction> getter, 8059 Handle<Map> receiver_map, 8060 BailoutId ast_id, 8061 BailoutId return_id) { 8062 if (TryInlineApiGetter(getter, receiver_map, ast_id)) return true; 8063 return TryInline(getter, 8064 0, 8065 NULL, 8066 ast_id, 8067 return_id, 8068 GETTER_CALL_RETURN, 8069 source_position()); 8070 } 8071 8072 8073 bool HOptimizedGraphBuilder::TryInlineSetter(Handle<JSFunction> setter, 8074 Handle<Map> receiver_map, 8075 BailoutId id, 8076 BailoutId assignment_id, 8077 HValue* implicit_return_value) { 8078 if (TryInlineApiSetter(setter, receiver_map, id)) return true; 8079 return TryInline(setter, 8080 1, 8081 implicit_return_value, 8082 id, assignment_id, 8083 SETTER_CALL_RETURN, 8084 source_position()); 8085 } 8086 8087 8088 bool HOptimizedGraphBuilder::TryInlineApply(Handle<JSFunction> function, 8089 Call* expr, 8090 int arguments_count) { 8091 return TryInline(function, 8092 arguments_count, 8093 NULL, 8094 expr->id(), 8095 expr->ReturnId(), 8096 NORMAL_RETURN, 8097 ScriptPositionToSourcePosition(expr->position())); 8098 } 8099 8100 8101 bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr) { 8102 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; 8103 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); 8104 switch (id) { 8105 case kMathExp: 8106 if (!FLAG_fast_math) break; 8107 // Fall through if FLAG_fast_math. 8108 case kMathRound: 8109 case kMathFround: 8110 case kMathFloor: 8111 case kMathAbs: 8112 case kMathSqrt: 8113 case kMathLog: 8114 case kMathClz32: 8115 if (expr->arguments()->length() == 1) { 8116 HValue* argument = Pop(); 8117 Drop(2); // Receiver and function. 8118 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); 8119 ast_context()->ReturnInstruction(op, expr->id()); 8120 return true; 8121 } 8122 break; 8123 case kMathImul: 8124 if (expr->arguments()->length() == 2) { 8125 HValue* right = Pop(); 8126 HValue* left = Pop(); 8127 Drop(2); // Receiver and function. 8128 HInstruction* op = HMul::NewImul(zone(), context(), left, right); 8129 ast_context()->ReturnInstruction(op, expr->id()); 8130 return true; 8131 } 8132 break; 8133 default: 8134 // Not supported for inlining yet. 8135 break; 8136 } 8137 return false; 8138 } 8139 8140 8141 bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( 8142 Call* expr, 8143 HValue* receiver, 8144 Handle<Map> receiver_map) { 8145 // Try to inline calls like Math.* as operations in the calling function. 8146 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; 8147 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); 8148 int argument_count = expr->arguments()->length() + 1; // Plus receiver. 8149 switch (id) { 8150 case kStringCharCodeAt: 8151 case kStringCharAt: 8152 if (argument_count == 2) { 8153 HValue* index = Pop(); 8154 HValue* string = Pop(); 8155 Drop(1); // Function. 8156 HInstruction* char_code = 8157 BuildStringCharCodeAt(string, index); 8158 if (id == kStringCharCodeAt) { 8159 ast_context()->ReturnInstruction(char_code, expr->id()); 8160 return true; 8161 } 8162 AddInstruction(char_code); 8163 HInstruction* result = NewUncasted<HStringCharFromCode>(char_code); 8164 ast_context()->ReturnInstruction(result, expr->id()); 8165 return true; 8166 } 8167 break; 8168 case kStringFromCharCode: 8169 if (argument_count == 2) { 8170 HValue* argument = Pop(); 8171 Drop(2); // Receiver and function. 8172 HInstruction* result = NewUncasted<HStringCharFromCode>(argument); 8173 ast_context()->ReturnInstruction(result, expr->id()); 8174 return true; 8175 } 8176 break; 8177 case kMathExp: 8178 if (!FLAG_fast_math) break; 8179 // Fall through if FLAG_fast_math. 8180 case kMathRound: 8181 case kMathFround: 8182 case kMathFloor: 8183 case kMathAbs: 8184 case kMathSqrt: 8185 case kMathLog: 8186 case kMathClz32: 8187 if (argument_count == 2) { 8188 HValue* argument = Pop(); 8189 Drop(2); // Receiver and function. 8190 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); 8191 ast_context()->ReturnInstruction(op, expr->id()); 8192 return true; 8193 } 8194 break; 8195 case kMathPow: 8196 if (argument_count == 3) { 8197 HValue* right = Pop(); 8198 HValue* left = Pop(); 8199 Drop(2); // Receiver and function. 8200 HInstruction* result = NULL; 8201 // Use sqrt() if exponent is 0.5 or -0.5. 8202 if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { 8203 double exponent = HConstant::cast(right)->DoubleValue(); 8204 if (exponent == 0.5) { 8205 result = NewUncasted<HUnaryMathOperation>(left, kMathPowHalf); 8206 } else if (exponent == -0.5) { 8207 HValue* one = graph()->GetConstant1(); 8208 HInstruction* sqrt = AddUncasted<HUnaryMathOperation>( 8209 left, kMathPowHalf); 8210 // MathPowHalf doesn't have side effects so there's no need for 8211 // an environment simulation here. 8212 DCHECK(!sqrt->HasObservableSideEffects()); 8213 result = NewUncasted<HDiv>(one, sqrt); 8214 } else if (exponent == 2.0) { 8215 result = NewUncasted<HMul>(left, left); 8216 } 8217 } 8218 8219 if (result == NULL) { 8220 result = NewUncasted<HPower>(left, right); 8221 } 8222 ast_context()->ReturnInstruction(result, expr->id()); 8223 return true; 8224 } 8225 break; 8226 case kMathMax: 8227 case kMathMin: 8228 if (argument_count == 3) { 8229 HValue* right = Pop(); 8230 HValue* left = Pop(); 8231 Drop(2); // Receiver and function. 8232 HMathMinMax::Operation op = (id == kMathMin) ? HMathMinMax::kMathMin 8233 : HMathMinMax::kMathMax; 8234 HInstruction* result = NewUncasted<HMathMinMax>(left, right, op); 8235 ast_context()->ReturnInstruction(result, expr->id()); 8236 return true; 8237 } 8238 break; 8239 case kMathImul: 8240 if (argument_count == 3) { 8241 HValue* right = Pop(); 8242 HValue* left = Pop(); 8243 Drop(2); // Receiver and function. 8244 HInstruction* result = HMul::NewImul(zone(), context(), left, right); 8245 ast_context()->ReturnInstruction(result, expr->id()); 8246 return true; 8247 } 8248 break; 8249 case kArrayPop: { 8250 if (receiver_map.is_null()) return false; 8251 if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false; 8252 ElementsKind elements_kind = receiver_map->elements_kind(); 8253 if (!IsFastElementsKind(elements_kind)) return false; 8254 if (receiver_map->is_observed()) return false; 8255 if (!receiver_map->is_extensible()) return false; 8256 8257 Drop(expr->arguments()->length()); 8258 HValue* result; 8259 HValue* reduced_length; 8260 HValue* receiver = Pop(); 8261 8262 HValue* checked_object = AddCheckMap(receiver, receiver_map); 8263 HValue* length = Add<HLoadNamedField>( 8264 checked_object, static_cast<HValue*>(NULL), 8265 HObjectAccess::ForArrayLength(elements_kind)); 8266 8267 Drop(1); // Function. 8268 8269 { NoObservableSideEffectsScope scope(this); 8270 IfBuilder length_checker(this); 8271 8272 HValue* bounds_check = length_checker.If<HCompareNumericAndBranch>( 8273 length, graph()->GetConstant0(), Token::EQ); 8274 length_checker.Then(); 8275 8276 if (!ast_context()->IsEffect()) Push(graph()->GetConstantUndefined()); 8277 8278 length_checker.Else(); 8279 HValue* elements = AddLoadElements(checked_object); 8280 // Ensure that we aren't popping from a copy-on-write array. 8281 if (IsFastSmiOrObjectElementsKind(elements_kind)) { 8282 elements = BuildCopyElementsOnWrite(checked_object, elements, 8283 elements_kind, length); 8284 } 8285 reduced_length = AddUncasted<HSub>(length, graph()->GetConstant1()); 8286 result = AddElementAccess(elements, reduced_length, NULL, 8287 bounds_check, elements_kind, LOAD); 8288 Factory* factory = isolate()->factory(); 8289 double nan_double = FixedDoubleArray::hole_nan_as_double(); 8290 HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind) 8291 ? Add<HConstant>(factory->the_hole_value()) 8292 : Add<HConstant>(nan_double); 8293 if (IsFastSmiOrObjectElementsKind(elements_kind)) { 8294 elements_kind = FAST_HOLEY_ELEMENTS; 8295 } 8296 AddElementAccess( 8297 elements, reduced_length, hole, bounds_check, elements_kind, STORE); 8298 Add<HStoreNamedField>( 8299 checked_object, HObjectAccess::ForArrayLength(elements_kind), 8300 reduced_length, STORE_TO_INITIALIZED_ENTRY); 8301 8302 if (!ast_context()->IsEffect()) Push(result); 8303 8304 length_checker.End(); 8305 } 8306 result = ast_context()->IsEffect() ? graph()->GetConstant0() : Top(); 8307 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); 8308 if (!ast_context()->IsEffect()) Drop(1); 8309 8310 ast_context()->ReturnValue(result); 8311 return true; 8312 } 8313 case kArrayPush: { 8314 if (receiver_map.is_null()) return false; 8315 if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false; 8316 ElementsKind elements_kind = receiver_map->elements_kind(); 8317 if (!IsFastElementsKind(elements_kind)) return false; 8318 if (receiver_map->is_observed()) return false; 8319 if (JSArray::IsReadOnlyLengthDescriptor(receiver_map)) return false; 8320 if (!receiver_map->is_extensible()) return false; 8321 8322 // If there may be elements accessors in the prototype chain, the fast 8323 // inlined version can't be used. 8324 if (receiver_map->DictionaryElementsInPrototypeChainOnly()) return false; 8325 // If there currently can be no elements accessors on the prototype chain, 8326 // it doesn't mean that there won't be any later. Install a full prototype 8327 // chain check to trap element accessors being installed on the prototype 8328 // chain, which would cause elements to go to dictionary mode and result 8329 // in a map change. 8330 Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype())); 8331 BuildCheckPrototypeMaps(prototype, Handle<JSObject>()); 8332 8333 const int argc = expr->arguments()->length(); 8334 if (argc != 1) return false; 8335 8336 HValue* value_to_push = Pop(); 8337 HValue* array = Pop(); 8338 Drop(1); // Drop function. 8339 8340 HInstruction* new_size = NULL; 8341 HValue* length = NULL; 8342 8343 { 8344 NoObservableSideEffectsScope scope(this); 8345 8346 length = Add<HLoadNamedField>(array, static_cast<HValue*>(NULL), 8347 HObjectAccess::ForArrayLength(elements_kind)); 8348 8349 new_size = AddUncasted<HAdd>(length, graph()->GetConstant1()); 8350 8351 bool is_array = receiver_map->instance_type() == JS_ARRAY_TYPE; 8352 BuildUncheckedMonomorphicElementAccess(array, length, 8353 value_to_push, is_array, 8354 elements_kind, STORE, 8355 NEVER_RETURN_HOLE, 8356 STORE_AND_GROW_NO_TRANSITION); 8357 8358 if (!ast_context()->IsEffect()) Push(new_size); 8359 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); 8360 if (!ast_context()->IsEffect()) Drop(1); 8361 } 8362 8363 ast_context()->ReturnValue(new_size); 8364 return true; 8365 } 8366 case kArrayShift: { 8367 if (receiver_map.is_null()) return false; 8368 if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false; 8369 ElementsKind kind = receiver_map->elements_kind(); 8370 if (!IsFastElementsKind(kind)) return false; 8371 if (receiver_map->is_observed()) return false; 8372 if (!receiver_map->is_extensible()) return false; 8373 8374 // If there may be elements accessors in the prototype chain, the fast 8375 // inlined version can't be used. 8376 if (receiver_map->DictionaryElementsInPrototypeChainOnly()) return false; 8377 8378 // If there currently can be no elements accessors on the prototype chain, 8379 // it doesn't mean that there won't be any later. Install a full prototype 8380 // chain check to trap element accessors being installed on the prototype 8381 // chain, which would cause elements to go to dictionary mode and result 8382 // in a map change. 8383 BuildCheckPrototypeMaps( 8384 handle(JSObject::cast(receiver_map->prototype()), isolate()), 8385 Handle<JSObject>::null()); 8386 8387 // Threshold for fast inlined Array.shift(). 8388 HConstant* inline_threshold = Add<HConstant>(static_cast<int32_t>(16)); 8389 8390 Drop(expr->arguments()->length()); 8391 HValue* receiver = Pop(); 8392 HValue* function = Pop(); 8393 HValue* result; 8394 8395 { 8396 NoObservableSideEffectsScope scope(this); 8397 8398 HValue* length = Add<HLoadNamedField>( 8399 receiver, static_cast<HValue*>(NULL), 8400 HObjectAccess::ForArrayLength(kind)); 8401 8402 IfBuilder if_lengthiszero(this); 8403 HValue* lengthiszero = if_lengthiszero.If<HCompareNumericAndBranch>( 8404 length, graph()->GetConstant0(), Token::EQ); 8405 if_lengthiszero.Then(); 8406 { 8407 if (!ast_context()->IsEffect()) Push(graph()->GetConstantUndefined()); 8408 } 8409 if_lengthiszero.Else(); 8410 { 8411 HValue* elements = AddLoadElements(receiver); 8412 8413 // Check if we can use the fast inlined Array.shift(). 8414 IfBuilder if_inline(this); 8415 if_inline.If<HCompareNumericAndBranch>( 8416 length, inline_threshold, Token::LTE); 8417 if (IsFastSmiOrObjectElementsKind(kind)) { 8418 // We cannot handle copy-on-write backing stores here. 8419 if_inline.AndIf<HCompareMap>( 8420 elements, isolate()->factory()->fixed_array_map()); 8421 } 8422 if_inline.Then(); 8423 { 8424 // Remember the result. 8425 if (!ast_context()->IsEffect()) { 8426 Push(AddElementAccess(elements, graph()->GetConstant0(), NULL, 8427 lengthiszero, kind, LOAD)); 8428 } 8429 8430 // Compute the new length. 8431 HValue* new_length = AddUncasted<HSub>( 8432 length, graph()->GetConstant1()); 8433 new_length->ClearFlag(HValue::kCanOverflow); 8434 8435 // Copy the remaining elements. 8436 LoopBuilder loop(this, context(), LoopBuilder::kPostIncrement); 8437 { 8438 HValue* new_key = loop.BeginBody( 8439 graph()->GetConstant0(), new_length, Token::LT); 8440 HValue* key = AddUncasted<HAdd>(new_key, graph()->GetConstant1()); 8441 key->ClearFlag(HValue::kCanOverflow); 8442 HValue* element = AddUncasted<HLoadKeyed>( 8443 elements, key, lengthiszero, kind, ALLOW_RETURN_HOLE); 8444 HStoreKeyed* store = Add<HStoreKeyed>( 8445 elements, new_key, element, kind); 8446 store->SetFlag(HValue::kAllowUndefinedAsNaN); 8447 } 8448 loop.EndBody(); 8449 8450 // Put a hole at the end. 8451 HValue* hole = IsFastSmiOrObjectElementsKind(kind) 8452 ? Add<HConstant>(isolate()->factory()->the_hole_value()) 8453 : Add<HConstant>(FixedDoubleArray::hole_nan_as_double()); 8454 if (IsFastSmiOrObjectElementsKind(kind)) kind = FAST_HOLEY_ELEMENTS; 8455 Add<HStoreKeyed>( 8456 elements, new_length, hole, kind, INITIALIZING_STORE); 8457 8458 // Remember new length. 8459 Add<HStoreNamedField>( 8460 receiver, HObjectAccess::ForArrayLength(kind), 8461 new_length, STORE_TO_INITIALIZED_ENTRY); 8462 } 8463 if_inline.Else(); 8464 { 8465 Add<HPushArguments>(receiver); 8466 result = Add<HCallJSFunction>(function, 1, true); 8467 if (!ast_context()->IsEffect()) Push(result); 8468 } 8469 if_inline.End(); 8470 } 8471 if_lengthiszero.End(); 8472 } 8473 result = ast_context()->IsEffect() ? graph()->GetConstant0() : Top(); 8474 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); 8475 if (!ast_context()->IsEffect()) Drop(1); 8476 ast_context()->ReturnValue(result); 8477 return true; 8478 } 8479 case kArrayIndexOf: 8480 case kArrayLastIndexOf: { 8481 if (receiver_map.is_null()) return false; 8482 if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false; 8483 ElementsKind kind = receiver_map->elements_kind(); 8484 if (!IsFastElementsKind(kind)) return false; 8485 if (receiver_map->is_observed()) return false; 8486 if (argument_count != 2) return false; 8487 if (!receiver_map->is_extensible()) return false; 8488 8489 // If there may be elements accessors in the prototype chain, the fast 8490 // inlined version can't be used. 8491 if (receiver_map->DictionaryElementsInPrototypeChainOnly()) return false; 8492 8493 // If there currently can be no elements accessors on the prototype chain, 8494 // it doesn't mean that there won't be any later. Install a full prototype 8495 // chain check to trap element accessors being installed on the prototype 8496 // chain, which would cause elements to go to dictionary mode and result 8497 // in a map change. 8498 BuildCheckPrototypeMaps( 8499 handle(JSObject::cast(receiver_map->prototype()), isolate()), 8500 Handle<JSObject>::null()); 8501 8502 HValue* search_element = Pop(); 8503 HValue* receiver = Pop(); 8504 Drop(1); // Drop function. 8505 8506 ArrayIndexOfMode mode = (id == kArrayIndexOf) 8507 ? kFirstIndexOf : kLastIndexOf; 8508 HValue* index = BuildArrayIndexOf(receiver, search_element, kind, mode); 8509 8510 if (!ast_context()->IsEffect()) Push(index); 8511 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); 8512 if (!ast_context()->IsEffect()) Drop(1); 8513 ast_context()->ReturnValue(index); 8514 return true; 8515 } 8516 default: 8517 // Not yet supported for inlining. 8518 break; 8519 } 8520 return false; 8521 } 8522 8523 8524 bool HOptimizedGraphBuilder::TryInlineApiFunctionCall(Call* expr, 8525 HValue* receiver) { 8526 Handle<JSFunction> function = expr->target(); 8527 int argc = expr->arguments()->length(); 8528 SmallMapList receiver_maps; 8529 return TryInlineApiCall(function, 8530 receiver, 8531 &receiver_maps, 8532 argc, 8533 expr->id(), 8534 kCallApiFunction); 8535 } 8536 8537 8538 bool HOptimizedGraphBuilder::TryInlineApiMethodCall( 8539 Call* expr, 8540 HValue* receiver, 8541 SmallMapList* receiver_maps) { 8542 Handle<JSFunction> function = expr->target(); 8543 int argc = expr->arguments()->length(); 8544 return TryInlineApiCall(function, 8545 receiver, 8546 receiver_maps, 8547 argc, 8548 expr->id(), 8549 kCallApiMethod); 8550 } 8551 8552 8553 bool HOptimizedGraphBuilder::TryInlineApiGetter(Handle<JSFunction> function, 8554 Handle<Map> receiver_map, 8555 BailoutId ast_id) { 8556 SmallMapList receiver_maps(1, zone()); 8557 receiver_maps.Add(receiver_map, zone()); 8558 return TryInlineApiCall(function, 8559 NULL, // Receiver is on expression stack. 8560 &receiver_maps, 8561 0, 8562 ast_id, 8563 kCallApiGetter); 8564 } 8565 8566 8567 bool HOptimizedGraphBuilder::TryInlineApiSetter(Handle<JSFunction> function, 8568 Handle<Map> receiver_map, 8569 BailoutId ast_id) { 8570 SmallMapList receiver_maps(1, zone()); 8571 receiver_maps.Add(receiver_map, zone()); 8572 return TryInlineApiCall(function, 8573 NULL, // Receiver is on expression stack. 8574 &receiver_maps, 8575 1, 8576 ast_id, 8577 kCallApiSetter); 8578 } 8579 8580 8581 bool HOptimizedGraphBuilder::TryInlineApiCall(Handle<JSFunction> function, 8582 HValue* receiver, 8583 SmallMapList* receiver_maps, 8584 int argc, 8585 BailoutId ast_id, 8586 ApiCallType call_type) { 8587 CallOptimization optimization(function); 8588 if (!optimization.is_simple_api_call()) return false; 8589 Handle<Map> holder_map; 8590 if (call_type == kCallApiFunction) { 8591 // Cannot embed a direct reference to the global proxy map 8592 // as it maybe dropped on deserialization. 8593 CHECK(!isolate()->serializer_enabled()); 8594 DCHECK_EQ(0, receiver_maps->length()); 8595 receiver_maps->Add(handle(function->global_proxy()->map()), zone()); 8596 } 8597 CallOptimization::HolderLookup holder_lookup = 8598 CallOptimization::kHolderNotFound; 8599 Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType( 8600 receiver_maps->first(), &holder_lookup); 8601 if (holder_lookup == CallOptimization::kHolderNotFound) return false; 8602 8603 if (FLAG_trace_inlining) { 8604 PrintF("Inlining api function "); 8605 function->ShortPrint(); 8606 PrintF("\n"); 8607 } 8608 8609 bool drop_extra = false; 8610 bool is_store = false; 8611 switch (call_type) { 8612 case kCallApiFunction: 8613 case kCallApiMethod: 8614 // Need to check that none of the receiver maps could have changed. 8615 Add<HCheckMaps>(receiver, receiver_maps); 8616 // Need to ensure the chain between receiver and api_holder is intact. 8617 if (holder_lookup == CallOptimization::kHolderFound) { 8618 AddCheckPrototypeMaps(api_holder, receiver_maps->first()); 8619 } else { 8620 DCHECK_EQ(holder_lookup, CallOptimization::kHolderIsReceiver); 8621 } 8622 // Includes receiver. 8623 PushArgumentsFromEnvironment(argc + 1); 8624 // Drop function after call. 8625 drop_extra = true; 8626 break; 8627 case kCallApiGetter: 8628 // Receiver and prototype chain cannot have changed. 8629 DCHECK_EQ(0, argc); 8630 DCHECK_EQ(NULL, receiver); 8631 // Receiver is on expression stack. 8632 receiver = Pop(); 8633 Add<HPushArguments>(receiver); 8634 break; 8635 case kCallApiSetter: 8636 { 8637 is_store = true; 8638 // Receiver and prototype chain cannot have changed. 8639 DCHECK_EQ(1, argc); 8640 DCHECK_EQ(NULL, receiver); 8641 // Receiver and value are on expression stack. 8642 HValue* value = Pop(); 8643 receiver = Pop(); 8644 Add<HPushArguments>(receiver, value); 8645 break; 8646 } 8647 } 8648 8649 HValue* holder = NULL; 8650 switch (holder_lookup) { 8651 case CallOptimization::kHolderFound: 8652 holder = Add<HConstant>(api_holder); 8653 break; 8654 case CallOptimization::kHolderIsReceiver: 8655 holder = receiver; 8656 break; 8657 case CallOptimization::kHolderNotFound: 8658 UNREACHABLE(); 8659 break; 8660 } 8661 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); 8662 Handle<Object> call_data_obj(api_call_info->data(), isolate()); 8663 bool call_data_is_undefined = call_data_obj->IsUndefined(); 8664 HValue* call_data = Add<HConstant>(call_data_obj); 8665 ApiFunction fun(v8::ToCData<Address>(api_call_info->callback())); 8666 ExternalReference ref = ExternalReference(&fun, 8667 ExternalReference::DIRECT_API_CALL, 8668 isolate()); 8669 HValue* api_function_address = Add<HConstant>(ExternalReference(ref)); 8670 8671 HValue* op_vals[] = { 8672 context(), 8673 Add<HConstant>(function), 8674 call_data, 8675 holder, 8676 api_function_address 8677 }; 8678 8679 ApiFunctionDescriptor descriptor(isolate()); 8680 CallApiFunctionStub stub(isolate(), is_store, call_data_is_undefined, argc); 8681 Handle<Code> code = stub.GetCode(); 8682 HConstant* code_value = Add<HConstant>(code); 8683 8684 DCHECK((sizeof(op_vals) / kPointerSize) == descriptor.GetEnvironmentLength()); 8685 8686 HInstruction* call = New<HCallWithDescriptor>( 8687 code_value, argc + 1, descriptor, 8688 Vector<HValue*>(op_vals, descriptor.GetEnvironmentLength())); 8689 8690 if (drop_extra) Drop(1); // Drop function. 8691 ast_context()->ReturnInstruction(call, ast_id); 8692 return true; 8693 } 8694 8695 8696 bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { 8697 DCHECK(expr->expression()->IsProperty()); 8698 8699 if (!expr->IsMonomorphic()) { 8700 return false; 8701 } 8702 Handle<Map> function_map = expr->GetReceiverTypes()->first(); 8703 if (function_map->instance_type() != JS_FUNCTION_TYPE || 8704 !expr->target()->shared()->HasBuiltinFunctionId() || 8705 expr->target()->shared()->builtin_function_id() != kFunctionApply) { 8706 return false; 8707 } 8708 8709 if (current_info()->scope()->arguments() == NULL) return false; 8710 8711 ZoneList<Expression*>* args = expr->arguments(); 8712 if (args->length() != 2) return false; 8713 8714 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); 8715 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; 8716 HValue* arg_two_value = LookupAndMakeLive(arg_two->var()); 8717 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; 8718 8719 // Found pattern f.apply(receiver, arguments). 8720 CHECK_ALIVE_OR_RETURN(VisitForValue(args->at(0)), true); 8721 HValue* receiver = Pop(); // receiver 8722 HValue* function = Pop(); // f 8723 Drop(1); // apply 8724 8725 HValue* checked_function = AddCheckMap(function, function_map); 8726 8727 if (function_state()->outer() == NULL) { 8728 HInstruction* elements = Add<HArgumentsElements>(false); 8729 HInstruction* length = Add<HArgumentsLength>(elements); 8730 HValue* wrapped_receiver = BuildWrapReceiver(receiver, checked_function); 8731 HInstruction* result = New<HApplyArguments>(function, 8732 wrapped_receiver, 8733 length, 8734 elements); 8735 ast_context()->ReturnInstruction(result, expr->id()); 8736 return true; 8737 } else { 8738 // We are inside inlined function and we know exactly what is inside 8739 // arguments object. But we need to be able to materialize at deopt. 8740 DCHECK_EQ(environment()->arguments_environment()->parameter_count(), 8741 function_state()->entry()->arguments_object()->arguments_count()); 8742 HArgumentsObject* args = function_state()->entry()->arguments_object(); 8743 const ZoneList<HValue*>* arguments_values = args->arguments_values(); 8744 int arguments_count = arguments_values->length(); 8745 Push(function); 8746 Push(BuildWrapReceiver(receiver, checked_function)); 8747 for (int i = 1; i < arguments_count; i++) { 8748 Push(arguments_values->at(i)); 8749 } 8750 8751 Handle<JSFunction> known_function; 8752 if (function->IsConstant() && 8753 HConstant::cast(function)->handle(isolate())->IsJSFunction()) { 8754 known_function = Handle<JSFunction>::cast( 8755 HConstant::cast(function)->handle(isolate())); 8756 int args_count = arguments_count - 1; // Excluding receiver. 8757 if (TryInlineApply(known_function, expr, args_count)) return true; 8758 } 8759 8760 PushArgumentsFromEnvironment(arguments_count); 8761 HInvokeFunction* call = New<HInvokeFunction>( 8762 function, known_function, arguments_count); 8763 Drop(1); // Function. 8764 ast_context()->ReturnInstruction(call, expr->id()); 8765 return true; 8766 } 8767 } 8768 8769 8770 HValue* HOptimizedGraphBuilder::ImplicitReceiverFor(HValue* function, 8771 Handle<JSFunction> target) { 8772 SharedFunctionInfo* shared = target->shared(); 8773 if (shared->strict_mode() == SLOPPY && !shared->native()) { 8774 // Cannot embed a direct reference to the global proxy 8775 // as is it dropped on deserialization. 8776 CHECK(!isolate()->serializer_enabled()); 8777 Handle<JSObject> global_proxy(target->context()->global_proxy()); 8778 return Add<HConstant>(global_proxy); 8779 } 8780 return graph()->GetConstantUndefined(); 8781 } 8782 8783 8784 void HOptimizedGraphBuilder::BuildArrayCall(Expression* expression, 8785 int arguments_count, 8786 HValue* function, 8787 Handle<AllocationSite> site) { 8788 Add<HCheckValue>(function, array_function()); 8789 8790 if (IsCallArrayInlineable(arguments_count, site)) { 8791 BuildInlinedCallArray(expression, arguments_count, site); 8792 return; 8793 } 8794 8795 HInstruction* call = PreProcessCall(New<HCallNewArray>( 8796 function, arguments_count + 1, site->GetElementsKind())); 8797 if (expression->IsCall()) { 8798 Drop(1); 8799 } 8800 ast_context()->ReturnInstruction(call, expression->id()); 8801 } 8802 8803 8804 HValue* HOptimizedGraphBuilder::BuildArrayIndexOf(HValue* receiver, 8805 HValue* search_element, 8806 ElementsKind kind, 8807 ArrayIndexOfMode mode) { 8808 DCHECK(IsFastElementsKind(kind)); 8809 8810 NoObservableSideEffectsScope no_effects(this); 8811 8812 HValue* elements = AddLoadElements(receiver); 8813 HValue* length = AddLoadArrayLength(receiver, kind); 8814 8815 HValue* initial; 8816 HValue* terminating; 8817 Token::Value token; 8818 LoopBuilder::Direction direction; 8819 if (mode == kFirstIndexOf) { 8820 initial = graph()->GetConstant0(); 8821 terminating = length; 8822 token = Token::LT; 8823 direction = LoopBuilder::kPostIncrement; 8824 } else { 8825 DCHECK_EQ(kLastIndexOf, mode); 8826 initial = length; 8827 terminating = graph()->GetConstant0(); 8828 token = Token::GT; 8829 direction = LoopBuilder::kPreDecrement; 8830 } 8831 8832 Push(graph()->GetConstantMinus1()); 8833 if (IsFastDoubleElementsKind(kind) || IsFastSmiElementsKind(kind)) { 8834 // Make sure that we can actually compare numbers correctly below, see 8835 // https://code.google.com/p/chromium/issues/detail?id=407946 for details. 8836 search_element = AddUncasted<HForceRepresentation>( 8837 search_element, IsFastSmiElementsKind(kind) ? Representation::Smi() 8838 : Representation::Double()); 8839 8840 LoopBuilder loop(this, context(), direction); 8841 { 8842 HValue* index = loop.BeginBody(initial, terminating, token); 8843 HValue* element = AddUncasted<HLoadKeyed>( 8844 elements, index, static_cast<HValue*>(NULL), 8845 kind, ALLOW_RETURN_HOLE); 8846 IfBuilder if_issame(this); 8847 if_issame.If<HCompareNumericAndBranch>(element, search_element, 8848 Token::EQ_STRICT); 8849 if_issame.Then(); 8850 { 8851 Drop(1); 8852 Push(index); 8853 loop.Break(); 8854 } 8855 if_issame.End(); 8856 } 8857 loop.EndBody(); 8858 } else { 8859 IfBuilder if_isstring(this); 8860 if_isstring.If<HIsStringAndBranch>(search_element); 8861 if_isstring.Then(); 8862 { 8863 LoopBuilder loop(this, context(), direction); 8864 { 8865 HValue* index = loop.BeginBody(initial, terminating, token); 8866 HValue* element = AddUncasted<HLoadKeyed>( 8867 elements, index, static_cast<HValue*>(NULL), 8868 kind, ALLOW_RETURN_HOLE); 8869 IfBuilder if_issame(this); 8870 if_issame.If<HIsStringAndBranch>(element); 8871 if_issame.AndIf<HStringCompareAndBranch>( 8872 element, search_element, Token::EQ_STRICT); 8873 if_issame.Then(); 8874 { 8875 Drop(1); 8876 Push(index); 8877 loop.Break(); 8878 } 8879 if_issame.End(); 8880 } 8881 loop.EndBody(); 8882 } 8883 if_isstring.Else(); 8884 { 8885 IfBuilder if_isnumber(this); 8886 if_isnumber.If<HIsSmiAndBranch>(search_element); 8887 if_isnumber.OrIf<HCompareMap>( 8888 search_element, isolate()->factory()->heap_number_map()); 8889 if_isnumber.Then(); 8890 { 8891 HValue* search_number = 8892 AddUncasted<HForceRepresentation>(search_element, 8893 Representation::Double()); 8894 LoopBuilder loop(this, context(), direction); 8895 { 8896 HValue* index = loop.BeginBody(initial, terminating, token); 8897 HValue* element = AddUncasted<HLoadKeyed>( 8898 elements, index, static_cast<HValue*>(NULL), 8899 kind, ALLOW_RETURN_HOLE); 8900 8901 IfBuilder if_element_isnumber(this); 8902 if_element_isnumber.If<HIsSmiAndBranch>(element); 8903 if_element_isnumber.OrIf<HCompareMap>( 8904 element, isolate()->factory()->heap_number_map()); 8905 if_element_isnumber.Then(); 8906 { 8907 HValue* number = 8908 AddUncasted<HForceRepresentation>(element, 8909 Representation::Double()); 8910 IfBuilder if_issame(this); 8911 if_issame.If<HCompareNumericAndBranch>( 8912 number, search_number, Token::EQ_STRICT); 8913 if_issame.Then(); 8914 { 8915 Drop(1); 8916 Push(index); 8917 loop.Break(); 8918 } 8919 if_issame.End(); 8920 } 8921 if_element_isnumber.End(); 8922 } 8923 loop.EndBody(); 8924 } 8925 if_isnumber.Else(); 8926 { 8927 LoopBuilder loop(this, context(), direction); 8928 { 8929 HValue* index = loop.BeginBody(initial, terminating, token); 8930 HValue* element = AddUncasted<HLoadKeyed>( 8931 elements, index, static_cast<HValue*>(NULL), 8932 kind, ALLOW_RETURN_HOLE); 8933 IfBuilder if_issame(this); 8934 if_issame.If<HCompareObjectEqAndBranch>( 8935 element, search_element); 8936 if_issame.Then(); 8937 { 8938 Drop(1); 8939 Push(index); 8940 loop.Break(); 8941 } 8942 if_issame.End(); 8943 } 8944 loop.EndBody(); 8945 } 8946 if_isnumber.End(); 8947 } 8948 if_isstring.End(); 8949 } 8950 8951 return Pop(); 8952 } 8953 8954 8955 bool HOptimizedGraphBuilder::TryHandleArrayCall(Call* expr, HValue* function) { 8956 if (!array_function().is_identical_to(expr->target())) { 8957 return false; 8958 } 8959 8960 Handle<AllocationSite> site = expr->allocation_site(); 8961 if (site.is_null()) return false; 8962 8963 BuildArrayCall(expr, 8964 expr->arguments()->length(), 8965 function, 8966 site); 8967 return true; 8968 } 8969 8970 8971 bool HOptimizedGraphBuilder::TryHandleArrayCallNew(CallNew* expr, 8972 HValue* function) { 8973 if (!array_function().is_identical_to(expr->target())) { 8974 return false; 8975 } 8976 8977 BuildArrayCall(expr, 8978 expr->arguments()->length(), 8979 function, 8980 expr->allocation_site()); 8981 return true; 8982 } 8983 8984 8985 void HOptimizedGraphBuilder::VisitCall(Call* expr) { 8986 DCHECK(!HasStackOverflow()); 8987 DCHECK(current_block() != NULL); 8988 DCHECK(current_block()->HasPredecessor()); 8989 Expression* callee = expr->expression(); 8990 int argument_count = expr->arguments()->length() + 1; // Plus receiver. 8991 HInstruction* call = NULL; 8992 8993 Property* prop = callee->AsProperty(); 8994 if (prop != NULL) { 8995 CHECK_ALIVE(VisitForValue(prop->obj())); 8996 HValue* receiver = Top(); 8997 8998 SmallMapList* types; 8999 ComputeReceiverTypes(expr, receiver, &types, zone()); 9000 9001 if (prop->key()->IsPropertyName() && types->length() > 0) { 9002 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); 9003 PropertyAccessInfo info(this, LOAD, ToType(types->first()), name); 9004 if (!info.CanAccessAsMonomorphic(types)) { 9005 HandlePolymorphicCallNamed(expr, receiver, types, name); 9006 return; 9007 } 9008 } 9009 9010 HValue* key = NULL; 9011 if (!prop->key()->IsPropertyName()) { 9012 CHECK_ALIVE(VisitForValue(prop->key())); 9013 key = Pop(); 9014 } 9015 9016 CHECK_ALIVE(PushLoad(prop, receiver, key)); 9017 HValue* function = Pop(); 9018 9019 if (FLAG_hydrogen_track_positions) SetSourcePosition(expr->position()); 9020 9021 // Push the function under the receiver. 9022 environment()->SetExpressionStackAt(0, function); 9023 9024 Push(receiver); 9025 9026 if (function->IsConstant() && 9027 HConstant::cast(function)->handle(isolate())->IsJSFunction()) { 9028 Handle<JSFunction> known_function = Handle<JSFunction>::cast( 9029 HConstant::cast(function)->handle(isolate())); 9030 expr->set_target(known_function); 9031 9032 if (TryCallApply(expr)) return; 9033 CHECK_ALIVE(VisitExpressions(expr->arguments())); 9034 9035 Handle<Map> map = types->length() == 1 ? types->first() : Handle<Map>(); 9036 if (TryInlineBuiltinMethodCall(expr, receiver, map)) { 9037 if (FLAG_trace_inlining) { 9038 PrintF("Inlining builtin "); 9039 known_function->ShortPrint(); 9040 PrintF("\n"); 9041 } 9042 return; 9043 } 9044 if (TryInlineApiMethodCall(expr, receiver, types)) return; 9045 9046 // Wrap the receiver if necessary. 9047 if (NeedsWrappingFor(ToType(types->first()), known_function)) { 9048 // Since HWrapReceiver currently cannot actually wrap numbers and 9049 // strings, use the regular CallFunctionStub for method calls to wrap 9050 // the receiver. 9051 // TODO(verwaest): Support creation of value wrappers directly in 9052 // HWrapReceiver. 9053 call = New<HCallFunction>( 9054 function, argument_count, WRAP_AND_CALL); 9055 } else if (TryInlineCall(expr)) { 9056 return; 9057 } else { 9058 call = BuildCallConstantFunction(known_function, argument_count); 9059 } 9060 9061 } else { 9062 CHECK_ALIVE(VisitExpressions(expr->arguments())); 9063 CallFunctionFlags flags = receiver->type().IsJSObject() 9064 ? NO_CALL_FUNCTION_FLAGS : CALL_AS_METHOD; 9065 call = New<HCallFunction>(function, argument_count, flags); 9066 } 9067 PushArgumentsFromEnvironment(argument_count); 9068 9069 } else { 9070 VariableProxy* proxy = expr->expression()->AsVariableProxy(); 9071 if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) { 9072 return Bailout(kPossibleDirectCallToEval); 9073 } 9074 9075 // The function is on the stack in the unoptimized code during 9076 // evaluation of the arguments. 9077 CHECK_ALIVE(VisitForValue(expr->expression())); 9078 HValue* function = Top(); 9079 if (expr->global_call()) { 9080 Variable* var = proxy->var(); 9081 bool known_global_function = false; 9082 // If there is a global property cell for the name at compile time and 9083 // access check is not enabled we assume that the function will not change 9084 // and generate optimized code for calling the function. 9085 Handle<GlobalObject> global(current_info()->global_object()); 9086 LookupIterator it(global, var->name(), 9087 LookupIterator::OWN_SKIP_INTERCEPTOR); 9088 GlobalPropertyAccess type = LookupGlobalProperty(var, &it, LOAD); 9089 if (type == kUseCell) { 9090 Handle<GlobalObject> global(current_info()->global_object()); 9091 known_global_function = expr->ComputeGlobalTarget(global, &it); 9092 } 9093 if (known_global_function) { 9094 Add<HCheckValue>(function, expr->target()); 9095 9096 // Placeholder for the receiver. 9097 Push(graph()->GetConstantUndefined()); 9098 CHECK_ALIVE(VisitExpressions(expr->arguments())); 9099 9100 // Patch the global object on the stack by the expected receiver. 9101 HValue* receiver = ImplicitReceiverFor(function, expr->target()); 9102 const int receiver_index = argument_count - 1; 9103 environment()->SetExpressionStackAt(receiver_index, receiver); 9104 9105 if (TryInlineBuiltinFunctionCall(expr)) { 9106 if (FLAG_trace_inlining) { 9107 PrintF("Inlining builtin "); 9108 expr->target()->ShortPrint(); 9109 PrintF("\n"); 9110 } 9111 return; 9112 } 9113 if (TryInlineApiFunctionCall(expr, receiver)) return; 9114 if (TryHandleArrayCall(expr, function)) return; 9115 if (TryInlineCall(expr)) return; 9116 9117 PushArgumentsFromEnvironment(argument_count); 9118 call = BuildCallConstantFunction(expr->target(), argument_count); 9119 } else { 9120 Push(graph()->GetConstantUndefined()); 9121 CHECK_ALIVE(VisitExpressions(expr->arguments())); 9122 PushArgumentsFromEnvironment(argument_count); 9123 call = New<HCallFunction>(function, argument_count); 9124 } 9125 9126 } else if (expr->IsMonomorphic()) { 9127 Add<HCheckValue>(function, expr->target()); 9128 9129 Push(graph()->GetConstantUndefined()); 9130 CHECK_ALIVE(VisitExpressions(expr->arguments())); 9131 9132 HValue* receiver = ImplicitReceiverFor(function, expr->target()); 9133 const int receiver_index = argument_count - 1; 9134 environment()->SetExpressionStackAt(receiver_index, receiver); 9135 9136 if (TryInlineBuiltinFunctionCall(expr)) { 9137 if (FLAG_trace_inlining) { 9138 PrintF("Inlining builtin "); 9139 expr->target()->ShortPrint(); 9140 PrintF("\n"); 9141 } 9142 return; 9143 } 9144 if (TryInlineApiFunctionCall(expr, receiver)) return; 9145 9146 if (TryInlineCall(expr)) return; 9147 9148 call = PreProcessCall(New<HInvokeFunction>( 9149 function, expr->target(), argument_count)); 9150 9151 } else { 9152 Push(graph()->GetConstantUndefined()); 9153 CHECK_ALIVE(VisitExpressions(expr->arguments())); 9154 PushArgumentsFromEnvironment(argument_count); 9155 call = New<HCallFunction>(function, argument_count); 9156 } 9157 } 9158 9159 Drop(1); // Drop the function. 9160 return ast_context()->ReturnInstruction(call, expr->id()); 9161 } 9162 9163 9164 void HOptimizedGraphBuilder::BuildInlinedCallArray( 9165 Expression* expression, 9166 int argument_count, 9167 Handle<AllocationSite> site) { 9168 DCHECK(!site.is_null()); 9169 DCHECK(argument_count >= 0 && argument_count <= 1); 9170 NoObservableSideEffectsScope no_effects(this); 9171 9172 // We should at least have the constructor on the expression stack. 9173 HValue* constructor = environment()->ExpressionStackAt(argument_count); 9174 9175 // Register on the site for deoptimization if the transition feedback changes. 9176 AllocationSite::AddDependentCompilationInfo( 9177 site, AllocationSite::TRANSITIONS, top_info()); 9178 ElementsKind kind = site->GetElementsKind(); 9179 HInstruction* site_instruction = Add<HConstant>(site); 9180 9181 // In the single constant argument case, we may have to adjust elements kind 9182 // to avoid creating a packed non-empty array. 9183 if (argument_count == 1 && !IsHoleyElementsKind(kind)) { 9184 HValue* argument = environment()->Top(); 9185 if (argument->IsConstant()) { 9186 HConstant* constant_argument = HConstant::cast(argument); 9187 DCHECK(constant_argument->HasSmiValue()); 9188 int constant_array_size = constant_argument->Integer32Value(); 9189 if (constant_array_size != 0) { 9190 kind = GetHoleyElementsKind(kind); 9191 } 9192 } 9193 } 9194 9195 // Build the array. 9196 JSArrayBuilder array_builder(this, 9197 kind, 9198 site_instruction, 9199 constructor, 9200 DISABLE_ALLOCATION_SITES); 9201 HValue* new_object = argument_count == 0 9202 ? array_builder.AllocateEmptyArray() 9203 : BuildAllocateArrayFromLength(&array_builder, Top()); 9204 9205 int args_to_drop = argument_count + (expression->IsCall() ? 2 : 1); 9206 Drop(args_to_drop); 9207 ast_context()->ReturnValue(new_object); 9208 } 9209 9210 9211 // Checks whether allocation using the given constructor can be inlined. 9212 static bool IsAllocationInlineable(Handle<JSFunction> constructor) { 9213 return constructor->has_initial_map() && 9214 constructor->initial_map()->instance_type() == JS_OBJECT_TYPE && 9215 constructor->initial_map()->instance_size() < HAllocate::kMaxInlineSize && 9216 constructor->initial_map()->InitialPropertiesLength() == 0; 9217 } 9218 9219 9220 bool HOptimizedGraphBuilder::IsCallArrayInlineable( 9221 int argument_count, 9222 Handle<AllocationSite> site) { 9223 Handle<JSFunction> caller = current_info()->closure(); 9224 Handle<JSFunction> target = array_function(); 9225 // We should have the function plus array arguments on the environment stack. 9226 DCHECK(environment()->length() >= (argument_count + 1)); 9227 DCHECK(!site.is_null()); 9228 9229 bool inline_ok = false; 9230 if (site->CanInlineCall()) { 9231 // We also want to avoid inlining in certain 1 argument scenarios. 9232 if (argument_count == 1) { 9233 HValue* argument = Top(); 9234 if (argument->IsConstant()) { 9235 // Do not inline if the constant length argument is not a smi or 9236 // outside the valid range for unrolled loop initialization. 9237 HConstant* constant_argument = HConstant::cast(argument); 9238 if (constant_argument->HasSmiValue()) { 9239 int value = constant_argument->Integer32Value(); 9240 inline_ok = value >= 0 && value <= kElementLoopUnrollThreshold; 9241 if (!inline_ok) { 9242 TraceInline(target, caller, 9243 "Constant length outside of valid inlining range."); 9244 } 9245 } 9246 } else { 9247 TraceInline(target, caller, 9248 "Dont inline [new] Array(n) where n isn't constant."); 9249 } 9250 } else if (argument_count == 0) { 9251 inline_ok = true; 9252 } else { 9253 TraceInline(target, caller, "Too many arguments to inline."); 9254 } 9255 } else { 9256 TraceInline(target, caller, "AllocationSite requested no inlining."); 9257 } 9258 9259 if (inline_ok) { 9260 TraceInline(target, caller, NULL); 9261 } 9262 return inline_ok; 9263 } 9264 9265 9266 void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { 9267 DCHECK(!HasStackOverflow()); 9268 DCHECK(current_block() != NULL); 9269 DCHECK(current_block()->HasPredecessor()); 9270 if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position()); 9271 int argument_count = expr->arguments()->length() + 1; // Plus constructor. 9272 Factory* factory = isolate()->factory(); 9273 9274 // The constructor function is on the stack in the unoptimized code 9275 // during evaluation of the arguments. 9276 CHECK_ALIVE(VisitForValue(expr->expression())); 9277 HValue* function = Top(); 9278 CHECK_ALIVE(VisitExpressions(expr->arguments())); 9279 9280 if (FLAG_inline_construct && 9281 expr->IsMonomorphic() && 9282 IsAllocationInlineable(expr->target())) { 9283 Handle<JSFunction> constructor = expr->target(); 9284 HValue* check = Add<HCheckValue>(function, constructor); 9285 9286 // Force completion of inobject slack tracking before generating 9287 // allocation code to finalize instance size. 9288 if (constructor->IsInobjectSlackTrackingInProgress()) { 9289 constructor->CompleteInobjectSlackTracking(); 9290 } 9291 9292 // Calculate instance size from initial map of constructor. 9293 DCHECK(constructor->has_initial_map()); 9294 Handle<Map> initial_map(constructor->initial_map()); 9295 int instance_size = initial_map->instance_size(); 9296 DCHECK(initial_map->InitialPropertiesLength() == 0); 9297 9298 // Allocate an instance of the implicit receiver object. 9299 HValue* size_in_bytes = Add<HConstant>(instance_size); 9300 HAllocationMode allocation_mode; 9301 if (FLAG_pretenuring_call_new) { 9302 if (FLAG_allocation_site_pretenuring) { 9303 // Try to use pretenuring feedback. 9304 Handle<AllocationSite> allocation_site = expr->allocation_site(); 9305 allocation_mode = HAllocationMode(allocation_site); 9306 // Take a dependency on allocation site. 9307 AllocationSite::AddDependentCompilationInfo(allocation_site, 9308 AllocationSite::TENURING, 9309 top_info()); 9310 } 9311 } 9312 9313 HAllocate* receiver = BuildAllocate( 9314 size_in_bytes, HType::JSObject(), JS_OBJECT_TYPE, allocation_mode); 9315 receiver->set_known_initial_map(initial_map); 9316 9317 // Initialize map and fields of the newly allocated object. 9318 { NoObservableSideEffectsScope no_effects(this); 9319 DCHECK(initial_map->instance_type() == JS_OBJECT_TYPE); 9320 Add<HStoreNamedField>(receiver, 9321 HObjectAccess::ForMapAndOffset(initial_map, JSObject::kMapOffset), 9322 Add<HConstant>(initial_map)); 9323 HValue* empty_fixed_array = Add<HConstant>(factory->empty_fixed_array()); 9324 Add<HStoreNamedField>(receiver, 9325 HObjectAccess::ForMapAndOffset(initial_map, 9326 JSObject::kPropertiesOffset), 9327 empty_fixed_array); 9328 Add<HStoreNamedField>(receiver, 9329 HObjectAccess::ForMapAndOffset(initial_map, 9330 JSObject::kElementsOffset), 9331 empty_fixed_array); 9332 if (initial_map->inobject_properties() != 0) { 9333 HConstant* undefined = graph()->GetConstantUndefined(); 9334 for (int i = 0; i < initial_map->inobject_properties(); i++) { 9335 int property_offset = initial_map->GetInObjectPropertyOffset(i); 9336 Add<HStoreNamedField>(receiver, 9337 HObjectAccess::ForMapAndOffset(initial_map, property_offset), 9338 undefined); 9339 } 9340 } 9341 } 9342 9343 // Replace the constructor function with a newly allocated receiver using 9344 // the index of the receiver from the top of the expression stack. 9345 const int receiver_index = argument_count - 1; 9346 DCHECK(environment()->ExpressionStackAt(receiver_index) == function); 9347 environment()->SetExpressionStackAt(receiver_index, receiver); 9348 9349 if (TryInlineConstruct(expr, receiver)) { 9350 // Inlining worked, add a dependency on the initial map to make sure that 9351 // this code is deoptimized whenever the initial map of the constructor 9352 // changes. 9353 Map::AddDependentCompilationInfo( 9354 initial_map, DependentCode::kInitialMapChangedGroup, top_info()); 9355 return; 9356 } 9357 9358 // TODO(mstarzinger): For now we remove the previous HAllocate and all 9359 // corresponding instructions and instead add HPushArguments for the 9360 // arguments in case inlining failed. What we actually should do is for 9361 // inlining to try to build a subgraph without mutating the parent graph. 9362 HInstruction* instr = current_block()->last(); 9363 do { 9364 HInstruction* prev_instr = instr->previous(); 9365 instr->DeleteAndReplaceWith(NULL); 9366 instr = prev_instr; 9367 } while (instr != check); 9368 environment()->SetExpressionStackAt(receiver_index, function); 9369 HInstruction* call = 9370 PreProcessCall(New<HCallNew>(function, argument_count)); 9371 return ast_context()->ReturnInstruction(call, expr->id()); 9372 } else { 9373 // The constructor function is both an operand to the instruction and an 9374 // argument to the construct call. 9375 if (TryHandleArrayCallNew(expr, function)) return; 9376 9377 HInstruction* call = 9378 PreProcessCall(New<HCallNew>(function, argument_count)); 9379 return ast_context()->ReturnInstruction(call, expr->id()); 9380 } 9381 } 9382 9383 9384 // Support for generating inlined runtime functions. 9385 9386 // Lookup table for generators for runtime calls that are generated inline. 9387 // Elements of the table are member pointers to functions of 9388 // HOptimizedGraphBuilder. 9389 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \ 9390 &HOptimizedGraphBuilder::Generate##Name, 9391 9392 const HOptimizedGraphBuilder::InlineFunctionGenerator 9393 HOptimizedGraphBuilder::kInlineFunctionGenerators[] = { 9394 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS) 9395 INLINE_OPTIMIZED_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS) 9396 }; 9397 #undef INLINE_FUNCTION_GENERATOR_ADDRESS 9398 9399 9400 template <class ViewClass> 9401 void HGraphBuilder::BuildArrayBufferViewInitialization( 9402 HValue* obj, 9403 HValue* buffer, 9404 HValue* byte_offset, 9405 HValue* byte_length) { 9406 9407 for (int offset = ViewClass::kSize; 9408 offset < ViewClass::kSizeWithInternalFields; 9409 offset += kPointerSize) { 9410 Add<HStoreNamedField>(obj, 9411 HObjectAccess::ForObservableJSObjectOffset(offset), 9412 graph()->GetConstant0()); 9413 } 9414 9415 Add<HStoreNamedField>( 9416 obj, 9417 HObjectAccess::ForJSArrayBufferViewByteOffset(), 9418 byte_offset); 9419 Add<HStoreNamedField>( 9420 obj, 9421 HObjectAccess::ForJSArrayBufferViewByteLength(), 9422 byte_length); 9423 9424 if (buffer != NULL) { 9425 Add<HStoreNamedField>( 9426 obj, 9427 HObjectAccess::ForJSArrayBufferViewBuffer(), buffer); 9428 HObjectAccess weak_first_view_access = 9429 HObjectAccess::ForJSArrayBufferWeakFirstView(); 9430 Add<HStoreNamedField>(obj, 9431 HObjectAccess::ForJSArrayBufferViewWeakNext(), 9432 Add<HLoadNamedField>(buffer, 9433 static_cast<HValue*>(NULL), 9434 weak_first_view_access)); 9435 Add<HStoreNamedField>(buffer, weak_first_view_access, obj); 9436 } else { 9437 Add<HStoreNamedField>( 9438 obj, 9439 HObjectAccess::ForJSArrayBufferViewBuffer(), 9440 Add<HConstant>(static_cast<int32_t>(0))); 9441 Add<HStoreNamedField>(obj, 9442 HObjectAccess::ForJSArrayBufferViewWeakNext(), 9443 graph()->GetConstantUndefined()); 9444 } 9445 } 9446 9447 9448 void HOptimizedGraphBuilder::GenerateDataViewInitialize( 9449 CallRuntime* expr) { 9450 ZoneList<Expression*>* arguments = expr->arguments(); 9451 9452 DCHECK(arguments->length()== 4); 9453 CHECK_ALIVE(VisitForValue(arguments->at(0))); 9454 HValue* obj = Pop(); 9455 9456 CHECK_ALIVE(VisitForValue(arguments->at(1))); 9457 HValue* buffer = Pop(); 9458 9459 CHECK_ALIVE(VisitForValue(arguments->at(2))); 9460 HValue* byte_offset = Pop(); 9461 9462 CHECK_ALIVE(VisitForValue(arguments->at(3))); 9463 HValue* byte_length = Pop(); 9464 9465 { 9466 NoObservableSideEffectsScope scope(this); 9467 BuildArrayBufferViewInitialization<JSDataView>( 9468 obj, buffer, byte_offset, byte_length); 9469 } 9470 } 9471 9472 9473 static Handle<Map> TypedArrayMap(Isolate* isolate, 9474 ExternalArrayType array_type, 9475 ElementsKind target_kind) { 9476 Handle<Context> native_context = isolate->native_context(); 9477 Handle<JSFunction> fun; 9478 switch (array_type) { 9479 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ 9480 case kExternal##Type##Array: \ 9481 fun = Handle<JSFunction>(native_context->type##_array_fun()); \ 9482 break; 9483 9484 TYPED_ARRAYS(TYPED_ARRAY_CASE) 9485 #undef TYPED_ARRAY_CASE 9486 } 9487 Handle<Map> map(fun->initial_map()); 9488 return Map::AsElementsKind(map, target_kind); 9489 } 9490 9491 9492 HValue* HOptimizedGraphBuilder::BuildAllocateExternalElements( 9493 ExternalArrayType array_type, 9494 bool is_zero_byte_offset, 9495 HValue* buffer, HValue* byte_offset, HValue* length) { 9496 Handle<Map> external_array_map( 9497 isolate()->heap()->MapForExternalArrayType(array_type)); 9498 9499 // The HForceRepresentation is to prevent possible deopt on int-smi 9500 // conversion after allocation but before the new object fields are set. 9501 length = AddUncasted<HForceRepresentation>(length, Representation::Smi()); 9502 HValue* elements = 9503 Add<HAllocate>( 9504 Add<HConstant>(ExternalArray::kAlignedSize), 9505 HType::HeapObject(), 9506 NOT_TENURED, 9507 external_array_map->instance_type()); 9508 9509 AddStoreMapConstant(elements, external_array_map); 9510 Add<HStoreNamedField>(elements, 9511 HObjectAccess::ForFixedArrayLength(), length); 9512 9513 HValue* backing_store = Add<HLoadNamedField>( 9514 buffer, static_cast<HValue*>(NULL), 9515 HObjectAccess::ForJSArrayBufferBackingStore()); 9516 9517 HValue* typed_array_start; 9518 if (is_zero_byte_offset) { 9519 typed_array_start = backing_store; 9520 } else { 9521 HInstruction* external_pointer = 9522 AddUncasted<HAdd>(backing_store, byte_offset); 9523 // Arguments are checked prior to call to TypedArrayInitialize, 9524 // including byte_offset. 9525 external_pointer->ClearFlag(HValue::kCanOverflow); 9526 typed_array_start = external_pointer; 9527 } 9528 9529 Add<HStoreNamedField>(elements, 9530 HObjectAccess::ForExternalArrayExternalPointer(), 9531 typed_array_start); 9532 9533 return elements; 9534 } 9535 9536 9537 HValue* HOptimizedGraphBuilder::BuildAllocateFixedTypedArray( 9538 ExternalArrayType array_type, size_t element_size, 9539 ElementsKind fixed_elements_kind, 9540 HValue* byte_length, HValue* length) { 9541 STATIC_ASSERT( 9542 (FixedTypedArrayBase::kHeaderSize & kObjectAlignmentMask) == 0); 9543 HValue* total_size; 9544 9545 // if fixed array's elements are not aligned to object's alignment, 9546 // we need to align the whole array to object alignment. 9547 if (element_size % kObjectAlignment != 0) { 9548 total_size = BuildObjectSizeAlignment( 9549 byte_length, FixedTypedArrayBase::kHeaderSize); 9550 } else { 9551 total_size = AddUncasted<HAdd>(byte_length, 9552 Add<HConstant>(FixedTypedArrayBase::kHeaderSize)); 9553 total_size->ClearFlag(HValue::kCanOverflow); 9554 } 9555 9556 // The HForceRepresentation is to prevent possible deopt on int-smi 9557 // conversion after allocation but before the new object fields are set. 9558 length = AddUncasted<HForceRepresentation>(length, Representation::Smi()); 9559 Handle<Map> fixed_typed_array_map( 9560 isolate()->heap()->MapForFixedTypedArray(array_type)); 9561 HValue* elements = 9562 Add<HAllocate>(total_size, HType::HeapObject(), 9563 NOT_TENURED, fixed_typed_array_map->instance_type()); 9564 AddStoreMapConstant(elements, fixed_typed_array_map); 9565 9566 Add<HStoreNamedField>(elements, 9567 HObjectAccess::ForFixedArrayLength(), 9568 length); 9569 9570 HValue* filler = Add<HConstant>(static_cast<int32_t>(0)); 9571 9572 { 9573 LoopBuilder builder(this, context(), LoopBuilder::kPostIncrement); 9574 9575 HValue* key = builder.BeginBody( 9576 Add<HConstant>(static_cast<int32_t>(0)), 9577 length, Token::LT); 9578 Add<HStoreKeyed>(elements, key, filler, fixed_elements_kind); 9579 9580 builder.EndBody(); 9581 } 9582 return elements; 9583 } 9584 9585 9586 void HOptimizedGraphBuilder::GenerateTypedArrayInitialize( 9587 CallRuntime* expr) { 9588 ZoneList<Expression*>* arguments = expr->arguments(); 9589 9590 static const int kObjectArg = 0; 9591 static const int kArrayIdArg = 1; 9592 static const int kBufferArg = 2; 9593 static const int kByteOffsetArg = 3; 9594 static const int kByteLengthArg = 4; 9595 static const int kArgsLength = 5; 9596 DCHECK(arguments->length() == kArgsLength); 9597 9598 9599 CHECK_ALIVE(VisitForValue(arguments->at(kObjectArg))); 9600 HValue* obj = Pop(); 9601 9602 if (arguments->at(kArrayIdArg)->IsLiteral()) { 9603 // This should never happen in real use, but can happen when fuzzing. 9604 // Just bail out. 9605 Bailout(kNeedSmiLiteral); 9606 return; 9607 } 9608 Handle<Object> value = 9609 static_cast<Literal*>(arguments->at(kArrayIdArg))->value(); 9610 if (!value->IsSmi()) { 9611 // This should never happen in real use, but can happen when fuzzing. 9612 // Just bail out. 9613 Bailout(kNeedSmiLiteral); 9614 return; 9615 } 9616 int array_id = Smi::cast(*value)->value(); 9617 9618 HValue* buffer; 9619 if (!arguments->at(kBufferArg)->IsNullLiteral()) { 9620 CHECK_ALIVE(VisitForValue(arguments->at(kBufferArg))); 9621 buffer = Pop(); 9622 } else { 9623 buffer = NULL; 9624 } 9625 9626 HValue* byte_offset; 9627 bool is_zero_byte_offset; 9628 9629 if (arguments->at(kByteOffsetArg)->IsLiteral() 9630 && Smi::FromInt(0) == 9631 *static_cast<Literal*>(arguments->at(kByteOffsetArg))->value()) { 9632 byte_offset = Add<HConstant>(static_cast<int32_t>(0)); 9633 is_zero_byte_offset = true; 9634 } else { 9635 CHECK_ALIVE(VisitForValue(arguments->at(kByteOffsetArg))); 9636 byte_offset = Pop(); 9637 is_zero_byte_offset = false; 9638 DCHECK(buffer != NULL); 9639 } 9640 9641 CHECK_ALIVE(VisitForValue(arguments->at(kByteLengthArg))); 9642 HValue* byte_length = Pop(); 9643 9644 NoObservableSideEffectsScope scope(this); 9645 IfBuilder byte_offset_smi(this); 9646 9647 if (!is_zero_byte_offset) { 9648 byte_offset_smi.If<HIsSmiAndBranch>(byte_offset); 9649 byte_offset_smi.Then(); 9650 } 9651 9652 ExternalArrayType array_type = 9653 kExternalInt8Array; // Bogus initialization. 9654 size_t element_size = 1; // Bogus initialization. 9655 ElementsKind external_elements_kind = // Bogus initialization. 9656 EXTERNAL_INT8_ELEMENTS; 9657 ElementsKind fixed_elements_kind = // Bogus initialization. 9658 INT8_ELEMENTS; 9659 Runtime::ArrayIdToTypeAndSize(array_id, 9660 &array_type, 9661 &external_elements_kind, 9662 &fixed_elements_kind, 9663 &element_size); 9664 9665 9666 { // byte_offset is Smi. 9667 BuildArrayBufferViewInitialization<JSTypedArray>( 9668 obj, buffer, byte_offset, byte_length); 9669 9670 9671 HInstruction* length = AddUncasted<HDiv>(byte_length, 9672 Add<HConstant>(static_cast<int32_t>(element_size))); 9673 9674 Add<HStoreNamedField>(obj, 9675 HObjectAccess::ForJSTypedArrayLength(), 9676 length); 9677 9678 HValue* elements; 9679 if (buffer != NULL) { 9680 elements = BuildAllocateExternalElements( 9681 array_type, is_zero_byte_offset, buffer, byte_offset, length); 9682 Handle<Map> obj_map = TypedArrayMap( 9683 isolate(), array_type, external_elements_kind); 9684 AddStoreMapConstant(obj, obj_map); 9685 } else { 9686 DCHECK(is_zero_byte_offset); 9687 elements = BuildAllocateFixedTypedArray( 9688 array_type, element_size, fixed_elements_kind, 9689 byte_length, length); 9690 } 9691 Add<HStoreNamedField>( 9692 obj, HObjectAccess::ForElementsPointer(), elements); 9693 } 9694 9695 if (!is_zero_byte_offset) { 9696 byte_offset_smi.Else(); 9697 { // byte_offset is not Smi. 9698 Push(obj); 9699 CHECK_ALIVE(VisitForValue(arguments->at(kArrayIdArg))); 9700 Push(buffer); 9701 Push(byte_offset); 9702 Push(byte_length); 9703 PushArgumentsFromEnvironment(kArgsLength); 9704 Add<HCallRuntime>(expr->name(), expr->function(), kArgsLength); 9705 } 9706 } 9707 byte_offset_smi.End(); 9708 } 9709 9710 9711 void HOptimizedGraphBuilder::GenerateMaxSmi(CallRuntime* expr) { 9712 DCHECK(expr->arguments()->length() == 0); 9713 HConstant* max_smi = New<HConstant>(static_cast<int32_t>(Smi::kMaxValue)); 9714 return ast_context()->ReturnInstruction(max_smi, expr->id()); 9715 } 9716 9717 9718 void HOptimizedGraphBuilder::GenerateTypedArrayMaxSizeInHeap( 9719 CallRuntime* expr) { 9720 DCHECK(expr->arguments()->length() == 0); 9721 HConstant* result = New<HConstant>(static_cast<int32_t>( 9722 FLAG_typed_array_max_size_in_heap)); 9723 return ast_context()->ReturnInstruction(result, expr->id()); 9724 } 9725 9726 9727 void HOptimizedGraphBuilder::GenerateArrayBufferGetByteLength( 9728 CallRuntime* expr) { 9729 DCHECK(expr->arguments()->length() == 1); 9730 CHECK_ALIVE(VisitForValue(expr->arguments()->at(0))); 9731 HValue* buffer = Pop(); 9732 HInstruction* result = New<HLoadNamedField>( 9733 buffer, 9734 static_cast<HValue*>(NULL), 9735 HObjectAccess::ForJSArrayBufferByteLength()); 9736 return ast_context()->ReturnInstruction(result, expr->id()); 9737 } 9738 9739 9740 void HOptimizedGraphBuilder::GenerateArrayBufferViewGetByteLength( 9741 CallRuntime* expr) { 9742 DCHECK(expr->arguments()->length() == 1); 9743 CHECK_ALIVE(VisitForValue(expr->arguments()->at(0))); 9744 HValue* buffer = Pop(); 9745 HInstruction* result = New<HLoadNamedField>( 9746 buffer, 9747 static_cast<HValue*>(NULL), 9748 HObjectAccess::ForJSArrayBufferViewByteLength()); 9749 return ast_context()->ReturnInstruction(result, expr->id()); 9750 } 9751 9752 9753 void HOptimizedGraphBuilder::GenerateArrayBufferViewGetByteOffset( 9754 CallRuntime* expr) { 9755 DCHECK(expr->arguments()->length() == 1); 9756 CHECK_ALIVE(VisitForValue(expr->arguments()->at(0))); 9757 HValue* buffer = Pop(); 9758 HInstruction* result = New<HLoadNamedField>( 9759 buffer, 9760 static_cast<HValue*>(NULL), 9761 HObjectAccess::ForJSArrayBufferViewByteOffset()); 9762 return ast_context()->ReturnInstruction(result, expr->id()); 9763 } 9764 9765 9766 void HOptimizedGraphBuilder::GenerateTypedArrayGetLength( 9767 CallRuntime* expr) { 9768 DCHECK(expr->arguments()->length() == 1); 9769 CHECK_ALIVE(VisitForValue(expr->arguments()->at(0))); 9770 HValue* buffer = Pop(); 9771 HInstruction* result = New<HLoadNamedField>( 9772 buffer, 9773 static_cast<HValue*>(NULL), 9774 HObjectAccess::ForJSTypedArrayLength()); 9775 return ast_context()->ReturnInstruction(result, expr->id()); 9776 } 9777 9778 9779 void HOptimizedGraphBuilder::VisitCallRuntime(CallRuntime* expr) { 9780 DCHECK(!HasStackOverflow()); 9781 DCHECK(current_block() != NULL); 9782 DCHECK(current_block()->HasPredecessor()); 9783 if (expr->is_jsruntime()) { 9784 return Bailout(kCallToAJavaScriptRuntimeFunction); 9785 } 9786 9787 const Runtime::Function* function = expr->function(); 9788 DCHECK(function != NULL); 9789 9790 if (function->intrinsic_type == Runtime::INLINE || 9791 function->intrinsic_type == Runtime::INLINE_OPTIMIZED) { 9792 DCHECK(expr->name()->length() > 0); 9793 DCHECK(expr->name()->Get(0) == '_'); 9794 // Call to an inline function. 9795 int lookup_index = static_cast<int>(function->function_id) - 9796 static_cast<int>(Runtime::kFirstInlineFunction); 9797 DCHECK(lookup_index >= 0); 9798 DCHECK(static_cast<size_t>(lookup_index) < 9799 arraysize(kInlineFunctionGenerators)); 9800 InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index]; 9801 9802 // Call the inline code generator using the pointer-to-member. 9803 (this->*generator)(expr); 9804 } else { 9805 DCHECK(function->intrinsic_type == Runtime::RUNTIME); 9806 Handle<String> name = expr->name(); 9807 int argument_count = expr->arguments()->length(); 9808 CHECK_ALIVE(VisitExpressions(expr->arguments())); 9809 PushArgumentsFromEnvironment(argument_count); 9810 HCallRuntime* call = New<HCallRuntime>(name, function, 9811 argument_count); 9812 return ast_context()->ReturnInstruction(call, expr->id()); 9813 } 9814 } 9815 9816 9817 void HOptimizedGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { 9818 DCHECK(!HasStackOverflow()); 9819 DCHECK(current_block() != NULL); 9820 DCHECK(current_block()->HasPredecessor()); 9821 switch (expr->op()) { 9822 case Token::DELETE: return VisitDelete(expr); 9823 case Token::VOID: return VisitVoid(expr); 9824 case Token::TYPEOF: return VisitTypeof(expr); 9825 case Token::NOT: return VisitNot(expr); 9826 default: UNREACHABLE(); 9827 } 9828 } 9829 9830 9831 void HOptimizedGraphBuilder::VisitDelete(UnaryOperation* expr) { 9832 Property* prop = expr->expression()->AsProperty(); 9833 VariableProxy* proxy = expr->expression()->AsVariableProxy(); 9834 if (prop != NULL) { 9835 CHECK_ALIVE(VisitForValue(prop->obj())); 9836 CHECK_ALIVE(VisitForValue(prop->key())); 9837 HValue* key = Pop(); 9838 HValue* obj = Pop(); 9839 HValue* function = AddLoadJSBuiltin(Builtins::DELETE); 9840 Add<HPushArguments>(obj, key, Add<HConstant>(function_strict_mode())); 9841 // TODO(olivf) InvokeFunction produces a check for the parameter count, 9842 // even though we are certain to pass the correct number of arguments here. 9843 HInstruction* instr = New<HInvokeFunction>(function, 3); 9844 return ast_context()->ReturnInstruction(instr, expr->id()); 9845 } else if (proxy != NULL) { 9846 Variable* var = proxy->var(); 9847 if (var->IsUnallocated()) { 9848 Bailout(kDeleteWithGlobalVariable); 9849 } else if (var->IsStackAllocated() || var->IsContextSlot()) { 9850 // Result of deleting non-global variables is false. 'this' is not 9851 // really a variable, though we implement it as one. The 9852 // subexpression does not have side effects. 9853 HValue* value = var->is_this() 9854 ? graph()->GetConstantTrue() 9855 : graph()->GetConstantFalse(); 9856 return ast_context()->ReturnValue(value); 9857 } else { 9858 Bailout(kDeleteWithNonGlobalVariable); 9859 } 9860 } else { 9861 // Result of deleting non-property, non-variable reference is true. 9862 // Evaluate the subexpression for side effects. 9863 CHECK_ALIVE(VisitForEffect(expr->expression())); 9864 return ast_context()->ReturnValue(graph()->GetConstantTrue()); 9865 } 9866 } 9867 9868 9869 void HOptimizedGraphBuilder::VisitVoid(UnaryOperation* expr) { 9870 CHECK_ALIVE(VisitForEffect(expr->expression())); 9871 return ast_context()->ReturnValue(graph()->GetConstantUndefined()); 9872 } 9873 9874 9875 void HOptimizedGraphBuilder::VisitTypeof(UnaryOperation* expr) { 9876 CHECK_ALIVE(VisitForTypeOf(expr->expression())); 9877 HValue* value = Pop(); 9878 HInstruction* instr = New<HTypeof>(value); 9879 return ast_context()->ReturnInstruction(instr, expr->id()); 9880 } 9881 9882 9883 void HOptimizedGraphBuilder::VisitNot(UnaryOperation* expr) { 9884 if (ast_context()->IsTest()) { 9885 TestContext* context = TestContext::cast(ast_context()); 9886 VisitForControl(expr->expression(), 9887 context->if_false(), 9888 context->if_true()); 9889 return; 9890 } 9891 9892 if (ast_context()->IsEffect()) { 9893 VisitForEffect(expr->expression()); 9894 return; 9895 } 9896 9897 DCHECK(ast_context()->IsValue()); 9898 HBasicBlock* materialize_false = graph()->CreateBasicBlock(); 9899 HBasicBlock* materialize_true = graph()->CreateBasicBlock(); 9900 CHECK_BAILOUT(VisitForControl(expr->expression(), 9901 materialize_false, 9902 materialize_true)); 9903 9904 if (materialize_false->HasPredecessor()) { 9905 materialize_false->SetJoinId(expr->MaterializeFalseId()); 9906 set_current_block(materialize_false); 9907 Push(graph()->GetConstantFalse()); 9908 } else { 9909 materialize_false = NULL; 9910 } 9911 9912 if (materialize_true->HasPredecessor()) { 9913 materialize_true->SetJoinId(expr->MaterializeTrueId()); 9914 set_current_block(materialize_true); 9915 Push(graph()->GetConstantTrue()); 9916 } else { 9917 materialize_true = NULL; 9918 } 9919 9920 HBasicBlock* join = 9921 CreateJoin(materialize_false, materialize_true, expr->id()); 9922 set_current_block(join); 9923 if (join != NULL) return ast_context()->ReturnValue(Pop()); 9924 } 9925 9926 9927 HInstruction* HOptimizedGraphBuilder::BuildIncrement( 9928 bool returns_original_input, 9929 CountOperation* expr) { 9930 // The input to the count operation is on top of the expression stack. 9931 Representation rep = Representation::FromType(expr->type()); 9932 if (rep.IsNone() || rep.IsTagged()) { 9933 rep = Representation::Smi(); 9934 } 9935 9936 if (returns_original_input) { 9937 // We need an explicit HValue representing ToNumber(input). The 9938 // actual HChange instruction we need is (sometimes) added in a later 9939 // phase, so it is not available now to be used as an input to HAdd and 9940 // as the return value. 9941 HInstruction* number_input = AddUncasted<HForceRepresentation>(Pop(), rep); 9942 if (!rep.IsDouble()) { 9943 number_input->SetFlag(HInstruction::kFlexibleRepresentation); 9944 number_input->SetFlag(HInstruction::kCannotBeTagged); 9945 } 9946 Push(number_input); 9947 } 9948 9949 // The addition has no side effects, so we do not need 9950 // to simulate the expression stack after this instruction. 9951 // Any later failures deopt to the load of the input or earlier. 9952 HConstant* delta = (expr->op() == Token::INC) 9953 ? graph()->GetConstant1() 9954 : graph()->GetConstantMinus1(); 9955 HInstruction* instr = AddUncasted<HAdd>(Top(), delta); 9956 if (instr->IsAdd()) { 9957 HAdd* add = HAdd::cast(instr); 9958 add->set_observed_input_representation(1, rep); 9959 add->set_observed_input_representation(2, Representation::Smi()); 9960 } 9961 instr->SetFlag(HInstruction::kCannotBeTagged); 9962 instr->ClearAllSideEffects(); 9963 return instr; 9964 } 9965 9966 9967 void HOptimizedGraphBuilder::BuildStoreForEffect(Expression* expr, 9968 Property* prop, 9969 BailoutId ast_id, 9970 BailoutId return_id, 9971 HValue* object, 9972 HValue* key, 9973 HValue* value) { 9974 EffectContext for_effect(this); 9975 Push(object); 9976 if (key != NULL) Push(key); 9977 Push(value); 9978 BuildStore(expr, prop, ast_id, return_id); 9979 } 9980 9981 9982 void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) { 9983 DCHECK(!HasStackOverflow()); 9984 DCHECK(current_block() != NULL); 9985 DCHECK(current_block()->HasPredecessor()); 9986 if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position()); 9987 Expression* target = expr->expression(); 9988 VariableProxy* proxy = target->AsVariableProxy(); 9989 Property* prop = target->AsProperty(); 9990 if (proxy == NULL && prop == NULL) { 9991 return Bailout(kInvalidLhsInCountOperation); 9992 } 9993 9994 // Match the full code generator stack by simulating an extra stack 9995 // element for postfix operations in a non-effect context. The return 9996 // value is ToNumber(input). 9997 bool returns_original_input = 9998 expr->is_postfix() && !ast_context()->IsEffect(); 9999 HValue* input = NULL; // ToNumber(original_input). 10000 HValue* after = NULL; // The result after incrementing or decrementing. 10001 10002 if (proxy != NULL) { 10003 Variable* var = proxy->var(); 10004 if (var->mode() == CONST_LEGACY) { 10005 return Bailout(kUnsupportedCountOperationWithConst); 10006 } 10007 // Argument of the count operation is a variable, not a property. 10008 DCHECK(prop == NULL); 10009 CHECK_ALIVE(VisitForValue(target)); 10010 10011 after = BuildIncrement(returns_original_input, expr); 10012 input = returns_original_input ? Top() : Pop(); 10013 Push(after); 10014 10015 switch (var->location()) { 10016 case Variable::UNALLOCATED: 10017 HandleGlobalVariableAssignment(var, 10018 after, 10019 expr->AssignmentId()); 10020 break; 10021 10022 case Variable::PARAMETER: 10023 case Variable::LOCAL: 10024 BindIfLive(var, after); 10025 break; 10026 10027 case Variable::CONTEXT: { 10028 // Bail out if we try to mutate a parameter value in a function 10029 // using the arguments object. We do not (yet) correctly handle the 10030 // arguments property of the function. 10031 if (current_info()->scope()->arguments() != NULL) { 10032 // Parameters will rewrite to context slots. We have no direct 10033 // way to detect that the variable is a parameter so we use a 10034 // linear search of the parameter list. 10035 int count = current_info()->scope()->num_parameters(); 10036 for (int i = 0; i < count; ++i) { 10037 if (var == current_info()->scope()->parameter(i)) { 10038 return Bailout(kAssignmentToParameterInArgumentsObject); 10039 } 10040 } 10041 } 10042 10043 HValue* context = BuildContextChainWalk(var); 10044 HStoreContextSlot::Mode mode = IsLexicalVariableMode(var->mode()) 10045 ? HStoreContextSlot::kCheckDeoptimize : HStoreContextSlot::kNoCheck; 10046 HStoreContextSlot* instr = Add<HStoreContextSlot>(context, var->index(), 10047 mode, after); 10048 if (instr->HasObservableSideEffects()) { 10049 Add<HSimulate>(expr->AssignmentId(), REMOVABLE_SIMULATE); 10050 } 10051 break; 10052 } 10053 10054 case Variable::LOOKUP: 10055 return Bailout(kLookupVariableInCountOperation); 10056 } 10057 10058 Drop(returns_original_input ? 2 : 1); 10059 return ast_context()->ReturnValue(expr->is_postfix() ? input : after); 10060 } 10061 10062 // Argument of the count operation is a property. 10063 DCHECK(prop != NULL); 10064 if (returns_original_input) Push(graph()->GetConstantUndefined()); 10065 10066 CHECK_ALIVE(VisitForValue(prop->obj())); 10067 HValue* object = Top(); 10068 10069 HValue* key = NULL; 10070 if (!prop->key()->IsPropertyName() || prop->IsStringAccess()) { 10071 CHECK_ALIVE(VisitForValue(prop->key())); 10072 key = Top(); 10073 } 10074 10075 CHECK_ALIVE(PushLoad(prop, object, key)); 10076 10077 after = BuildIncrement(returns_original_input, expr); 10078 10079 if (returns_original_input) { 10080 input = Pop(); 10081 // Drop object and key to push it again in the effect context below. 10082 Drop(key == NULL ? 1 : 2); 10083 environment()->SetExpressionStackAt(0, input); 10084 CHECK_ALIVE(BuildStoreForEffect( 10085 expr, prop, expr->id(), expr->AssignmentId(), object, key, after)); 10086 return ast_context()->ReturnValue(Pop()); 10087 } 10088 10089 environment()->SetExpressionStackAt(0, after); 10090 return BuildStore(expr, prop, expr->id(), expr->AssignmentId()); 10091 } 10092 10093 10094 HInstruction* HOptimizedGraphBuilder::BuildStringCharCodeAt( 10095 HValue* string, 10096 HValue* index) { 10097 if (string->IsConstant() && index->IsConstant()) { 10098 HConstant* c_string = HConstant::cast(string); 10099 HConstant* c_index = HConstant::cast(index); 10100 if (c_string->HasStringValue() && c_index->HasNumberValue()) { 10101 int32_t i = c_index->NumberValueAsInteger32(); 10102 Handle<String> s = c_string->StringValue(); 10103 if (i < 0 || i >= s->length()) { 10104 return New<HConstant>(base::OS::nan_value()); 10105 } 10106 return New<HConstant>(s->Get(i)); 10107 } 10108 } 10109 string = BuildCheckString(string); 10110 index = Add<HBoundsCheck>(index, AddLoadStringLength(string)); 10111 return New<HStringCharCodeAt>(string, index); 10112 } 10113 10114 10115 // Checks if the given shift amounts have following forms: 10116 // (N1) and (N2) with N1 + N2 = 32; (sa) and (32 - sa). 10117 static bool ShiftAmountsAllowReplaceByRotate(HValue* sa, 10118 HValue* const32_minus_sa) { 10119 if (sa->IsConstant() && const32_minus_sa->IsConstant()) { 10120 const HConstant* c1 = HConstant::cast(sa); 10121 const HConstant* c2 = HConstant::cast(const32_minus_sa); 10122 return c1->HasInteger32Value() && c2->HasInteger32Value() && 10123 (c1->Integer32Value() + c2->Integer32Value() == 32); 10124 } 10125 if (!const32_minus_sa->IsSub()) return false; 10126 HSub* sub = HSub::cast(const32_minus_sa); 10127 return sub->left()->EqualsInteger32Constant(32) && sub->right() == sa; 10128 } 10129 10130 10131 // Checks if the left and the right are shift instructions with the oposite 10132 // directions that can be replaced by one rotate right instruction or not. 10133 // Returns the operand and the shift amount for the rotate instruction in the 10134 // former case. 10135 bool HGraphBuilder::MatchRotateRight(HValue* left, 10136 HValue* right, 10137 HValue** operand, 10138 HValue** shift_amount) { 10139 HShl* shl; 10140 HShr* shr; 10141 if (left->IsShl() && right->IsShr()) { 10142 shl = HShl::cast(left); 10143 shr = HShr::cast(right); 10144 } else if (left->IsShr() && right->IsShl()) { 10145 shl = HShl::cast(right); 10146 shr = HShr::cast(left); 10147 } else { 10148 return false; 10149 } 10150 if (shl->left() != shr->left()) return false; 10151 10152 if (!ShiftAmountsAllowReplaceByRotate(shl->right(), shr->right()) && 10153 !ShiftAmountsAllowReplaceByRotate(shr->right(), shl->right())) { 10154 return false; 10155 } 10156 *operand= shr->left(); 10157 *shift_amount = shr->right(); 10158 return true; 10159 } 10160 10161 10162 bool CanBeZero(HValue* right) { 10163 if (right->IsConstant()) { 10164 HConstant* right_const = HConstant::cast(right); 10165 if (right_const->HasInteger32Value() && 10166 (right_const->Integer32Value() & 0x1f) != 0) { 10167 return false; 10168 } 10169 } 10170 return true; 10171 } 10172 10173 10174 HValue* HGraphBuilder::EnforceNumberType(HValue* number, 10175 Type* expected) { 10176 if (expected->Is(Type::SignedSmall())) { 10177 return AddUncasted<HForceRepresentation>(number, Representation::Smi()); 10178 } 10179 if (expected->Is(Type::Signed32())) { 10180 return AddUncasted<HForceRepresentation>(number, 10181 Representation::Integer32()); 10182 } 10183 return number; 10184 } 10185 10186 10187 HValue* HGraphBuilder::TruncateToNumber(HValue* value, Type** expected) { 10188 if (value->IsConstant()) { 10189 HConstant* constant = HConstant::cast(value); 10190 Maybe<HConstant*> number = constant->CopyToTruncatedNumber(zone()); 10191 if (number.has_value) { 10192 *expected = Type::Number(zone()); 10193 return AddInstruction(number.value); 10194 } 10195 } 10196 10197 // We put temporary values on the stack, which don't correspond to anything 10198 // in baseline code. Since nothing is observable we avoid recording those 10199 // pushes with a NoObservableSideEffectsScope. 10200 NoObservableSideEffectsScope no_effects(this); 10201 10202 Type* expected_type = *expected; 10203 10204 // Separate the number type from the rest. 10205 Type* expected_obj = 10206 Type::Intersect(expected_type, Type::NonNumber(zone()), zone()); 10207 Type* expected_number = 10208 Type::Intersect(expected_type, Type::Number(zone()), zone()); 10209 10210 // We expect to get a number. 10211 // (We need to check first, since Type::None->Is(Type::Any()) == true. 10212 if (expected_obj->Is(Type::None())) { 10213 DCHECK(!expected_number->Is(Type::None(zone()))); 10214 return value; 10215 } 10216 10217 if (expected_obj->Is(Type::Undefined(zone()))) { 10218 // This is already done by HChange. 10219 *expected = Type::Union(expected_number, Type::Number(zone()), zone()); 10220 return value; 10221 } 10222 10223 return value; 10224 } 10225 10226 10227 HValue* HOptimizedGraphBuilder::BuildBinaryOperation( 10228 BinaryOperation* expr, 10229 HValue* left, 10230 HValue* right, 10231 PushBeforeSimulateBehavior push_sim_result) { 10232 Type* left_type = expr->left()->bounds().lower; 10233 Type* right_type = expr->right()->bounds().lower; 10234 Type* result_type = expr->bounds().lower; 10235 Maybe<int> fixed_right_arg = expr->fixed_right_arg(); 10236 Handle<AllocationSite> allocation_site = expr->allocation_site(); 10237 10238 HAllocationMode allocation_mode; 10239 if (FLAG_allocation_site_pretenuring && !allocation_site.is_null()) { 10240 allocation_mode = HAllocationMode(allocation_site); 10241 } 10242 10243 HValue* result = HGraphBuilder::BuildBinaryOperation( 10244 expr->op(), left, right, left_type, right_type, result_type, 10245 fixed_right_arg, allocation_mode); 10246 // Add a simulate after instructions with observable side effects, and 10247 // after phis, which are the result of BuildBinaryOperation when we 10248 // inlined some complex subgraph. 10249 if (result->HasObservableSideEffects() || result->IsPhi()) { 10250 if (push_sim_result == PUSH_BEFORE_SIMULATE) { 10251 Push(result); 10252 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); 10253 Drop(1); 10254 } else { 10255 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); 10256 } 10257 } 10258 return result; 10259 } 10260 10261 10262 HValue* HGraphBuilder::BuildBinaryOperation( 10263 Token::Value op, 10264 HValue* left, 10265 HValue* right, 10266 Type* left_type, 10267 Type* right_type, 10268 Type* result_type, 10269 Maybe<int> fixed_right_arg, 10270 HAllocationMode allocation_mode) { 10271 10272 Representation left_rep = Representation::FromType(left_type); 10273 Representation right_rep = Representation::FromType(right_type); 10274 10275 bool maybe_string_add = op == Token::ADD && 10276 (left_type->Maybe(Type::String()) || 10277 left_type->Maybe(Type::Receiver()) || 10278 right_type->Maybe(Type::String()) || 10279 right_type->Maybe(Type::Receiver())); 10280 10281 if (!left_type->IsInhabited()) { 10282 Add<HDeoptimize>("Insufficient type feedback for LHS of binary operation", 10283 Deoptimizer::SOFT); 10284 // TODO(rossberg): we should be able to get rid of non-continuous 10285 // defaults. 10286 left_type = Type::Any(zone()); 10287 } else { 10288 if (!maybe_string_add) left = TruncateToNumber(left, &left_type); 10289 left_rep = Representation::FromType(left_type); 10290 } 10291 10292 if (!right_type->IsInhabited()) { 10293 Add<HDeoptimize>("Insufficient type feedback for RHS of binary operation", 10294 Deoptimizer::SOFT); 10295 right_type = Type::Any(zone()); 10296 } else { 10297 if (!maybe_string_add) right = TruncateToNumber(right, &right_type); 10298 right_rep = Representation::FromType(right_type); 10299 } 10300 10301 // Special case for string addition here. 10302 if (op == Token::ADD && 10303 (left_type->Is(Type::String()) || right_type->Is(Type::String()))) { 10304 // Validate type feedback for left argument. 10305 if (left_type->Is(Type::String())) { 10306 left = BuildCheckString(left); 10307 } 10308 10309 // Validate type feedback for right argument. 10310 if (right_type->Is(Type::String())) { 10311 right = BuildCheckString(right); 10312 } 10313 10314 // Convert left argument as necessary. 10315 if (left_type->Is(Type::Number())) { 10316 DCHECK(right_type->Is(Type::String())); 10317 left = BuildNumberToString(left, left_type); 10318 } else if (!left_type->Is(Type::String())) { 10319 DCHECK(right_type->Is(Type::String())); 10320 HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_RIGHT); 10321 Add<HPushArguments>(left, right); 10322 return AddUncasted<HInvokeFunction>(function, 2); 10323 } 10324 10325 // Convert right argument as necessary. 10326 if (right_type->Is(Type::Number())) { 10327 DCHECK(left_type->Is(Type::String())); 10328 right = BuildNumberToString(right, right_type); 10329 } else if (!right_type->Is(Type::String())) { 10330 DCHECK(left_type->Is(Type::String())); 10331 HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_LEFT); 10332 Add<HPushArguments>(left, right); 10333 return AddUncasted<HInvokeFunction>(function, 2); 10334 } 10335 10336 // Fast path for empty constant strings. 10337 if (left->IsConstant() && 10338 HConstant::cast(left)->HasStringValue() && 10339 HConstant::cast(left)->StringValue()->length() == 0) { 10340 return right; 10341 } 10342 if (right->IsConstant() && 10343 HConstant::cast(right)->HasStringValue() && 10344 HConstant::cast(right)->StringValue()->length() == 0) { 10345 return left; 10346 } 10347 10348 // Register the dependent code with the allocation site. 10349 if (!allocation_mode.feedback_site().is_null()) { 10350 DCHECK(!graph()->info()->IsStub()); 10351 Handle<AllocationSite> site(allocation_mode.feedback_site()); 10352 AllocationSite::AddDependentCompilationInfo( 10353 site, AllocationSite::TENURING, top_info()); 10354 } 10355 10356 // Inline the string addition into the stub when creating allocation 10357 // mementos to gather allocation site feedback, or if we can statically 10358 // infer that we're going to create a cons string. 10359 if ((graph()->info()->IsStub() && 10360 allocation_mode.CreateAllocationMementos()) || 10361 (left->IsConstant() && 10362 HConstant::cast(left)->HasStringValue() && 10363 HConstant::cast(left)->StringValue()->length() + 1 >= 10364 ConsString::kMinLength) || 10365 (right->IsConstant() && 10366 HConstant::cast(right)->HasStringValue() && 10367 HConstant::cast(right)->StringValue()->length() + 1 >= 10368 ConsString::kMinLength)) { 10369 return BuildStringAdd(left, right, allocation_mode); 10370 } 10371 10372 // Fallback to using the string add stub. 10373 return AddUncasted<HStringAdd>( 10374 left, right, allocation_mode.GetPretenureMode(), 10375 STRING_ADD_CHECK_NONE, allocation_mode.feedback_site()); 10376 } 10377 10378 if (graph()->info()->IsStub()) { 10379 left = EnforceNumberType(left, left_type); 10380 right = EnforceNumberType(right, right_type); 10381 } 10382 10383 Representation result_rep = Representation::FromType(result_type); 10384 10385 bool is_non_primitive = (left_rep.IsTagged() && !left_rep.IsSmi()) || 10386 (right_rep.IsTagged() && !right_rep.IsSmi()); 10387 10388 HInstruction* instr = NULL; 10389 // Only the stub is allowed to call into the runtime, since otherwise we would 10390 // inline several instructions (including the two pushes) for every tagged 10391 // operation in optimized code, which is more expensive, than a stub call. 10392 if (graph()->info()->IsStub() && is_non_primitive) { 10393 HValue* function = AddLoadJSBuiltin(BinaryOpIC::TokenToJSBuiltin(op)); 10394 Add<HPushArguments>(left, right); 10395 instr = AddUncasted<HInvokeFunction>(function, 2); 10396 } else { 10397 switch (op) { 10398 case Token::ADD: 10399 instr = AddUncasted<HAdd>(left, right); 10400 break; 10401 case Token::SUB: 10402 instr = AddUncasted<HSub>(left, right); 10403 break; 10404 case Token::MUL: 10405 instr = AddUncasted<HMul>(left, right); 10406 break; 10407 case Token::MOD: { 10408 if (fixed_right_arg.has_value && 10409 !right->EqualsInteger32Constant(fixed_right_arg.value)) { 10410 HConstant* fixed_right = Add<HConstant>( 10411 static_cast<int>(fixed_right_arg.value)); 10412 IfBuilder if_same(this); 10413 if_same.If<HCompareNumericAndBranch>(right, fixed_right, Token::EQ); 10414 if_same.Then(); 10415 if_same.ElseDeopt("Unexpected RHS of binary operation"); 10416 right = fixed_right; 10417 } 10418 instr = AddUncasted<HMod>(left, right); 10419 break; 10420 } 10421 case Token::DIV: 10422 instr = AddUncasted<HDiv>(left, right); 10423 break; 10424 case Token::BIT_XOR: 10425 case Token::BIT_AND: 10426 instr = AddUncasted<HBitwise>(op, left, right); 10427 break; 10428 case Token::BIT_OR: { 10429 HValue* operand, *shift_amount; 10430 if (left_type->Is(Type::Signed32()) && 10431 right_type->Is(Type::Signed32()) && 10432 MatchRotateRight(left, right, &operand, &shift_amount)) { 10433 instr = AddUncasted<HRor>(operand, shift_amount); 10434 } else { 10435 instr = AddUncasted<HBitwise>(op, left, right); 10436 } 10437 break; 10438 } 10439 case Token::SAR: 10440 instr = AddUncasted<HSar>(left, right); 10441 break; 10442 case Token::SHR: 10443 instr = AddUncasted<HShr>(left, right); 10444 if (FLAG_opt_safe_uint32_operations && instr->IsShr() && 10445 CanBeZero(right)) { 10446 graph()->RecordUint32Instruction(instr); 10447 } 10448 break; 10449 case Token::SHL: 10450 instr = AddUncasted<HShl>(left, right); 10451 break; 10452 default: 10453 UNREACHABLE(); 10454 } 10455 } 10456 10457 if (instr->IsBinaryOperation()) { 10458 HBinaryOperation* binop = HBinaryOperation::cast(instr); 10459 binop->set_observed_input_representation(1, left_rep); 10460 binop->set_observed_input_representation(2, right_rep); 10461 binop->initialize_output_representation(result_rep); 10462 if (graph()->info()->IsStub()) { 10463 // Stub should not call into stub. 10464 instr->SetFlag(HValue::kCannotBeTagged); 10465 // And should truncate on HForceRepresentation already. 10466 if (left->IsForceRepresentation()) { 10467 left->CopyFlag(HValue::kTruncatingToSmi, instr); 10468 left->CopyFlag(HValue::kTruncatingToInt32, instr); 10469 } 10470 if (right->IsForceRepresentation()) { 10471 right->CopyFlag(HValue::kTruncatingToSmi, instr); 10472 right->CopyFlag(HValue::kTruncatingToInt32, instr); 10473 } 10474 } 10475 } 10476 return instr; 10477 } 10478 10479 10480 // Check for the form (%_ClassOf(foo) === 'BarClass'). 10481 static bool IsClassOfTest(CompareOperation* expr) { 10482 if (expr->op() != Token::EQ_STRICT) return false; 10483 CallRuntime* call = expr->left()->AsCallRuntime(); 10484 if (call == NULL) return false; 10485 Literal* literal = expr->right()->AsLiteral(); 10486 if (literal == NULL) return false; 10487 if (!literal->value()->IsString()) return false; 10488 if (!call->name()->IsOneByteEqualTo(STATIC_CHAR_VECTOR("_ClassOf"))) { 10489 return false; 10490 } 10491 DCHECK(call->arguments()->length() == 1); 10492 return true; 10493 } 10494 10495 10496 void HOptimizedGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { 10497 DCHECK(!HasStackOverflow()); 10498 DCHECK(current_block() != NULL); 10499 DCHECK(current_block()->HasPredecessor()); 10500 switch (expr->op()) { 10501 case Token::COMMA: 10502 return VisitComma(expr); 10503 case Token::OR: 10504 case Token::AND: 10505 return VisitLogicalExpression(expr); 10506 default: 10507 return VisitArithmeticExpression(expr); 10508 } 10509 } 10510 10511 10512 void HOptimizedGraphBuilder::VisitComma(BinaryOperation* expr) { 10513 CHECK_ALIVE(VisitForEffect(expr->left())); 10514 // Visit the right subexpression in the same AST context as the entire 10515 // expression. 10516 Visit(expr->right()); 10517 } 10518 10519 10520 void HOptimizedGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) { 10521 bool is_logical_and = expr->op() == Token::AND; 10522 if (ast_context()->IsTest()) { 10523 TestContext* context = TestContext::cast(ast_context()); 10524 // Translate left subexpression. 10525 HBasicBlock* eval_right = graph()->CreateBasicBlock(); 10526 if (is_logical_and) { 10527 CHECK_BAILOUT(VisitForControl(expr->left(), 10528 eval_right, 10529 context->if_false())); 10530 } else { 10531 CHECK_BAILOUT(VisitForControl(expr->left(), 10532 context->if_true(), 10533 eval_right)); 10534 } 10535 10536 // Translate right subexpression by visiting it in the same AST 10537 // context as the entire expression. 10538 if (eval_right->HasPredecessor()) { 10539 eval_right->SetJoinId(expr->RightId()); 10540 set_current_block(eval_right); 10541 Visit(expr->right()); 10542 } 10543 10544 } else if (ast_context()->IsValue()) { 10545 CHECK_ALIVE(VisitForValue(expr->left())); 10546 DCHECK(current_block() != NULL); 10547 HValue* left_value = Top(); 10548 10549 // Short-circuit left values that always evaluate to the same boolean value. 10550 if (expr->left()->ToBooleanIsTrue() || expr->left()->ToBooleanIsFalse()) { 10551 // l (evals true) && r -> r 10552 // l (evals true) || r -> l 10553 // l (evals false) && r -> l 10554 // l (evals false) || r -> r 10555 if (is_logical_and == expr->left()->ToBooleanIsTrue()) { 10556 Drop(1); 10557 CHECK_ALIVE(VisitForValue(expr->right())); 10558 } 10559 return ast_context()->ReturnValue(Pop()); 10560 } 10561 10562 // We need an extra block to maintain edge-split form. 10563 HBasicBlock* empty_block = graph()->CreateBasicBlock(); 10564 HBasicBlock* eval_right = graph()->CreateBasicBlock(); 10565 ToBooleanStub::Types expected(expr->left()->to_boolean_types()); 10566 HBranch* test = is_logical_and 10567 ? New<HBranch>(left_value, expected, eval_right, empty_block) 10568 : New<HBranch>(left_value, expected, empty_block, eval_right); 10569 FinishCurrentBlock(test); 10570 10571 set_current_block(eval_right); 10572 Drop(1); // Value of the left subexpression. 10573 CHECK_BAILOUT(VisitForValue(expr->right())); 10574 10575 HBasicBlock* join_block = 10576 CreateJoin(empty_block, current_block(), expr->id()); 10577 set_current_block(join_block); 10578 return ast_context()->ReturnValue(Pop()); 10579 10580 } else { 10581 DCHECK(ast_context()->IsEffect()); 10582 // In an effect context, we don't need the value of the left subexpression, 10583 // only its control flow and side effects. We need an extra block to 10584 // maintain edge-split form. 10585 HBasicBlock* empty_block = graph()->CreateBasicBlock(); 10586 HBasicBlock* right_block = graph()->CreateBasicBlock(); 10587 if (is_logical_and) { 10588 CHECK_BAILOUT(VisitForControl(expr->left(), right_block, empty_block)); 10589 } else { 10590 CHECK_BAILOUT(VisitForControl(expr->left(), empty_block, right_block)); 10591 } 10592 10593 // TODO(kmillikin): Find a way to fix this. It's ugly that there are 10594 // actually two empty blocks (one here and one inserted by 10595 // TestContext::BuildBranch, and that they both have an HSimulate though the 10596 // second one is not a merge node, and that we really have no good AST ID to 10597 // put on that first HSimulate. 10598 10599 if (empty_block->HasPredecessor()) { 10600 empty_block->SetJoinId(expr->id()); 10601 } else { 10602 empty_block = NULL; 10603 } 10604 10605 if (right_block->HasPredecessor()) { 10606 right_block->SetJoinId(expr->RightId()); 10607 set_current_block(right_block); 10608 CHECK_BAILOUT(VisitForEffect(expr->right())); 10609 right_block = current_block(); 10610 } else { 10611 right_block = NULL; 10612 } 10613 10614 HBasicBlock* join_block = 10615 CreateJoin(empty_block, right_block, expr->id()); 10616 set_current_block(join_block); 10617 // We did not materialize any value in the predecessor environments, 10618 // so there is no need to handle it here. 10619 } 10620 } 10621 10622 10623 void HOptimizedGraphBuilder::VisitArithmeticExpression(BinaryOperation* expr) { 10624 CHECK_ALIVE(VisitForValue(expr->left())); 10625 CHECK_ALIVE(VisitForValue(expr->right())); 10626 SetSourcePosition(expr->position()); 10627 HValue* right = Pop(); 10628 HValue* left = Pop(); 10629 HValue* result = 10630 BuildBinaryOperation(expr, left, right, 10631 ast_context()->IsEffect() ? NO_PUSH_BEFORE_SIMULATE 10632 : PUSH_BEFORE_SIMULATE); 10633 if (FLAG_hydrogen_track_positions && result->IsBinaryOperation()) { 10634 HBinaryOperation::cast(result)->SetOperandPositions( 10635 zone(), 10636 ScriptPositionToSourcePosition(expr->left()->position()), 10637 ScriptPositionToSourcePosition(expr->right()->position())); 10638 } 10639 return ast_context()->ReturnValue(result); 10640 } 10641 10642 10643 void HOptimizedGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* expr, 10644 Expression* sub_expr, 10645 Handle<String> check) { 10646 CHECK_ALIVE(VisitForTypeOf(sub_expr)); 10647 SetSourcePosition(expr->position()); 10648 HValue* value = Pop(); 10649 HTypeofIsAndBranch* instr = New<HTypeofIsAndBranch>(value, check); 10650 return ast_context()->ReturnControl(instr, expr->id()); 10651 } 10652 10653 10654 static bool IsLiteralCompareBool(Isolate* isolate, 10655 HValue* left, 10656 Token::Value op, 10657 HValue* right) { 10658 return op == Token::EQ_STRICT && 10659 ((left->IsConstant() && 10660 HConstant::cast(left)->handle(isolate)->IsBoolean()) || 10661 (right->IsConstant() && 10662 HConstant::cast(right)->handle(isolate)->IsBoolean())); 10663 } 10664 10665 10666 void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) { 10667 DCHECK(!HasStackOverflow()); 10668 DCHECK(current_block() != NULL); 10669 DCHECK(current_block()->HasPredecessor()); 10670 10671 if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position()); 10672 10673 // Check for a few fast cases. The AST visiting behavior must be in sync 10674 // with the full codegen: We don't push both left and right values onto 10675 // the expression stack when one side is a special-case literal. 10676 Expression* sub_expr = NULL; 10677 Handle<String> check; 10678 if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) { 10679 return HandleLiteralCompareTypeof(expr, sub_expr, check); 10680 } 10681 if (expr->IsLiteralCompareUndefined(&sub_expr, isolate())) { 10682 return HandleLiteralCompareNil(expr, sub_expr, kUndefinedValue); 10683 } 10684 if (expr->IsLiteralCompareNull(&sub_expr)) { 10685 return HandleLiteralCompareNil(expr, sub_expr, kNullValue); 10686 } 10687 10688 if (IsClassOfTest(expr)) { 10689 CallRuntime* call = expr->left()->AsCallRuntime(); 10690 DCHECK(call->arguments()->length() == 1); 10691 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 10692 HValue* value = Pop(); 10693 Literal* literal = expr->right()->AsLiteral(); 10694 Handle<String> rhs = Handle<String>::cast(literal->value()); 10695 HClassOfTestAndBranch* instr = New<HClassOfTestAndBranch>(value, rhs); 10696 return ast_context()->ReturnControl(instr, expr->id()); 10697 } 10698 10699 Type* left_type = expr->left()->bounds().lower; 10700 Type* right_type = expr->right()->bounds().lower; 10701 Type* combined_type = expr->combined_type(); 10702 10703 CHECK_ALIVE(VisitForValue(expr->left())); 10704 CHECK_ALIVE(VisitForValue(expr->right())); 10705 10706 if (FLAG_hydrogen_track_positions) SetSourcePosition(expr->position()); 10707 10708 HValue* right = Pop(); 10709 HValue* left = Pop(); 10710 Token::Value op = expr->op(); 10711 10712 if (IsLiteralCompareBool(isolate(), left, op, right)) { 10713 HCompareObjectEqAndBranch* result = 10714 New<HCompareObjectEqAndBranch>(left, right); 10715 return ast_context()->ReturnControl(result, expr->id()); 10716 } 10717 10718 if (op == Token::INSTANCEOF) { 10719 // Check to see if the rhs of the instanceof is a global function not 10720 // residing in new space. If it is we assume that the function will stay the 10721 // same. 10722 Handle<JSFunction> target = Handle<JSFunction>::null(); 10723 VariableProxy* proxy = expr->right()->AsVariableProxy(); 10724 bool global_function = (proxy != NULL) && proxy->var()->IsUnallocated(); 10725 if (global_function && current_info()->has_global_object()) { 10726 Handle<String> name = proxy->name(); 10727 Handle<GlobalObject> global(current_info()->global_object()); 10728 LookupIterator it(global, name, LookupIterator::OWN_SKIP_INTERCEPTOR); 10729 Handle<Object> value = JSObject::GetDataProperty(&it); 10730 if (it.IsFound() && value->IsJSFunction()) { 10731 Handle<JSFunction> candidate = Handle<JSFunction>::cast(value); 10732 // If the function is in new space we assume it's more likely to 10733 // change and thus prefer the general IC code. 10734 if (!isolate()->heap()->InNewSpace(*candidate)) { 10735 target = candidate; 10736 } 10737 } 10738 } 10739 10740 // If the target is not null we have found a known global function that is 10741 // assumed to stay the same for this instanceof. 10742 if (target.is_null()) { 10743 HInstanceOf* result = New<HInstanceOf>(left, right); 10744 return ast_context()->ReturnInstruction(result, expr->id()); 10745 } else { 10746 Add<HCheckValue>(right, target); 10747 HInstanceOfKnownGlobal* result = 10748 New<HInstanceOfKnownGlobal>(left, target); 10749 return ast_context()->ReturnInstruction(result, expr->id()); 10750 } 10751 10752 // Code below assumes that we don't fall through. 10753 UNREACHABLE(); 10754 } else if (op == Token::IN) { 10755 HValue* function = AddLoadJSBuiltin(Builtins::IN); 10756 Add<HPushArguments>(left, right); 10757 // TODO(olivf) InvokeFunction produces a check for the parameter count, 10758 // even though we are certain to pass the correct number of arguments here. 10759 HInstruction* result = New<HInvokeFunction>(function, 2); 10760 return ast_context()->ReturnInstruction(result, expr->id()); 10761 } 10762 10763 PushBeforeSimulateBehavior push_behavior = 10764 ast_context()->IsEffect() ? NO_PUSH_BEFORE_SIMULATE 10765 : PUSH_BEFORE_SIMULATE; 10766 HControlInstruction* compare = BuildCompareInstruction( 10767 op, left, right, left_type, right_type, combined_type, 10768 ScriptPositionToSourcePosition(expr->left()->position()), 10769 ScriptPositionToSourcePosition(expr->right()->position()), 10770 push_behavior, expr->id()); 10771 if (compare == NULL) return; // Bailed out. 10772 return ast_context()->ReturnControl(compare, expr->id()); 10773 } 10774 10775 10776 HControlInstruction* HOptimizedGraphBuilder::BuildCompareInstruction( 10777 Token::Value op, 10778 HValue* left, 10779 HValue* right, 10780 Type* left_type, 10781 Type* right_type, 10782 Type* combined_type, 10783 HSourcePosition left_position, 10784 HSourcePosition right_position, 10785 PushBeforeSimulateBehavior push_sim_result, 10786 BailoutId bailout_id) { 10787 // Cases handled below depend on collected type feedback. They should 10788 // soft deoptimize when there is no type feedback. 10789 if (!combined_type->IsInhabited()) { 10790 Add<HDeoptimize>("Insufficient type feedback for combined type " 10791 "of binary operation", 10792 Deoptimizer::SOFT); 10793 combined_type = left_type = right_type = Type::Any(zone()); 10794 } 10795 10796 Representation left_rep = Representation::FromType(left_type); 10797 Representation right_rep = Representation::FromType(right_type); 10798 Representation combined_rep = Representation::FromType(combined_type); 10799 10800 if (combined_type->Is(Type::Receiver())) { 10801 if (Token::IsEqualityOp(op)) { 10802 // HCompareObjectEqAndBranch can only deal with object, so 10803 // exclude numbers. 10804 if ((left->IsConstant() && 10805 HConstant::cast(left)->HasNumberValue()) || 10806 (right->IsConstant() && 10807 HConstant::cast(right)->HasNumberValue())) { 10808 Add<HDeoptimize>("Type mismatch between feedback and constant", 10809 Deoptimizer::SOFT); 10810 // The caller expects a branch instruction, so make it happy. 10811 return New<HBranch>(graph()->GetConstantTrue()); 10812 } 10813 // Can we get away with map check and not instance type check? 10814 HValue* operand_to_check = 10815 left->block()->block_id() < right->block()->block_id() ? left : right; 10816 if (combined_type->IsClass()) { 10817 Handle<Map> map = combined_type->AsClass()->Map(); 10818 AddCheckMap(operand_to_check, map); 10819 HCompareObjectEqAndBranch* result = 10820 New<HCompareObjectEqAndBranch>(left, right); 10821 if (FLAG_hydrogen_track_positions) { 10822 result->set_operand_position(zone(), 0, left_position); 10823 result->set_operand_position(zone(), 1, right_position); 10824 } 10825 return result; 10826 } else { 10827 BuildCheckHeapObject(operand_to_check); 10828 Add<HCheckInstanceType>(operand_to_check, 10829 HCheckInstanceType::IS_SPEC_OBJECT); 10830 HCompareObjectEqAndBranch* result = 10831 New<HCompareObjectEqAndBranch>(left, right); 10832 return result; 10833 } 10834 } else { 10835 Bailout(kUnsupportedNonPrimitiveCompare); 10836 return NULL; 10837 } 10838 } else if (combined_type->Is(Type::InternalizedString()) && 10839 Token::IsEqualityOp(op)) { 10840 // If we have a constant argument, it should be consistent with the type 10841 // feedback (otherwise we fail assertions in HCompareObjectEqAndBranch). 10842 if ((left->IsConstant() && 10843 !HConstant::cast(left)->HasInternalizedStringValue()) || 10844 (right->IsConstant() && 10845 !HConstant::cast(right)->HasInternalizedStringValue())) { 10846 Add<HDeoptimize>("Type mismatch between feedback and constant", 10847 Deoptimizer::SOFT); 10848 // The caller expects a branch instruction, so make it happy. 10849 return New<HBranch>(graph()->GetConstantTrue()); 10850 } 10851 BuildCheckHeapObject(left); 10852 Add<HCheckInstanceType>(left, HCheckInstanceType::IS_INTERNALIZED_STRING); 10853 BuildCheckHeapObject(right); 10854 Add<HCheckInstanceType>(right, HCheckInstanceType::IS_INTERNALIZED_STRING); 10855 HCompareObjectEqAndBranch* result = 10856 New<HCompareObjectEqAndBranch>(left, right); 10857 return result; 10858 } else if (combined_type->Is(Type::String())) { 10859 BuildCheckHeapObject(left); 10860 Add<HCheckInstanceType>(left, HCheckInstanceType::IS_STRING); 10861 BuildCheckHeapObject(right); 10862 Add<HCheckInstanceType>(right, HCheckInstanceType::IS_STRING); 10863 HStringCompareAndBranch* result = 10864 New<HStringCompareAndBranch>(left, right, op); 10865 return result; 10866 } else { 10867 if (combined_rep.IsTagged() || combined_rep.IsNone()) { 10868 HCompareGeneric* result = Add<HCompareGeneric>(left, right, op); 10869 result->set_observed_input_representation(1, left_rep); 10870 result->set_observed_input_representation(2, right_rep); 10871 if (result->HasObservableSideEffects()) { 10872 if (push_sim_result == PUSH_BEFORE_SIMULATE) { 10873 Push(result); 10874 AddSimulate(bailout_id, REMOVABLE_SIMULATE); 10875 Drop(1); 10876 } else { 10877 AddSimulate(bailout_id, REMOVABLE_SIMULATE); 10878 } 10879 } 10880 // TODO(jkummerow): Can we make this more efficient? 10881 HBranch* branch = New<HBranch>(result); 10882 return branch; 10883 } else { 10884 HCompareNumericAndBranch* result = 10885 New<HCompareNumericAndBranch>(left, right, op); 10886 result->set_observed_input_representation(left_rep, right_rep); 10887 if (FLAG_hydrogen_track_positions) { 10888 result->SetOperandPositions(zone(), left_position, right_position); 10889 } 10890 return result; 10891 } 10892 } 10893 } 10894 10895 10896 void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr, 10897 Expression* sub_expr, 10898 NilValue nil) { 10899 DCHECK(!HasStackOverflow()); 10900 DCHECK(current_block() != NULL); 10901 DCHECK(current_block()->HasPredecessor()); 10902 DCHECK(expr->op() == Token::EQ || expr->op() == Token::EQ_STRICT); 10903 if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position()); 10904 CHECK_ALIVE(VisitForValue(sub_expr)); 10905 HValue* value = Pop(); 10906 if (expr->op() == Token::EQ_STRICT) { 10907 HConstant* nil_constant = nil == kNullValue 10908 ? graph()->GetConstantNull() 10909 : graph()->GetConstantUndefined(); 10910 HCompareObjectEqAndBranch* instr = 10911 New<HCompareObjectEqAndBranch>(value, nil_constant); 10912 return ast_context()->ReturnControl(instr, expr->id()); 10913 } else { 10914 DCHECK_EQ(Token::EQ, expr->op()); 10915 Type* type = expr->combined_type()->Is(Type::None()) 10916 ? Type::Any(zone()) : expr->combined_type(); 10917 HIfContinuation continuation; 10918 BuildCompareNil(value, type, &continuation); 10919 return ast_context()->ReturnContinuation(&continuation, expr->id()); 10920 } 10921 } 10922 10923 10924 HInstruction* HOptimizedGraphBuilder::BuildThisFunction() { 10925 // If we share optimized code between different closures, the 10926 // this-function is not a constant, except inside an inlined body. 10927 if (function_state()->outer() != NULL) { 10928 return New<HConstant>( 10929 function_state()->compilation_info()->closure()); 10930 } else { 10931 return New<HThisFunction>(); 10932 } 10933 } 10934 10935 10936 HInstruction* HOptimizedGraphBuilder::BuildFastLiteral( 10937 Handle<JSObject> boilerplate_object, 10938 AllocationSiteUsageContext* site_context) { 10939 NoObservableSideEffectsScope no_effects(this); 10940 InstanceType instance_type = boilerplate_object->map()->instance_type(); 10941 DCHECK(instance_type == JS_ARRAY_TYPE || instance_type == JS_OBJECT_TYPE); 10942 10943 HType type = instance_type == JS_ARRAY_TYPE 10944 ? HType::JSArray() : HType::JSObject(); 10945 HValue* object_size_constant = Add<HConstant>( 10946 boilerplate_object->map()->instance_size()); 10947 10948 PretenureFlag pretenure_flag = NOT_TENURED; 10949 if (FLAG_allocation_site_pretenuring) { 10950 pretenure_flag = site_context->current()->GetPretenureMode(); 10951 Handle<AllocationSite> site(site_context->current()); 10952 AllocationSite::AddDependentCompilationInfo( 10953 site, AllocationSite::TENURING, top_info()); 10954 } 10955 10956 HInstruction* object = Add<HAllocate>(object_size_constant, type, 10957 pretenure_flag, instance_type, site_context->current()); 10958 10959 // If allocation folding reaches Page::kMaxRegularHeapObjectSize the 10960 // elements array may not get folded into the object. Hence, we set the 10961 // elements pointer to empty fixed array and let store elimination remove 10962 // this store in the folding case. 10963 HConstant* empty_fixed_array = Add<HConstant>( 10964 isolate()->factory()->empty_fixed_array()); 10965 Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(), 10966 empty_fixed_array); 10967 10968 BuildEmitObjectHeader(boilerplate_object, object); 10969 10970 Handle<FixedArrayBase> elements(boilerplate_object->elements()); 10971 int elements_size = (elements->length() > 0 && 10972 elements->map() != isolate()->heap()->fixed_cow_array_map()) ? 10973 elements->Size() : 0; 10974 10975 if (pretenure_flag == TENURED && 10976 elements->map() == isolate()->heap()->fixed_cow_array_map() && 10977 isolate()->heap()->InNewSpace(*elements)) { 10978 // If we would like to pretenure a fixed cow array, we must ensure that the 10979 // array is already in old space, otherwise we'll create too many old-to- 10980 // new-space pointers (overflowing the store buffer). 10981 elements = Handle<FixedArrayBase>( 10982 isolate()->factory()->CopyAndTenureFixedCOWArray( 10983 Handle<FixedArray>::cast(elements))); 10984 boilerplate_object->set_elements(*elements); 10985 } 10986 10987 HInstruction* object_elements = NULL; 10988 if (elements_size > 0) { 10989 HValue* object_elements_size = Add<HConstant>(elements_size); 10990 InstanceType instance_type = boilerplate_object->HasFastDoubleElements() 10991 ? FIXED_DOUBLE_ARRAY_TYPE : FIXED_ARRAY_TYPE; 10992 object_elements = Add<HAllocate>( 10993 object_elements_size, HType::HeapObject(), 10994 pretenure_flag, instance_type, site_context->current()); 10995 } 10996 BuildInitElementsInObjectHeader(boilerplate_object, object, object_elements); 10997 10998 // Copy object elements if non-COW. 10999 if (object_elements != NULL) { 11000 BuildEmitElements(boilerplate_object, elements, object_elements, 11001 site_context); 11002 } 11003 11004 // Copy in-object properties. 11005 if (boilerplate_object->map()->NumberOfFields() != 0 || 11006 boilerplate_object->map()->unused_property_fields() > 0) { 11007 BuildEmitInObjectProperties(boilerplate_object, object, site_context, 11008 pretenure_flag); 11009 } 11010 return object; 11011 } 11012 11013 11014 void HOptimizedGraphBuilder::BuildEmitObjectHeader( 11015 Handle<JSObject> boilerplate_object, 11016 HInstruction* object) { 11017 DCHECK(boilerplate_object->properties()->length() == 0); 11018 11019 Handle<Map> boilerplate_object_map(boilerplate_object->map()); 11020 AddStoreMapConstant(object, boilerplate_object_map); 11021 11022 Handle<Object> properties_field = 11023 Handle<Object>(boilerplate_object->properties(), isolate()); 11024 DCHECK(*properties_field == isolate()->heap()->empty_fixed_array()); 11025 HInstruction* properties = Add<HConstant>(properties_field); 11026 HObjectAccess access = HObjectAccess::ForPropertiesPointer(); 11027 Add<HStoreNamedField>(object, access, properties); 11028 11029 if (boilerplate_object->IsJSArray()) { 11030 Handle<JSArray> boilerplate_array = 11031 Handle<JSArray>::cast(boilerplate_object); 11032 Handle<Object> length_field = 11033 Handle<Object>(boilerplate_array->length(), isolate()); 11034 HInstruction* length = Add<HConstant>(length_field); 11035 11036 DCHECK(boilerplate_array->length()->IsSmi()); 11037 Add<HStoreNamedField>(object, HObjectAccess::ForArrayLength( 11038 boilerplate_array->GetElementsKind()), length); 11039 } 11040 } 11041 11042 11043 void HOptimizedGraphBuilder::BuildInitElementsInObjectHeader( 11044 Handle<JSObject> boilerplate_object, 11045 HInstruction* object, 11046 HInstruction* object_elements) { 11047 DCHECK(boilerplate_object->properties()->length() == 0); 11048 if (object_elements == NULL) { 11049 Handle<Object> elements_field = 11050 Handle<Object>(boilerplate_object->elements(), isolate()); 11051 object_elements = Add<HConstant>(elements_field); 11052 } 11053 Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(), 11054 object_elements); 11055 } 11056 11057 11058 void HOptimizedGraphBuilder::BuildEmitInObjectProperties( 11059 Handle<JSObject> boilerplate_object, 11060 HInstruction* object, 11061 AllocationSiteUsageContext* site_context, 11062 PretenureFlag pretenure_flag) { 11063 Handle<Map> boilerplate_map(boilerplate_object->map()); 11064 Handle<DescriptorArray> descriptors(boilerplate_map->instance_descriptors()); 11065 int limit = boilerplate_map->NumberOfOwnDescriptors(); 11066 11067 int copied_fields = 0; 11068 for (int i = 0; i < limit; i++) { 11069 PropertyDetails details = descriptors->GetDetails(i); 11070 if (details.type() != FIELD) continue; 11071 copied_fields++; 11072 int index = descriptors->GetFieldIndex(i); 11073 int property_offset = boilerplate_object->GetInObjectPropertyOffset(index); 11074 Handle<Name> name(descriptors->GetKey(i)); 11075 Handle<Object> value = 11076 Handle<Object>(boilerplate_object->InObjectPropertyAt(index), 11077 isolate()); 11078 11079 // The access for the store depends on the type of the boilerplate. 11080 HObjectAccess access = boilerplate_object->IsJSArray() ? 11081 HObjectAccess::ForJSArrayOffset(property_offset) : 11082 HObjectAccess::ForMapAndOffset(boilerplate_map, property_offset); 11083 11084 if (value->IsJSObject()) { 11085 Handle<JSObject> value_object = Handle<JSObject>::cast(value); 11086 Handle<AllocationSite> current_site = site_context->EnterNewScope(); 11087 HInstruction* result = 11088 BuildFastLiteral(value_object, site_context); 11089 site_context->ExitScope(current_site, value_object); 11090 Add<HStoreNamedField>(object, access, result); 11091 } else { 11092 Representation representation = details.representation(); 11093 HInstruction* value_instruction; 11094 11095 if (representation.IsDouble()) { 11096 // Allocate a HeapNumber box and store the value into it. 11097 HValue* heap_number_constant = Add<HConstant>(HeapNumber::kSize); 11098 // This heap number alloc does not have a corresponding 11099 // AllocationSite. That is okay because 11100 // 1) it's a child object of another object with a valid allocation site 11101 // 2) we can just use the mode of the parent object for pretenuring 11102 HInstruction* double_box = 11103 Add<HAllocate>(heap_number_constant, HType::HeapObject(), 11104 pretenure_flag, MUTABLE_HEAP_NUMBER_TYPE); 11105 AddStoreMapConstant(double_box, 11106 isolate()->factory()->mutable_heap_number_map()); 11107 // Unwrap the mutable heap number from the boilerplate. 11108 HValue* double_value = 11109 Add<HConstant>(Handle<HeapNumber>::cast(value)->value()); 11110 Add<HStoreNamedField>( 11111 double_box, HObjectAccess::ForHeapNumberValue(), double_value); 11112 value_instruction = double_box; 11113 } else if (representation.IsSmi()) { 11114 value_instruction = value->IsUninitialized() 11115 ? graph()->GetConstant0() 11116 : Add<HConstant>(value); 11117 // Ensure that value is stored as smi. 11118 access = access.WithRepresentation(representation); 11119 } else { 11120 value_instruction = Add<HConstant>(value); 11121 } 11122 11123 Add<HStoreNamedField>(object, access, value_instruction); 11124 } 11125 } 11126 11127 int inobject_properties = boilerplate_object->map()->inobject_properties(); 11128 HInstruction* value_instruction = 11129 Add<HConstant>(isolate()->factory()->one_pointer_filler_map()); 11130 for (int i = copied_fields; i < inobject_properties; i++) { 11131 DCHECK(boilerplate_object->IsJSObject()); 11132 int property_offset = boilerplate_object->GetInObjectPropertyOffset(i); 11133 HObjectAccess access = 11134 HObjectAccess::ForMapAndOffset(boilerplate_map, property_offset); 11135 Add<HStoreNamedField>(object, access, value_instruction); 11136 } 11137 } 11138 11139 11140 void HOptimizedGraphBuilder::BuildEmitElements( 11141 Handle<JSObject> boilerplate_object, 11142 Handle<FixedArrayBase> elements, 11143 HValue* object_elements, 11144 AllocationSiteUsageContext* site_context) { 11145 ElementsKind kind = boilerplate_object->map()->elements_kind(); 11146 int elements_length = elements->length(); 11147 HValue* object_elements_length = Add<HConstant>(elements_length); 11148 BuildInitializeElementsHeader(object_elements, kind, object_elements_length); 11149 11150 // Copy elements backing store content. 11151 if (elements->IsFixedDoubleArray()) { 11152 BuildEmitFixedDoubleArray(elements, kind, object_elements); 11153 } else if (elements->IsFixedArray()) { 11154 BuildEmitFixedArray(elements, kind, object_elements, 11155 site_context); 11156 } else { 11157 UNREACHABLE(); 11158 } 11159 } 11160 11161 11162 void HOptimizedGraphBuilder::BuildEmitFixedDoubleArray( 11163 Handle<FixedArrayBase> elements, 11164 ElementsKind kind, 11165 HValue* object_elements) { 11166 HInstruction* boilerplate_elements = Add<HConstant>(elements); 11167 int elements_length = elements->length(); 11168 for (int i = 0; i < elements_length; i++) { 11169 HValue* key_constant = Add<HConstant>(i); 11170 HInstruction* value_instruction = 11171 Add<HLoadKeyed>(boilerplate_elements, key_constant, 11172 static_cast<HValue*>(NULL), kind, 11173 ALLOW_RETURN_HOLE); 11174 HInstruction* store = Add<HStoreKeyed>(object_elements, key_constant, 11175 value_instruction, kind); 11176 store->SetFlag(HValue::kAllowUndefinedAsNaN); 11177 } 11178 } 11179 11180 11181 void HOptimizedGraphBuilder::BuildEmitFixedArray( 11182 Handle<FixedArrayBase> elements, 11183 ElementsKind kind, 11184 HValue* object_elements, 11185 AllocationSiteUsageContext* site_context) { 11186 HInstruction* boilerplate_elements = Add<HConstant>(elements); 11187 int elements_length = elements->length(); 11188 Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements); 11189 for (int i = 0; i < elements_length; i++) { 11190 Handle<Object> value(fast_elements->get(i), isolate()); 11191 HValue* key_constant = Add<HConstant>(i); 11192 if (value->IsJSObject()) { 11193 Handle<JSObject> value_object = Handle<JSObject>::cast(value); 11194 Handle<AllocationSite> current_site = site_context->EnterNewScope(); 11195 HInstruction* result = 11196 BuildFastLiteral(value_object, site_context); 11197 site_context->ExitScope(current_site, value_object); 11198 Add<HStoreKeyed>(object_elements, key_constant, result, kind); 11199 } else { 11200 HInstruction* value_instruction = 11201 Add<HLoadKeyed>(boilerplate_elements, key_constant, 11202 static_cast<HValue*>(NULL), kind, 11203 ALLOW_RETURN_HOLE); 11204 Add<HStoreKeyed>(object_elements, key_constant, value_instruction, kind); 11205 } 11206 } 11207 } 11208 11209 11210 void HOptimizedGraphBuilder::VisitThisFunction(ThisFunction* expr) { 11211 DCHECK(!HasStackOverflow()); 11212 DCHECK(current_block() != NULL); 11213 DCHECK(current_block()->HasPredecessor()); 11214 HInstruction* instr = BuildThisFunction(); 11215 return ast_context()->ReturnInstruction(instr, expr->id()); 11216 } 11217 11218 11219 void HOptimizedGraphBuilder::VisitSuperReference(SuperReference* expr) { 11220 DCHECK(!HasStackOverflow()); 11221 DCHECK(current_block() != NULL); 11222 DCHECK(current_block()->HasPredecessor()); 11223 return Bailout(kSuperReference); 11224 } 11225 11226 11227 void HOptimizedGraphBuilder::VisitDeclarations( 11228 ZoneList<Declaration*>* declarations) { 11229 DCHECK(globals_.is_empty()); 11230 AstVisitor::VisitDeclarations(declarations); 11231 if (!globals_.is_empty()) { 11232 Handle<FixedArray> array = 11233 isolate()->factory()->NewFixedArray(globals_.length(), TENURED); 11234 for (int i = 0; i < globals_.length(); ++i) array->set(i, *globals_.at(i)); 11235 int flags = DeclareGlobalsEvalFlag::encode(current_info()->is_eval()) | 11236 DeclareGlobalsNativeFlag::encode(current_info()->is_native()) | 11237 DeclareGlobalsStrictMode::encode(current_info()->strict_mode()); 11238 Add<HDeclareGlobals>(array, flags); 11239 globals_.Rewind(0); 11240 } 11241 } 11242 11243 11244 void HOptimizedGraphBuilder::VisitVariableDeclaration( 11245 VariableDeclaration* declaration) { 11246 VariableProxy* proxy = declaration->proxy(); 11247 VariableMode mode = declaration->mode(); 11248 Variable* variable = proxy->var(); 11249 bool hole_init = mode == LET || mode == CONST || mode == CONST_LEGACY; 11250 switch (variable->location()) { 11251 case Variable::UNALLOCATED: 11252 globals_.Add(variable->name(), zone()); 11253 globals_.Add(variable->binding_needs_init() 11254 ? isolate()->factory()->the_hole_value() 11255 : isolate()->factory()->undefined_value(), zone()); 11256 return; 11257 case Variable::PARAMETER: 11258 case Variable::LOCAL: 11259 if (hole_init) { 11260 HValue* value = graph()->GetConstantHole(); 11261 environment()->Bind(variable, value); 11262 } 11263 break; 11264 case Variable::CONTEXT: 11265 if (hole_init) { 11266 HValue* value = graph()->GetConstantHole(); 11267 HValue* context = environment()->context(); 11268 HStoreContextSlot* store = Add<HStoreContextSlot>( 11269 context, variable->index(), HStoreContextSlot::kNoCheck, value); 11270 if (store->HasObservableSideEffects()) { 11271 Add<HSimulate>(proxy->id(), REMOVABLE_SIMULATE); 11272 } 11273 } 11274 break; 11275 case Variable::LOOKUP: 11276 return Bailout(kUnsupportedLookupSlotInDeclaration); 11277 } 11278 } 11279 11280 11281 void HOptimizedGraphBuilder::VisitFunctionDeclaration( 11282 FunctionDeclaration* declaration) { 11283 VariableProxy* proxy = declaration->proxy(); 11284 Variable* variable = proxy->var(); 11285 switch (variable->location()) { 11286 case Variable::UNALLOCATED: { 11287 globals_.Add(variable->name(), zone()); 11288 Handle<SharedFunctionInfo> function = Compiler::BuildFunctionInfo( 11289 declaration->fun(), current_info()->script(), top_info()); 11290 // Check for stack-overflow exception. 11291 if (function.is_null()) return SetStackOverflow(); 11292 globals_.Add(function, zone()); 11293 return; 11294 } 11295 case Variable::PARAMETER: 11296 case Variable::LOCAL: { 11297 CHECK_ALIVE(VisitForValue(declaration->fun())); 11298 HValue* value = Pop(); 11299 BindIfLive(variable, value); 11300 break; 11301 } 11302 case Variable::CONTEXT: { 11303 CHECK_ALIVE(VisitForValue(declaration->fun())); 11304 HValue* value = Pop(); 11305 HValue* context = environment()->context(); 11306 HStoreContextSlot* store = Add<HStoreContextSlot>( 11307 context, variable->index(), HStoreContextSlot::kNoCheck, value); 11308 if (store->HasObservableSideEffects()) { 11309 Add<HSimulate>(proxy->id(), REMOVABLE_SIMULATE); 11310 } 11311 break; 11312 } 11313 case Variable::LOOKUP: 11314 return Bailout(kUnsupportedLookupSlotInDeclaration); 11315 } 11316 } 11317 11318 11319 void HOptimizedGraphBuilder::VisitModuleDeclaration( 11320 ModuleDeclaration* declaration) { 11321 UNREACHABLE(); 11322 } 11323 11324 11325 void HOptimizedGraphBuilder::VisitImportDeclaration( 11326 ImportDeclaration* declaration) { 11327 UNREACHABLE(); 11328 } 11329 11330 11331 void HOptimizedGraphBuilder::VisitExportDeclaration( 11332 ExportDeclaration* declaration) { 11333 UNREACHABLE(); 11334 } 11335 11336 11337 void HOptimizedGraphBuilder::VisitModuleLiteral(ModuleLiteral* module) { 11338 UNREACHABLE(); 11339 } 11340 11341 11342 void HOptimizedGraphBuilder::VisitModuleVariable(ModuleVariable* module) { 11343 UNREACHABLE(); 11344 } 11345 11346 11347 void HOptimizedGraphBuilder::VisitModulePath(ModulePath* module) { 11348 UNREACHABLE(); 11349 } 11350 11351 11352 void HOptimizedGraphBuilder::VisitModuleUrl(ModuleUrl* module) { 11353 UNREACHABLE(); 11354 } 11355 11356 11357 void HOptimizedGraphBuilder::VisitModuleStatement(ModuleStatement* stmt) { 11358 UNREACHABLE(); 11359 } 11360 11361 11362 // Generators for inline runtime functions. 11363 // Support for types. 11364 void HOptimizedGraphBuilder::GenerateIsSmi(CallRuntime* call) { 11365 DCHECK(call->arguments()->length() == 1); 11366 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11367 HValue* value = Pop(); 11368 HIsSmiAndBranch* result = New<HIsSmiAndBranch>(value); 11369 return ast_context()->ReturnControl(result, call->id()); 11370 } 11371 11372 11373 void HOptimizedGraphBuilder::GenerateIsSpecObject(CallRuntime* call) { 11374 DCHECK(call->arguments()->length() == 1); 11375 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11376 HValue* value = Pop(); 11377 HHasInstanceTypeAndBranch* result = 11378 New<HHasInstanceTypeAndBranch>(value, 11379 FIRST_SPEC_OBJECT_TYPE, 11380 LAST_SPEC_OBJECT_TYPE); 11381 return ast_context()->ReturnControl(result, call->id()); 11382 } 11383 11384 11385 void HOptimizedGraphBuilder::GenerateIsFunction(CallRuntime* call) { 11386 DCHECK(call->arguments()->length() == 1); 11387 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11388 HValue* value = Pop(); 11389 HHasInstanceTypeAndBranch* result = 11390 New<HHasInstanceTypeAndBranch>(value, JS_FUNCTION_TYPE); 11391 return ast_context()->ReturnControl(result, call->id()); 11392 } 11393 11394 11395 void HOptimizedGraphBuilder::GenerateIsMinusZero(CallRuntime* call) { 11396 DCHECK(call->arguments()->length() == 1); 11397 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11398 HValue* value = Pop(); 11399 HCompareMinusZeroAndBranch* result = New<HCompareMinusZeroAndBranch>(value); 11400 return ast_context()->ReturnControl(result, call->id()); 11401 } 11402 11403 11404 void HOptimizedGraphBuilder::GenerateHasCachedArrayIndex(CallRuntime* call) { 11405 DCHECK(call->arguments()->length() == 1); 11406 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11407 HValue* value = Pop(); 11408 HHasCachedArrayIndexAndBranch* result = 11409 New<HHasCachedArrayIndexAndBranch>(value); 11410 return ast_context()->ReturnControl(result, call->id()); 11411 } 11412 11413 11414 void HOptimizedGraphBuilder::GenerateIsArray(CallRuntime* call) { 11415 DCHECK(call->arguments()->length() == 1); 11416 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11417 HValue* value = Pop(); 11418 HHasInstanceTypeAndBranch* result = 11419 New<HHasInstanceTypeAndBranch>(value, JS_ARRAY_TYPE); 11420 return ast_context()->ReturnControl(result, call->id()); 11421 } 11422 11423 11424 void HOptimizedGraphBuilder::GenerateIsRegExp(CallRuntime* call) { 11425 DCHECK(call->arguments()->length() == 1); 11426 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11427 HValue* value = Pop(); 11428 HHasInstanceTypeAndBranch* result = 11429 New<HHasInstanceTypeAndBranch>(value, JS_REGEXP_TYPE); 11430 return ast_context()->ReturnControl(result, call->id()); 11431 } 11432 11433 11434 void HOptimizedGraphBuilder::GenerateIsObject(CallRuntime* call) { 11435 DCHECK(call->arguments()->length() == 1); 11436 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11437 HValue* value = Pop(); 11438 HIsObjectAndBranch* result = New<HIsObjectAndBranch>(value); 11439 return ast_context()->ReturnControl(result, call->id()); 11440 } 11441 11442 11443 void HOptimizedGraphBuilder::GenerateIsNonNegativeSmi(CallRuntime* call) { 11444 return Bailout(kInlinedRuntimeFunctionIsNonNegativeSmi); 11445 } 11446 11447 11448 void HOptimizedGraphBuilder::GenerateIsUndetectableObject(CallRuntime* call) { 11449 DCHECK(call->arguments()->length() == 1); 11450 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11451 HValue* value = Pop(); 11452 HIsUndetectableAndBranch* result = New<HIsUndetectableAndBranch>(value); 11453 return ast_context()->ReturnControl(result, call->id()); 11454 } 11455 11456 11457 void HOptimizedGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf( 11458 CallRuntime* call) { 11459 return Bailout(kInlinedRuntimeFunctionIsStringWrapperSafeForDefaultValueOf); 11460 } 11461 11462 11463 // Support for construct call checks. 11464 void HOptimizedGraphBuilder::GenerateIsConstructCall(CallRuntime* call) { 11465 DCHECK(call->arguments()->length() == 0); 11466 if (function_state()->outer() != NULL) { 11467 // We are generating graph for inlined function. 11468 HValue* value = function_state()->inlining_kind() == CONSTRUCT_CALL_RETURN 11469 ? graph()->GetConstantTrue() 11470 : graph()->GetConstantFalse(); 11471 return ast_context()->ReturnValue(value); 11472 } else { 11473 return ast_context()->ReturnControl(New<HIsConstructCallAndBranch>(), 11474 call->id()); 11475 } 11476 } 11477 11478 11479 // Support for arguments.length and arguments[?]. 11480 void HOptimizedGraphBuilder::GenerateArgumentsLength(CallRuntime* call) { 11481 DCHECK(call->arguments()->length() == 0); 11482 HInstruction* result = NULL; 11483 if (function_state()->outer() == NULL) { 11484 HInstruction* elements = Add<HArgumentsElements>(false); 11485 result = New<HArgumentsLength>(elements); 11486 } else { 11487 // Number of arguments without receiver. 11488 int argument_count = environment()-> 11489 arguments_environment()->parameter_count() - 1; 11490 result = New<HConstant>(argument_count); 11491 } 11492 return ast_context()->ReturnInstruction(result, call->id()); 11493 } 11494 11495 11496 void HOptimizedGraphBuilder::GenerateArguments(CallRuntime* call) { 11497 DCHECK(call->arguments()->length() == 1); 11498 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11499 HValue* index = Pop(); 11500 HInstruction* result = NULL; 11501 if (function_state()->outer() == NULL) { 11502 HInstruction* elements = Add<HArgumentsElements>(false); 11503 HInstruction* length = Add<HArgumentsLength>(elements); 11504 HInstruction* checked_index = Add<HBoundsCheck>(index, length); 11505 result = New<HAccessArgumentsAt>(elements, length, checked_index); 11506 } else { 11507 EnsureArgumentsArePushedForAccess(); 11508 11509 // Number of arguments without receiver. 11510 HInstruction* elements = function_state()->arguments_elements(); 11511 int argument_count = environment()-> 11512 arguments_environment()->parameter_count() - 1; 11513 HInstruction* length = Add<HConstant>(argument_count); 11514 HInstruction* checked_key = Add<HBoundsCheck>(index, length); 11515 result = New<HAccessArgumentsAt>(elements, length, checked_key); 11516 } 11517 return ast_context()->ReturnInstruction(result, call->id()); 11518 } 11519 11520 11521 // Support for accessing the class and value fields of an object. 11522 void HOptimizedGraphBuilder::GenerateClassOf(CallRuntime* call) { 11523 // The special form detected by IsClassOfTest is detected before we get here 11524 // and does not cause a bailout. 11525 return Bailout(kInlinedRuntimeFunctionClassOf); 11526 } 11527 11528 11529 void HOptimizedGraphBuilder::GenerateValueOf(CallRuntime* call) { 11530 DCHECK(call->arguments()->length() == 1); 11531 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11532 HValue* object = Pop(); 11533 11534 IfBuilder if_objectisvalue(this); 11535 HValue* objectisvalue = if_objectisvalue.If<HHasInstanceTypeAndBranch>( 11536 object, JS_VALUE_TYPE); 11537 if_objectisvalue.Then(); 11538 { 11539 // Return the actual value. 11540 Push(Add<HLoadNamedField>( 11541 object, objectisvalue, 11542 HObjectAccess::ForObservableJSObjectOffset( 11543 JSValue::kValueOffset))); 11544 Add<HSimulate>(call->id(), FIXED_SIMULATE); 11545 } 11546 if_objectisvalue.Else(); 11547 { 11548 // If the object is not a value return the object. 11549 Push(object); 11550 Add<HSimulate>(call->id(), FIXED_SIMULATE); 11551 } 11552 if_objectisvalue.End(); 11553 return ast_context()->ReturnValue(Pop()); 11554 } 11555 11556 11557 void HOptimizedGraphBuilder::GenerateDateField(CallRuntime* call) { 11558 DCHECK(call->arguments()->length() == 2); 11559 DCHECK_NE(NULL, call->arguments()->at(1)->AsLiteral()); 11560 Smi* index = Smi::cast(*(call->arguments()->at(1)->AsLiteral()->value())); 11561 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11562 HValue* date = Pop(); 11563 HDateField* result = New<HDateField>(date, index); 11564 return ast_context()->ReturnInstruction(result, call->id()); 11565 } 11566 11567 11568 void HOptimizedGraphBuilder::GenerateOneByteSeqStringSetChar( 11569 CallRuntime* call) { 11570 DCHECK(call->arguments()->length() == 3); 11571 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11572 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); 11573 CHECK_ALIVE(VisitForValue(call->arguments()->at(2))); 11574 HValue* string = Pop(); 11575 HValue* value = Pop(); 11576 HValue* index = Pop(); 11577 Add<HSeqStringSetChar>(String::ONE_BYTE_ENCODING, string, 11578 index, value); 11579 Add<HSimulate>(call->id(), FIXED_SIMULATE); 11580 return ast_context()->ReturnValue(graph()->GetConstantUndefined()); 11581 } 11582 11583 11584 void HOptimizedGraphBuilder::GenerateTwoByteSeqStringSetChar( 11585 CallRuntime* call) { 11586 DCHECK(call->arguments()->length() == 3); 11587 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11588 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); 11589 CHECK_ALIVE(VisitForValue(call->arguments()->at(2))); 11590 HValue* string = Pop(); 11591 HValue* value = Pop(); 11592 HValue* index = Pop(); 11593 Add<HSeqStringSetChar>(String::TWO_BYTE_ENCODING, string, 11594 index, value); 11595 Add<HSimulate>(call->id(), FIXED_SIMULATE); 11596 return ast_context()->ReturnValue(graph()->GetConstantUndefined()); 11597 } 11598 11599 11600 void HOptimizedGraphBuilder::GenerateSetValueOf(CallRuntime* call) { 11601 DCHECK(call->arguments()->length() == 2); 11602 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11603 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); 11604 HValue* value = Pop(); 11605 HValue* object = Pop(); 11606 11607 // Check if object is a JSValue. 11608 IfBuilder if_objectisvalue(this); 11609 if_objectisvalue.If<HHasInstanceTypeAndBranch>(object, JS_VALUE_TYPE); 11610 if_objectisvalue.Then(); 11611 { 11612 // Create in-object property store to kValueOffset. 11613 Add<HStoreNamedField>(object, 11614 HObjectAccess::ForObservableJSObjectOffset(JSValue::kValueOffset), 11615 value); 11616 if (!ast_context()->IsEffect()) { 11617 Push(value); 11618 } 11619 Add<HSimulate>(call->id(), FIXED_SIMULATE); 11620 } 11621 if_objectisvalue.Else(); 11622 { 11623 // Nothing to do in this case. 11624 if (!ast_context()->IsEffect()) { 11625 Push(value); 11626 } 11627 Add<HSimulate>(call->id(), FIXED_SIMULATE); 11628 } 11629 if_objectisvalue.End(); 11630 if (!ast_context()->IsEffect()) { 11631 Drop(1); 11632 } 11633 return ast_context()->ReturnValue(value); 11634 } 11635 11636 11637 // Fast support for charCodeAt(n). 11638 void HOptimizedGraphBuilder::GenerateStringCharCodeAt(CallRuntime* call) { 11639 DCHECK(call->arguments()->length() == 2); 11640 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11641 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); 11642 HValue* index = Pop(); 11643 HValue* string = Pop(); 11644 HInstruction* result = BuildStringCharCodeAt(string, index); 11645 return ast_context()->ReturnInstruction(result, call->id()); 11646 } 11647 11648 11649 // Fast support for string.charAt(n) and string[n]. 11650 void HOptimizedGraphBuilder::GenerateStringCharFromCode(CallRuntime* call) { 11651 DCHECK(call->arguments()->length() == 1); 11652 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11653 HValue* char_code = Pop(); 11654 HInstruction* result = NewUncasted<HStringCharFromCode>(char_code); 11655 return ast_context()->ReturnInstruction(result, call->id()); 11656 } 11657 11658 11659 // Fast support for string.charAt(n) and string[n]. 11660 void HOptimizedGraphBuilder::GenerateStringCharAt(CallRuntime* call) { 11661 DCHECK(call->arguments()->length() == 2); 11662 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11663 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); 11664 HValue* index = Pop(); 11665 HValue* string = Pop(); 11666 HInstruction* char_code = BuildStringCharCodeAt(string, index); 11667 AddInstruction(char_code); 11668 HInstruction* result = NewUncasted<HStringCharFromCode>(char_code); 11669 return ast_context()->ReturnInstruction(result, call->id()); 11670 } 11671 11672 11673 // Fast support for object equality testing. 11674 void HOptimizedGraphBuilder::GenerateObjectEquals(CallRuntime* call) { 11675 DCHECK(call->arguments()->length() == 2); 11676 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11677 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); 11678 HValue* right = Pop(); 11679 HValue* left = Pop(); 11680 HCompareObjectEqAndBranch* result = 11681 New<HCompareObjectEqAndBranch>(left, right); 11682 return ast_context()->ReturnControl(result, call->id()); 11683 } 11684 11685 11686 // Fast support for StringAdd. 11687 void HOptimizedGraphBuilder::GenerateStringAdd(CallRuntime* call) { 11688 DCHECK_EQ(2, call->arguments()->length()); 11689 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11690 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); 11691 HValue* right = Pop(); 11692 HValue* left = Pop(); 11693 HInstruction* result = NewUncasted<HStringAdd>(left, right); 11694 return ast_context()->ReturnInstruction(result, call->id()); 11695 } 11696 11697 11698 // Fast support for SubString. 11699 void HOptimizedGraphBuilder::GenerateSubString(CallRuntime* call) { 11700 DCHECK_EQ(3, call->arguments()->length()); 11701 CHECK_ALIVE(VisitExpressions(call->arguments())); 11702 PushArgumentsFromEnvironment(call->arguments()->length()); 11703 HCallStub* result = New<HCallStub>(CodeStub::SubString, 3); 11704 return ast_context()->ReturnInstruction(result, call->id()); 11705 } 11706 11707 11708 // Fast support for StringCompare. 11709 void HOptimizedGraphBuilder::GenerateStringCompare(CallRuntime* call) { 11710 DCHECK_EQ(2, call->arguments()->length()); 11711 CHECK_ALIVE(VisitExpressions(call->arguments())); 11712 PushArgumentsFromEnvironment(call->arguments()->length()); 11713 HCallStub* result = New<HCallStub>(CodeStub::StringCompare, 2); 11714 return ast_context()->ReturnInstruction(result, call->id()); 11715 } 11716 11717 11718 // Support for direct calls from JavaScript to native RegExp code. 11719 void HOptimizedGraphBuilder::GenerateRegExpExec(CallRuntime* call) { 11720 DCHECK_EQ(4, call->arguments()->length()); 11721 CHECK_ALIVE(VisitExpressions(call->arguments())); 11722 PushArgumentsFromEnvironment(call->arguments()->length()); 11723 HCallStub* result = New<HCallStub>(CodeStub::RegExpExec, 4); 11724 return ast_context()->ReturnInstruction(result, call->id()); 11725 } 11726 11727 11728 void HOptimizedGraphBuilder::GenerateDoubleLo(CallRuntime* call) { 11729 DCHECK_EQ(1, call->arguments()->length()); 11730 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11731 HValue* value = Pop(); 11732 HInstruction* result = NewUncasted<HDoubleBits>(value, HDoubleBits::LOW); 11733 return ast_context()->ReturnInstruction(result, call->id()); 11734 } 11735 11736 11737 void HOptimizedGraphBuilder::GenerateDoubleHi(CallRuntime* call) { 11738 DCHECK_EQ(1, call->arguments()->length()); 11739 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11740 HValue* value = Pop(); 11741 HInstruction* result = NewUncasted<HDoubleBits>(value, HDoubleBits::HIGH); 11742 return ast_context()->ReturnInstruction(result, call->id()); 11743 } 11744 11745 11746 void HOptimizedGraphBuilder::GenerateConstructDouble(CallRuntime* call) { 11747 DCHECK_EQ(2, call->arguments()->length()); 11748 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11749 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); 11750 HValue* lo = Pop(); 11751 HValue* hi = Pop(); 11752 HInstruction* result = NewUncasted<HConstructDouble>(hi, lo); 11753 return ast_context()->ReturnInstruction(result, call->id()); 11754 } 11755 11756 11757 // Construct a RegExp exec result with two in-object properties. 11758 void HOptimizedGraphBuilder::GenerateRegExpConstructResult(CallRuntime* call) { 11759 DCHECK_EQ(3, call->arguments()->length()); 11760 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11761 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); 11762 CHECK_ALIVE(VisitForValue(call->arguments()->at(2))); 11763 HValue* input = Pop(); 11764 HValue* index = Pop(); 11765 HValue* length = Pop(); 11766 HValue* result = BuildRegExpConstructResult(length, index, input); 11767 return ast_context()->ReturnValue(result); 11768 } 11769 11770 11771 // Support for fast native caches. 11772 void HOptimizedGraphBuilder::GenerateGetFromCache(CallRuntime* call) { 11773 return Bailout(kInlinedRuntimeFunctionGetFromCache); 11774 } 11775 11776 11777 // Fast support for number to string. 11778 void HOptimizedGraphBuilder::GenerateNumberToString(CallRuntime* call) { 11779 DCHECK_EQ(1, call->arguments()->length()); 11780 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11781 HValue* number = Pop(); 11782 HValue* result = BuildNumberToString(number, Type::Any(zone())); 11783 return ast_context()->ReturnValue(result); 11784 } 11785 11786 11787 // Fast call for custom callbacks. 11788 void HOptimizedGraphBuilder::GenerateCallFunction(CallRuntime* call) { 11789 // 1 ~ The function to call is not itself an argument to the call. 11790 int arg_count = call->arguments()->length() - 1; 11791 DCHECK(arg_count >= 1); // There's always at least a receiver. 11792 11793 CHECK_ALIVE(VisitExpressions(call->arguments())); 11794 // The function is the last argument 11795 HValue* function = Pop(); 11796 // Push the arguments to the stack 11797 PushArgumentsFromEnvironment(arg_count); 11798 11799 IfBuilder if_is_jsfunction(this); 11800 if_is_jsfunction.If<HHasInstanceTypeAndBranch>(function, JS_FUNCTION_TYPE); 11801 11802 if_is_jsfunction.Then(); 11803 { 11804 HInstruction* invoke_result = 11805 Add<HInvokeFunction>(function, arg_count); 11806 if (!ast_context()->IsEffect()) { 11807 Push(invoke_result); 11808 } 11809 Add<HSimulate>(call->id(), FIXED_SIMULATE); 11810 } 11811 11812 if_is_jsfunction.Else(); 11813 { 11814 HInstruction* call_result = 11815 Add<HCallFunction>(function, arg_count); 11816 if (!ast_context()->IsEffect()) { 11817 Push(call_result); 11818 } 11819 Add<HSimulate>(call->id(), FIXED_SIMULATE); 11820 } 11821 if_is_jsfunction.End(); 11822 11823 if (ast_context()->IsEffect()) { 11824 // EffectContext::ReturnValue ignores the value, so we can just pass 11825 // 'undefined' (as we do not have the call result anymore). 11826 return ast_context()->ReturnValue(graph()->GetConstantUndefined()); 11827 } else { 11828 return ast_context()->ReturnValue(Pop()); 11829 } 11830 } 11831 11832 11833 // Fast call to math functions. 11834 void HOptimizedGraphBuilder::GenerateMathPow(CallRuntime* call) { 11835 DCHECK_EQ(2, call->arguments()->length()); 11836 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11837 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); 11838 HValue* right = Pop(); 11839 HValue* left = Pop(); 11840 HInstruction* result = NewUncasted<HPower>(left, right); 11841 return ast_context()->ReturnInstruction(result, call->id()); 11842 } 11843 11844 11845 void HOptimizedGraphBuilder::GenerateMathLogRT(CallRuntime* call) { 11846 DCHECK(call->arguments()->length() == 1); 11847 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11848 HValue* value = Pop(); 11849 HInstruction* result = NewUncasted<HUnaryMathOperation>(value, kMathLog); 11850 return ast_context()->ReturnInstruction(result, call->id()); 11851 } 11852 11853 11854 void HOptimizedGraphBuilder::GenerateMathSqrtRT(CallRuntime* call) { 11855 DCHECK(call->arguments()->length() == 1); 11856 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11857 HValue* value = Pop(); 11858 HInstruction* result = NewUncasted<HUnaryMathOperation>(value, kMathSqrt); 11859 return ast_context()->ReturnInstruction(result, call->id()); 11860 } 11861 11862 11863 void HOptimizedGraphBuilder::GenerateGetCachedArrayIndex(CallRuntime* call) { 11864 DCHECK(call->arguments()->length() == 1); 11865 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); 11866 HValue* value = Pop(); 11867 HGetCachedArrayIndex* result = New<HGetCachedArrayIndex>(value); 11868 return ast_context()->ReturnInstruction(result, call->id()); 11869 } 11870 11871 11872 void HOptimizedGraphBuilder::GenerateFastOneByteArrayJoin(CallRuntime* call) { 11873 return Bailout(kInlinedRuntimeFunctionFastOneByteArrayJoin); 11874 } 11875 11876 11877 // Support for generators. 11878 void HOptimizedGraphBuilder::GenerateGeneratorNext(CallRuntime* call) { 11879 return Bailout(kInlinedRuntimeFunctionGeneratorNext); 11880 } 11881 11882 11883 void HOptimizedGraphBuilder::GenerateGeneratorThrow(CallRuntime* call) { 11884 return Bailout(kInlinedRuntimeFunctionGeneratorThrow); 11885 } 11886 11887 11888 void HOptimizedGraphBuilder::GenerateDebugBreakInOptimizedCode( 11889 CallRuntime* call) { 11890 Add<HDebugBreak>(); 11891 return ast_context()->ReturnValue(graph()->GetConstant0()); 11892 } 11893 11894 11895 void HOptimizedGraphBuilder::GenerateDebugIsActive(CallRuntime* call) { 11896 DCHECK(call->arguments()->length() == 0); 11897 HValue* ref = 11898 Add<HConstant>(ExternalReference::debug_is_active_address(isolate())); 11899 HValue* value = Add<HLoadNamedField>( 11900 ref, static_cast<HValue*>(NULL), HObjectAccess::ForExternalUInteger8()); 11901 return ast_context()->ReturnValue(value); 11902 } 11903 11904 11905 #undef CHECK_BAILOUT 11906 #undef CHECK_ALIVE 11907 11908 11909 HEnvironment::HEnvironment(HEnvironment* outer, 11910 Scope* scope, 11911 Handle<JSFunction> closure, 11912 Zone* zone) 11913 : closure_(closure), 11914 values_(0, zone), 11915 frame_type_(JS_FUNCTION), 11916 parameter_count_(0), 11917 specials_count_(1), 11918 local_count_(0), 11919 outer_(outer), 11920 entry_(NULL), 11921 pop_count_(0), 11922 push_count_(0), 11923 ast_id_(BailoutId::None()), 11924 zone_(zone) { 11925 Scope* declaration_scope = scope->DeclarationScope(); 11926 Initialize(declaration_scope->num_parameters() + 1, 11927 declaration_scope->num_stack_slots(), 0); 11928 } 11929 11930 11931 HEnvironment::HEnvironment(Zone* zone, int parameter_count) 11932 : values_(0, zone), 11933 frame_type_(STUB), 11934 parameter_count_(parameter_count), 11935 specials_count_(1), 11936 local_count_(0), 11937 outer_(NULL), 11938 entry_(NULL), 11939 pop_count_(0), 11940 push_count_(0), 11941 ast_id_(BailoutId::None()), 11942 zone_(zone) { 11943 Initialize(parameter_count, 0, 0); 11944 } 11945 11946 11947 HEnvironment::HEnvironment(const HEnvironment* other, Zone* zone) 11948 : values_(0, zone), 11949 frame_type_(JS_FUNCTION), 11950 parameter_count_(0), 11951 specials_count_(0), 11952 local_count_(0), 11953 outer_(NULL), 11954 entry_(NULL), 11955 pop_count_(0), 11956 push_count_(0), 11957 ast_id_(other->ast_id()), 11958 zone_(zone) { 11959 Initialize(other); 11960 } 11961 11962 11963 HEnvironment::HEnvironment(HEnvironment* outer, 11964 Handle<JSFunction> closure, 11965 FrameType frame_type, 11966 int arguments, 11967 Zone* zone) 11968 : closure_(closure), 11969 values_(arguments, zone), 11970 frame_type_(frame_type), 11971 parameter_count_(arguments), 11972 specials_count_(0), 11973 local_count_(0), 11974 outer_(outer), 11975 entry_(NULL), 11976 pop_count_(0), 11977 push_count_(0), 11978 ast_id_(BailoutId::None()), 11979 zone_(zone) { 11980 } 11981 11982 11983 void HEnvironment::Initialize(int parameter_count, 11984 int local_count, 11985 int stack_height) { 11986 parameter_count_ = parameter_count; 11987 local_count_ = local_count; 11988 11989 // Avoid reallocating the temporaries' backing store on the first Push. 11990 int total = parameter_count + specials_count_ + local_count + stack_height; 11991 values_.Initialize(total + 4, zone()); 11992 for (int i = 0; i < total; ++i) values_.Add(NULL, zone()); 11993 } 11994 11995 11996 void HEnvironment::Initialize(const HEnvironment* other) { 11997 closure_ = other->closure(); 11998 values_.AddAll(other->values_, zone()); 11999 assigned_variables_.Union(other->assigned_variables_, zone()); 12000 frame_type_ = other->frame_type_; 12001 parameter_count_ = other->parameter_count_; 12002 local_count_ = other->local_count_; 12003 if (other->outer_ != NULL) outer_ = other->outer_->Copy(); // Deep copy. 12004 entry_ = other->entry_; 12005 pop_count_ = other->pop_count_; 12006 push_count_ = other->push_count_; 12007 specials_count_ = other->specials_count_; 12008 ast_id_ = other->ast_id_; 12009 } 12010 12011 12012 void HEnvironment::AddIncomingEdge(HBasicBlock* block, HEnvironment* other) { 12013 DCHECK(!block->IsLoopHeader()); 12014 DCHECK(values_.length() == other->values_.length()); 12015 12016 int length = values_.length(); 12017 for (int i = 0; i < length; ++i) { 12018 HValue* value = values_[i]; 12019 if (value != NULL && value->IsPhi() && value->block() == block) { 12020 // There is already a phi for the i'th value. 12021 HPhi* phi = HPhi::cast(value); 12022 // Assert index is correct and that we haven't missed an incoming edge. 12023 DCHECK(phi->merged_index() == i || !phi->HasMergedIndex()); 12024 DCHECK(phi->OperandCount() == block->predecessors()->length()); 12025 phi->AddInput(other->values_[i]); 12026 } else if (values_[i] != other->values_[i]) { 12027 // There is a fresh value on the incoming edge, a phi is needed. 12028 DCHECK(values_[i] != NULL && other->values_[i] != NULL); 12029 HPhi* phi = block->AddNewPhi(i); 12030 HValue* old_value = values_[i]; 12031 for (int j = 0; j < block->predecessors()->length(); j++) { 12032 phi->AddInput(old_value); 12033 } 12034 phi->AddInput(other->values_[i]); 12035 this->values_[i] = phi; 12036 } 12037 } 12038 } 12039 12040 12041 void HEnvironment::Bind(int index, HValue* value) { 12042 DCHECK(value != NULL); 12043 assigned_variables_.Add(index, zone()); 12044 values_[index] = value; 12045 } 12046 12047 12048 bool HEnvironment::HasExpressionAt(int index) const { 12049 return index >= parameter_count_ + specials_count_ + local_count_; 12050 } 12051 12052 12053 bool HEnvironment::ExpressionStackIsEmpty() const { 12054 DCHECK(length() >= first_expression_index()); 12055 return length() == first_expression_index(); 12056 } 12057 12058 12059 void HEnvironment::SetExpressionStackAt(int index_from_top, HValue* value) { 12060 int count = index_from_top + 1; 12061 int index = values_.length() - count; 12062 DCHECK(HasExpressionAt(index)); 12063 // The push count must include at least the element in question or else 12064 // the new value will not be included in this environment's history. 12065 if (push_count_ < count) { 12066 // This is the same effect as popping then re-pushing 'count' elements. 12067 pop_count_ += (count - push_count_); 12068 push_count_ = count; 12069 } 12070 values_[index] = value; 12071 } 12072 12073 12074 void HEnvironment::Drop(int count) { 12075 for (int i = 0; i < count; ++i) { 12076 Pop(); 12077 } 12078 } 12079 12080 12081 HEnvironment* HEnvironment::Copy() const { 12082 return new(zone()) HEnvironment(this, zone()); 12083 } 12084 12085 12086 HEnvironment* HEnvironment::CopyWithoutHistory() const { 12087 HEnvironment* result = Copy(); 12088 result->ClearHistory(); 12089 return result; 12090 } 12091 12092 12093 HEnvironment* HEnvironment::CopyAsLoopHeader(HBasicBlock* loop_header) const { 12094 HEnvironment* new_env = Copy(); 12095 for (int i = 0; i < values_.length(); ++i) { 12096 HPhi* phi = loop_header->AddNewPhi(i); 12097 phi->AddInput(values_[i]); 12098 new_env->values_[i] = phi; 12099 } 12100 new_env->ClearHistory(); 12101 return new_env; 12102 } 12103 12104 12105 HEnvironment* HEnvironment::CreateStubEnvironment(HEnvironment* outer, 12106 Handle<JSFunction> target, 12107 FrameType frame_type, 12108 int arguments) const { 12109 HEnvironment* new_env = 12110 new(zone()) HEnvironment(outer, target, frame_type, 12111 arguments + 1, zone()); 12112 for (int i = 0; i <= arguments; ++i) { // Include receiver. 12113 new_env->Push(ExpressionStackAt(arguments - i)); 12114 } 12115 new_env->ClearHistory(); 12116 return new_env; 12117 } 12118 12119 12120 HEnvironment* HEnvironment::CopyForInlining( 12121 Handle<JSFunction> target, 12122 int arguments, 12123 FunctionLiteral* function, 12124 HConstant* undefined, 12125 InliningKind inlining_kind) const { 12126 DCHECK(frame_type() == JS_FUNCTION); 12127 12128 // Outer environment is a copy of this one without the arguments. 12129 int arity = function->scope()->num_parameters(); 12130 12131 HEnvironment* outer = Copy(); 12132 outer->Drop(arguments + 1); // Including receiver. 12133 outer->ClearHistory(); 12134 12135 if (inlining_kind == CONSTRUCT_CALL_RETURN) { 12136 // Create artificial constructor stub environment. The receiver should 12137 // actually be the constructor function, but we pass the newly allocated 12138 // object instead, DoComputeConstructStubFrame() relies on that. 12139 outer = CreateStubEnvironment(outer, target, JS_CONSTRUCT, arguments); 12140 } else if (inlining_kind == GETTER_CALL_RETURN) { 12141 // We need an additional StackFrame::INTERNAL frame for restoring the 12142 // correct context. 12143 outer = CreateStubEnvironment(outer, target, JS_GETTER, arguments); 12144 } else if (inlining_kind == SETTER_CALL_RETURN) { 12145 // We need an additional StackFrame::INTERNAL frame for temporarily saving 12146 // the argument of the setter, see StoreStubCompiler::CompileStoreViaSetter. 12147 outer = CreateStubEnvironment(outer, target, JS_SETTER, arguments); 12148 } 12149 12150 if (arity != arguments) { 12151 // Create artificial arguments adaptation environment. 12152 outer = CreateStubEnvironment(outer, target, ARGUMENTS_ADAPTOR, arguments); 12153 } 12154 12155 HEnvironment* inner = 12156 new(zone()) HEnvironment(outer, function->scope(), target, zone()); 12157 // Get the argument values from the original environment. 12158 for (int i = 0; i <= arity; ++i) { // Include receiver. 12159 HValue* push = (i <= arguments) ? 12160 ExpressionStackAt(arguments - i) : undefined; 12161 inner->SetValueAt(i, push); 12162 } 12163 inner->SetValueAt(arity + 1, context()); 12164 for (int i = arity + 2; i < inner->length(); ++i) { 12165 inner->SetValueAt(i, undefined); 12166 } 12167 12168 inner->set_ast_id(BailoutId::FunctionEntry()); 12169 return inner; 12170 } 12171 12172 12173 OStream& operator<<(OStream& os, const HEnvironment& env) { 12174 for (int i = 0; i < env.length(); i++) { 12175 if (i == 0) os << "parameters\n"; 12176 if (i == env.parameter_count()) os << "specials\n"; 12177 if (i == env.parameter_count() + env.specials_count()) os << "locals\n"; 12178 if (i == env.parameter_count() + env.specials_count() + env.local_count()) { 12179 os << "expressions\n"; 12180 } 12181 HValue* val = env.values()->at(i); 12182 os << i << ": "; 12183 if (val != NULL) { 12184 os << val; 12185 } else { 12186 os << "NULL"; 12187 } 12188 os << "\n"; 12189 } 12190 return os << "\n"; 12191 } 12192 12193 12194 void HTracer::TraceCompilation(CompilationInfo* info) { 12195 Tag tag(this, "compilation"); 12196 if (info->IsOptimizing()) { 12197 Handle<String> name = info->function()->debug_name(); 12198 PrintStringProperty("name", name->ToCString().get()); 12199 PrintIndent(); 12200 trace_.Add("method \"%s:%d\"\n", 12201 name->ToCString().get(), 12202 info->optimization_id()); 12203 } else { 12204 CodeStub::Major major_key = info->code_stub()->MajorKey(); 12205 PrintStringProperty("name", CodeStub::MajorName(major_key, false)); 12206 PrintStringProperty("method", "stub"); 12207 } 12208 PrintLongProperty("date", 12209 static_cast<int64_t>(base::OS::TimeCurrentMillis())); 12210 } 12211 12212 12213 void HTracer::TraceLithium(const char* name, LChunk* chunk) { 12214 DCHECK(!chunk->isolate()->concurrent_recompilation_enabled()); 12215 AllowHandleDereference allow_deref; 12216 AllowDeferredHandleDereference allow_deferred_deref; 12217 Trace(name, chunk->graph(), chunk); 12218 } 12219 12220 12221 void HTracer::TraceHydrogen(const char* name, HGraph* graph) { 12222 DCHECK(!graph->isolate()->concurrent_recompilation_enabled()); 12223 AllowHandleDereference allow_deref; 12224 AllowDeferredHandleDereference allow_deferred_deref; 12225 Trace(name, graph, NULL); 12226 } 12227 12228 12229 void HTracer::Trace(const char* name, HGraph* graph, LChunk* chunk) { 12230 Tag tag(this, "cfg"); 12231 PrintStringProperty("name", name); 12232 const ZoneList<HBasicBlock*>* blocks = graph->blocks(); 12233 for (int i = 0; i < blocks->length(); i++) { 12234 HBasicBlock* current = blocks->at(i); 12235 Tag block_tag(this, "block"); 12236 PrintBlockProperty("name", current->block_id()); 12237 PrintIntProperty("from_bci", -1); 12238 PrintIntProperty("to_bci", -1); 12239 12240 if (!current->predecessors()->is_empty()) { 12241 PrintIndent(); 12242 trace_.Add("predecessors"); 12243 for (int j = 0; j < current->predecessors()->length(); ++j) { 12244 trace_.Add(" \"B%d\"", current->predecessors()->at(j)->block_id()); 12245 } 12246 trace_.Add("\n"); 12247 } else { 12248 PrintEmptyProperty("predecessors"); 12249 } 12250 12251 if (current->end()->SuccessorCount() == 0) { 12252 PrintEmptyProperty("successors"); 12253 } else { 12254 PrintIndent(); 12255 trace_.Add("successors"); 12256 for (HSuccessorIterator it(current->end()); !it.Done(); it.Advance()) { 12257 trace_.Add(" \"B%d\"", it.Current()->block_id()); 12258 } 12259 trace_.Add("\n"); 12260 } 12261 12262 PrintEmptyProperty("xhandlers"); 12263 12264 { 12265 PrintIndent(); 12266 trace_.Add("flags"); 12267 if (current->IsLoopSuccessorDominator()) { 12268 trace_.Add(" \"dom-loop-succ\""); 12269 } 12270 if (current->IsUnreachable()) { 12271 trace_.Add(" \"dead\""); 12272 } 12273 if (current->is_osr_entry()) { 12274 trace_.Add(" \"osr\""); 12275 } 12276 trace_.Add("\n"); 12277 } 12278 12279 if (current->dominator() != NULL) { 12280 PrintBlockProperty("dominator", current->dominator()->block_id()); 12281 } 12282 12283 PrintIntProperty("loop_depth", current->LoopNestingDepth()); 12284 12285 if (chunk != NULL) { 12286 int first_index = current->first_instruction_index(); 12287 int last_index = current->last_instruction_index(); 12288 PrintIntProperty( 12289 "first_lir_id", 12290 LifetimePosition::FromInstructionIndex(first_index).Value()); 12291 PrintIntProperty( 12292 "last_lir_id", 12293 LifetimePosition::FromInstructionIndex(last_index).Value()); 12294 } 12295 12296 { 12297 Tag states_tag(this, "states"); 12298 Tag locals_tag(this, "locals"); 12299 int total = current->phis()->length(); 12300 PrintIntProperty("size", current->phis()->length()); 12301 PrintStringProperty("method", "None"); 12302 for (int j = 0; j < total; ++j) { 12303 HPhi* phi = current->phis()->at(j); 12304 PrintIndent(); 12305 OStringStream os; 12306 os << phi->merged_index() << " " << NameOf(phi) << " " << *phi << "\n"; 12307 trace_.Add(os.c_str()); 12308 } 12309 } 12310 12311 { 12312 Tag HIR_tag(this, "HIR"); 12313 for (HInstructionIterator it(current); !it.Done(); it.Advance()) { 12314 HInstruction* instruction = it.Current(); 12315 int uses = instruction->UseCount(); 12316 PrintIndent(); 12317 OStringStream os; 12318 os << "0 " << uses << " " << NameOf(instruction) << " " << *instruction; 12319 if (FLAG_hydrogen_track_positions && 12320 instruction->has_position() && 12321 instruction->position().raw() != 0) { 12322 const HSourcePosition pos = instruction->position(); 12323 os << " pos:"; 12324 if (pos.inlining_id() != 0) os << pos.inlining_id() << "_"; 12325 os << pos.position(); 12326 } 12327 os << " <|@\n"; 12328 trace_.Add(os.c_str()); 12329 } 12330 } 12331 12332 12333 if (chunk != NULL) { 12334 Tag LIR_tag(this, "LIR"); 12335 int first_index = current->first_instruction_index(); 12336 int last_index = current->last_instruction_index(); 12337 if (first_index != -1 && last_index != -1) { 12338 const ZoneList<LInstruction*>* instructions = chunk->instructions(); 12339 for (int i = first_index; i <= last_index; ++i) { 12340 LInstruction* linstr = instructions->at(i); 12341 if (linstr != NULL) { 12342 PrintIndent(); 12343 trace_.Add("%d ", 12344 LifetimePosition::FromInstructionIndex(i).Value()); 12345 linstr->PrintTo(&trace_); 12346 OStringStream os; 12347 os << " [hir:" << NameOf(linstr->hydrogen_value()) << "] <|@\n"; 12348 trace_.Add(os.c_str()); 12349 } 12350 } 12351 } 12352 } 12353 } 12354 } 12355 12356 12357 void HTracer::TraceLiveRanges(const char* name, LAllocator* allocator) { 12358 Tag tag(this, "intervals"); 12359 PrintStringProperty("name", name); 12360 12361 const Vector<LiveRange*>* fixed_d = allocator->fixed_double_live_ranges(); 12362 for (int i = 0; i < fixed_d->length(); ++i) { 12363 TraceLiveRange(fixed_d->at(i), "fixed", allocator->zone()); 12364 } 12365 12366 const Vector<LiveRange*>* fixed = allocator->fixed_live_ranges(); 12367 for (int i = 0; i < fixed->length(); ++i) { 12368 TraceLiveRange(fixed->at(i), "fixed", allocator->zone()); 12369 } 12370 12371 const ZoneList<LiveRange*>* live_ranges = allocator->live_ranges(); 12372 for (int i = 0; i < live_ranges->length(); ++i) { 12373 TraceLiveRange(live_ranges->at(i), "object", allocator->zone()); 12374 } 12375 } 12376 12377 12378 void HTracer::TraceLiveRange(LiveRange* range, const char* type, 12379 Zone* zone) { 12380 if (range != NULL && !range->IsEmpty()) { 12381 PrintIndent(); 12382 trace_.Add("%d %s", range->id(), type); 12383 if (range->HasRegisterAssigned()) { 12384 LOperand* op = range->CreateAssignedOperand(zone); 12385 int assigned_reg = op->index(); 12386 if (op->IsDoubleRegister()) { 12387 trace_.Add(" \"%s\"", 12388 DoubleRegister::AllocationIndexToString(assigned_reg)); 12389 } else { 12390 DCHECK(op->IsRegister()); 12391 trace_.Add(" \"%s\"", Register::AllocationIndexToString(assigned_reg)); 12392 } 12393 } else if (range->IsSpilled()) { 12394 LOperand* op = range->TopLevel()->GetSpillOperand(); 12395 if (op->IsDoubleStackSlot()) { 12396 trace_.Add(" \"double_stack:%d\"", op->index()); 12397 } else { 12398 DCHECK(op->IsStackSlot()); 12399 trace_.Add(" \"stack:%d\"", op->index()); 12400 } 12401 } 12402 int parent_index = -1; 12403 if (range->IsChild()) { 12404 parent_index = range->parent()->id(); 12405 } else { 12406 parent_index = range->id(); 12407 } 12408 LOperand* op = range->FirstHint(); 12409 int hint_index = -1; 12410 if (op != NULL && op->IsUnallocated()) { 12411 hint_index = LUnallocated::cast(op)->virtual_register(); 12412 } 12413 trace_.Add(" %d %d", parent_index, hint_index); 12414 UseInterval* cur_interval = range->first_interval(); 12415 while (cur_interval != NULL && range->Covers(cur_interval->start())) { 12416 trace_.Add(" [%d, %d[", 12417 cur_interval->start().Value(), 12418 cur_interval->end().Value()); 12419 cur_interval = cur_interval->next(); 12420 } 12421 12422 UsePosition* current_pos = range->first_pos(); 12423 while (current_pos != NULL) { 12424 if (current_pos->RegisterIsBeneficial() || FLAG_trace_all_uses) { 12425 trace_.Add(" %d M", current_pos->pos().Value()); 12426 } 12427 current_pos = current_pos->next(); 12428 } 12429 12430 trace_.Add(" \"\"\n"); 12431 } 12432 } 12433 12434 12435 void HTracer::FlushToFile() { 12436 AppendChars(filename_.start(), trace_.ToCString().get(), trace_.length(), 12437 false); 12438 trace_.Reset(); 12439 } 12440 12441 12442 void HStatistics::Initialize(CompilationInfo* info) { 12443 if (info->shared_info().is_null()) return; 12444 source_size_ += info->shared_info()->SourceSize(); 12445 } 12446 12447 12448 void HStatistics::Print(const char* stats_name) { 12449 PrintF( 12450 "\n" 12451 "----------------------------------------" 12452 "----------------------------------------\n" 12453 "--- %s timing results:\n" 12454 "----------------------------------------" 12455 "----------------------------------------\n", 12456 stats_name); 12457 base::TimeDelta sum; 12458 for (int i = 0; i < times_.length(); ++i) { 12459 sum += times_[i]; 12460 } 12461 12462 for (int i = 0; i < names_.length(); ++i) { 12463 PrintF("%33s", names_[i]); 12464 double ms = times_[i].InMillisecondsF(); 12465 double percent = times_[i].PercentOf(sum); 12466 PrintF(" %8.3f ms / %4.1f %% ", ms, percent); 12467 12468 unsigned size = sizes_[i]; 12469 double size_percent = static_cast<double>(size) * 100 / total_size_; 12470 PrintF(" %9u bytes / %4.1f %%\n", size, size_percent); 12471 } 12472 12473 PrintF( 12474 "----------------------------------------" 12475 "----------------------------------------\n"); 12476 base::TimeDelta total = create_graph_ + optimize_graph_ + generate_code_; 12477 PrintF("%33s %8.3f ms / %4.1f %% \n", "Create graph", 12478 create_graph_.InMillisecondsF(), create_graph_.PercentOf(total)); 12479 PrintF("%33s %8.3f ms / %4.1f %% \n", "Optimize graph", 12480 optimize_graph_.InMillisecondsF(), optimize_graph_.PercentOf(total)); 12481 PrintF("%33s %8.3f ms / %4.1f %% \n", "Generate and install code", 12482 generate_code_.InMillisecondsF(), generate_code_.PercentOf(total)); 12483 PrintF( 12484 "----------------------------------------" 12485 "----------------------------------------\n"); 12486 PrintF("%33s %8.3f ms %9u bytes\n", "Total", 12487 total.InMillisecondsF(), total_size_); 12488 PrintF("%33s (%.1f times slower than full code gen)\n", "", 12489 total.TimesOf(full_code_gen_)); 12490 12491 double source_size_in_kb = static_cast<double>(source_size_) / 1024; 12492 double normalized_time = source_size_in_kb > 0 12493 ? total.InMillisecondsF() / source_size_in_kb 12494 : 0; 12495 double normalized_size_in_kb = source_size_in_kb > 0 12496 ? total_size_ / 1024 / source_size_in_kb 12497 : 0; 12498 PrintF("%33s %8.3f ms %7.3f kB allocated\n", 12499 "Average per kB source", normalized_time, normalized_size_in_kb); 12500 } 12501 12502 12503 void HStatistics::SaveTiming(const char* name, base::TimeDelta time, 12504 unsigned size) { 12505 total_size_ += size; 12506 for (int i = 0; i < names_.length(); ++i) { 12507 if (strcmp(names_[i], name) == 0) { 12508 times_[i] += time; 12509 sizes_[i] += size; 12510 return; 12511 } 12512 } 12513 names_.Add(name); 12514 times_.Add(time); 12515 sizes_.Add(size); 12516 } 12517 12518 12519 HPhase::~HPhase() { 12520 if (ShouldProduceTraceOutput()) { 12521 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); 12522 } 12523 12524 #ifdef DEBUG 12525 graph_->Verify(false); // No full verify. 12526 #endif 12527 } 12528 12529 } } // namespace v8::internal 12530