1 // Copyright 2011 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include "v8.h" 29 #include "hydrogen.h" 30 31 #include "codegen.h" 32 #include "data-flow.h" 33 #include "full-codegen.h" 34 #include "hashmap.h" 35 #include "lithium-allocator.h" 36 #include "parser.h" 37 #include "scopes.h" 38 #include "stub-cache.h" 39 40 #if V8_TARGET_ARCH_IA32 41 #include "ia32/lithium-codegen-ia32.h" 42 #elif V8_TARGET_ARCH_X64 43 #include "x64/lithium-codegen-x64.h" 44 #elif V8_TARGET_ARCH_ARM 45 #include "arm/lithium-codegen-arm.h" 46 #elif V8_TARGET_ARCH_MIPS 47 #include "mips/lithium-codegen-mips.h" 48 #else 49 #error Unsupported target architecture. 50 #endif 51 52 namespace v8 { 53 namespace internal { 54 55 HBasicBlock::HBasicBlock(HGraph* graph) 56 : block_id_(graph->GetNextBlockID()), 57 graph_(graph), 58 phis_(4), 59 first_(NULL), 60 last_(NULL), 61 end_(NULL), 62 loop_information_(NULL), 63 predecessors_(2), 64 dominator_(NULL), 65 dominated_blocks_(4), 66 last_environment_(NULL), 67 argument_count_(-1), 68 first_instruction_index_(-1), 69 last_instruction_index_(-1), 70 deleted_phis_(4), 71 parent_loop_header_(NULL), 72 is_inline_return_target_(false) { 73 } 74 75 76 void HBasicBlock::AttachLoopInformation() { 77 ASSERT(!IsLoopHeader()); 78 loop_information_ = new(zone()) HLoopInformation(this); 79 } 80 81 82 void HBasicBlock::DetachLoopInformation() { 83 ASSERT(IsLoopHeader()); 84 loop_information_ = NULL; 85 } 86 87 88 void HBasicBlock::AddPhi(HPhi* phi) { 89 ASSERT(!IsStartBlock()); 90 phis_.Add(phi); 91 phi->SetBlock(this); 92 } 93 94 95 void HBasicBlock::RemovePhi(HPhi* phi) { 96 ASSERT(phi->block() == this); 97 ASSERT(phis_.Contains(phi)); 98 ASSERT(phi->HasNoUses() || !phi->is_live()); 99 phi->ClearOperands(); 100 phis_.RemoveElement(phi); 101 phi->SetBlock(NULL); 102 } 103 104 105 void HBasicBlock::AddInstruction(HInstruction* instr) { 106 ASSERT(!IsStartBlock() || !IsFinished()); 107 ASSERT(!instr->IsLinked()); 108 ASSERT(!IsFinished()); 109 if (first_ == NULL) { 110 HBlockEntry* entry = new(zone()) HBlockEntry(); 111 entry->InitializeAsFirst(this); 112 first_ = last_ = entry; 113 } 114 instr->InsertAfter(last_); 115 last_ = instr; 116 } 117 118 119 HDeoptimize* HBasicBlock::CreateDeoptimize() { 120 ASSERT(HasEnvironment()); 121 HEnvironment* environment = last_environment(); 122 123 HDeoptimize* instr = new(zone()) HDeoptimize(environment->length()); 124 125 for (int i = 0; i < environment->length(); i++) { 126 HValue* val = environment->values()->at(i); 127 instr->AddEnvironmentValue(val); 128 } 129 130 return instr; 131 } 132 133 134 HSimulate* HBasicBlock::CreateSimulate(int id) { 135 ASSERT(HasEnvironment()); 136 HEnvironment* environment = last_environment(); 137 ASSERT(id == AstNode::kNoNumber || 138 environment->closure()->shared()->VerifyBailoutId(id)); 139 140 int push_count = environment->push_count(); 141 int pop_count = environment->pop_count(); 142 143 HSimulate* instr = new(zone()) HSimulate(id, pop_count); 144 for (int i = push_count - 1; i >= 0; --i) { 145 instr->AddPushedValue(environment->ExpressionStackAt(i)); 146 } 147 for (int i = 0; i < environment->assigned_variables()->length(); ++i) { 148 int index = environment->assigned_variables()->at(i); 149 instr->AddAssignedValue(index, environment->Lookup(index)); 150 } 151 environment->ClearHistory(); 152 return instr; 153 } 154 155 156 void HBasicBlock::Finish(HControlInstruction* end) { 157 ASSERT(!IsFinished()); 158 AddInstruction(end); 159 end_ = end; 160 if (end->FirstSuccessor() != NULL) { 161 end->FirstSuccessor()->RegisterPredecessor(this); 162 if (end->SecondSuccessor() != NULL) { 163 end->SecondSuccessor()->RegisterPredecessor(this); 164 } 165 } 166 } 167 168 169 void HBasicBlock::Goto(HBasicBlock* block, bool include_stack_check) { 170 if (block->IsInlineReturnTarget()) { 171 AddInstruction(new(zone()) HLeaveInlined); 172 last_environment_ = last_environment()->outer(); 173 } 174 AddSimulate(AstNode::kNoNumber); 175 HGoto* instr = new(zone()) HGoto(block); 176 instr->set_include_stack_check(include_stack_check); 177 Finish(instr); 178 } 179 180 181 void HBasicBlock::AddLeaveInlined(HValue* return_value, HBasicBlock* target) { 182 ASSERT(target->IsInlineReturnTarget()); 183 ASSERT(return_value != NULL); 184 AddInstruction(new(zone()) HLeaveInlined); 185 last_environment_ = last_environment()->outer(); 186 last_environment()->Push(return_value); 187 AddSimulate(AstNode::kNoNumber); 188 HGoto* instr = new(zone()) HGoto(target); 189 Finish(instr); 190 } 191 192 193 void HBasicBlock::SetInitialEnvironment(HEnvironment* env) { 194 ASSERT(!HasEnvironment()); 195 ASSERT(first() == NULL); 196 UpdateEnvironment(env); 197 } 198 199 200 void HBasicBlock::SetJoinId(int id) { 201 int length = predecessors_.length(); 202 ASSERT(length > 0); 203 for (int i = 0; i < length; i++) { 204 HBasicBlock* predecessor = predecessors_[i]; 205 ASSERT(predecessor->end()->IsGoto()); 206 HSimulate* simulate = HSimulate::cast(predecessor->end()->previous()); 207 // We only need to verify the ID once. 208 ASSERT(i != 0 || 209 predecessor->last_environment()->closure()->shared() 210 ->VerifyBailoutId(id)); 211 simulate->set_ast_id(id); 212 } 213 } 214 215 216 bool HBasicBlock::Dominates(HBasicBlock* other) const { 217 HBasicBlock* current = other->dominator(); 218 while (current != NULL) { 219 if (current == this) return true; 220 current = current->dominator(); 221 } 222 return false; 223 } 224 225 226 void HBasicBlock::PostProcessLoopHeader(IterationStatement* stmt) { 227 ASSERT(IsLoopHeader()); 228 229 SetJoinId(stmt->EntryId()); 230 if (predecessors()->length() == 1) { 231 // This is a degenerated loop. 232 DetachLoopInformation(); 233 return; 234 } 235 236 // Only the first entry into the loop is from outside the loop. All other 237 // entries must be back edges. 238 for (int i = 1; i < predecessors()->length(); ++i) { 239 loop_information()->RegisterBackEdge(predecessors()->at(i)); 240 } 241 } 242 243 244 void HBasicBlock::RegisterPredecessor(HBasicBlock* pred) { 245 if (!predecessors_.is_empty()) { 246 // Only loop header blocks can have a predecessor added after 247 // instructions have been added to the block (they have phis for all 248 // values in the environment, these phis may be eliminated later). 249 ASSERT(IsLoopHeader() || first_ == NULL); 250 HEnvironment* incoming_env = pred->last_environment(); 251 if (IsLoopHeader()) { 252 ASSERT(phis()->length() == incoming_env->length()); 253 for (int i = 0; i < phis_.length(); ++i) { 254 phis_[i]->AddInput(incoming_env->values()->at(i)); 255 } 256 } else { 257 last_environment()->AddIncomingEdge(this, pred->last_environment()); 258 } 259 } else if (!HasEnvironment() && !IsFinished()) { 260 ASSERT(!IsLoopHeader()); 261 SetInitialEnvironment(pred->last_environment()->Copy()); 262 } 263 264 predecessors_.Add(pred); 265 } 266 267 268 void HBasicBlock::AddDominatedBlock(HBasicBlock* block) { 269 ASSERT(!dominated_blocks_.Contains(block)); 270 // Keep the list of dominated blocks sorted such that if there is two 271 // succeeding block in this list, the predecessor is before the successor. 272 int index = 0; 273 while (index < dominated_blocks_.length() && 274 dominated_blocks_[index]->block_id() < block->block_id()) { 275 ++index; 276 } 277 dominated_blocks_.InsertAt(index, block); 278 } 279 280 281 void HBasicBlock::AssignCommonDominator(HBasicBlock* other) { 282 if (dominator_ == NULL) { 283 dominator_ = other; 284 other->AddDominatedBlock(this); 285 } else if (other->dominator() != NULL) { 286 HBasicBlock* first = dominator_; 287 HBasicBlock* second = other; 288 289 while (first != second) { 290 if (first->block_id() > second->block_id()) { 291 first = first->dominator(); 292 } else { 293 second = second->dominator(); 294 } 295 ASSERT(first != NULL && second != NULL); 296 } 297 298 if (dominator_ != first) { 299 ASSERT(dominator_->dominated_blocks_.Contains(this)); 300 dominator_->dominated_blocks_.RemoveElement(this); 301 dominator_ = first; 302 first->AddDominatedBlock(this); 303 } 304 } 305 } 306 307 308 int HBasicBlock::PredecessorIndexOf(HBasicBlock* predecessor) const { 309 for (int i = 0; i < predecessors_.length(); ++i) { 310 if (predecessors_[i] == predecessor) return i; 311 } 312 UNREACHABLE(); 313 return -1; 314 } 315 316 317 #ifdef DEBUG 318 void HBasicBlock::Verify() { 319 // Check that every block is finished. 320 ASSERT(IsFinished()); 321 ASSERT(block_id() >= 0); 322 323 // Check that the incoming edges are in edge split form. 324 if (predecessors_.length() > 1) { 325 for (int i = 0; i < predecessors_.length(); ++i) { 326 ASSERT(predecessors_[i]->end()->SecondSuccessor() == NULL); 327 } 328 } 329 } 330 #endif 331 332 333 void HLoopInformation::RegisterBackEdge(HBasicBlock* block) { 334 this->back_edges_.Add(block); 335 AddBlock(block); 336 } 337 338 339 HBasicBlock* HLoopInformation::GetLastBackEdge() const { 340 int max_id = -1; 341 HBasicBlock* result = NULL; 342 for (int i = 0; i < back_edges_.length(); ++i) { 343 HBasicBlock* cur = back_edges_[i]; 344 if (cur->block_id() > max_id) { 345 max_id = cur->block_id(); 346 result = cur; 347 } 348 } 349 return result; 350 } 351 352 353 void HLoopInformation::AddBlock(HBasicBlock* block) { 354 if (block == loop_header()) return; 355 if (block->parent_loop_header() == loop_header()) return; 356 if (block->parent_loop_header() != NULL) { 357 AddBlock(block->parent_loop_header()); 358 } else { 359 block->set_parent_loop_header(loop_header()); 360 blocks_.Add(block); 361 for (int i = 0; i < block->predecessors()->length(); ++i) { 362 AddBlock(block->predecessors()->at(i)); 363 } 364 } 365 } 366 367 368 #ifdef DEBUG 369 370 // Checks reachability of the blocks in this graph and stores a bit in 371 // the BitVector "reachable()" for every block that can be reached 372 // from the start block of the graph. If "dont_visit" is non-null, the given 373 // block is treated as if it would not be part of the graph. "visited_count()" 374 // returns the number of reachable blocks. 375 class ReachabilityAnalyzer BASE_EMBEDDED { 376 public: 377 ReachabilityAnalyzer(HBasicBlock* entry_block, 378 int block_count, 379 HBasicBlock* dont_visit) 380 : visited_count_(0), 381 stack_(16), 382 reachable_(block_count), 383 dont_visit_(dont_visit) { 384 PushBlock(entry_block); 385 Analyze(); 386 } 387 388 int visited_count() const { return visited_count_; } 389 const BitVector* reachable() const { return &reachable_; } 390 391 private: 392 void PushBlock(HBasicBlock* block) { 393 if (block != NULL && block != dont_visit_ && 394 !reachable_.Contains(block->block_id())) { 395 reachable_.Add(block->block_id()); 396 stack_.Add(block); 397 visited_count_++; 398 } 399 } 400 401 void Analyze() { 402 while (!stack_.is_empty()) { 403 HControlInstruction* end = stack_.RemoveLast()->end(); 404 PushBlock(end->FirstSuccessor()); 405 PushBlock(end->SecondSuccessor()); 406 } 407 } 408 409 int visited_count_; 410 ZoneList<HBasicBlock*> stack_; 411 BitVector reachable_; 412 HBasicBlock* dont_visit_; 413 }; 414 415 416 void HGraph::Verify() const { 417 for (int i = 0; i < blocks_.length(); i++) { 418 HBasicBlock* block = blocks_.at(i); 419 420 block->Verify(); 421 422 // Check that every block contains at least one node and that only the last 423 // node is a control instruction. 424 HInstruction* current = block->first(); 425 ASSERT(current != NULL && current->IsBlockEntry()); 426 while (current != NULL) { 427 ASSERT((current->next() == NULL) == current->IsControlInstruction()); 428 ASSERT(current->block() == block); 429 current->Verify(); 430 current = current->next(); 431 } 432 433 // Check that successors are correctly set. 434 HBasicBlock* first = block->end()->FirstSuccessor(); 435 HBasicBlock* second = block->end()->SecondSuccessor(); 436 ASSERT(second == NULL || first != NULL); 437 438 // Check that the predecessor array is correct. 439 if (first != NULL) { 440 ASSERT(first->predecessors()->Contains(block)); 441 if (second != NULL) { 442 ASSERT(second->predecessors()->Contains(block)); 443 } 444 } 445 446 // Check that phis have correct arguments. 447 for (int j = 0; j < block->phis()->length(); j++) { 448 HPhi* phi = block->phis()->at(j); 449 phi->Verify(); 450 } 451 452 // Check that all join blocks have predecessors that end with an 453 // unconditional goto and agree on their environment node id. 454 if (block->predecessors()->length() >= 2) { 455 int id = block->predecessors()->first()->last_environment()->ast_id(); 456 for (int k = 0; k < block->predecessors()->length(); k++) { 457 HBasicBlock* predecessor = block->predecessors()->at(k); 458 ASSERT(predecessor->end()->IsGoto()); 459 ASSERT(predecessor->last_environment()->ast_id() == id); 460 } 461 } 462 } 463 464 // Check special property of first block to have no predecessors. 465 ASSERT(blocks_.at(0)->predecessors()->is_empty()); 466 467 // Check that the graph is fully connected. 468 ReachabilityAnalyzer analyzer(entry_block_, blocks_.length(), NULL); 469 ASSERT(analyzer.visited_count() == blocks_.length()); 470 471 // Check that entry block dominator is NULL. 472 ASSERT(entry_block_->dominator() == NULL); 473 474 // Check dominators. 475 for (int i = 0; i < blocks_.length(); ++i) { 476 HBasicBlock* block = blocks_.at(i); 477 if (block->dominator() == NULL) { 478 // Only start block may have no dominator assigned to. 479 ASSERT(i == 0); 480 } else { 481 // Assert that block is unreachable if dominator must not be visited. 482 ReachabilityAnalyzer dominator_analyzer(entry_block_, 483 blocks_.length(), 484 block->dominator()); 485 ASSERT(!dominator_analyzer.reachable()->Contains(block->block_id())); 486 } 487 } 488 } 489 490 #endif 491 492 493 HConstant* HGraph::GetConstant(SetOncePointer<HConstant>* pointer, 494 Object* value) { 495 if (!pointer->is_set()) { 496 HConstant* constant = new(zone()) HConstant(Handle<Object>(value), 497 Representation::Tagged()); 498 constant->InsertAfter(GetConstantUndefined()); 499 pointer->set(constant); 500 } 501 return pointer->get(); 502 } 503 504 505 HConstant* HGraph::GetConstant1() { 506 return GetConstant(&constant_1_, Smi::FromInt(1)); 507 } 508 509 510 HConstant* HGraph::GetConstantMinus1() { 511 return GetConstant(&constant_minus1_, Smi::FromInt(-1)); 512 } 513 514 515 HConstant* HGraph::GetConstantTrue() { 516 return GetConstant(&constant_true_, isolate()->heap()->true_value()); 517 } 518 519 520 HConstant* HGraph::GetConstantFalse() { 521 return GetConstant(&constant_false_, isolate()->heap()->false_value()); 522 } 523 524 525 HBasicBlock* HGraphBuilder::CreateJoin(HBasicBlock* first, 526 HBasicBlock* second, 527 int join_id) { 528 if (first == NULL) { 529 return second; 530 } else if (second == NULL) { 531 return first; 532 } else { 533 HBasicBlock* join_block = graph_->CreateBasicBlock(); 534 first->Goto(join_block); 535 second->Goto(join_block); 536 join_block->SetJoinId(join_id); 537 return join_block; 538 } 539 } 540 541 542 HBasicBlock* HGraphBuilder::JoinContinue(IterationStatement* statement, 543 HBasicBlock* exit_block, 544 HBasicBlock* continue_block) { 545 if (continue_block != NULL) { 546 if (exit_block != NULL) exit_block->Goto(continue_block); 547 continue_block->SetJoinId(statement->ContinueId()); 548 return continue_block; 549 } 550 return exit_block; 551 } 552 553 554 HBasicBlock* HGraphBuilder::CreateLoop(IterationStatement* statement, 555 HBasicBlock* loop_entry, 556 HBasicBlock* body_exit, 557 HBasicBlock* loop_successor, 558 HBasicBlock* break_block) { 559 if (body_exit != NULL) body_exit->Goto(loop_entry, true); 560 loop_entry->PostProcessLoopHeader(statement); 561 if (break_block != NULL) { 562 if (loop_successor != NULL) loop_successor->Goto(break_block); 563 break_block->SetJoinId(statement->ExitId()); 564 return break_block; 565 } 566 return loop_successor; 567 } 568 569 570 void HBasicBlock::FinishExit(HControlInstruction* instruction) { 571 Finish(instruction); 572 ClearEnvironment(); 573 } 574 575 576 HGraph::HGraph(CompilationInfo* info) 577 : isolate_(info->isolate()), 578 next_block_id_(0), 579 entry_block_(NULL), 580 blocks_(8), 581 values_(16), 582 phi_list_(NULL) { 583 start_environment_ = 584 new(zone()) HEnvironment(NULL, info->scope(), info->closure()); 585 start_environment_->set_ast_id(AstNode::kFunctionEntryId); 586 entry_block_ = CreateBasicBlock(); 587 entry_block_->SetInitialEnvironment(start_environment_); 588 } 589 590 591 Handle<Code> HGraph::Compile(CompilationInfo* info) { 592 int values = GetMaximumValueID(); 593 if (values > LAllocator::max_initial_value_ids()) { 594 if (FLAG_trace_bailout) PrintF("Function is too big\n"); 595 return Handle<Code>::null(); 596 } 597 598 LAllocator allocator(values, this); 599 LChunkBuilder builder(info, this, &allocator); 600 LChunk* chunk = builder.Build(); 601 if (chunk == NULL) return Handle<Code>::null(); 602 603 if (!FLAG_alloc_lithium) return Handle<Code>::null(); 604 605 allocator.Allocate(chunk); 606 607 if (!FLAG_use_lithium) return Handle<Code>::null(); 608 609 MacroAssembler assembler(info->isolate(), NULL, 0); 610 LCodeGen generator(chunk, &assembler, info); 611 612 if (FLAG_eliminate_empty_blocks) { 613 chunk->MarkEmptyBlocks(); 614 } 615 616 if (generator.GenerateCode()) { 617 if (FLAG_trace_codegen) { 618 PrintF("Crankshaft Compiler - "); 619 } 620 CodeGenerator::MakeCodePrologue(info); 621 Code::Flags flags = 622 Code::ComputeFlags(Code::OPTIMIZED_FUNCTION, NOT_IN_LOOP); 623 Handle<Code> code = 624 CodeGenerator::MakeCodeEpilogue(&assembler, flags, info); 625 generator.FinishCode(code); 626 CodeGenerator::PrintCode(code, info); 627 return code; 628 } 629 return Handle<Code>::null(); 630 } 631 632 633 HBasicBlock* HGraph::CreateBasicBlock() { 634 HBasicBlock* result = new(zone()) HBasicBlock(this); 635 blocks_.Add(result); 636 return result; 637 } 638 639 640 void HGraph::Canonicalize() { 641 if (!FLAG_use_canonicalizing) return; 642 HPhase phase("Canonicalize", this); 643 for (int i = 0; i < blocks()->length(); ++i) { 644 HInstruction* instr = blocks()->at(i)->first(); 645 while (instr != NULL) { 646 HValue* value = instr->Canonicalize(); 647 if (value != instr) instr->ReplaceAndDelete(value); 648 instr = instr->next(); 649 } 650 } 651 } 652 653 654 void HGraph::OrderBlocks() { 655 HPhase phase("Block ordering"); 656 BitVector visited(blocks_.length()); 657 658 ZoneList<HBasicBlock*> reverse_result(8); 659 HBasicBlock* start = blocks_[0]; 660 Postorder(start, &visited, &reverse_result, NULL); 661 662 blocks_.Rewind(0); 663 int index = 0; 664 for (int i = reverse_result.length() - 1; i >= 0; --i) { 665 HBasicBlock* b = reverse_result[i]; 666 blocks_.Add(b); 667 b->set_block_id(index++); 668 } 669 } 670 671 672 void HGraph::PostorderLoopBlocks(HLoopInformation* loop, 673 BitVector* visited, 674 ZoneList<HBasicBlock*>* order, 675 HBasicBlock* loop_header) { 676 for (int i = 0; i < loop->blocks()->length(); ++i) { 677 HBasicBlock* b = loop->blocks()->at(i); 678 Postorder(b->end()->SecondSuccessor(), visited, order, loop_header); 679 Postorder(b->end()->FirstSuccessor(), visited, order, loop_header); 680 if (b->IsLoopHeader() && b != loop->loop_header()) { 681 PostorderLoopBlocks(b->loop_information(), visited, order, loop_header); 682 } 683 } 684 } 685 686 687 void HGraph::Postorder(HBasicBlock* block, 688 BitVector* visited, 689 ZoneList<HBasicBlock*>* order, 690 HBasicBlock* loop_header) { 691 if (block == NULL || visited->Contains(block->block_id())) return; 692 if (block->parent_loop_header() != loop_header) return; 693 visited->Add(block->block_id()); 694 if (block->IsLoopHeader()) { 695 PostorderLoopBlocks(block->loop_information(), visited, order, loop_header); 696 Postorder(block->end()->SecondSuccessor(), visited, order, block); 697 Postorder(block->end()->FirstSuccessor(), visited, order, block); 698 } else { 699 Postorder(block->end()->SecondSuccessor(), visited, order, loop_header); 700 Postorder(block->end()->FirstSuccessor(), visited, order, loop_header); 701 } 702 ASSERT(block->end()->FirstSuccessor() == NULL || 703 order->Contains(block->end()->FirstSuccessor()) || 704 block->end()->FirstSuccessor()->IsLoopHeader()); 705 ASSERT(block->end()->SecondSuccessor() == NULL || 706 order->Contains(block->end()->SecondSuccessor()) || 707 block->end()->SecondSuccessor()->IsLoopHeader()); 708 order->Add(block); 709 } 710 711 712 void HGraph::AssignDominators() { 713 HPhase phase("Assign dominators", this); 714 for (int i = 0; i < blocks_.length(); ++i) { 715 if (blocks_[i]->IsLoopHeader()) { 716 blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->first()); 717 } else { 718 for (int j = 0; j < blocks_[i]->predecessors()->length(); ++j) { 719 blocks_[i]->AssignCommonDominator(blocks_[i]->predecessors()->at(j)); 720 } 721 } 722 } 723 } 724 725 726 void HGraph::EliminateRedundantPhis() { 727 HPhase phase("Redundant phi elimination", this); 728 729 // Worklist of phis that can potentially be eliminated. Initialized 730 // with all phi nodes. When elimination of a phi node modifies 731 // another phi node the modified phi node is added to the worklist. 732 ZoneList<HPhi*> worklist(blocks_.length()); 733 for (int i = 0; i < blocks_.length(); ++i) { 734 worklist.AddAll(*blocks_[i]->phis()); 735 } 736 737 while (!worklist.is_empty()) { 738 HPhi* phi = worklist.RemoveLast(); 739 HBasicBlock* block = phi->block(); 740 741 // Skip phi node if it was already replaced. 742 if (block == NULL) continue; 743 744 // Get replacement value if phi is redundant. 745 HValue* value = phi->GetRedundantReplacement(); 746 747 if (value != NULL) { 748 // Iterate through uses finding the ones that should be 749 // replaced. 750 SmallPointerList<HValue>* uses = phi->uses(); 751 while (!uses->is_empty()) { 752 HValue* use = uses->RemoveLast(); 753 if (use != NULL) { 754 phi->ReplaceAtUse(use, value); 755 if (use->IsPhi()) worklist.Add(HPhi::cast(use)); 756 } 757 } 758 block->RemovePhi(phi); 759 } 760 } 761 } 762 763 764 void HGraph::EliminateUnreachablePhis() { 765 HPhase phase("Unreachable phi elimination", this); 766 767 // Initialize worklist. 768 ZoneList<HPhi*> phi_list(blocks_.length()); 769 ZoneList<HPhi*> worklist(blocks_.length()); 770 for (int i = 0; i < blocks_.length(); ++i) { 771 for (int j = 0; j < blocks_[i]->phis()->length(); j++) { 772 HPhi* phi = blocks_[i]->phis()->at(j); 773 phi_list.Add(phi); 774 // We can't eliminate phis in the receiver position in the environment 775 // because in case of throwing an error we need this value to 776 // construct a stack trace. 777 if (phi->HasRealUses() || phi->IsReceiver()) { 778 phi->set_is_live(true); 779 worklist.Add(phi); 780 } 781 } 782 } 783 784 // Iteratively mark live phis. 785 while (!worklist.is_empty()) { 786 HPhi* phi = worklist.RemoveLast(); 787 for (int i = 0; i < phi->OperandCount(); i++) { 788 HValue* operand = phi->OperandAt(i); 789 if (operand->IsPhi() && !HPhi::cast(operand)->is_live()) { 790 HPhi::cast(operand)->set_is_live(true); 791 worklist.Add(HPhi::cast(operand)); 792 } 793 } 794 } 795 796 // Remove unreachable phis. 797 for (int i = 0; i < phi_list.length(); i++) { 798 HPhi* phi = phi_list[i]; 799 if (!phi->is_live()) { 800 HBasicBlock* block = phi->block(); 801 block->RemovePhi(phi); 802 block->RecordDeletedPhi(phi->merged_index()); 803 } 804 } 805 } 806 807 808 bool HGraph::CollectPhis() { 809 int block_count = blocks_.length(); 810 phi_list_ = new ZoneList<HPhi*>(block_count); 811 for (int i = 0; i < block_count; ++i) { 812 for (int j = 0; j < blocks_[i]->phis()->length(); ++j) { 813 HPhi* phi = blocks_[i]->phis()->at(j); 814 phi_list_->Add(phi); 815 // We don't support phi uses of arguments for now. 816 if (phi->CheckFlag(HValue::kIsArguments)) return false; 817 } 818 } 819 return true; 820 } 821 822 823 void HGraph::InferTypes(ZoneList<HValue*>* worklist) { 824 BitVector in_worklist(GetMaximumValueID()); 825 for (int i = 0; i < worklist->length(); ++i) { 826 ASSERT(!in_worklist.Contains(worklist->at(i)->id())); 827 in_worklist.Add(worklist->at(i)->id()); 828 } 829 830 while (!worklist->is_empty()) { 831 HValue* current = worklist->RemoveLast(); 832 in_worklist.Remove(current->id()); 833 if (current->UpdateInferredType()) { 834 for (int j = 0; j < current->uses()->length(); j++) { 835 HValue* use = current->uses()->at(j); 836 if (!in_worklist.Contains(use->id())) { 837 in_worklist.Add(use->id()); 838 worklist->Add(use); 839 } 840 } 841 } 842 } 843 } 844 845 846 class HRangeAnalysis BASE_EMBEDDED { 847 public: 848 explicit HRangeAnalysis(HGraph* graph) : graph_(graph), changed_ranges_(16) {} 849 850 void Analyze(); 851 852 private: 853 void TraceRange(const char* msg, ...); 854 void Analyze(HBasicBlock* block); 855 void InferControlFlowRange(HTest* test, HBasicBlock* dest); 856 void InferControlFlowRange(Token::Value op, HValue* value, HValue* other); 857 void InferPhiRange(HPhi* phi); 858 void InferRange(HValue* value); 859 void RollBackTo(int index); 860 void AddRange(HValue* value, Range* range); 861 862 HGraph* graph_; 863 ZoneList<HValue*> changed_ranges_; 864 }; 865 866 867 void HRangeAnalysis::TraceRange(const char* msg, ...) { 868 if (FLAG_trace_range) { 869 va_list arguments; 870 va_start(arguments, msg); 871 OS::VPrint(msg, arguments); 872 va_end(arguments); 873 } 874 } 875 876 877 void HRangeAnalysis::Analyze() { 878 HPhase phase("Range analysis", graph_); 879 Analyze(graph_->blocks()->at(0)); 880 } 881 882 883 void HRangeAnalysis::Analyze(HBasicBlock* block) { 884 TraceRange("Analyzing block B%d\n", block->block_id()); 885 886 int last_changed_range = changed_ranges_.length() - 1; 887 888 // Infer range based on control flow. 889 if (block->predecessors()->length() == 1) { 890 HBasicBlock* pred = block->predecessors()->first(); 891 if (pred->end()->IsTest()) { 892 InferControlFlowRange(HTest::cast(pred->end()), block); 893 } 894 } 895 896 // Process phi instructions. 897 for (int i = 0; i < block->phis()->length(); ++i) { 898 HPhi* phi = block->phis()->at(i); 899 InferPhiRange(phi); 900 } 901 902 // Go through all instructions of the current block. 903 HInstruction* instr = block->first(); 904 while (instr != block->end()) { 905 InferRange(instr); 906 instr = instr->next(); 907 } 908 909 // Continue analysis in all dominated blocks. 910 for (int i = 0; i < block->dominated_blocks()->length(); ++i) { 911 Analyze(block->dominated_blocks()->at(i)); 912 } 913 914 RollBackTo(last_changed_range); 915 } 916 917 918 void HRangeAnalysis::InferControlFlowRange(HTest* test, HBasicBlock* dest) { 919 ASSERT((test->FirstSuccessor() == dest) == (test->SecondSuccessor() != dest)); 920 if (test->value()->IsCompare()) { 921 HCompare* compare = HCompare::cast(test->value()); 922 if (compare->GetInputRepresentation().IsInteger32()) { 923 Token::Value op = compare->token(); 924 if (test->SecondSuccessor() == dest) { 925 op = Token::NegateCompareOp(op); 926 } 927 Token::Value inverted_op = Token::InvertCompareOp(op); 928 InferControlFlowRange(op, compare->left(), compare->right()); 929 InferControlFlowRange(inverted_op, compare->right(), compare->left()); 930 } 931 } 932 } 933 934 935 // We know that value [op] other. Use this information to update the range on 936 // value. 937 void HRangeAnalysis::InferControlFlowRange(Token::Value op, 938 HValue* value, 939 HValue* other) { 940 Range temp_range; 941 Range* range = other->range() != NULL ? other->range() : &temp_range; 942 Range* new_range = NULL; 943 944 TraceRange("Control flow range infer %d %s %d\n", 945 value->id(), 946 Token::Name(op), 947 other->id()); 948 949 if (op == Token::EQ || op == Token::EQ_STRICT) { 950 // The same range has to apply for value. 951 new_range = range->Copy(); 952 } else if (op == Token::LT || op == Token::LTE) { 953 new_range = range->CopyClearLower(); 954 if (op == Token::LT) { 955 new_range->AddConstant(-1); 956 } 957 } else if (op == Token::GT || op == Token::GTE) { 958 new_range = range->CopyClearUpper(); 959 if (op == Token::GT) { 960 new_range->AddConstant(1); 961 } 962 } 963 964 if (new_range != NULL && !new_range->IsMostGeneric()) { 965 AddRange(value, new_range); 966 } 967 } 968 969 970 void HRangeAnalysis::InferPhiRange(HPhi* phi) { 971 // TODO(twuerthinger): Infer loop phi ranges. 972 InferRange(phi); 973 } 974 975 976 void HRangeAnalysis::InferRange(HValue* value) { 977 ASSERT(!value->HasRange()); 978 if (!value->representation().IsNone()) { 979 value->ComputeInitialRange(); 980 Range* range = value->range(); 981 TraceRange("Initial inferred range of %d (%s) set to [%d,%d]\n", 982 value->id(), 983 value->Mnemonic(), 984 range->lower(), 985 range->upper()); 986 } 987 } 988 989 990 void HRangeAnalysis::RollBackTo(int index) { 991 for (int i = index + 1; i < changed_ranges_.length(); ++i) { 992 changed_ranges_[i]->RemoveLastAddedRange(); 993 } 994 changed_ranges_.Rewind(index + 1); 995 } 996 997 998 void HRangeAnalysis::AddRange(HValue* value, Range* range) { 999 Range* original_range = value->range(); 1000 value->AddNewRange(range); 1001 changed_ranges_.Add(value); 1002 Range* new_range = value->range(); 1003 TraceRange("Updated range of %d set to [%d,%d]\n", 1004 value->id(), 1005 new_range->lower(), 1006 new_range->upper()); 1007 if (original_range != NULL) { 1008 TraceRange("Original range was [%d,%d]\n", 1009 original_range->lower(), 1010 original_range->upper()); 1011 } 1012 TraceRange("New information was [%d,%d]\n", 1013 range->lower(), 1014 range->upper()); 1015 } 1016 1017 1018 void TraceGVN(const char* msg, ...) { 1019 if (FLAG_trace_gvn) { 1020 va_list arguments; 1021 va_start(arguments, msg); 1022 OS::VPrint(msg, arguments); 1023 va_end(arguments); 1024 } 1025 } 1026 1027 1028 HValueMap::HValueMap(const HValueMap* other) 1029 : array_size_(other->array_size_), 1030 lists_size_(other->lists_size_), 1031 count_(other->count_), 1032 present_flags_(other->present_flags_), 1033 array_(ZONE->NewArray<HValueMapListElement>(other->array_size_)), 1034 lists_(ZONE->NewArray<HValueMapListElement>(other->lists_size_)), 1035 free_list_head_(other->free_list_head_) { 1036 memcpy(array_, other->array_, array_size_ * sizeof(HValueMapListElement)); 1037 memcpy(lists_, other->lists_, lists_size_ * sizeof(HValueMapListElement)); 1038 } 1039 1040 1041 void HValueMap::Kill(int flags) { 1042 int depends_flags = HValue::ConvertChangesToDependsFlags(flags); 1043 if ((present_flags_ & depends_flags) == 0) return; 1044 present_flags_ = 0; 1045 for (int i = 0; i < array_size_; ++i) { 1046 HValue* value = array_[i].value; 1047 if (value != NULL) { 1048 // Clear list of collisions first, so we know if it becomes empty. 1049 int kept = kNil; // List of kept elements. 1050 int next; 1051 for (int current = array_[i].next; current != kNil; current = next) { 1052 next = lists_[current].next; 1053 if ((lists_[current].value->flags() & depends_flags) != 0) { 1054 // Drop it. 1055 count_--; 1056 lists_[current].next = free_list_head_; 1057 free_list_head_ = current; 1058 } else { 1059 // Keep it. 1060 lists_[current].next = kept; 1061 kept = current; 1062 present_flags_ |= lists_[current].value->flags(); 1063 } 1064 } 1065 array_[i].next = kept; 1066 1067 // Now possibly drop directly indexed element. 1068 if ((array_[i].value->flags() & depends_flags) != 0) { // Drop it. 1069 count_--; 1070 int head = array_[i].next; 1071 if (head == kNil) { 1072 array_[i].value = NULL; 1073 } else { 1074 array_[i].value = lists_[head].value; 1075 array_[i].next = lists_[head].next; 1076 lists_[head].next = free_list_head_; 1077 free_list_head_ = head; 1078 } 1079 } else { 1080 present_flags_ |= array_[i].value->flags(); // Keep it. 1081 } 1082 } 1083 } 1084 } 1085 1086 1087 HValue* HValueMap::Lookup(HValue* value) const { 1088 uint32_t hash = static_cast<uint32_t>(value->Hashcode()); 1089 uint32_t pos = Bound(hash); 1090 if (array_[pos].value != NULL) { 1091 if (array_[pos].value->Equals(value)) return array_[pos].value; 1092 int next = array_[pos].next; 1093 while (next != kNil) { 1094 if (lists_[next].value->Equals(value)) return lists_[next].value; 1095 next = lists_[next].next; 1096 } 1097 } 1098 return NULL; 1099 } 1100 1101 1102 void HValueMap::Resize(int new_size) { 1103 ASSERT(new_size > count_); 1104 // Hashing the values into the new array has no more collisions than in the 1105 // old hash map, so we can use the existing lists_ array, if we are careful. 1106 1107 // Make sure we have at least one free element. 1108 if (free_list_head_ == kNil) { 1109 ResizeLists(lists_size_ << 1); 1110 } 1111 1112 HValueMapListElement* new_array = 1113 ZONE->NewArray<HValueMapListElement>(new_size); 1114 memset(new_array, 0, sizeof(HValueMapListElement) * new_size); 1115 1116 HValueMapListElement* old_array = array_; 1117 int old_size = array_size_; 1118 1119 int old_count = count_; 1120 count_ = 0; 1121 // Do not modify present_flags_. It is currently correct. 1122 array_size_ = new_size; 1123 array_ = new_array; 1124 1125 if (old_array != NULL) { 1126 // Iterate over all the elements in lists, rehashing them. 1127 for (int i = 0; i < old_size; ++i) { 1128 if (old_array[i].value != NULL) { 1129 int current = old_array[i].next; 1130 while (current != kNil) { 1131 Insert(lists_[current].value); 1132 int next = lists_[current].next; 1133 lists_[current].next = free_list_head_; 1134 free_list_head_ = current; 1135 current = next; 1136 } 1137 // Rehash the directly stored value. 1138 Insert(old_array[i].value); 1139 } 1140 } 1141 } 1142 USE(old_count); 1143 ASSERT(count_ == old_count); 1144 } 1145 1146 1147 void HValueMap::ResizeLists(int new_size) { 1148 ASSERT(new_size > lists_size_); 1149 1150 HValueMapListElement* new_lists = 1151 ZONE->NewArray<HValueMapListElement>(new_size); 1152 memset(new_lists, 0, sizeof(HValueMapListElement) * new_size); 1153 1154 HValueMapListElement* old_lists = lists_; 1155 int old_size = lists_size_; 1156 1157 lists_size_ = new_size; 1158 lists_ = new_lists; 1159 1160 if (old_lists != NULL) { 1161 memcpy(lists_, old_lists, old_size * sizeof(HValueMapListElement)); 1162 } 1163 for (int i = old_size; i < lists_size_; ++i) { 1164 lists_[i].next = free_list_head_; 1165 free_list_head_ = i; 1166 } 1167 } 1168 1169 1170 void HValueMap::Insert(HValue* value) { 1171 ASSERT(value != NULL); 1172 // Resizing when half of the hashtable is filled up. 1173 if (count_ >= array_size_ >> 1) Resize(array_size_ << 1); 1174 ASSERT(count_ < array_size_); 1175 count_++; 1176 uint32_t pos = Bound(static_cast<uint32_t>(value->Hashcode())); 1177 if (array_[pos].value == NULL) { 1178 array_[pos].value = value; 1179 array_[pos].next = kNil; 1180 } else { 1181 if (free_list_head_ == kNil) { 1182 ResizeLists(lists_size_ << 1); 1183 } 1184 int new_element_pos = free_list_head_; 1185 ASSERT(new_element_pos != kNil); 1186 free_list_head_ = lists_[free_list_head_].next; 1187 lists_[new_element_pos].value = value; 1188 lists_[new_element_pos].next = array_[pos].next; 1189 ASSERT(array_[pos].next == kNil || lists_[array_[pos].next].value != NULL); 1190 array_[pos].next = new_element_pos; 1191 } 1192 } 1193 1194 1195 class HStackCheckEliminator BASE_EMBEDDED { 1196 public: 1197 explicit HStackCheckEliminator(HGraph* graph) : graph_(graph) { } 1198 1199 void Process(); 1200 1201 private: 1202 void RemoveStackCheck(HBasicBlock* block); 1203 1204 HGraph* graph_; 1205 }; 1206 1207 1208 void HStackCheckEliminator::Process() { 1209 // For each loop block walk the dominator tree from the backwards branch to 1210 // the loop header. If a call instruction is encountered the backwards branch 1211 // is dominated by a call and the stack check in the backwards branch can be 1212 // removed. 1213 for (int i = 0; i < graph_->blocks()->length(); i++) { 1214 HBasicBlock* block = graph_->blocks()->at(i); 1215 if (block->IsLoopHeader()) { 1216 HBasicBlock* back_edge = block->loop_information()->GetLastBackEdge(); 1217 HBasicBlock* dominator = back_edge; 1218 bool back_edge_dominated_by_call = false; 1219 while (dominator != block && !back_edge_dominated_by_call) { 1220 HInstruction* instr = dominator->first(); 1221 while (instr != NULL && !back_edge_dominated_by_call) { 1222 if (instr->IsCall()) { 1223 RemoveStackCheck(back_edge); 1224 back_edge_dominated_by_call = true; 1225 } 1226 instr = instr->next(); 1227 } 1228 dominator = dominator->dominator(); 1229 } 1230 } 1231 } 1232 } 1233 1234 1235 void HStackCheckEliminator::RemoveStackCheck(HBasicBlock* block) { 1236 HInstruction* instr = block->first(); 1237 while (instr != NULL) { 1238 if (instr->IsGoto()) { 1239 HGoto::cast(instr)->set_include_stack_check(false); 1240 return; 1241 } 1242 instr = instr->next(); 1243 } 1244 } 1245 1246 1247 class HGlobalValueNumberer BASE_EMBEDDED { 1248 public: 1249 explicit HGlobalValueNumberer(HGraph* graph, CompilationInfo* info) 1250 : graph_(graph), 1251 info_(info), 1252 block_side_effects_(graph_->blocks()->length()), 1253 loop_side_effects_(graph_->blocks()->length()) { 1254 ASSERT(info->isolate()->heap()->allow_allocation(false)); 1255 block_side_effects_.AddBlock(0, graph_->blocks()->length()); 1256 loop_side_effects_.AddBlock(0, graph_->blocks()->length()); 1257 } 1258 ~HGlobalValueNumberer() { 1259 ASSERT(!info_->isolate()->heap()->allow_allocation(true)); 1260 } 1261 1262 void Analyze(); 1263 1264 private: 1265 void AnalyzeBlock(HBasicBlock* block, HValueMap* map); 1266 void ComputeBlockSideEffects(); 1267 void LoopInvariantCodeMotion(); 1268 void ProcessLoopBlock(HBasicBlock* block, 1269 HBasicBlock* before_loop, 1270 int loop_kills); 1271 bool AllowCodeMotion(); 1272 bool ShouldMove(HInstruction* instr, HBasicBlock* loop_header); 1273 1274 HGraph* graph() { return graph_; } 1275 CompilationInfo* info() { return info_; } 1276 Zone* zone() { return graph_->zone(); } 1277 1278 HGraph* graph_; 1279 CompilationInfo* info_; 1280 1281 // A map of block IDs to their side effects. 1282 ZoneList<int> block_side_effects_; 1283 1284 // A map of loop header block IDs to their loop's side effects. 1285 ZoneList<int> loop_side_effects_; 1286 }; 1287 1288 1289 void HGlobalValueNumberer::Analyze() { 1290 ComputeBlockSideEffects(); 1291 if (FLAG_loop_invariant_code_motion) { 1292 LoopInvariantCodeMotion(); 1293 } 1294 HValueMap* map = new(zone()) HValueMap(); 1295 AnalyzeBlock(graph_->blocks()->at(0), map); 1296 } 1297 1298 1299 void HGlobalValueNumberer::ComputeBlockSideEffects() { 1300 for (int i = graph_->blocks()->length() - 1; i >= 0; --i) { 1301 // Compute side effects for the block. 1302 HBasicBlock* block = graph_->blocks()->at(i); 1303 HInstruction* instr = block->first(); 1304 int id = block->block_id(); 1305 int side_effects = 0; 1306 while (instr != NULL) { 1307 side_effects |= (instr->flags() & HValue::ChangesFlagsMask()); 1308 instr = instr->next(); 1309 } 1310 block_side_effects_[id] |= side_effects; 1311 1312 // Loop headers are part of their loop. 1313 if (block->IsLoopHeader()) { 1314 loop_side_effects_[id] |= side_effects; 1315 } 1316 1317 // Propagate loop side effects upwards. 1318 if (block->HasParentLoopHeader()) { 1319 int header_id = block->parent_loop_header()->block_id(); 1320 loop_side_effects_[header_id] |= 1321 block->IsLoopHeader() ? loop_side_effects_[id] : side_effects; 1322 } 1323 } 1324 } 1325 1326 1327 void HGlobalValueNumberer::LoopInvariantCodeMotion() { 1328 for (int i = graph_->blocks()->length() - 1; i >= 0; --i) { 1329 HBasicBlock* block = graph_->blocks()->at(i); 1330 if (block->IsLoopHeader()) { 1331 int side_effects = loop_side_effects_[block->block_id()]; 1332 TraceGVN("Try loop invariant motion for block B%d effects=0x%x\n", 1333 block->block_id(), 1334 side_effects); 1335 1336 HBasicBlock* last = block->loop_information()->GetLastBackEdge(); 1337 for (int j = block->block_id(); j <= last->block_id(); ++j) { 1338 ProcessLoopBlock(graph_->blocks()->at(j), block, side_effects); 1339 } 1340 } 1341 } 1342 } 1343 1344 1345 void HGlobalValueNumberer::ProcessLoopBlock(HBasicBlock* block, 1346 HBasicBlock* loop_header, 1347 int loop_kills) { 1348 HBasicBlock* pre_header = loop_header->predecessors()->at(0); 1349 int depends_flags = HValue::ConvertChangesToDependsFlags(loop_kills); 1350 TraceGVN("Loop invariant motion for B%d depends_flags=0x%x\n", 1351 block->block_id(), 1352 depends_flags); 1353 HInstruction* instr = block->first(); 1354 while (instr != NULL) { 1355 HInstruction* next = instr->next(); 1356 if (instr->CheckFlag(HValue::kUseGVN) && 1357 (instr->flags() & depends_flags) == 0) { 1358 TraceGVN("Checking instruction %d (%s)\n", 1359 instr->id(), 1360 instr->Mnemonic()); 1361 bool inputs_loop_invariant = true; 1362 for (int i = 0; i < instr->OperandCount(); ++i) { 1363 if (instr->OperandAt(i)->IsDefinedAfter(pre_header)) { 1364 inputs_loop_invariant = false; 1365 } 1366 } 1367 1368 if (inputs_loop_invariant && ShouldMove(instr, loop_header)) { 1369 TraceGVN("Found loop invariant instruction %d\n", instr->id()); 1370 // Move the instruction out of the loop. 1371 instr->Unlink(); 1372 instr->InsertBefore(pre_header->end()); 1373 } 1374 } 1375 instr = next; 1376 } 1377 } 1378 1379 1380 bool HGlobalValueNumberer::AllowCodeMotion() { 1381 return info()->shared_info()->opt_count() + 1 < Compiler::kDefaultMaxOptCount; 1382 } 1383 1384 1385 bool HGlobalValueNumberer::ShouldMove(HInstruction* instr, 1386 HBasicBlock* loop_header) { 1387 // If we've disabled code motion, don't move any instructions. 1388 if (!AllowCodeMotion()) return false; 1389 1390 // If --aggressive-loop-invariant-motion, move everything except change 1391 // instructions. 1392 if (FLAG_aggressive_loop_invariant_motion && !instr->IsChange()) { 1393 return true; 1394 } 1395 1396 // Otherwise only move instructions that postdominate the loop header 1397 // (i.e. are always executed inside the loop). This is to avoid 1398 // unnecessary deoptimizations assuming the loop is executed at least 1399 // once. TODO(fschneider): Better type feedback should give us 1400 // information about code that was never executed. 1401 HBasicBlock* block = instr->block(); 1402 bool result = true; 1403 if (block != loop_header) { 1404 for (int i = 1; i < loop_header->predecessors()->length(); ++i) { 1405 bool found = false; 1406 HBasicBlock* pred = loop_header->predecessors()->at(i); 1407 while (pred != loop_header) { 1408 if (pred == block) found = true; 1409 pred = pred->dominator(); 1410 } 1411 if (!found) { 1412 result = false; 1413 break; 1414 } 1415 } 1416 } 1417 return result; 1418 } 1419 1420 1421 void HGlobalValueNumberer::AnalyzeBlock(HBasicBlock* block, HValueMap* map) { 1422 TraceGVN("Analyzing block B%d\n", block->block_id()); 1423 1424 // If this is a loop header kill everything killed by the loop. 1425 if (block->IsLoopHeader()) { 1426 map->Kill(loop_side_effects_[block->block_id()]); 1427 } 1428 1429 // Go through all instructions of the current block. 1430 HInstruction* instr = block->first(); 1431 while (instr != NULL) { 1432 HInstruction* next = instr->next(); 1433 int flags = (instr->flags() & HValue::ChangesFlagsMask()); 1434 if (flags != 0) { 1435 ASSERT(!instr->CheckFlag(HValue::kUseGVN)); 1436 // Clear all instructions in the map that are affected by side effects. 1437 map->Kill(flags); 1438 TraceGVN("Instruction %d kills\n", instr->id()); 1439 } else if (instr->CheckFlag(HValue::kUseGVN)) { 1440 HValue* other = map->Lookup(instr); 1441 if (other != NULL) { 1442 ASSERT(instr->Equals(other) && other->Equals(instr)); 1443 TraceGVN("Replacing value %d (%s) with value %d (%s)\n", 1444 instr->id(), 1445 instr->Mnemonic(), 1446 other->id(), 1447 other->Mnemonic()); 1448 instr->ReplaceAndDelete(other); 1449 } else { 1450 map->Add(instr); 1451 } 1452 } 1453 instr = next; 1454 } 1455 1456 // Recursively continue analysis for all immediately dominated blocks. 1457 int length = block->dominated_blocks()->length(); 1458 for (int i = 0; i < length; ++i) { 1459 HBasicBlock* dominated = block->dominated_blocks()->at(i); 1460 // No need to copy the map for the last child in the dominator tree. 1461 HValueMap* successor_map = (i == length - 1) ? map : map->Copy(zone()); 1462 1463 // If the dominated block is not a successor to this block we have to 1464 // kill everything killed on any path between this block and the 1465 // dominated block. Note we rely on the block ordering. 1466 bool is_successor = false; 1467 int predecessor_count = dominated->predecessors()->length(); 1468 for (int j = 0; !is_successor && j < predecessor_count; ++j) { 1469 is_successor = (dominated->predecessors()->at(j) == block); 1470 } 1471 1472 if (!is_successor) { 1473 int side_effects = 0; 1474 for (int j = block->block_id() + 1; j < dominated->block_id(); ++j) { 1475 side_effects |= block_side_effects_[j]; 1476 } 1477 successor_map->Kill(side_effects); 1478 } 1479 1480 AnalyzeBlock(dominated, successor_map); 1481 } 1482 } 1483 1484 1485 class HInferRepresentation BASE_EMBEDDED { 1486 public: 1487 explicit HInferRepresentation(HGraph* graph) 1488 : graph_(graph), worklist_(8), in_worklist_(graph->GetMaximumValueID()) {} 1489 1490 void Analyze(); 1491 1492 private: 1493 Representation TryChange(HValue* current); 1494 void AddToWorklist(HValue* current); 1495 void InferBasedOnInputs(HValue* current); 1496 void AddDependantsToWorklist(HValue* current); 1497 void InferBasedOnUses(HValue* current); 1498 1499 Zone* zone() { return graph_->zone(); } 1500 1501 HGraph* graph_; 1502 ZoneList<HValue*> worklist_; 1503 BitVector in_worklist_; 1504 }; 1505 1506 1507 void HInferRepresentation::AddToWorklist(HValue* current) { 1508 if (current->representation().IsSpecialization()) return; 1509 if (!current->CheckFlag(HValue::kFlexibleRepresentation)) return; 1510 if (in_worklist_.Contains(current->id())) return; 1511 worklist_.Add(current); 1512 in_worklist_.Add(current->id()); 1513 } 1514 1515 1516 // This method tries to specialize the representation type of the value 1517 // given as a parameter. The value is asked to infer its representation type 1518 // based on its inputs. If the inferred type is more specialized, then this 1519 // becomes the new representation type of the node. 1520 void HInferRepresentation::InferBasedOnInputs(HValue* current) { 1521 Representation r = current->representation(); 1522 if (r.IsSpecialization()) return; 1523 ASSERT(current->CheckFlag(HValue::kFlexibleRepresentation)); 1524 Representation inferred = current->InferredRepresentation(); 1525 if (inferred.IsSpecialization()) { 1526 current->ChangeRepresentation(inferred); 1527 AddDependantsToWorklist(current); 1528 } 1529 } 1530 1531 1532 void HInferRepresentation::AddDependantsToWorklist(HValue* current) { 1533 for (int i = 0; i < current->uses()->length(); ++i) { 1534 AddToWorklist(current->uses()->at(i)); 1535 } 1536 for (int i = 0; i < current->OperandCount(); ++i) { 1537 AddToWorklist(current->OperandAt(i)); 1538 } 1539 } 1540 1541 1542 // This method calculates whether specializing the representation of the value 1543 // given as the parameter has a benefit in terms of less necessary type 1544 // conversions. If there is a benefit, then the representation of the value is 1545 // specialized. 1546 void HInferRepresentation::InferBasedOnUses(HValue* current) { 1547 Representation r = current->representation(); 1548 if (r.IsSpecialization() || current->HasNoUses()) return; 1549 ASSERT(current->CheckFlag(HValue::kFlexibleRepresentation)); 1550 Representation new_rep = TryChange(current); 1551 if (!new_rep.IsNone()) { 1552 if (!current->representation().Equals(new_rep)) { 1553 current->ChangeRepresentation(new_rep); 1554 AddDependantsToWorklist(current); 1555 } 1556 } 1557 } 1558 1559 1560 Representation HInferRepresentation::TryChange(HValue* current) { 1561 // Array of use counts for each representation. 1562 int use_count[Representation::kNumRepresentations]; 1563 for (int i = 0; i < Representation::kNumRepresentations; i++) { 1564 use_count[i] = 0; 1565 } 1566 1567 for (int i = 0; i < current->uses()->length(); ++i) { 1568 HValue* use = current->uses()->at(i); 1569 int index = use->LookupOperandIndex(0, current); 1570 Representation req_rep = use->RequiredInputRepresentation(index); 1571 if (req_rep.IsNone()) continue; 1572 if (use->IsPhi()) { 1573 HPhi* phi = HPhi::cast(use); 1574 phi->AddIndirectUsesTo(&use_count[0]); 1575 } 1576 use_count[req_rep.kind()]++; 1577 } 1578 int tagged_count = use_count[Representation::kTagged]; 1579 int double_count = use_count[Representation::kDouble]; 1580 int int32_count = use_count[Representation::kInteger32]; 1581 int non_tagged_count = double_count + int32_count; 1582 1583 // If a non-loop phi has tagged uses, don't convert it to untagged. 1584 if (current->IsPhi() && !current->block()->IsLoopHeader()) { 1585 if (tagged_count > 0) return Representation::None(); 1586 } 1587 1588 if (non_tagged_count >= tagged_count) { 1589 // More untagged than tagged. 1590 if (double_count > 0) { 1591 // There is at least one usage that is a double => guess that the 1592 // correct representation is double. 1593 return Representation::Double(); 1594 } else if (int32_count > 0) { 1595 return Representation::Integer32(); 1596 } 1597 } 1598 return Representation::None(); 1599 } 1600 1601 1602 void HInferRepresentation::Analyze() { 1603 HPhase phase("Infer representations", graph_); 1604 1605 // (1) Initialize bit vectors and count real uses. Each phi 1606 // gets a bit-vector of length <number of phis>. 1607 const ZoneList<HPhi*>* phi_list = graph_->phi_list(); 1608 int num_phis = phi_list->length(); 1609 ScopedVector<BitVector*> connected_phis(num_phis); 1610 for (int i = 0; i < num_phis; i++) { 1611 phi_list->at(i)->InitRealUses(i); 1612 connected_phis[i] = new(zone()) BitVector(num_phis); 1613 connected_phis[i]->Add(i); 1614 } 1615 1616 // (2) Do a fixed point iteration to find the set of connected phis. 1617 // A phi is connected to another phi if its value is used either 1618 // directly or indirectly through a transitive closure of the def-use 1619 // relation. 1620 bool change = true; 1621 while (change) { 1622 change = false; 1623 for (int i = 0; i < num_phis; i++) { 1624 HPhi* phi = phi_list->at(i); 1625 for (int j = 0; j < phi->uses()->length(); j++) { 1626 HValue* use = phi->uses()->at(j); 1627 if (use->IsPhi()) { 1628 int phi_use = HPhi::cast(use)->phi_id(); 1629 if (connected_phis[i]->UnionIsChanged(*connected_phis[phi_use])) { 1630 change = true; 1631 } 1632 } 1633 } 1634 } 1635 } 1636 1637 // (3) Sum up the non-phi use counts of all connected phis. 1638 // Don't include the non-phi uses of the phi itself. 1639 for (int i = 0; i < num_phis; i++) { 1640 HPhi* phi = phi_list->at(i); 1641 for (BitVector::Iterator it(connected_phis.at(i)); 1642 !it.Done(); 1643 it.Advance()) { 1644 int index = it.Current(); 1645 if (index != i) { 1646 HPhi* it_use = phi_list->at(it.Current()); 1647 phi->AddNonPhiUsesFrom(it_use); 1648 } 1649 } 1650 } 1651 1652 for (int i = 0; i < graph_->blocks()->length(); ++i) { 1653 HBasicBlock* block = graph_->blocks()->at(i); 1654 const ZoneList<HPhi*>* phis = block->phis(); 1655 for (int j = 0; j < phis->length(); ++j) { 1656 AddToWorklist(phis->at(j)); 1657 } 1658 1659 HInstruction* current = block->first(); 1660 while (current != NULL) { 1661 AddToWorklist(current); 1662 current = current->next(); 1663 } 1664 } 1665 1666 while (!worklist_.is_empty()) { 1667 HValue* current = worklist_.RemoveLast(); 1668 in_worklist_.Remove(current->id()); 1669 InferBasedOnInputs(current); 1670 InferBasedOnUses(current); 1671 } 1672 } 1673 1674 1675 void HGraph::InitializeInferredTypes() { 1676 HPhase phase("Inferring types", this); 1677 InitializeInferredTypes(0, this->blocks_.length() - 1); 1678 } 1679 1680 1681 void HGraph::InitializeInferredTypes(int from_inclusive, int to_inclusive) { 1682 for (int i = from_inclusive; i <= to_inclusive; ++i) { 1683 HBasicBlock* block = blocks_[i]; 1684 1685 const ZoneList<HPhi*>* phis = block->phis(); 1686 for (int j = 0; j < phis->length(); j++) { 1687 phis->at(j)->UpdateInferredType(); 1688 } 1689 1690 HInstruction* current = block->first(); 1691 while (current != NULL) { 1692 current->UpdateInferredType(); 1693 current = current->next(); 1694 } 1695 1696 if (block->IsLoopHeader()) { 1697 HBasicBlock* last_back_edge = 1698 block->loop_information()->GetLastBackEdge(); 1699 InitializeInferredTypes(i + 1, last_back_edge->block_id()); 1700 // Skip all blocks already processed by the recursive call. 1701 i = last_back_edge->block_id(); 1702 // Update phis of the loop header now after the whole loop body is 1703 // guaranteed to be processed. 1704 ZoneList<HValue*> worklist(block->phis()->length()); 1705 for (int j = 0; j < block->phis()->length(); ++j) { 1706 worklist.Add(block->phis()->at(j)); 1707 } 1708 InferTypes(&worklist); 1709 } 1710 } 1711 } 1712 1713 1714 void HGraph::PropagateMinusZeroChecks(HValue* value, BitVector* visited) { 1715 HValue* current = value; 1716 while (current != NULL) { 1717 if (visited->Contains(current->id())) return; 1718 1719 // For phis, we must propagate the check to all of its inputs. 1720 if (current->IsPhi()) { 1721 visited->Add(current->id()); 1722 HPhi* phi = HPhi::cast(current); 1723 for (int i = 0; i < phi->OperandCount(); ++i) { 1724 PropagateMinusZeroChecks(phi->OperandAt(i), visited); 1725 } 1726 break; 1727 } 1728 1729 // For multiplication and division, we must propagate to the left and 1730 // the right side. 1731 if (current->IsMul()) { 1732 HMul* mul = HMul::cast(current); 1733 mul->EnsureAndPropagateNotMinusZero(visited); 1734 PropagateMinusZeroChecks(mul->left(), visited); 1735 PropagateMinusZeroChecks(mul->right(), visited); 1736 } else if (current->IsDiv()) { 1737 HDiv* div = HDiv::cast(current); 1738 div->EnsureAndPropagateNotMinusZero(visited); 1739 PropagateMinusZeroChecks(div->left(), visited); 1740 PropagateMinusZeroChecks(div->right(), visited); 1741 } 1742 1743 current = current->EnsureAndPropagateNotMinusZero(visited); 1744 } 1745 } 1746 1747 1748 void HGraph::InsertRepresentationChangeForUse(HValue* value, 1749 HValue* use, 1750 Representation to) { 1751 // Insert the representation change right before its use. For phi-uses we 1752 // insert at the end of the corresponding predecessor. 1753 HInstruction* next = NULL; 1754 if (use->IsPhi()) { 1755 int index = 0; 1756 while (use->OperandAt(index) != value) ++index; 1757 next = use->block()->predecessors()->at(index)->end(); 1758 } else { 1759 next = HInstruction::cast(use); 1760 } 1761 1762 // For constants we try to make the representation change at compile 1763 // time. When a representation change is not possible without loss of 1764 // information we treat constants like normal instructions and insert the 1765 // change instructions for them. 1766 HInstruction* new_value = NULL; 1767 bool is_truncating = use->CheckFlag(HValue::kTruncatingToInt32); 1768 bool deoptimize_on_undefined = use->CheckFlag(HValue::kDeoptimizeOnUndefined); 1769 if (value->IsConstant()) { 1770 HConstant* constant = HConstant::cast(value); 1771 // Try to create a new copy of the constant with the new representation. 1772 new_value = is_truncating 1773 ? constant->CopyToTruncatedInt32() 1774 : constant->CopyToRepresentation(to); 1775 } 1776 1777 if (new_value == NULL) { 1778 new_value = new(zone()) HChange(value, value->representation(), to, 1779 is_truncating, deoptimize_on_undefined); 1780 } 1781 1782 new_value->InsertBefore(next); 1783 value->ReplaceFirstAtUse(use, new_value, to); 1784 } 1785 1786 1787 int CompareConversionUses(HValue* a, 1788 HValue* b, 1789 Representation a_rep, 1790 Representation b_rep) { 1791 if (a_rep.kind() > b_rep.kind()) { 1792 // Make sure specializations are separated in the result array. 1793 return 1; 1794 } 1795 // Put truncating conversions before non-truncating conversions. 1796 bool a_truncate = a->CheckFlag(HValue::kTruncatingToInt32); 1797 bool b_truncate = b->CheckFlag(HValue::kTruncatingToInt32); 1798 if (a_truncate != b_truncate) { 1799 return a_truncate ? -1 : 1; 1800 } 1801 // Sort by increasing block ID. 1802 return a->block()->block_id() - b->block()->block_id(); 1803 } 1804 1805 1806 void HGraph::InsertRepresentationChangesForValue( 1807 HValue* current, 1808 ZoneList<HValue*>* to_convert, 1809 ZoneList<Representation>* to_convert_reps) { 1810 Representation r = current->representation(); 1811 if (r.IsNone()) return; 1812 if (current->uses()->length() == 0) return; 1813 1814 // Collect the representation changes in a sorted list. This allows 1815 // us to avoid duplicate changes without searching the list. 1816 ASSERT(to_convert->is_empty()); 1817 ASSERT(to_convert_reps->is_empty()); 1818 for (int i = 0; i < current->uses()->length(); ++i) { 1819 HValue* use = current->uses()->at(i); 1820 // The occurrences index means the index within the operand array of "use" 1821 // at which "current" is used. While iterating through the use array we 1822 // also have to iterate over the different occurrence indices. 1823 int occurrence_index = 0; 1824 if (use->UsesMultipleTimes(current)) { 1825 occurrence_index = current->uses()->CountOccurrences(use, 0, i - 1); 1826 if (FLAG_trace_representation) { 1827 PrintF("Instruction %d is used multiple times at %d; occurrence=%d\n", 1828 current->id(), 1829 use->id(), 1830 occurrence_index); 1831 } 1832 } 1833 int operand_index = use->LookupOperandIndex(occurrence_index, current); 1834 Representation req = use->RequiredInputRepresentation(operand_index); 1835 if (req.IsNone() || req.Equals(r)) continue; 1836 int index = 0; 1837 while (index < to_convert->length() && 1838 CompareConversionUses(to_convert->at(index), 1839 use, 1840 to_convert_reps->at(index), 1841 req) < 0) { 1842 ++index; 1843 } 1844 if (FLAG_trace_representation) { 1845 PrintF("Inserting a representation change to %s of %d for use at %d\n", 1846 req.Mnemonic(), 1847 current->id(), 1848 use->id()); 1849 } 1850 to_convert->InsertAt(index, use); 1851 to_convert_reps->InsertAt(index, req); 1852 } 1853 1854 for (int i = 0; i < to_convert->length(); ++i) { 1855 HValue* use = to_convert->at(i); 1856 Representation r_to = to_convert_reps->at(i); 1857 InsertRepresentationChangeForUse(current, use, r_to); 1858 } 1859 1860 if (current->uses()->is_empty()) { 1861 ASSERT(current->IsConstant()); 1862 current->Delete(); 1863 } 1864 to_convert->Rewind(0); 1865 to_convert_reps->Rewind(0); 1866 } 1867 1868 1869 void HGraph::InsertRepresentationChanges() { 1870 HPhase phase("Insert representation changes", this); 1871 1872 1873 // Compute truncation flag for phis: Initially assume that all 1874 // int32-phis allow truncation and iteratively remove the ones that 1875 // are used in an operation that does not allow a truncating 1876 // conversion. 1877 // TODO(fschneider): Replace this with a worklist-based iteration. 1878 for (int i = 0; i < phi_list()->length(); i++) { 1879 HPhi* phi = phi_list()->at(i); 1880 if (phi->representation().IsInteger32()) { 1881 phi->SetFlag(HValue::kTruncatingToInt32); 1882 } 1883 } 1884 bool change = true; 1885 while (change) { 1886 change = false; 1887 for (int i = 0; i < phi_list()->length(); i++) { 1888 HPhi* phi = phi_list()->at(i); 1889 if (!phi->CheckFlag(HValue::kTruncatingToInt32)) continue; 1890 for (int j = 0; j < phi->uses()->length(); j++) { 1891 HValue* use = phi->uses()->at(j); 1892 if (!use->CheckFlag(HValue::kTruncatingToInt32)) { 1893 phi->ClearFlag(HValue::kTruncatingToInt32); 1894 change = true; 1895 break; 1896 } 1897 } 1898 } 1899 } 1900 1901 ZoneList<HValue*> value_list(4); 1902 ZoneList<Representation> rep_list(4); 1903 for (int i = 0; i < blocks_.length(); ++i) { 1904 // Process phi instructions first. 1905 for (int j = 0; j < blocks_[i]->phis()->length(); j++) { 1906 HPhi* phi = blocks_[i]->phis()->at(j); 1907 InsertRepresentationChangesForValue(phi, &value_list, &rep_list); 1908 } 1909 1910 // Process normal instructions. 1911 HInstruction* current = blocks_[i]->first(); 1912 while (current != NULL) { 1913 InsertRepresentationChangesForValue(current, &value_list, &rep_list); 1914 current = current->next(); 1915 } 1916 } 1917 } 1918 1919 1920 void HGraph::RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi* phi) { 1921 if (phi->CheckFlag(HValue::kDeoptimizeOnUndefined)) return; 1922 phi->SetFlag(HValue::kDeoptimizeOnUndefined); 1923 for (int i = 0; i < phi->OperandCount(); ++i) { 1924 HValue* input = phi->OperandAt(i); 1925 if (input->IsPhi()) { 1926 RecursivelyMarkPhiDeoptimizeOnUndefined(HPhi::cast(input)); 1927 } 1928 } 1929 } 1930 1931 1932 void HGraph::MarkDeoptimizeOnUndefined() { 1933 HPhase phase("MarkDeoptimizeOnUndefined", this); 1934 // Compute DeoptimizeOnUndefined flag for phis. 1935 // Any phi that can reach a use with DeoptimizeOnUndefined set must 1936 // have DeoptimizeOnUndefined set. Currently only HCompare, with 1937 // double input representation, has this flag set. 1938 // The flag is used by HChange tagged->double, which must deoptimize 1939 // if one of its uses has this flag set. 1940 for (int i = 0; i < phi_list()->length(); i++) { 1941 HPhi* phi = phi_list()->at(i); 1942 if (phi->representation().IsDouble()) { 1943 for (int j = 0; j < phi->uses()->length(); j++) { 1944 HValue* use = phi->uses()->at(j); 1945 if (use->CheckFlag(HValue::kDeoptimizeOnUndefined)) { 1946 RecursivelyMarkPhiDeoptimizeOnUndefined(phi); 1947 break; 1948 } 1949 } 1950 } 1951 } 1952 } 1953 1954 1955 void HGraph::ComputeMinusZeroChecks() { 1956 BitVector visited(GetMaximumValueID()); 1957 for (int i = 0; i < blocks_.length(); ++i) { 1958 for (HInstruction* current = blocks_[i]->first(); 1959 current != NULL; 1960 current = current->next()) { 1961 if (current->IsChange()) { 1962 HChange* change = HChange::cast(current); 1963 // Propagate flags for negative zero checks upwards from conversions 1964 // int32-to-tagged and int32-to-double. 1965 Representation from = change->value()->representation(); 1966 ASSERT(from.Equals(change->from())); 1967 if (from.IsInteger32()) { 1968 ASSERT(change->to().IsTagged() || change->to().IsDouble()); 1969 ASSERT(visited.IsEmpty()); 1970 PropagateMinusZeroChecks(change->value(), &visited); 1971 visited.Clear(); 1972 } 1973 } 1974 } 1975 } 1976 } 1977 1978 1979 // Implementation of utility class to encapsulate the translation state for 1980 // a (possibly inlined) function. 1981 FunctionState::FunctionState(HGraphBuilder* owner, 1982 CompilationInfo* info, 1983 TypeFeedbackOracle* oracle) 1984 : owner_(owner), 1985 compilation_info_(info), 1986 oracle_(oracle), 1987 call_context_(NULL), 1988 function_return_(NULL), 1989 test_context_(NULL), 1990 outer_(owner->function_state()) { 1991 if (outer_ != NULL) { 1992 // State for an inline function. 1993 if (owner->ast_context()->IsTest()) { 1994 HBasicBlock* if_true = owner->graph()->CreateBasicBlock(); 1995 HBasicBlock* if_false = owner->graph()->CreateBasicBlock(); 1996 if_true->MarkAsInlineReturnTarget(); 1997 if_false->MarkAsInlineReturnTarget(); 1998 // The AstContext constructor pushed on the context stack. This newed 1999 // instance is the reason that AstContext can't be BASE_EMBEDDED. 2000 test_context_ = new TestContext(owner, if_true, if_false); 2001 } else { 2002 function_return_ = owner->graph()->CreateBasicBlock(); 2003 function_return()->MarkAsInlineReturnTarget(); 2004 } 2005 // Set this after possibly allocating a new TestContext above. 2006 call_context_ = owner->ast_context(); 2007 } 2008 2009 // Push on the state stack. 2010 owner->set_function_state(this); 2011 } 2012 2013 2014 FunctionState::~FunctionState() { 2015 delete test_context_; 2016 owner_->set_function_state(outer_); 2017 } 2018 2019 2020 // Implementation of utility classes to represent an expression's context in 2021 // the AST. 2022 AstContext::AstContext(HGraphBuilder* owner, Expression::Context kind) 2023 : owner_(owner), 2024 kind_(kind), 2025 outer_(owner->ast_context()), 2026 for_typeof_(false) { 2027 owner->set_ast_context(this); // Push. 2028 #ifdef DEBUG 2029 original_length_ = owner->environment()->length(); 2030 #endif 2031 } 2032 2033 2034 AstContext::~AstContext() { 2035 owner_->set_ast_context(outer_); // Pop. 2036 } 2037 2038 2039 EffectContext::~EffectContext() { 2040 ASSERT(owner()->HasStackOverflow() || 2041 owner()->current_block() == NULL || 2042 owner()->environment()->length() == original_length_); 2043 } 2044 2045 2046 ValueContext::~ValueContext() { 2047 ASSERT(owner()->HasStackOverflow() || 2048 owner()->current_block() == NULL || 2049 owner()->environment()->length() == original_length_ + 1); 2050 } 2051 2052 2053 void EffectContext::ReturnValue(HValue* value) { 2054 // The value is simply ignored. 2055 } 2056 2057 2058 void ValueContext::ReturnValue(HValue* value) { 2059 // The value is tracked in the bailout environment, and communicated 2060 // through the environment as the result of the expression. 2061 owner()->Push(value); 2062 } 2063 2064 2065 void TestContext::ReturnValue(HValue* value) { 2066 BuildBranch(value); 2067 } 2068 2069 2070 void EffectContext::ReturnInstruction(HInstruction* instr, int ast_id) { 2071 owner()->AddInstruction(instr); 2072 if (instr->HasSideEffects()) owner()->AddSimulate(ast_id); 2073 } 2074 2075 2076 void ValueContext::ReturnInstruction(HInstruction* instr, int ast_id) { 2077 owner()->AddInstruction(instr); 2078 owner()->Push(instr); 2079 if (instr->HasSideEffects()) owner()->AddSimulate(ast_id); 2080 } 2081 2082 2083 void TestContext::ReturnInstruction(HInstruction* instr, int ast_id) { 2084 HGraphBuilder* builder = owner(); 2085 builder->AddInstruction(instr); 2086 // We expect a simulate after every expression with side effects, though 2087 // this one isn't actually needed (and wouldn't work if it were targeted). 2088 if (instr->HasSideEffects()) { 2089 builder->Push(instr); 2090 builder->AddSimulate(ast_id); 2091 builder->Pop(); 2092 } 2093 BuildBranch(instr); 2094 } 2095 2096 2097 void TestContext::BuildBranch(HValue* value) { 2098 // We expect the graph to be in edge-split form: there is no edge that 2099 // connects a branch node to a join node. We conservatively ensure that 2100 // property by always adding an empty block on the outgoing edges of this 2101 // branch. 2102 HGraphBuilder* builder = owner(); 2103 HBasicBlock* empty_true = builder->graph()->CreateBasicBlock(); 2104 HBasicBlock* empty_false = builder->graph()->CreateBasicBlock(); 2105 HTest* test = new(zone()) HTest(value, empty_true, empty_false); 2106 builder->current_block()->Finish(test); 2107 2108 empty_true->Goto(if_true(), false); 2109 empty_false->Goto(if_false(), false); 2110 builder->set_current_block(NULL); 2111 } 2112 2113 2114 // HGraphBuilder infrastructure for bailing out and checking bailouts. 2115 #define BAILOUT(reason) \ 2116 do { \ 2117 Bailout(reason); \ 2118 return; \ 2119 } while (false) 2120 2121 2122 #define CHECK_BAILOUT \ 2123 do { \ 2124 if (HasStackOverflow()) return; \ 2125 } while (false) 2126 2127 2128 #define VISIT_FOR_EFFECT(expr) \ 2129 do { \ 2130 VisitForEffect(expr); \ 2131 if (HasStackOverflow()) return; \ 2132 } while (false) 2133 2134 2135 #define VISIT_FOR_VALUE(expr) \ 2136 do { \ 2137 VisitForValue(expr); \ 2138 if (HasStackOverflow()) return; \ 2139 } while (false) 2140 2141 2142 #define VISIT_FOR_CONTROL(expr, true_block, false_block) \ 2143 do { \ 2144 VisitForControl(expr, true_block, false_block); \ 2145 if (HasStackOverflow()) return; \ 2146 } while (false) 2147 2148 2149 void HGraphBuilder::Bailout(const char* reason) { 2150 if (FLAG_trace_bailout) { 2151 SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString()); 2152 PrintF("Bailout in HGraphBuilder: @\"%s\": %s\n", *name, reason); 2153 } 2154 SetStackOverflow(); 2155 } 2156 2157 2158 void HGraphBuilder::VisitForEffect(Expression* expr) { 2159 EffectContext for_effect(this); 2160 Visit(expr); 2161 } 2162 2163 2164 void HGraphBuilder::VisitForValue(Expression* expr) { 2165 ValueContext for_value(this); 2166 Visit(expr); 2167 } 2168 2169 2170 void HGraphBuilder::VisitForTypeOf(Expression* expr) { 2171 ValueContext for_value(this); 2172 for_value.set_for_typeof(true); 2173 Visit(expr); 2174 } 2175 2176 2177 2178 void HGraphBuilder::VisitForControl(Expression* expr, 2179 HBasicBlock* true_block, 2180 HBasicBlock* false_block) { 2181 TestContext for_test(this, true_block, false_block); 2182 Visit(expr); 2183 } 2184 2185 2186 void HGraphBuilder::VisitArgument(Expression* expr) { 2187 VISIT_FOR_VALUE(expr); 2188 Push(AddInstruction(new(zone()) HPushArgument(Pop()))); 2189 } 2190 2191 2192 void HGraphBuilder::VisitArgumentList(ZoneList<Expression*>* arguments) { 2193 for (int i = 0; i < arguments->length(); i++) { 2194 VisitArgument(arguments->at(i)); 2195 if (HasStackOverflow() || current_block() == NULL) return; 2196 } 2197 } 2198 2199 2200 void HGraphBuilder::VisitExpressions(ZoneList<Expression*>* exprs) { 2201 for (int i = 0; i < exprs->length(); ++i) { 2202 VISIT_FOR_VALUE(exprs->at(i)); 2203 } 2204 } 2205 2206 2207 HGraph* HGraphBuilder::CreateGraph() { 2208 graph_ = new(zone()) HGraph(info()); 2209 if (FLAG_hydrogen_stats) HStatistics::Instance()->Initialize(info()); 2210 2211 { 2212 HPhase phase("Block building"); 2213 current_block_ = graph()->entry_block(); 2214 2215 Scope* scope = info()->scope(); 2216 if (scope->HasIllegalRedeclaration()) { 2217 Bailout("function with illegal redeclaration"); 2218 return NULL; 2219 } 2220 SetupScope(scope); 2221 VisitDeclarations(scope->declarations()); 2222 AddInstruction(new(zone()) HStackCheck()); 2223 2224 // Add an edge to the body entry. This is warty: the graph's start 2225 // environment will be used by the Lithium translation as the initial 2226 // environment on graph entry, but it has now been mutated by the 2227 // Hydrogen translation of the instructions in the start block. This 2228 // environment uses values which have not been defined yet. These 2229 // Hydrogen instructions will then be replayed by the Lithium 2230 // translation, so they cannot have an environment effect. The edge to 2231 // the body's entry block (along with some special logic for the start 2232 // block in HInstruction::InsertAfter) seals the start block from 2233 // getting unwanted instructions inserted. 2234 // 2235 // TODO(kmillikin): Fix this. Stop mutating the initial environment. 2236 // Make the Hydrogen instructions in the initial block into Hydrogen 2237 // values (but not instructions), present in the initial environment and 2238 // not replayed by the Lithium translation. 2239 HEnvironment* initial_env = environment()->CopyWithoutHistory(); 2240 HBasicBlock* body_entry = CreateBasicBlock(initial_env); 2241 current_block()->Goto(body_entry); 2242 body_entry->SetJoinId(AstNode::kFunctionEntryId); 2243 set_current_block(body_entry); 2244 VisitStatements(info()->function()->body()); 2245 if (HasStackOverflow()) return NULL; 2246 2247 if (current_block() != NULL) { 2248 HReturn* instr = new(zone()) HReturn(graph()->GetConstantUndefined()); 2249 current_block()->FinishExit(instr); 2250 set_current_block(NULL); 2251 } 2252 } 2253 2254 graph()->OrderBlocks(); 2255 graph()->AssignDominators(); 2256 graph()->EliminateRedundantPhis(); 2257 if (FLAG_eliminate_dead_phis) graph()->EliminateUnreachablePhis(); 2258 if (!graph()->CollectPhis()) { 2259 Bailout("Phi-use of arguments object"); 2260 return NULL; 2261 } 2262 2263 HInferRepresentation rep(graph()); 2264 rep.Analyze(); 2265 2266 if (FLAG_use_range) { 2267 HRangeAnalysis rangeAnalysis(graph()); 2268 rangeAnalysis.Analyze(); 2269 } 2270 2271 graph()->InitializeInferredTypes(); 2272 graph()->Canonicalize(); 2273 graph()->MarkDeoptimizeOnUndefined(); 2274 graph()->InsertRepresentationChanges(); 2275 graph()->ComputeMinusZeroChecks(); 2276 2277 // Eliminate redundant stack checks on backwards branches. 2278 HStackCheckEliminator sce(graph()); 2279 sce.Process(); 2280 2281 // Perform common subexpression elimination and loop-invariant code motion. 2282 if (FLAG_use_gvn) { 2283 HPhase phase("Global value numbering", graph()); 2284 HGlobalValueNumberer gvn(graph(), info()); 2285 gvn.Analyze(); 2286 } 2287 2288 // Replace the results of check instructions with the original value, if the 2289 // result is used. This is safe now, since we don't do code motion after this 2290 // point. It enables better register allocation since the value produced by 2291 // check instructions is really a copy of the original value. 2292 graph()->ReplaceCheckedValues(); 2293 2294 return graph(); 2295 } 2296 2297 2298 void HGraph::ReplaceCheckedValues() { 2299 HPhase phase("Replace checked values", this); 2300 for (int i = 0; i < blocks()->length(); ++i) { 2301 HInstruction* instr = blocks()->at(i)->first(); 2302 while (instr != NULL) { 2303 if (instr->IsBoundsCheck()) { 2304 // Replace all uses of the checked value with the original input. 2305 ASSERT(instr->uses()->length() > 0); 2306 instr->ReplaceValue(HBoundsCheck::cast(instr)->index()); 2307 } 2308 instr = instr->next(); 2309 } 2310 } 2311 } 2312 2313 2314 HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) { 2315 ASSERT(current_block() != NULL); 2316 current_block()->AddInstruction(instr); 2317 return instr; 2318 } 2319 2320 2321 void HGraphBuilder::AddSimulate(int id) { 2322 ASSERT(current_block() != NULL); 2323 current_block()->AddSimulate(id); 2324 } 2325 2326 2327 void HGraphBuilder::AddPhi(HPhi* instr) { 2328 ASSERT(current_block() != NULL); 2329 current_block()->AddPhi(instr); 2330 } 2331 2332 2333 void HGraphBuilder::PushAndAdd(HInstruction* instr) { 2334 Push(instr); 2335 AddInstruction(instr); 2336 } 2337 2338 2339 template <int V> 2340 HInstruction* HGraphBuilder::PreProcessCall(HCall<V>* call) { 2341 int count = call->argument_count(); 2342 ZoneList<HValue*> arguments(count); 2343 for (int i = 0; i < count; ++i) { 2344 arguments.Add(Pop()); 2345 } 2346 2347 while (!arguments.is_empty()) { 2348 AddInstruction(new(zone()) HPushArgument(arguments.RemoveLast())); 2349 } 2350 return call; 2351 } 2352 2353 2354 void HGraphBuilder::SetupScope(Scope* scope) { 2355 // We don't yet handle the function name for named function expressions. 2356 if (scope->function() != NULL) BAILOUT("named function expression"); 2357 2358 HConstant* undefined_constant = new(zone()) HConstant( 2359 isolate()->factory()->undefined_value(), Representation::Tagged()); 2360 AddInstruction(undefined_constant); 2361 graph_->set_undefined_constant(undefined_constant); 2362 2363 // Set the initial values of parameters including "this". "This" has 2364 // parameter index 0. 2365 int count = scope->num_parameters() + 1; 2366 for (int i = 0; i < count; ++i) { 2367 HInstruction* parameter = AddInstruction(new(zone()) HParameter(i)); 2368 environment()->Bind(i, parameter); 2369 } 2370 2371 // Set the initial values of stack-allocated locals. 2372 for (int i = count; i < environment()->length(); ++i) { 2373 environment()->Bind(i, undefined_constant); 2374 } 2375 2376 // Handle the arguments and arguments shadow variables specially (they do 2377 // not have declarations). 2378 if (scope->arguments() != NULL) { 2379 if (!scope->arguments()->IsStackAllocated() || 2380 (scope->arguments_shadow() != NULL && 2381 !scope->arguments_shadow()->IsStackAllocated())) { 2382 BAILOUT("context-allocated arguments"); 2383 } 2384 HArgumentsObject* object = new(zone()) HArgumentsObject; 2385 AddInstruction(object); 2386 graph()->SetArgumentsObject(object); 2387 environment()->Bind(scope->arguments(), object); 2388 if (scope->arguments_shadow() != NULL) { 2389 environment()->Bind(scope->arguments_shadow(), object); 2390 } 2391 } 2392 } 2393 2394 2395 void HGraphBuilder::VisitStatements(ZoneList<Statement*>* statements) { 2396 for (int i = 0; i < statements->length(); i++) { 2397 Visit(statements->at(i)); 2398 if (HasStackOverflow() || current_block() == NULL) break; 2399 } 2400 } 2401 2402 2403 HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) { 2404 HBasicBlock* b = graph()->CreateBasicBlock(); 2405 b->SetInitialEnvironment(env); 2406 return b; 2407 } 2408 2409 2410 HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() { 2411 HBasicBlock* header = graph()->CreateBasicBlock(); 2412 HEnvironment* entry_env = environment()->CopyAsLoopHeader(header); 2413 header->SetInitialEnvironment(entry_env); 2414 header->AttachLoopInformation(); 2415 return header; 2416 } 2417 2418 2419 void HGraphBuilder::VisitBlock(Block* stmt) { 2420 BreakAndContinueInfo break_info(stmt); 2421 { BreakAndContinueScope push(&break_info, this); 2422 VisitStatements(stmt->statements()); 2423 CHECK_BAILOUT; 2424 } 2425 HBasicBlock* break_block = break_info.break_block(); 2426 if (break_block != NULL) { 2427 if (current_block() != NULL) current_block()->Goto(break_block); 2428 break_block->SetJoinId(stmt->ExitId()); 2429 set_current_block(break_block); 2430 } 2431 } 2432 2433 2434 void HGraphBuilder::VisitExpressionStatement(ExpressionStatement* stmt) { 2435 VisitForEffect(stmt->expression()); 2436 } 2437 2438 2439 void HGraphBuilder::VisitEmptyStatement(EmptyStatement* stmt) { 2440 } 2441 2442 2443 void HGraphBuilder::VisitIfStatement(IfStatement* stmt) { 2444 if (stmt->condition()->ToBooleanIsTrue()) { 2445 AddSimulate(stmt->ThenId()); 2446 Visit(stmt->then_statement()); 2447 } else if (stmt->condition()->ToBooleanIsFalse()) { 2448 AddSimulate(stmt->ElseId()); 2449 Visit(stmt->else_statement()); 2450 } else { 2451 HBasicBlock* cond_true = graph()->CreateBasicBlock(); 2452 HBasicBlock* cond_false = graph()->CreateBasicBlock(); 2453 VISIT_FOR_CONTROL(stmt->condition(), cond_true, cond_false); 2454 cond_true->SetJoinId(stmt->ThenId()); 2455 cond_false->SetJoinId(stmt->ElseId()); 2456 2457 set_current_block(cond_true); 2458 Visit(stmt->then_statement()); 2459 CHECK_BAILOUT; 2460 HBasicBlock* other = current_block(); 2461 2462 set_current_block(cond_false); 2463 Visit(stmt->else_statement()); 2464 CHECK_BAILOUT; 2465 2466 HBasicBlock* join = CreateJoin(other, current_block(), stmt->id()); 2467 set_current_block(join); 2468 } 2469 } 2470 2471 2472 HBasicBlock* HGraphBuilder::BreakAndContinueScope::Get( 2473 BreakableStatement* stmt, 2474 BreakType type) { 2475 BreakAndContinueScope* current = this; 2476 while (current != NULL && current->info()->target() != stmt) { 2477 current = current->next(); 2478 } 2479 ASSERT(current != NULL); // Always found (unless stack is malformed). 2480 HBasicBlock* block = NULL; 2481 switch (type) { 2482 case BREAK: 2483 block = current->info()->break_block(); 2484 if (block == NULL) { 2485 block = current->owner()->graph()->CreateBasicBlock(); 2486 current->info()->set_break_block(block); 2487 } 2488 break; 2489 2490 case CONTINUE: 2491 block = current->info()->continue_block(); 2492 if (block == NULL) { 2493 block = current->owner()->graph()->CreateBasicBlock(); 2494 current->info()->set_continue_block(block); 2495 } 2496 break; 2497 } 2498 2499 return block; 2500 } 2501 2502 2503 void HGraphBuilder::VisitContinueStatement(ContinueStatement* stmt) { 2504 HBasicBlock* continue_block = break_scope()->Get(stmt->target(), CONTINUE); 2505 current_block()->Goto(continue_block); 2506 set_current_block(NULL); 2507 } 2508 2509 2510 void HGraphBuilder::VisitBreakStatement(BreakStatement* stmt) { 2511 HBasicBlock* break_block = break_scope()->Get(stmt->target(), BREAK); 2512 current_block()->Goto(break_block); 2513 set_current_block(NULL); 2514 } 2515 2516 2517 void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) { 2518 AstContext* context = call_context(); 2519 if (context == NULL) { 2520 // Not an inlined return, so an actual one. 2521 VISIT_FOR_VALUE(stmt->expression()); 2522 HValue* result = environment()->Pop(); 2523 current_block()->FinishExit(new(zone()) HReturn(result)); 2524 set_current_block(NULL); 2525 } else { 2526 // Return from an inlined function, visit the subexpression in the 2527 // expression context of the call. 2528 if (context->IsTest()) { 2529 TestContext* test = TestContext::cast(context); 2530 VisitForControl(stmt->expression(), 2531 test->if_true(), 2532 test->if_false()); 2533 } else if (context->IsEffect()) { 2534 VISIT_FOR_EFFECT(stmt->expression()); 2535 current_block()->Goto(function_return(), false); 2536 } else { 2537 ASSERT(context->IsValue()); 2538 VISIT_FOR_VALUE(stmt->expression()); 2539 HValue* return_value = environment()->Pop(); 2540 current_block()->AddLeaveInlined(return_value, function_return()); 2541 } 2542 set_current_block(NULL); 2543 } 2544 } 2545 2546 2547 void HGraphBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) { 2548 BAILOUT("WithEnterStatement"); 2549 } 2550 2551 2552 void HGraphBuilder::VisitWithExitStatement(WithExitStatement* stmt) { 2553 BAILOUT("WithExitStatement"); 2554 } 2555 2556 2557 void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { 2558 // We only optimize switch statements with smi-literal smi comparisons, 2559 // with a bounded number of clauses. 2560 const int kCaseClauseLimit = 128; 2561 ZoneList<CaseClause*>* clauses = stmt->cases(); 2562 int clause_count = clauses->length(); 2563 if (clause_count > kCaseClauseLimit) { 2564 BAILOUT("SwitchStatement: too many clauses"); 2565 } 2566 2567 VISIT_FOR_VALUE(stmt->tag()); 2568 AddSimulate(stmt->EntryId()); 2569 HValue* tag_value = Pop(); 2570 HBasicBlock* first_test_block = current_block(); 2571 2572 // 1. Build all the tests, with dangling true branches. Unconditionally 2573 // deoptimize if we encounter a non-smi comparison. 2574 for (int i = 0; i < clause_count; ++i) { 2575 CaseClause* clause = clauses->at(i); 2576 if (clause->is_default()) continue; 2577 if (!clause->label()->IsSmiLiteral()) { 2578 BAILOUT("SwitchStatement: non-literal switch label"); 2579 } 2580 2581 // Unconditionally deoptimize on the first non-smi compare. 2582 clause->RecordTypeFeedback(oracle()); 2583 if (!clause->IsSmiCompare()) { 2584 current_block()->FinishExitWithDeoptimization(); 2585 set_current_block(NULL); 2586 break; 2587 } 2588 2589 // Otherwise generate a compare and branch. 2590 VISIT_FOR_VALUE(clause->label()); 2591 HValue* label_value = Pop(); 2592 HCompare* compare = 2593 new(zone()) HCompare(tag_value, label_value, Token::EQ_STRICT); 2594 compare->SetInputRepresentation(Representation::Integer32()); 2595 ASSERT(!compare->HasSideEffects()); 2596 AddInstruction(compare); 2597 HBasicBlock* body_block = graph()->CreateBasicBlock(); 2598 HBasicBlock* next_test_block = graph()->CreateBasicBlock(); 2599 HTest* branch = new(zone()) HTest(compare, body_block, next_test_block); 2600 current_block()->Finish(branch); 2601 set_current_block(next_test_block); 2602 } 2603 2604 // Save the current block to use for the default or to join with the 2605 // exit. This block is NULL if we deoptimized. 2606 HBasicBlock* last_block = current_block(); 2607 2608 // 2. Loop over the clauses and the linked list of tests in lockstep, 2609 // translating the clause bodies. 2610 HBasicBlock* curr_test_block = first_test_block; 2611 HBasicBlock* fall_through_block = NULL; 2612 BreakAndContinueInfo break_info(stmt); 2613 { BreakAndContinueScope push(&break_info, this); 2614 for (int i = 0; i < clause_count; ++i) { 2615 CaseClause* clause = clauses->at(i); 2616 2617 // Identify the block where normal (non-fall-through) control flow 2618 // goes to. 2619 HBasicBlock* normal_block = NULL; 2620 if (clause->is_default()) { 2621 if (last_block != NULL) { 2622 normal_block = last_block; 2623 last_block = NULL; // Cleared to indicate we've handled it. 2624 } 2625 } else if (!curr_test_block->end()->IsDeoptimize()) { 2626 normal_block = curr_test_block->end()->FirstSuccessor(); 2627 curr_test_block = curr_test_block->end()->SecondSuccessor(); 2628 } 2629 2630 // Identify a block to emit the body into. 2631 if (normal_block == NULL) { 2632 if (fall_through_block == NULL) { 2633 // (a) Unreachable. 2634 if (clause->is_default()) { 2635 continue; // Might still be reachable clause bodies. 2636 } else { 2637 break; 2638 } 2639 } else { 2640 // (b) Reachable only as fall through. 2641 set_current_block(fall_through_block); 2642 } 2643 } else if (fall_through_block == NULL) { 2644 // (c) Reachable only normally. 2645 set_current_block(normal_block); 2646 } else { 2647 // (d) Reachable both ways. 2648 HBasicBlock* join = CreateJoin(fall_through_block, 2649 normal_block, 2650 clause->EntryId()); 2651 set_current_block(join); 2652 } 2653 2654 VisitStatements(clause->statements()); 2655 CHECK_BAILOUT; 2656 fall_through_block = current_block(); 2657 } 2658 } 2659 2660 // Create an up-to-3-way join. Use the break block if it exists since 2661 // it's already a join block. 2662 HBasicBlock* break_block = break_info.break_block(); 2663 if (break_block == NULL) { 2664 set_current_block(CreateJoin(fall_through_block, 2665 last_block, 2666 stmt->ExitId())); 2667 } else { 2668 if (fall_through_block != NULL) fall_through_block->Goto(break_block); 2669 if (last_block != NULL) last_block->Goto(break_block); 2670 break_block->SetJoinId(stmt->ExitId()); 2671 set_current_block(break_block); 2672 } 2673 } 2674 2675 2676 bool HGraphBuilder::HasOsrEntryAt(IterationStatement* statement) { 2677 return statement->OsrEntryId() == info()->osr_ast_id(); 2678 } 2679 2680 2681 void HGraphBuilder::PreProcessOsrEntry(IterationStatement* statement) { 2682 if (!HasOsrEntryAt(statement)) return; 2683 2684 HBasicBlock* non_osr_entry = graph()->CreateBasicBlock(); 2685 HBasicBlock* osr_entry = graph()->CreateBasicBlock(); 2686 HValue* true_value = graph()->GetConstantTrue(); 2687 HTest* test = new(zone()) HTest(true_value, non_osr_entry, osr_entry); 2688 current_block()->Finish(test); 2689 2690 HBasicBlock* loop_predecessor = graph()->CreateBasicBlock(); 2691 non_osr_entry->Goto(loop_predecessor); 2692 2693 set_current_block(osr_entry); 2694 int osr_entry_id = statement->OsrEntryId(); 2695 // We want the correct environment at the OsrEntry instruction. Build 2696 // it explicitly. The expression stack should be empty. 2697 int count = environment()->length(); 2698 ASSERT(count == 2699 (environment()->parameter_count() + environment()->local_count())); 2700 for (int i = 0; i < count; ++i) { 2701 HUnknownOSRValue* unknown = new(zone()) HUnknownOSRValue; 2702 AddInstruction(unknown); 2703 environment()->Bind(i, unknown); 2704 } 2705 2706 AddSimulate(osr_entry_id); 2707 AddInstruction(new(zone()) HOsrEntry(osr_entry_id)); 2708 current_block()->Goto(loop_predecessor); 2709 loop_predecessor->SetJoinId(statement->EntryId()); 2710 set_current_block(loop_predecessor); 2711 } 2712 2713 2714 void HGraphBuilder::VisitDoWhileStatement(DoWhileStatement* stmt) { 2715 ASSERT(current_block() != NULL); 2716 PreProcessOsrEntry(stmt); 2717 HBasicBlock* loop_entry = CreateLoopHeaderBlock(); 2718 current_block()->Goto(loop_entry, false); 2719 set_current_block(loop_entry); 2720 2721 BreakAndContinueInfo break_info(stmt); 2722 { BreakAndContinueScope push(&break_info, this); 2723 Visit(stmt->body()); 2724 CHECK_BAILOUT; 2725 } 2726 HBasicBlock* body_exit = 2727 JoinContinue(stmt, current_block(), break_info.continue_block()); 2728 HBasicBlock* loop_successor = NULL; 2729 if (body_exit != NULL && !stmt->cond()->ToBooleanIsTrue()) { 2730 set_current_block(body_exit); 2731 // The block for a true condition, the actual predecessor block of the 2732 // back edge. 2733 body_exit = graph()->CreateBasicBlock(); 2734 loop_successor = graph()->CreateBasicBlock(); 2735 VISIT_FOR_CONTROL(stmt->cond(), body_exit, loop_successor); 2736 body_exit->SetJoinId(stmt->BackEdgeId()); 2737 loop_successor->SetJoinId(stmt->ExitId()); 2738 } 2739 HBasicBlock* loop_exit = CreateLoop(stmt, 2740 loop_entry, 2741 body_exit, 2742 loop_successor, 2743 break_info.break_block()); 2744 set_current_block(loop_exit); 2745 } 2746 2747 2748 void HGraphBuilder::VisitWhileStatement(WhileStatement* stmt) { 2749 ASSERT(current_block() != NULL); 2750 PreProcessOsrEntry(stmt); 2751 HBasicBlock* loop_entry = CreateLoopHeaderBlock(); 2752 current_block()->Goto(loop_entry, false); 2753 set_current_block(loop_entry); 2754 2755 // If the condition is constant true, do not generate a branch. 2756 HBasicBlock* loop_successor = NULL; 2757 if (!stmt->cond()->ToBooleanIsTrue()) { 2758 HBasicBlock* body_entry = graph()->CreateBasicBlock(); 2759 loop_successor = graph()->CreateBasicBlock(); 2760 VISIT_FOR_CONTROL(stmt->cond(), body_entry, loop_successor); 2761 body_entry->SetJoinId(stmt->BodyId()); 2762 loop_successor->SetJoinId(stmt->ExitId()); 2763 set_current_block(body_entry); 2764 } 2765 2766 BreakAndContinueInfo break_info(stmt); 2767 { BreakAndContinueScope push(&break_info, this); 2768 Visit(stmt->body()); 2769 CHECK_BAILOUT; 2770 } 2771 HBasicBlock* body_exit = 2772 JoinContinue(stmt, current_block(), break_info.continue_block()); 2773 HBasicBlock* loop_exit = CreateLoop(stmt, 2774 loop_entry, 2775 body_exit, 2776 loop_successor, 2777 break_info.break_block()); 2778 set_current_block(loop_exit); 2779 } 2780 2781 2782 void HGraphBuilder::VisitForStatement(ForStatement* stmt) { 2783 if (stmt->init() != NULL) { 2784 Visit(stmt->init()); 2785 CHECK_BAILOUT; 2786 } 2787 ASSERT(current_block() != NULL); 2788 PreProcessOsrEntry(stmt); 2789 HBasicBlock* loop_entry = CreateLoopHeaderBlock(); 2790 current_block()->Goto(loop_entry, false); 2791 set_current_block(loop_entry); 2792 2793 HBasicBlock* loop_successor = NULL; 2794 if (stmt->cond() != NULL) { 2795 HBasicBlock* body_entry = graph()->CreateBasicBlock(); 2796 loop_successor = graph()->CreateBasicBlock(); 2797 VISIT_FOR_CONTROL(stmt->cond(), body_entry, loop_successor); 2798 body_entry->SetJoinId(stmt->BodyId()); 2799 loop_successor->SetJoinId(stmt->ExitId()); 2800 set_current_block(body_entry); 2801 } 2802 2803 BreakAndContinueInfo break_info(stmt); 2804 { BreakAndContinueScope push(&break_info, this); 2805 Visit(stmt->body()); 2806 CHECK_BAILOUT; 2807 } 2808 HBasicBlock* body_exit = 2809 JoinContinue(stmt, current_block(), break_info.continue_block()); 2810 2811 if (stmt->next() != NULL && body_exit != NULL) { 2812 set_current_block(body_exit); 2813 Visit(stmt->next()); 2814 CHECK_BAILOUT; 2815 body_exit = current_block(); 2816 } 2817 2818 HBasicBlock* loop_exit = CreateLoop(stmt, 2819 loop_entry, 2820 body_exit, 2821 loop_successor, 2822 break_info.break_block()); 2823 set_current_block(loop_exit); 2824 } 2825 2826 2827 void HGraphBuilder::VisitForInStatement(ForInStatement* stmt) { 2828 BAILOUT("ForInStatement"); 2829 } 2830 2831 2832 void HGraphBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) { 2833 BAILOUT("TryCatchStatement"); 2834 } 2835 2836 2837 void HGraphBuilder::VisitTryFinallyStatement(TryFinallyStatement* stmt) { 2838 BAILOUT("TryFinallyStatement"); 2839 } 2840 2841 2842 void HGraphBuilder::VisitDebuggerStatement(DebuggerStatement* stmt) { 2843 BAILOUT("DebuggerStatement"); 2844 } 2845 2846 2847 static Handle<SharedFunctionInfo> SearchSharedFunctionInfo( 2848 Code* unoptimized_code, FunctionLiteral* expr) { 2849 int start_position = expr->start_position(); 2850 RelocIterator it(unoptimized_code); 2851 for (;!it.done(); it.next()) { 2852 RelocInfo* rinfo = it.rinfo(); 2853 if (rinfo->rmode() != RelocInfo::EMBEDDED_OBJECT) continue; 2854 Object* obj = rinfo->target_object(); 2855 if (obj->IsSharedFunctionInfo()) { 2856 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj); 2857 if (shared->start_position() == start_position) { 2858 return Handle<SharedFunctionInfo>(shared); 2859 } 2860 } 2861 } 2862 2863 return Handle<SharedFunctionInfo>(); 2864 } 2865 2866 2867 void HGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) { 2868 Handle<SharedFunctionInfo> shared_info = 2869 SearchSharedFunctionInfo(info()->shared_info()->code(), 2870 expr); 2871 if (shared_info.is_null()) { 2872 shared_info = Compiler::BuildFunctionInfo(expr, info()->script()); 2873 } 2874 CHECK_BAILOUT; 2875 HFunctionLiteral* instr = 2876 new(zone()) HFunctionLiteral(shared_info, expr->pretenure()); 2877 ast_context()->ReturnInstruction(instr, expr->id()); 2878 } 2879 2880 2881 void HGraphBuilder::VisitSharedFunctionInfoLiteral( 2882 SharedFunctionInfoLiteral* expr) { 2883 BAILOUT("SharedFunctionInfoLiteral"); 2884 } 2885 2886 2887 void HGraphBuilder::VisitConditional(Conditional* expr) { 2888 HBasicBlock* cond_true = graph()->CreateBasicBlock(); 2889 HBasicBlock* cond_false = graph()->CreateBasicBlock(); 2890 VISIT_FOR_CONTROL(expr->condition(), cond_true, cond_false); 2891 cond_true->SetJoinId(expr->ThenId()); 2892 cond_false->SetJoinId(expr->ElseId()); 2893 2894 // Visit the true and false subexpressions in the same AST context as the 2895 // whole expression. 2896 set_current_block(cond_true); 2897 Visit(expr->then_expression()); 2898 CHECK_BAILOUT; 2899 HBasicBlock* other = current_block(); 2900 2901 set_current_block(cond_false); 2902 Visit(expr->else_expression()); 2903 CHECK_BAILOUT; 2904 2905 if (!ast_context()->IsTest()) { 2906 HBasicBlock* join = CreateJoin(other, current_block(), expr->id()); 2907 set_current_block(join); 2908 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); 2909 } 2910 } 2911 2912 2913 HGraphBuilder::GlobalPropertyAccess HGraphBuilder::LookupGlobalProperty( 2914 Variable* var, LookupResult* lookup, bool is_store) { 2915 if (var->is_this() || !info()->has_global_object()) { 2916 return kUseGeneric; 2917 } 2918 Handle<GlobalObject> global(info()->global_object()); 2919 global->Lookup(*var->name(), lookup); 2920 if (!lookup->IsProperty() || 2921 lookup->type() != NORMAL || 2922 (is_store && lookup->IsReadOnly()) || 2923 lookup->holder() != *global) { 2924 return kUseGeneric; 2925 } 2926 2927 return kUseCell; 2928 } 2929 2930 2931 HValue* HGraphBuilder::BuildContextChainWalk(Variable* var) { 2932 ASSERT(var->IsContextSlot()); 2933 HInstruction* context = new(zone()) HContext; 2934 AddInstruction(context); 2935 int length = info()->scope()->ContextChainLength(var->scope()); 2936 while (length-- > 0) { 2937 context = new(zone()) HOuterContext(context); 2938 AddInstruction(context); 2939 } 2940 return context; 2941 } 2942 2943 2944 void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { 2945 Variable* variable = expr->AsVariable(); 2946 if (variable == NULL) { 2947 BAILOUT("reference to rewritten variable"); 2948 } else if (variable->IsStackAllocated()) { 2949 if (environment()->Lookup(variable)->CheckFlag(HValue::kIsArguments)) { 2950 BAILOUT("unsupported context for arguments object"); 2951 } 2952 ast_context()->ReturnValue(environment()->Lookup(variable)); 2953 } else if (variable->IsContextSlot()) { 2954 if (variable->mode() == Variable::CONST) { 2955 BAILOUT("reference to const context slot"); 2956 } 2957 HValue* context = BuildContextChainWalk(variable); 2958 int index = variable->AsSlot()->index(); 2959 HLoadContextSlot* instr = new(zone()) HLoadContextSlot(context, index); 2960 ast_context()->ReturnInstruction(instr, expr->id()); 2961 } else if (variable->is_global()) { 2962 LookupResult lookup; 2963 GlobalPropertyAccess type = LookupGlobalProperty(variable, &lookup, false); 2964 2965 if (type == kUseCell && 2966 info()->global_object()->IsAccessCheckNeeded()) { 2967 type = kUseGeneric; 2968 } 2969 2970 if (type == kUseCell) { 2971 Handle<GlobalObject> global(info()->global_object()); 2972 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); 2973 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); 2974 HLoadGlobalCell* instr = new(zone()) HLoadGlobalCell(cell, check_hole); 2975 ast_context()->ReturnInstruction(instr, expr->id()); 2976 } else { 2977 HContext* context = new(zone()) HContext; 2978 AddInstruction(context); 2979 HGlobalObject* global_object = new(zone()) HGlobalObject(context); 2980 AddInstruction(global_object); 2981 HLoadGlobalGeneric* instr = 2982 new(zone()) HLoadGlobalGeneric(context, 2983 global_object, 2984 variable->name(), 2985 ast_context()->is_for_typeof()); 2986 instr->set_position(expr->position()); 2987 ASSERT(instr->HasSideEffects()); 2988 ast_context()->ReturnInstruction(instr, expr->id()); 2989 } 2990 } else { 2991 BAILOUT("reference to a variable which requires dynamic lookup"); 2992 } 2993 } 2994 2995 2996 void HGraphBuilder::VisitLiteral(Literal* expr) { 2997 HConstant* instr = 2998 new(zone()) HConstant(expr->handle(), Representation::Tagged()); 2999 ast_context()->ReturnInstruction(instr, expr->id()); 3000 } 3001 3002 3003 void HGraphBuilder::VisitRegExpLiteral(RegExpLiteral* expr) { 3004 HRegExpLiteral* instr = new(zone()) HRegExpLiteral(expr->pattern(), 3005 expr->flags(), 3006 expr->literal_index()); 3007 ast_context()->ReturnInstruction(instr, expr->id()); 3008 } 3009 3010 3011 void HGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) { 3012 HContext* context = new(zone()) HContext; 3013 AddInstruction(context); 3014 HObjectLiteral* literal = 3015 new(zone()) HObjectLiteral(context, 3016 expr->constant_properties(), 3017 expr->fast_elements(), 3018 expr->literal_index(), 3019 expr->depth(), 3020 expr->has_function()); 3021 // The object is expected in the bailout environment during computation 3022 // of the property values and is the value of the entire expression. 3023 PushAndAdd(literal); 3024 3025 expr->CalculateEmitStore(); 3026 3027 for (int i = 0; i < expr->properties()->length(); i++) { 3028 ObjectLiteral::Property* property = expr->properties()->at(i); 3029 if (property->IsCompileTimeValue()) continue; 3030 3031 Literal* key = property->key(); 3032 Expression* value = property->value(); 3033 3034 switch (property->kind()) { 3035 case ObjectLiteral::Property::MATERIALIZED_LITERAL: 3036 ASSERT(!CompileTimeValue::IsCompileTimeValue(value)); 3037 // Fall through. 3038 case ObjectLiteral::Property::COMPUTED: 3039 if (key->handle()->IsSymbol()) { 3040 if (property->emit_store()) { 3041 VISIT_FOR_VALUE(value); 3042 HValue* value = Pop(); 3043 Handle<String> name = Handle<String>::cast(key->handle()); 3044 HStoreNamedGeneric* store = 3045 new(zone()) HStoreNamedGeneric( 3046 context, 3047 literal, 3048 name, 3049 value, 3050 function_strict_mode()); 3051 AddInstruction(store); 3052 AddSimulate(key->id()); 3053 } else { 3054 VISIT_FOR_EFFECT(value); 3055 } 3056 break; 3057 } 3058 // Fall through. 3059 case ObjectLiteral::Property::PROTOTYPE: 3060 case ObjectLiteral::Property::SETTER: 3061 case ObjectLiteral::Property::GETTER: 3062 BAILOUT("Object literal with complex property"); 3063 default: UNREACHABLE(); 3064 } 3065 } 3066 3067 if (expr->has_function()) { 3068 // Return the result of the transformation to fast properties 3069 // instead of the original since this operation changes the map 3070 // of the object. This makes sure that the original object won't 3071 // be used by other optimized code before it is transformed 3072 // (e.g. because of code motion). 3073 HToFastProperties* result = new(zone()) HToFastProperties(Pop()); 3074 AddInstruction(result); 3075 ast_context()->ReturnValue(result); 3076 } else { 3077 ast_context()->ReturnValue(Pop()); 3078 } 3079 } 3080 3081 3082 void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { 3083 ZoneList<Expression*>* subexprs = expr->values(); 3084 int length = subexprs->length(); 3085 3086 HArrayLiteral* literal = new(zone()) HArrayLiteral(expr->constant_elements(), 3087 length, 3088 expr->literal_index(), 3089 expr->depth()); 3090 // The array is expected in the bailout environment during computation 3091 // of the property values and is the value of the entire expression. 3092 PushAndAdd(literal); 3093 3094 HLoadElements* elements = NULL; 3095 3096 for (int i = 0; i < length; i++) { 3097 Expression* subexpr = subexprs->at(i); 3098 // If the subexpression is a literal or a simple materialized literal it 3099 // is already set in the cloned array. 3100 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; 3101 3102 VISIT_FOR_VALUE(subexpr); 3103 HValue* value = Pop(); 3104 if (!Smi::IsValid(i)) BAILOUT("Non-smi key in array literal"); 3105 3106 // Load the elements array before the first store. 3107 if (elements == NULL) { 3108 elements = new(zone()) HLoadElements(literal); 3109 AddInstruction(elements); 3110 } 3111 3112 HValue* key = AddInstruction( 3113 new(zone()) HConstant(Handle<Object>(Smi::FromInt(i)), 3114 Representation::Integer32())); 3115 AddInstruction(new(zone()) HStoreKeyedFastElement(elements, key, value)); 3116 AddSimulate(expr->GetIdForElement(i)); 3117 } 3118 ast_context()->ReturnValue(Pop()); 3119 } 3120 3121 3122 void HGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) { 3123 BAILOUT("CatchExtensionObject"); 3124 } 3125 3126 3127 // Sets the lookup result and returns true if the store can be inlined. 3128 static bool ComputeStoredField(Handle<Map> type, 3129 Handle<String> name, 3130 LookupResult* lookup) { 3131 type->LookupInDescriptors(NULL, *name, lookup); 3132 if (!lookup->IsPropertyOrTransition()) return false; 3133 if (lookup->type() == FIELD) return true; 3134 return (lookup->type() == MAP_TRANSITION) && 3135 (type->unused_property_fields() > 0); 3136 } 3137 3138 3139 static int ComputeStoredFieldIndex(Handle<Map> type, 3140 Handle<String> name, 3141 LookupResult* lookup) { 3142 ASSERT(lookup->type() == FIELD || lookup->type() == MAP_TRANSITION); 3143 if (lookup->type() == FIELD) { 3144 return lookup->GetLocalFieldIndexFromMap(*type); 3145 } else { 3146 Map* transition = lookup->GetTransitionMapFromMap(*type); 3147 return transition->PropertyIndexFor(*name) - type->inobject_properties(); 3148 } 3149 } 3150 3151 3152 HInstruction* HGraphBuilder::BuildStoreNamedField(HValue* object, 3153 Handle<String> name, 3154 HValue* value, 3155 Handle<Map> type, 3156 LookupResult* lookup, 3157 bool smi_and_map_check) { 3158 if (smi_and_map_check) { 3159 AddInstruction(new(zone()) HCheckNonSmi(object)); 3160 AddInstruction(new(zone()) HCheckMap(object, type)); 3161 } 3162 3163 int index = ComputeStoredFieldIndex(type, name, lookup); 3164 bool is_in_object = index < 0; 3165 int offset = index * kPointerSize; 3166 if (index < 0) { 3167 // Negative property indices are in-object properties, indexed 3168 // from the end of the fixed part of the object. 3169 offset += type->instance_size(); 3170 } else { 3171 offset += FixedArray::kHeaderSize; 3172 } 3173 HStoreNamedField* instr = 3174 new(zone()) HStoreNamedField(object, name, value, is_in_object, offset); 3175 if (lookup->type() == MAP_TRANSITION) { 3176 Handle<Map> transition(lookup->GetTransitionMapFromMap(*type)); 3177 instr->set_transition(transition); 3178 // TODO(fschneider): Record the new map type of the object in the IR to 3179 // enable elimination of redundant checks after the transition store. 3180 instr->SetFlag(HValue::kChangesMaps); 3181 } 3182 return instr; 3183 } 3184 3185 3186 HInstruction* HGraphBuilder::BuildStoreNamedGeneric(HValue* object, 3187 Handle<String> name, 3188 HValue* value) { 3189 HContext* context = new(zone()) HContext; 3190 AddInstruction(context); 3191 return new(zone()) HStoreNamedGeneric( 3192 context, 3193 object, 3194 name, 3195 value, 3196 function_strict_mode()); 3197 } 3198 3199 3200 HInstruction* HGraphBuilder::BuildStoreNamed(HValue* object, 3201 HValue* value, 3202 Expression* expr) { 3203 Property* prop = (expr->AsProperty() != NULL) 3204 ? expr->AsProperty() 3205 : expr->AsAssignment()->target()->AsProperty(); 3206 Literal* key = prop->key()->AsLiteral(); 3207 Handle<String> name = Handle<String>::cast(key->handle()); 3208 ASSERT(!name.is_null()); 3209 3210 LookupResult lookup; 3211 ZoneMapList* types = expr->GetReceiverTypes(); 3212 bool is_monomorphic = expr->IsMonomorphic() && 3213 ComputeStoredField(types->first(), name, &lookup); 3214 3215 return is_monomorphic 3216 ? BuildStoreNamedField(object, name, value, types->first(), &lookup, 3217 true) // Needs smi and map check. 3218 : BuildStoreNamedGeneric(object, name, value); 3219 } 3220 3221 3222 void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr, 3223 HValue* object, 3224 HValue* value, 3225 ZoneMapList* types, 3226 Handle<String> name) { 3227 // TODO(ager): We should recognize when the prototype chains for different 3228 // maps are identical. In that case we can avoid repeatedly generating the 3229 // same prototype map checks. 3230 int count = 0; 3231 HBasicBlock* join = NULL; 3232 for (int i = 0; i < types->length() && count < kMaxStorePolymorphism; ++i) { 3233 Handle<Map> map = types->at(i); 3234 LookupResult lookup; 3235 if (ComputeStoredField(map, name, &lookup)) { 3236 if (count == 0) { 3237 AddInstruction(new(zone()) HCheckNonSmi(object)); // Only needed once. 3238 join = graph()->CreateBasicBlock(); 3239 } 3240 ++count; 3241 HBasicBlock* if_true = graph()->CreateBasicBlock(); 3242 HBasicBlock* if_false = graph()->CreateBasicBlock(); 3243 HCompareMap* compare = 3244 new(zone()) HCompareMap(object, map, if_true, if_false); 3245 current_block()->Finish(compare); 3246 3247 set_current_block(if_true); 3248 HInstruction* instr = 3249 BuildStoreNamedField(object, name, value, map, &lookup, false); 3250 instr->set_position(expr->position()); 3251 // Goto will add the HSimulate for the store. 3252 AddInstruction(instr); 3253 if (!ast_context()->IsEffect()) Push(value); 3254 current_block()->Goto(join); 3255 3256 set_current_block(if_false); 3257 } 3258 } 3259 3260 // Finish up. Unconditionally deoptimize if we've handled all the maps we 3261 // know about and do not want to handle ones we've never seen. Otherwise 3262 // use a generic IC. 3263 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { 3264 current_block()->FinishExitWithDeoptimization(); 3265 } else { 3266 HInstruction* instr = BuildStoreNamedGeneric(object, name, value); 3267 instr->set_position(expr->position()); 3268 AddInstruction(instr); 3269 3270 if (join != NULL) { 3271 if (!ast_context()->IsEffect()) Push(value); 3272 current_block()->Goto(join); 3273 } else { 3274 // The HSimulate for the store should not see the stored value in 3275 // effect contexts (it is not materialized at expr->id() in the 3276 // unoptimized code). 3277 if (instr->HasSideEffects()) { 3278 if (ast_context()->IsEffect()) { 3279 AddSimulate(expr->id()); 3280 } else { 3281 Push(value); 3282 AddSimulate(expr->id()); 3283 Drop(1); 3284 } 3285 } 3286 ast_context()->ReturnValue(value); 3287 return; 3288 } 3289 } 3290 3291 ASSERT(join != NULL); 3292 join->SetJoinId(expr->id()); 3293 set_current_block(join); 3294 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); 3295 } 3296 3297 3298 void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) { 3299 Property* prop = expr->target()->AsProperty(); 3300 ASSERT(prop != NULL); 3301 expr->RecordTypeFeedback(oracle()); 3302 VISIT_FOR_VALUE(prop->obj()); 3303 3304 HValue* value = NULL; 3305 HInstruction* instr = NULL; 3306 3307 if (prop->key()->IsPropertyName()) { 3308 // Named store. 3309 VISIT_FOR_VALUE(expr->value()); 3310 value = Pop(); 3311 HValue* object = Pop(); 3312 3313 Literal* key = prop->key()->AsLiteral(); 3314 Handle<String> name = Handle<String>::cast(key->handle()); 3315 ASSERT(!name.is_null()); 3316 3317 ZoneMapList* types = expr->GetReceiverTypes(); 3318 LookupResult lookup; 3319 3320 if (expr->IsMonomorphic()) { 3321 instr = BuildStoreNamed(object, value, expr); 3322 3323 } else if (types != NULL && types->length() > 1) { 3324 HandlePolymorphicStoreNamedField(expr, object, value, types, name); 3325 return; 3326 3327 } else { 3328 instr = BuildStoreNamedGeneric(object, name, value); 3329 } 3330 3331 } else { 3332 // Keyed store. 3333 VISIT_FOR_VALUE(prop->key()); 3334 VISIT_FOR_VALUE(expr->value()); 3335 value = Pop(); 3336 HValue* key = Pop(); 3337 HValue* object = Pop(); 3338 instr = BuildStoreKeyed(object, key, value, expr); 3339 } 3340 Push(value); 3341 instr->set_position(expr->position()); 3342 AddInstruction(instr); 3343 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); 3344 ast_context()->ReturnValue(Pop()); 3345 } 3346 3347 3348 // Because not every expression has a position and there is not common 3349 // superclass of Assignment and CountOperation, we cannot just pass the 3350 // owning expression instead of position and ast_id separately. 3351 void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var, 3352 HValue* value, 3353 int position, 3354 int ast_id) { 3355 LookupResult lookup; 3356 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, true); 3357 if (type == kUseCell) { 3358 bool check_hole = !lookup.IsDontDelete() || lookup.IsReadOnly(); 3359 Handle<GlobalObject> global(info()->global_object()); 3360 Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup)); 3361 HInstruction* instr = new(zone()) HStoreGlobalCell(value, cell, check_hole); 3362 instr->set_position(position); 3363 AddInstruction(instr); 3364 if (instr->HasSideEffects()) AddSimulate(ast_id); 3365 } else { 3366 HContext* context = new(zone()) HContext; 3367 AddInstruction(context); 3368 HGlobalObject* global_object = new(zone()) HGlobalObject(context); 3369 AddInstruction(global_object); 3370 HStoreGlobalGeneric* instr = 3371 new(zone()) HStoreGlobalGeneric(context, 3372 global_object, 3373 var->name(), 3374 value, 3375 function_strict_mode()); 3376 instr->set_position(position); 3377 AddInstruction(instr); 3378 ASSERT(instr->HasSideEffects()); 3379 if (instr->HasSideEffects()) AddSimulate(ast_id); 3380 } 3381 } 3382 3383 3384 void HGraphBuilder::HandleCompoundAssignment(Assignment* expr) { 3385 Expression* target = expr->target(); 3386 VariableProxy* proxy = target->AsVariableProxy(); 3387 Variable* var = proxy->AsVariable(); 3388 Property* prop = target->AsProperty(); 3389 ASSERT(var == NULL || prop == NULL); 3390 3391 // We have a second position recorded in the FullCodeGenerator to have 3392 // type feedback for the binary operation. 3393 BinaryOperation* operation = expr->binary_operation(); 3394 3395 if (var != NULL) { 3396 VISIT_FOR_VALUE(operation); 3397 3398 if (var->is_global()) { 3399 HandleGlobalVariableAssignment(var, 3400 Top(), 3401 expr->position(), 3402 expr->AssignmentId()); 3403 } else if (var->IsStackAllocated()) { 3404 Bind(var, Top()); 3405 } else if (var->IsContextSlot()) { 3406 HValue* context = BuildContextChainWalk(var); 3407 int index = var->AsSlot()->index(); 3408 HStoreContextSlot* instr = 3409 new(zone()) HStoreContextSlot(context, index, Top()); 3410 AddInstruction(instr); 3411 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); 3412 } else { 3413 BAILOUT("compound assignment to lookup slot"); 3414 } 3415 ast_context()->ReturnValue(Pop()); 3416 3417 } else if (prop != NULL) { 3418 prop->RecordTypeFeedback(oracle()); 3419 3420 if (prop->key()->IsPropertyName()) { 3421 // Named property. 3422 VISIT_FOR_VALUE(prop->obj()); 3423 HValue* obj = Top(); 3424 3425 HInstruction* load = NULL; 3426 if (prop->IsMonomorphic()) { 3427 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); 3428 Handle<Map> map = prop->GetReceiverTypes()->first(); 3429 load = BuildLoadNamed(obj, prop, map, name); 3430 } else { 3431 load = BuildLoadNamedGeneric(obj, prop); 3432 } 3433 PushAndAdd(load); 3434 if (load->HasSideEffects()) AddSimulate(expr->CompoundLoadId()); 3435 3436 VISIT_FOR_VALUE(expr->value()); 3437 HValue* right = Pop(); 3438 HValue* left = Pop(); 3439 3440 HInstruction* instr = BuildBinaryOperation(operation, left, right); 3441 PushAndAdd(instr); 3442 if (instr->HasSideEffects()) AddSimulate(operation->id()); 3443 3444 HInstruction* store = BuildStoreNamed(obj, instr, prop); 3445 AddInstruction(store); 3446 // Drop the simulated receiver and value. Return the value. 3447 Drop(2); 3448 Push(instr); 3449 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); 3450 ast_context()->ReturnValue(Pop()); 3451 3452 } else { 3453 // Keyed property. 3454 VISIT_FOR_VALUE(prop->obj()); 3455 VISIT_FOR_VALUE(prop->key()); 3456 HValue* obj = environment()->ExpressionStackAt(1); 3457 HValue* key = environment()->ExpressionStackAt(0); 3458 3459 HInstruction* load = BuildLoadKeyed(obj, key, prop); 3460 PushAndAdd(load); 3461 if (load->HasSideEffects()) AddSimulate(expr->CompoundLoadId()); 3462 3463 VISIT_FOR_VALUE(expr->value()); 3464 HValue* right = Pop(); 3465 HValue* left = Pop(); 3466 3467 HInstruction* instr = BuildBinaryOperation(operation, left, right); 3468 PushAndAdd(instr); 3469 if (instr->HasSideEffects()) AddSimulate(operation->id()); 3470 3471 expr->RecordTypeFeedback(oracle()); 3472 HInstruction* store = BuildStoreKeyed(obj, key, instr, expr); 3473 AddInstruction(store); 3474 // Drop the simulated receiver, key, and value. Return the value. 3475 Drop(3); 3476 Push(instr); 3477 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); 3478 ast_context()->ReturnValue(Pop()); 3479 } 3480 3481 } else { 3482 BAILOUT("invalid lhs in compound assignment"); 3483 } 3484 } 3485 3486 3487 void HGraphBuilder::VisitAssignment(Assignment* expr) { 3488 VariableProxy* proxy = expr->target()->AsVariableProxy(); 3489 Variable* var = proxy->AsVariable(); 3490 Property* prop = expr->target()->AsProperty(); 3491 ASSERT(var == NULL || prop == NULL); 3492 3493 if (expr->is_compound()) { 3494 HandleCompoundAssignment(expr); 3495 return; 3496 } 3497 3498 if (var != NULL) { 3499 if (proxy->IsArguments()) BAILOUT("assignment to arguments"); 3500 3501 // Handle the assignment. 3502 if (var->IsStackAllocated()) { 3503 HValue* value = NULL; 3504 // Handle stack-allocated variables on the right-hand side directly. 3505 // We do not allow the arguments object to occur in a context where it 3506 // may escape, but assignments to stack-allocated locals are 3507 // permitted. Handling such assignments here bypasses the check for 3508 // the arguments object in VisitVariableProxy. 3509 Variable* rhs_var = expr->value()->AsVariableProxy()->AsVariable(); 3510 if (rhs_var != NULL && rhs_var->IsStackAllocated()) { 3511 value = environment()->Lookup(rhs_var); 3512 } else { 3513 VISIT_FOR_VALUE(expr->value()); 3514 value = Pop(); 3515 } 3516 Bind(var, value); 3517 ast_context()->ReturnValue(value); 3518 3519 } else if (var->IsContextSlot() && var->mode() != Variable::CONST) { 3520 VISIT_FOR_VALUE(expr->value()); 3521 HValue* context = BuildContextChainWalk(var); 3522 int index = var->AsSlot()->index(); 3523 HStoreContextSlot* instr = 3524 new(zone()) HStoreContextSlot(context, index, Top()); 3525 AddInstruction(instr); 3526 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); 3527 ast_context()->ReturnValue(Pop()); 3528 3529 } else if (var->is_global()) { 3530 VISIT_FOR_VALUE(expr->value()); 3531 HandleGlobalVariableAssignment(var, 3532 Top(), 3533 expr->position(), 3534 expr->AssignmentId()); 3535 ast_context()->ReturnValue(Pop()); 3536 3537 } else { 3538 BAILOUT("assignment to LOOKUP or const CONTEXT variable"); 3539 } 3540 3541 } else if (prop != NULL) { 3542 HandlePropertyAssignment(expr); 3543 } else { 3544 BAILOUT("invalid left-hand side in assignment"); 3545 } 3546 } 3547 3548 3549 void HGraphBuilder::VisitThrow(Throw* expr) { 3550 // We don't optimize functions with invalid left-hand sides in 3551 // assignments, count operations, or for-in. Consequently throw can 3552 // currently only occur in an effect context. 3553 ASSERT(ast_context()->IsEffect()); 3554 VISIT_FOR_VALUE(expr->exception()); 3555 3556 HValue* value = environment()->Pop(); 3557 HThrow* instr = new(zone()) HThrow(value); 3558 instr->set_position(expr->position()); 3559 AddInstruction(instr); 3560 AddSimulate(expr->id()); 3561 current_block()->FinishExit(new(zone()) HAbnormalExit); 3562 set_current_block(NULL); 3563 } 3564 3565 3566 HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object, 3567 Property* expr, 3568 Handle<Map> type, 3569 LookupResult* lookup, 3570 bool smi_and_map_check) { 3571 if (smi_and_map_check) { 3572 AddInstruction(new(zone()) HCheckNonSmi(object)); 3573 AddInstruction(new(zone()) HCheckMap(object, type)); 3574 } 3575 3576 int index = lookup->GetLocalFieldIndexFromMap(*type); 3577 if (index < 0) { 3578 // Negative property indices are in-object properties, indexed 3579 // from the end of the fixed part of the object. 3580 int offset = (index * kPointerSize) + type->instance_size(); 3581 return new(zone()) HLoadNamedField(object, true, offset); 3582 } else { 3583 // Non-negative property indices are in the properties array. 3584 int offset = (index * kPointerSize) + FixedArray::kHeaderSize; 3585 return new(zone()) HLoadNamedField(object, false, offset); 3586 } 3587 } 3588 3589 3590 HInstruction* HGraphBuilder::BuildLoadNamedGeneric(HValue* obj, 3591 Property* expr) { 3592 ASSERT(expr->key()->IsPropertyName()); 3593 Handle<Object> name = expr->key()->AsLiteral()->handle(); 3594 HContext* context = new(zone()) HContext; 3595 AddInstruction(context); 3596 return new(zone()) HLoadNamedGeneric(context, obj, name); 3597 } 3598 3599 3600 HInstruction* HGraphBuilder::BuildLoadNamed(HValue* obj, 3601 Property* expr, 3602 Handle<Map> map, 3603 Handle<String> name) { 3604 LookupResult lookup; 3605 map->LookupInDescriptors(NULL, *name, &lookup); 3606 if (lookup.IsProperty() && lookup.type() == FIELD) { 3607 return BuildLoadNamedField(obj, 3608 expr, 3609 map, 3610 &lookup, 3611 true); 3612 } else if (lookup.IsProperty() && lookup.type() == CONSTANT_FUNCTION) { 3613 AddInstruction(new(zone()) HCheckNonSmi(obj)); 3614 AddInstruction(new(zone()) HCheckMap(obj, map)); 3615 Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*map)); 3616 return new(zone()) HConstant(function, Representation::Tagged()); 3617 } else { 3618 return BuildLoadNamedGeneric(obj, expr); 3619 } 3620 } 3621 3622 3623 HInstruction* HGraphBuilder::BuildLoadKeyedGeneric(HValue* object, 3624 HValue* key) { 3625 HContext* context = new(zone()) HContext; 3626 AddInstruction(context); 3627 return new(zone()) HLoadKeyedGeneric(context, object, key); 3628 } 3629 3630 3631 HInstruction* HGraphBuilder::BuildLoadKeyedFastElement(HValue* object, 3632 HValue* key, 3633 Property* expr) { 3634 ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic()); 3635 AddInstruction(new(zone()) HCheckNonSmi(object)); 3636 Handle<Map> map = expr->GetMonomorphicReceiverType(); 3637 ASSERT(map->has_fast_elements()); 3638 AddInstruction(new(zone()) HCheckMap(object, map)); 3639 bool is_array = (map->instance_type() == JS_ARRAY_TYPE); 3640 HLoadElements* elements = new(zone()) HLoadElements(object); 3641 HInstruction* length = NULL; 3642 HInstruction* checked_key = NULL; 3643 if (is_array) { 3644 length = AddInstruction(new(zone()) HJSArrayLength(object)); 3645 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); 3646 AddInstruction(elements); 3647 } else { 3648 AddInstruction(elements); 3649 length = AddInstruction(new(zone()) HFixedArrayLength(elements)); 3650 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); 3651 } 3652 return new(zone()) HLoadKeyedFastElement(elements, checked_key); 3653 } 3654 3655 3656 HInstruction* HGraphBuilder::BuildLoadKeyedSpecializedArrayElement( 3657 HValue* object, 3658 HValue* key, 3659 Property* expr) { 3660 ASSERT(!expr->key()->IsPropertyName() && expr->IsMonomorphic()); 3661 AddInstruction(new(zone()) HCheckNonSmi(object)); 3662 Handle<Map> map = expr->GetMonomorphicReceiverType(); 3663 ASSERT(!map->has_fast_elements()); 3664 ASSERT(map->has_external_array_elements()); 3665 AddInstruction(new(zone()) HCheckMap(object, map)); 3666 HLoadElements* elements = new(zone()) HLoadElements(object); 3667 AddInstruction(elements); 3668 HInstruction* length = new(zone()) HExternalArrayLength(elements); 3669 AddInstruction(length); 3670 HInstruction* checked_key = 3671 AddInstruction(new(zone()) HBoundsCheck(key, length)); 3672 HLoadExternalArrayPointer* external_elements = 3673 new(zone()) HLoadExternalArrayPointer(elements); 3674 AddInstruction(external_elements); 3675 HLoadKeyedSpecializedArrayElement* pixel_array_value = 3676 new(zone()) HLoadKeyedSpecializedArrayElement( 3677 external_elements, checked_key, expr->external_array_type()); 3678 return pixel_array_value; 3679 } 3680 3681 3682 HInstruction* HGraphBuilder::BuildLoadKeyed(HValue* obj, 3683 HValue* key, 3684 Property* prop) { 3685 if (prop->IsMonomorphic()) { 3686 Handle<Map> receiver_type(prop->GetMonomorphicReceiverType()); 3687 // An object has either fast elements or pixel array elements, but never 3688 // both. Pixel array maps that are assigned to pixel array elements are 3689 // always created with the fast elements flag cleared. 3690 if (receiver_type->has_external_array_elements()) { 3691 return BuildLoadKeyedSpecializedArrayElement(obj, key, prop); 3692 } else if (receiver_type->has_fast_elements()) { 3693 return BuildLoadKeyedFastElement(obj, key, prop); 3694 } 3695 } 3696 return BuildLoadKeyedGeneric(obj, key); 3697 } 3698 3699 3700 HInstruction* HGraphBuilder::BuildStoreKeyedGeneric(HValue* object, 3701 HValue* key, 3702 HValue* value) { 3703 HContext* context = new(zone()) HContext; 3704 AddInstruction(context); 3705 return new(zone()) HStoreKeyedGeneric( 3706 context, 3707 object, 3708 key, 3709 value, 3710 function_strict_mode()); 3711 } 3712 3713 3714 HInstruction* HGraphBuilder::BuildStoreKeyedFastElement(HValue* object, 3715 HValue* key, 3716 HValue* val, 3717 Expression* expr) { 3718 ASSERT(expr->IsMonomorphic()); 3719 AddInstruction(new(zone()) HCheckNonSmi(object)); 3720 Handle<Map> map = expr->GetMonomorphicReceiverType(); 3721 ASSERT(map->has_fast_elements()); 3722 AddInstruction(new(zone()) HCheckMap(object, map)); 3723 HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); 3724 AddInstruction(new(zone()) HCheckMap( 3725 elements, isolate()->factory()->fixed_array_map())); 3726 bool is_array = (map->instance_type() == JS_ARRAY_TYPE); 3727 HInstruction* length = NULL; 3728 if (is_array) { 3729 length = AddInstruction(new(zone()) HJSArrayLength(object)); 3730 } else { 3731 length = AddInstruction(new(zone()) HFixedArrayLength(elements)); 3732 } 3733 HInstruction* checked_key = 3734 AddInstruction(new(zone()) HBoundsCheck(key, length)); 3735 return new(zone()) HStoreKeyedFastElement(elements, checked_key, val); 3736 } 3737 3738 3739 HInstruction* HGraphBuilder::BuildStoreKeyedSpecializedArrayElement( 3740 HValue* object, 3741 HValue* key, 3742 HValue* val, 3743 Expression* expr) { 3744 ASSERT(expr->IsMonomorphic()); 3745 AddInstruction(new(zone()) HCheckNonSmi(object)); 3746 Handle<Map> map = expr->GetMonomorphicReceiverType(); 3747 ASSERT(!map->has_fast_elements()); 3748 ASSERT(map->has_external_array_elements()); 3749 AddInstruction(new(zone()) HCheckMap(object, map)); 3750 HLoadElements* elements = new(zone()) HLoadElements(object); 3751 AddInstruction(elements); 3752 HInstruction* length = AddInstruction( 3753 new(zone()) HExternalArrayLength(elements)); 3754 HInstruction* checked_key = 3755 AddInstruction(new(zone()) HBoundsCheck(key, length)); 3756 HLoadExternalArrayPointer* external_elements = 3757 new(zone()) HLoadExternalArrayPointer(elements); 3758 AddInstruction(external_elements); 3759 return new(zone()) HStoreKeyedSpecializedArrayElement( 3760 external_elements, 3761 checked_key, 3762 val, 3763 expr->external_array_type()); 3764 } 3765 3766 3767 HInstruction* HGraphBuilder::BuildStoreKeyed(HValue* object, 3768 HValue* key, 3769 HValue* value, 3770 Expression* expr) { 3771 if (expr->IsMonomorphic()) { 3772 Handle<Map> receiver_type(expr->GetMonomorphicReceiverType()); 3773 // An object has either fast elements or external array elements, but 3774 // never both. Pixel array maps that are assigned to pixel array elements 3775 // are always created with the fast elements flag cleared. 3776 if (receiver_type->has_external_array_elements()) { 3777 return BuildStoreKeyedSpecializedArrayElement(object, 3778 key, 3779 value, 3780 expr); 3781 } else if (receiver_type->has_fast_elements()) { 3782 return BuildStoreKeyedFastElement(object, key, value, expr); 3783 } 3784 } 3785 return BuildStoreKeyedGeneric(object, key, value); 3786 } 3787 3788 3789 bool HGraphBuilder::TryArgumentsAccess(Property* expr) { 3790 VariableProxy* proxy = expr->obj()->AsVariableProxy(); 3791 if (proxy == NULL) return false; 3792 if (!proxy->var()->IsStackAllocated()) return false; 3793 if (!environment()->Lookup(proxy->var())->CheckFlag(HValue::kIsArguments)) { 3794 return false; 3795 } 3796 3797 // Our implementation of arguments (based on this stack frame or an 3798 // adapter below it) does not work for inlined functions. 3799 if (function_state()->outer() != NULL) { 3800 Bailout("arguments access in inlined function"); 3801 return true; 3802 } 3803 3804 HInstruction* result = NULL; 3805 if (expr->key()->IsPropertyName()) { 3806 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); 3807 if (!name->IsEqualTo(CStrVector("length"))) return false; 3808 HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); 3809 result = new(zone()) HArgumentsLength(elements); 3810 } else { 3811 Push(graph()->GetArgumentsObject()); 3812 VisitForValue(expr->key()); 3813 if (HasStackOverflow()) return false; 3814 HValue* key = Pop(); 3815 Drop(1); // Arguments object. 3816 HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); 3817 HInstruction* length = AddInstruction( 3818 new(zone()) HArgumentsLength(elements)); 3819 HInstruction* checked_key = 3820 AddInstruction(new(zone()) HBoundsCheck(key, length)); 3821 result = new(zone()) HAccessArgumentsAt(elements, length, checked_key); 3822 } 3823 ast_context()->ReturnInstruction(result, expr->id()); 3824 return true; 3825 } 3826 3827 3828 void HGraphBuilder::VisitProperty(Property* expr) { 3829 expr->RecordTypeFeedback(oracle()); 3830 3831 if (TryArgumentsAccess(expr)) return; 3832 CHECK_BAILOUT; 3833 3834 VISIT_FOR_VALUE(expr->obj()); 3835 3836 HInstruction* instr = NULL; 3837 if (expr->IsArrayLength()) { 3838 HValue* array = Pop(); 3839 AddInstruction(new(zone()) HCheckNonSmi(array)); 3840 AddInstruction(new(zone()) HCheckInstanceType(array, 3841 JS_ARRAY_TYPE, 3842 JS_ARRAY_TYPE)); 3843 instr = new(zone()) HJSArrayLength(array); 3844 3845 } else if (expr->IsStringLength()) { 3846 HValue* string = Pop(); 3847 AddInstruction(new(zone()) HCheckNonSmi(string)); 3848 AddInstruction(new(zone()) HCheckInstanceType(string, 3849 FIRST_STRING_TYPE, 3850 LAST_STRING_TYPE)); 3851 instr = new(zone()) HStringLength(string); 3852 } else if (expr->IsStringAccess()) { 3853 VISIT_FOR_VALUE(expr->key()); 3854 HValue* index = Pop(); 3855 HValue* string = Pop(); 3856 HStringCharCodeAt* char_code = BuildStringCharCodeAt(string, index); 3857 AddInstruction(char_code); 3858 instr = new(zone()) HStringCharFromCode(char_code); 3859 3860 } else if (expr->IsFunctionPrototype()) { 3861 HValue* function = Pop(); 3862 AddInstruction(new(zone()) HCheckNonSmi(function)); 3863 instr = new(zone()) HLoadFunctionPrototype(function); 3864 3865 } else if (expr->key()->IsPropertyName()) { 3866 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); 3867 ZoneMapList* types = expr->GetReceiverTypes(); 3868 3869 HValue* obj = Pop(); 3870 if (expr->IsMonomorphic()) { 3871 instr = BuildLoadNamed(obj, expr, types->first(), name); 3872 } else if (types != NULL && types->length() > 1) { 3873 AddInstruction(new(zone()) HCheckNonSmi(obj)); 3874 instr = new(zone()) HLoadNamedFieldPolymorphic(obj, types, name); 3875 } else { 3876 instr = BuildLoadNamedGeneric(obj, expr); 3877 } 3878 3879 } else { 3880 VISIT_FOR_VALUE(expr->key()); 3881 3882 HValue* key = Pop(); 3883 HValue* obj = Pop(); 3884 instr = BuildLoadKeyed(obj, key, expr); 3885 } 3886 instr->set_position(expr->position()); 3887 ast_context()->ReturnInstruction(instr, expr->id()); 3888 } 3889 3890 3891 void HGraphBuilder::AddCheckConstantFunction(Call* expr, 3892 HValue* receiver, 3893 Handle<Map> receiver_map, 3894 bool smi_and_map_check) { 3895 // Constant functions have the nice property that the map will change if they 3896 // are overwritten. Therefore it is enough to check the map of the holder and 3897 // its prototypes. 3898 if (smi_and_map_check) { 3899 AddInstruction(new(zone()) HCheckNonSmi(receiver)); 3900 AddInstruction(new(zone()) HCheckMap(receiver, receiver_map)); 3901 } 3902 if (!expr->holder().is_null()) { 3903 AddInstruction(new(zone()) HCheckPrototypeMaps( 3904 Handle<JSObject>(JSObject::cast(receiver_map->prototype())), 3905 expr->holder())); 3906 } 3907 } 3908 3909 3910 void HGraphBuilder::HandlePolymorphicCallNamed(Call* expr, 3911 HValue* receiver, 3912 ZoneMapList* types, 3913 Handle<String> name) { 3914 // TODO(ager): We should recognize when the prototype chains for different 3915 // maps are identical. In that case we can avoid repeatedly generating the 3916 // same prototype map checks. 3917 int argument_count = expr->arguments()->length() + 1; // Includes receiver. 3918 int count = 0; 3919 HBasicBlock* join = NULL; 3920 for (int i = 0; i < types->length() && count < kMaxCallPolymorphism; ++i) { 3921 Handle<Map> map = types->at(i); 3922 if (expr->ComputeTarget(map, name)) { 3923 if (count == 0) { 3924 // Only needed once. 3925 AddInstruction(new(zone()) HCheckNonSmi(receiver)); 3926 join = graph()->CreateBasicBlock(); 3927 } 3928 ++count; 3929 HBasicBlock* if_true = graph()->CreateBasicBlock(); 3930 HBasicBlock* if_false = graph()->CreateBasicBlock(); 3931 HCompareMap* compare = 3932 new(zone()) HCompareMap(receiver, map, if_true, if_false); 3933 current_block()->Finish(compare); 3934 3935 set_current_block(if_true); 3936 AddCheckConstantFunction(expr, receiver, map, false); 3937 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { 3938 PrintF("Trying to inline the polymorphic call to %s\n", 3939 *name->ToCString()); 3940 } 3941 if (!FLAG_polymorphic_inlining || !TryInline(expr)) { 3942 // Check for bailout, as trying to inline might fail due to bailout 3943 // during hydrogen processing. 3944 CHECK_BAILOUT; 3945 HCallConstantFunction* call = 3946 new(zone()) HCallConstantFunction(expr->target(), argument_count); 3947 call->set_position(expr->position()); 3948 PreProcessCall(call); 3949 AddInstruction(call); 3950 if (!ast_context()->IsEffect()) Push(call); 3951 } 3952 3953 if (current_block() != NULL) current_block()->Goto(join); 3954 set_current_block(if_false); 3955 } 3956 } 3957 3958 // Finish up. Unconditionally deoptimize if we've handled all the maps we 3959 // know about and do not want to handle ones we've never seen. Otherwise 3960 // use a generic IC. 3961 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { 3962 current_block()->FinishExitWithDeoptimization(); 3963 } else { 3964 HContext* context = new(zone()) HContext; 3965 AddInstruction(context); 3966 HCallNamed* call = new(zone()) HCallNamed(context, name, argument_count); 3967 call->set_position(expr->position()); 3968 PreProcessCall(call); 3969 3970 if (join != NULL) { 3971 AddInstruction(call); 3972 if (!ast_context()->IsEffect()) Push(call); 3973 current_block()->Goto(join); 3974 } else { 3975 ast_context()->ReturnInstruction(call, expr->id()); 3976 return; 3977 } 3978 } 3979 3980 // We assume that control flow is always live after an expression. So 3981 // even without predecessors to the join block, we set it as the exit 3982 // block and continue by adding instructions there. 3983 ASSERT(join != NULL); 3984 set_current_block(join); 3985 if (join->HasPredecessor()) { 3986 join->SetJoinId(expr->id()); 3987 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); 3988 } 3989 } 3990 3991 3992 void HGraphBuilder::TraceInline(Handle<JSFunction> target, const char* reason) { 3993 if (FLAG_trace_inlining) { 3994 if (reason == NULL) { 3995 // We are currently in the context of inlined function thus we have 3996 // to go to an outer FunctionState to get caller. 3997 SmartPointer<char> callee = target->shared()->DebugName()->ToCString(); 3998 SmartPointer<char> caller = 3999 function_state()->outer()->compilation_info()->function()-> 4000 debug_name()->ToCString(); 4001 PrintF("Inlined %s called from %s.\n", *callee, *caller); 4002 } else { 4003 SmartPointer<char> callee = target->shared()->DebugName()->ToCString(); 4004 SmartPointer<char> caller = 4005 info()->function()->debug_name()->ToCString(); 4006 PrintF("Did not inline %s called from %s (%s).\n", 4007 *callee, *caller, reason); 4008 } 4009 } 4010 } 4011 4012 4013 bool HGraphBuilder::TryInline(Call* expr) { 4014 if (!FLAG_use_inlining) return false; 4015 4016 // Precondition: call is monomorphic and we have found a target with the 4017 // appropriate arity. 4018 Handle<JSFunction> target = expr->target(); 4019 4020 // Do a quick check on source code length to avoid parsing large 4021 // inlining candidates. 4022 if (FLAG_limit_inlining && target->shared()->SourceSize() > kMaxSourceSize) { 4023 TraceInline(target, "target text too big"); 4024 return false; 4025 } 4026 4027 // Target must be inlineable. 4028 if (!target->IsInlineable()) { 4029 TraceInline(target, "target not inlineable"); 4030 return false; 4031 } 4032 4033 // No context change required. 4034 CompilationInfo* outer_info = info(); 4035 if (target->context() != outer_info->closure()->context() || 4036 outer_info->scope()->contains_with() || 4037 outer_info->scope()->num_heap_slots() > 0) { 4038 TraceInline(target, "target requires context change"); 4039 return false; 4040 } 4041 4042 // Don't inline deeper than kMaxInliningLevels calls. 4043 HEnvironment* env = environment(); 4044 int current_level = 1; 4045 while (env->outer() != NULL) { 4046 if (current_level == Compiler::kMaxInliningLevels) { 4047 TraceInline(target, "inline depth limit reached"); 4048 return false; 4049 } 4050 current_level++; 4051 env = env->outer(); 4052 } 4053 4054 // Don't inline recursive functions. 4055 if (target->shared() == outer_info->closure()->shared()) { 4056 TraceInline(target, "target is recursive"); 4057 return false; 4058 } 4059 4060 // We don't want to add more than a certain number of nodes from inlining. 4061 if (FLAG_limit_inlining && inlined_count_ > kMaxInlinedNodes) { 4062 TraceInline(target, "cumulative AST node limit reached"); 4063 return false; 4064 } 4065 4066 int count_before = AstNode::Count(); 4067 4068 // Parse and allocate variables. 4069 CompilationInfo target_info(target); 4070 if (!ParserApi::Parse(&target_info) || 4071 !Scope::Analyze(&target_info)) { 4072 if (target_info.isolate()->has_pending_exception()) { 4073 // Parse or scope error, never optimize this function. 4074 SetStackOverflow(); 4075 target->shared()->set_optimization_disabled(true); 4076 } 4077 TraceInline(target, "parse failure"); 4078 return false; 4079 } 4080 4081 if (target_info.scope()->num_heap_slots() > 0) { 4082 TraceInline(target, "target has context-allocated variables"); 4083 return false; 4084 } 4085 FunctionLiteral* function = target_info.function(); 4086 4087 // Count the number of AST nodes added by inlining this call. 4088 int nodes_added = AstNode::Count() - count_before; 4089 if (FLAG_limit_inlining && nodes_added > kMaxInlinedSize) { 4090 TraceInline(target, "target AST is too large"); 4091 return false; 4092 } 4093 4094 // Check if we can handle all declarations in the inlined functions. 4095 VisitDeclarations(target_info.scope()->declarations()); 4096 if (HasStackOverflow()) { 4097 TraceInline(target, "target has non-trivial declaration"); 4098 ClearStackOverflow(); 4099 return false; 4100 } 4101 4102 // Don't inline functions that uses the arguments object or that 4103 // have a mismatching number of parameters. 4104 Handle<SharedFunctionInfo> target_shared(target->shared()); 4105 int arity = expr->arguments()->length(); 4106 if (function->scope()->arguments() != NULL || 4107 arity != target_shared->formal_parameter_count()) { 4108 TraceInline(target, "target requires special argument handling"); 4109 return false; 4110 } 4111 4112 // All statements in the body must be inlineable. 4113 for (int i = 0, count = function->body()->length(); i < count; ++i) { 4114 if (!function->body()->at(i)->IsInlineable()) { 4115 TraceInline(target, "target contains unsupported syntax"); 4116 return false; 4117 } 4118 } 4119 4120 // Generate the deoptimization data for the unoptimized version of 4121 // the target function if we don't already have it. 4122 if (!target_shared->has_deoptimization_support()) { 4123 // Note that we compile here using the same AST that we will use for 4124 // generating the optimized inline code. 4125 target_info.EnableDeoptimizationSupport(); 4126 if (!FullCodeGenerator::MakeCode(&target_info)) { 4127 TraceInline(target, "could not generate deoptimization info"); 4128 return false; 4129 } 4130 target_shared->EnableDeoptimizationSupport(*target_info.code()); 4131 Compiler::RecordFunctionCompilation(Logger::FUNCTION_TAG, 4132 &target_info, 4133 target_shared); 4134 } 4135 4136 // ---------------------------------------------------------------- 4137 // Save the pending call context and type feedback oracle. Set up new ones 4138 // for the inlined function. 4139 ASSERT(target_shared->has_deoptimization_support()); 4140 TypeFeedbackOracle target_oracle( 4141 Handle<Code>(target_shared->code()), 4142 Handle<Context>(target->context()->global_context())); 4143 FunctionState target_state(this, &target_info, &target_oracle); 4144 4145 HConstant* undefined = graph()->GetConstantUndefined(); 4146 HEnvironment* inner_env = 4147 environment()->CopyForInlining(target, function, true, undefined); 4148 HBasicBlock* body_entry = CreateBasicBlock(inner_env); 4149 current_block()->Goto(body_entry); 4150 4151 body_entry->SetJoinId(expr->ReturnId()); 4152 set_current_block(body_entry); 4153 AddInstruction(new(zone()) HEnterInlined(target, function)); 4154 VisitStatements(function->body()); 4155 if (HasStackOverflow()) { 4156 // Bail out if the inline function did, as we cannot residualize a call 4157 // instead. 4158 TraceInline(target, "inline graph construction failed"); 4159 return false; 4160 } 4161 4162 // Update inlined nodes count. 4163 inlined_count_ += nodes_added; 4164 4165 TraceInline(target, NULL); 4166 4167 if (current_block() != NULL) { 4168 // Add a return of undefined if control can fall off the body. In a 4169 // test context, undefined is false. 4170 if (inlined_test_context() == NULL) { 4171 ASSERT(function_return() != NULL); 4172 ASSERT(call_context()->IsEffect() || call_context()->IsValue()); 4173 if (call_context()->IsEffect()) { 4174 current_block()->Goto(function_return(), false); 4175 } else { 4176 current_block()->AddLeaveInlined(undefined, function_return()); 4177 } 4178 } else { 4179 // The graph builder assumes control can reach both branches of a 4180 // test, so we materialize the undefined value and test it rather than 4181 // simply jumping to the false target. 4182 // 4183 // TODO(3168478): refactor to avoid this. 4184 HBasicBlock* empty_true = graph()->CreateBasicBlock(); 4185 HBasicBlock* empty_false = graph()->CreateBasicBlock(); 4186 HTest* test = new(zone()) HTest(undefined, empty_true, empty_false); 4187 current_block()->Finish(test); 4188 4189 empty_true->Goto(inlined_test_context()->if_true(), false); 4190 empty_false->Goto(inlined_test_context()->if_false(), false); 4191 } 4192 } 4193 4194 // Fix up the function exits. 4195 if (inlined_test_context() != NULL) { 4196 HBasicBlock* if_true = inlined_test_context()->if_true(); 4197 HBasicBlock* if_false = inlined_test_context()->if_false(); 4198 if_true->SetJoinId(expr->id()); 4199 if_false->SetJoinId(expr->id()); 4200 ASSERT(ast_context() == inlined_test_context()); 4201 // Pop the return test context from the expression context stack. 4202 ClearInlinedTestContext(); 4203 4204 // Forward to the real test context. 4205 HBasicBlock* true_target = TestContext::cast(ast_context())->if_true(); 4206 HBasicBlock* false_target = TestContext::cast(ast_context())->if_false(); 4207 if_true->Goto(true_target, false); 4208 if_false->Goto(false_target, false); 4209 4210 // TODO(kmillikin): Come up with a better way to handle this. It is too 4211 // subtle. NULL here indicates that the enclosing context has no control 4212 // flow to handle. 4213 set_current_block(NULL); 4214 4215 } else { 4216 function_return()->SetJoinId(expr->id()); 4217 set_current_block(function_return()); 4218 } 4219 4220 return true; 4221 } 4222 4223 4224 bool HGraphBuilder::TryInlineBuiltinFunction(Call* expr, 4225 HValue* receiver, 4226 Handle<Map> receiver_map, 4227 CheckType check_type) { 4228 ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null()); 4229 // Try to inline calls like Math.* as operations in the calling function. 4230 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; 4231 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); 4232 int argument_count = expr->arguments()->length() + 1; // Plus receiver. 4233 switch (id) { 4234 case kStringCharCodeAt: 4235 case kStringCharAt: 4236 if (argument_count == 2 && check_type == STRING_CHECK) { 4237 HValue* index = Pop(); 4238 HValue* string = Pop(); 4239 ASSERT(!expr->holder().is_null()); 4240 AddInstruction(new(zone()) HCheckPrototypeMaps( 4241 oracle()->GetPrototypeForPrimitiveCheck(STRING_CHECK), 4242 expr->holder())); 4243 HStringCharCodeAt* char_code = BuildStringCharCodeAt(string, index); 4244 if (id == kStringCharCodeAt) { 4245 ast_context()->ReturnInstruction(char_code, expr->id()); 4246 return true; 4247 } 4248 AddInstruction(char_code); 4249 HStringCharFromCode* result = 4250 new(zone()) HStringCharFromCode(char_code); 4251 ast_context()->ReturnInstruction(result, expr->id()); 4252 return true; 4253 } 4254 break; 4255 case kMathRound: 4256 case kMathFloor: 4257 case kMathAbs: 4258 case kMathSqrt: 4259 case kMathLog: 4260 case kMathSin: 4261 case kMathCos: 4262 if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) { 4263 AddCheckConstantFunction(expr, receiver, receiver_map, true); 4264 HValue* argument = Pop(); 4265 Drop(1); // Receiver. 4266 HUnaryMathOperation* op = new(zone()) HUnaryMathOperation(argument, id); 4267 op->set_position(expr->position()); 4268 ast_context()->ReturnInstruction(op, expr->id()); 4269 return true; 4270 } 4271 break; 4272 case kMathPow: 4273 if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) { 4274 AddCheckConstantFunction(expr, receiver, receiver_map, true); 4275 HValue* right = Pop(); 4276 HValue* left = Pop(); 4277 Pop(); // Pop receiver. 4278 HInstruction* result = NULL; 4279 // Use sqrt() if exponent is 0.5 or -0.5. 4280 if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { 4281 double exponent = HConstant::cast(right)->DoubleValue(); 4282 if (exponent == 0.5) { 4283 result = new(zone()) HUnaryMathOperation(left, kMathPowHalf); 4284 } else if (exponent == -0.5) { 4285 HConstant* double_one = 4286 new(zone()) HConstant(Handle<Object>(Smi::FromInt(1)), 4287 Representation::Double()); 4288 AddInstruction(double_one); 4289 HUnaryMathOperation* square_root = 4290 new(zone()) HUnaryMathOperation(left, kMathPowHalf); 4291 AddInstruction(square_root); 4292 // MathPowHalf doesn't have side effects so there's no need for 4293 // an environment simulation here. 4294 ASSERT(!square_root->HasSideEffects()); 4295 result = new(zone()) HDiv(double_one, square_root); 4296 } else if (exponent == 2.0) { 4297 result = new(zone()) HMul(left, left); 4298 } 4299 } else if (right->IsConstant() && 4300 HConstant::cast(right)->HasInteger32Value() && 4301 HConstant::cast(right)->Integer32Value() == 2) { 4302 result = new(zone()) HMul(left, left); 4303 } 4304 4305 if (result == NULL) { 4306 result = new(zone()) HPower(left, right); 4307 } 4308 ast_context()->ReturnInstruction(result, expr->id()); 4309 return true; 4310 } 4311 break; 4312 default: 4313 // Not yet supported for inlining. 4314 break; 4315 } 4316 return false; 4317 } 4318 4319 4320 bool HGraphBuilder::TryCallApply(Call* expr) { 4321 Expression* callee = expr->expression(); 4322 Property* prop = callee->AsProperty(); 4323 ASSERT(prop != NULL); 4324 4325 if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) { 4326 return false; 4327 } 4328 Handle<Map> function_map = expr->GetReceiverTypes()->first(); 4329 if (function_map->instance_type() != JS_FUNCTION_TYPE || 4330 !expr->target()->shared()->HasBuiltinFunctionId() || 4331 expr->target()->shared()->builtin_function_id() != kFunctionApply) { 4332 return false; 4333 } 4334 4335 if (info()->scope()->arguments() == NULL) return false; 4336 4337 ZoneList<Expression*>* args = expr->arguments(); 4338 if (args->length() != 2) return false; 4339 4340 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); 4341 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; 4342 HValue* arg_two_value = environment()->Lookup(arg_two->var()); 4343 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; 4344 4345 // Our implementation of arguments (based on this stack frame or an 4346 // adapter below it) does not work for inlined functions. 4347 if (function_state()->outer() != NULL) { 4348 Bailout("Function.prototype.apply optimization in inlined function"); 4349 return true; 4350 } 4351 4352 // Found pattern f.apply(receiver, arguments). 4353 VisitForValue(prop->obj()); 4354 if (HasStackOverflow()) return false; 4355 HValue* function = Pop(); 4356 VisitForValue(args->at(0)); 4357 if (HasStackOverflow()) return false; 4358 HValue* receiver = Pop(); 4359 HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); 4360 HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements)); 4361 AddCheckConstantFunction(expr, function, function_map, true); 4362 HInstruction* result = 4363 new(zone()) HApplyArguments(function, receiver, length, elements); 4364 result->set_position(expr->position()); 4365 ast_context()->ReturnInstruction(result, expr->id()); 4366 return true; 4367 } 4368 4369 4370 void HGraphBuilder::VisitCall(Call* expr) { 4371 Expression* callee = expr->expression(); 4372 int argument_count = expr->arguments()->length() + 1; // Plus receiver. 4373 HInstruction* call = NULL; 4374 4375 Property* prop = callee->AsProperty(); 4376 if (prop != NULL) { 4377 if (!prop->key()->IsPropertyName()) { 4378 // Keyed function call. 4379 VISIT_FOR_VALUE(prop->obj()); 4380 4381 VISIT_FOR_VALUE(prop->key()); 4382 // Push receiver and key like the non-optimized code generator expects it. 4383 HValue* key = Pop(); 4384 HValue* receiver = Pop(); 4385 Push(key); 4386 Push(receiver); 4387 4388 VisitExpressions(expr->arguments()); 4389 CHECK_BAILOUT; 4390 4391 HContext* context = new(zone()) HContext; 4392 AddInstruction(context); 4393 call = PreProcessCall( 4394 new(zone()) HCallKeyed(context, key, argument_count)); 4395 call->set_position(expr->position()); 4396 Drop(1); // Key. 4397 ast_context()->ReturnInstruction(call, expr->id()); 4398 return; 4399 } 4400 4401 // Named function call. 4402 expr->RecordTypeFeedback(oracle()); 4403 4404 if (TryCallApply(expr)) return; 4405 CHECK_BAILOUT; 4406 4407 VISIT_FOR_VALUE(prop->obj()); 4408 VisitExpressions(expr->arguments()); 4409 CHECK_BAILOUT; 4410 4411 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); 4412 4413 expr->RecordTypeFeedback(oracle()); 4414 ZoneMapList* types = expr->GetReceiverTypes(); 4415 4416 HValue* receiver = 4417 environment()->ExpressionStackAt(expr->arguments()->length()); 4418 if (expr->IsMonomorphic()) { 4419 Handle<Map> receiver_map = 4420 (types == NULL) ? Handle<Map>::null() : types->first(); 4421 if (TryInlineBuiltinFunction(expr, 4422 receiver, 4423 receiver_map, 4424 expr->check_type())) { 4425 return; 4426 } 4427 4428 if (CallStubCompiler::HasCustomCallGenerator(*expr->target()) || 4429 expr->check_type() != RECEIVER_MAP_CHECK) { 4430 // When the target has a custom call IC generator, use the IC, 4431 // because it is likely to generate better code. Also use the IC 4432 // when a primitive receiver check is required. 4433 HContext* context = new(zone()) HContext; 4434 AddInstruction(context); 4435 call = PreProcessCall( 4436 new(zone()) HCallNamed(context, name, argument_count)); 4437 } else { 4438 AddCheckConstantFunction(expr, receiver, receiver_map, true); 4439 4440 if (TryInline(expr)) { 4441 return; 4442 } else { 4443 // Check for bailout, as the TryInline call in the if condition above 4444 // might return false due to bailout during hydrogen processing. 4445 CHECK_BAILOUT; 4446 call = PreProcessCall( 4447 new(zone()) HCallConstantFunction(expr->target(), 4448 argument_count)); 4449 } 4450 } 4451 } else if (types != NULL && types->length() > 1) { 4452 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); 4453 HandlePolymorphicCallNamed(expr, receiver, types, name); 4454 return; 4455 4456 } else { 4457 HContext* context = new(zone()) HContext; 4458 AddInstruction(context); 4459 call = PreProcessCall( 4460 new(zone()) HCallNamed(context, name, argument_count)); 4461 } 4462 4463 } else { 4464 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); 4465 bool global_call = (var != NULL) && var->is_global() && !var->is_this(); 4466 4467 if (!global_call) { 4468 ++argument_count; 4469 VISIT_FOR_VALUE(expr->expression()); 4470 } 4471 4472 if (global_call) { 4473 bool known_global_function = false; 4474 // If there is a global property cell for the name at compile time and 4475 // access check is not enabled we assume that the function will not change 4476 // and generate optimized code for calling the function. 4477 LookupResult lookup; 4478 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, false); 4479 if (type == kUseCell && 4480 !info()->global_object()->IsAccessCheckNeeded()) { 4481 Handle<GlobalObject> global(info()->global_object()); 4482 known_global_function = expr->ComputeGlobalTarget(global, &lookup); 4483 } 4484 if (known_global_function) { 4485 // Push the global object instead of the global receiver because 4486 // code generated by the full code generator expects it. 4487 HContext* context = new(zone()) HContext; 4488 HGlobalObject* global_object = new(zone()) HGlobalObject(context); 4489 AddInstruction(context); 4490 PushAndAdd(global_object); 4491 VisitExpressions(expr->arguments()); 4492 CHECK_BAILOUT; 4493 4494 VISIT_FOR_VALUE(expr->expression()); 4495 HValue* function = Pop(); 4496 AddInstruction(new(zone()) HCheckFunction(function, expr->target())); 4497 4498 // Replace the global object with the global receiver. 4499 HGlobalReceiver* global_receiver = 4500 new(zone()) HGlobalReceiver(global_object); 4501 // Index of the receiver from the top of the expression stack. 4502 const int receiver_index = argument_count - 1; 4503 AddInstruction(global_receiver); 4504 ASSERT(environment()->ExpressionStackAt(receiver_index)-> 4505 IsGlobalObject()); 4506 environment()->SetExpressionStackAt(receiver_index, global_receiver); 4507 4508 if (TryInline(expr)) { 4509 return; 4510 } 4511 // Check for bailout, as trying to inline might fail due to bailout 4512 // during hydrogen processing. 4513 CHECK_BAILOUT; 4514 4515 call = PreProcessCall(new(zone()) HCallKnownGlobal(expr->target(), 4516 argument_count)); 4517 } else { 4518 HContext* context = new(zone()) HContext; 4519 AddInstruction(context); 4520 PushAndAdd(new(zone()) HGlobalObject(context)); 4521 VisitExpressions(expr->arguments()); 4522 CHECK_BAILOUT; 4523 4524 call = PreProcessCall(new(zone()) HCallGlobal(context, 4525 var->name(), 4526 argument_count)); 4527 } 4528 4529 } else { 4530 HContext* context = new(zone()) HContext; 4531 HGlobalObject* global_object = new(zone()) HGlobalObject(context); 4532 AddInstruction(context); 4533 AddInstruction(global_object); 4534 PushAndAdd(new(zone()) HGlobalReceiver(global_object)); 4535 VisitExpressions(expr->arguments()); 4536 CHECK_BAILOUT; 4537 4538 call = PreProcessCall(new(zone()) HCallFunction(context, argument_count)); 4539 } 4540 } 4541 4542 call->set_position(expr->position()); 4543 ast_context()->ReturnInstruction(call, expr->id()); 4544 } 4545 4546 4547 void HGraphBuilder::VisitCallNew(CallNew* expr) { 4548 // The constructor function is also used as the receiver argument to the 4549 // JS construct call builtin. 4550 VISIT_FOR_VALUE(expr->expression()); 4551 VisitExpressions(expr->arguments()); 4552 CHECK_BAILOUT; 4553 4554 HContext* context = new(zone()) HContext; 4555 AddInstruction(context); 4556 4557 // The constructor is both an operand to the instruction and an argument 4558 // to the construct call. 4559 int arg_count = expr->arguments()->length() + 1; // Plus constructor. 4560 HValue* constructor = environment()->ExpressionStackAt(arg_count - 1); 4561 HCallNew* call = new(zone()) HCallNew(context, constructor, arg_count); 4562 call->set_position(expr->position()); 4563 PreProcessCall(call); 4564 ast_context()->ReturnInstruction(call, expr->id()); 4565 } 4566 4567 4568 // Support for generating inlined runtime functions. 4569 4570 // Lookup table for generators for runtime calls that are generated inline. 4571 // Elements of the table are member pointers to functions of HGraphBuilder. 4572 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \ 4573 &HGraphBuilder::Generate##Name, 4574 4575 const HGraphBuilder::InlineFunctionGenerator 4576 HGraphBuilder::kInlineFunctionGenerators[] = { 4577 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS) 4578 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS) 4579 }; 4580 #undef INLINE_FUNCTION_GENERATOR_ADDRESS 4581 4582 4583 void HGraphBuilder::VisitCallRuntime(CallRuntime* expr) { 4584 if (expr->is_jsruntime()) { 4585 BAILOUT("call to a JavaScript runtime function"); 4586 } 4587 4588 const Runtime::Function* function = expr->function(); 4589 ASSERT(function != NULL); 4590 if (function->intrinsic_type == Runtime::INLINE) { 4591 ASSERT(expr->name()->length() > 0); 4592 ASSERT(expr->name()->Get(0) == '_'); 4593 // Call to an inline function. 4594 int lookup_index = static_cast<int>(function->function_id) - 4595 static_cast<int>(Runtime::kFirstInlineFunction); 4596 ASSERT(lookup_index >= 0); 4597 ASSERT(static_cast<size_t>(lookup_index) < 4598 ARRAY_SIZE(kInlineFunctionGenerators)); 4599 InlineFunctionGenerator generator = kInlineFunctionGenerators[lookup_index]; 4600 4601 // Call the inline code generator using the pointer-to-member. 4602 (this->*generator)(expr); 4603 } else { 4604 ASSERT(function->intrinsic_type == Runtime::RUNTIME); 4605 VisitArgumentList(expr->arguments()); 4606 CHECK_BAILOUT; 4607 4608 Handle<String> name = expr->name(); 4609 int argument_count = expr->arguments()->length(); 4610 HCallRuntime* call = 4611 new(zone()) HCallRuntime(name, function, argument_count); 4612 call->set_position(RelocInfo::kNoPosition); 4613 Drop(argument_count); 4614 ast_context()->ReturnInstruction(call, expr->id()); 4615 } 4616 } 4617 4618 4619 void HGraphBuilder::VisitUnaryOperation(UnaryOperation* expr) { 4620 Token::Value op = expr->op(); 4621 if (op == Token::VOID) { 4622 VISIT_FOR_EFFECT(expr->expression()); 4623 ast_context()->ReturnValue(graph()->GetConstantUndefined()); 4624 } else if (op == Token::DELETE) { 4625 Property* prop = expr->expression()->AsProperty(); 4626 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); 4627 if (prop == NULL && var == NULL) { 4628 // Result of deleting non-property, non-variable reference is true. 4629 // Evaluate the subexpression for side effects. 4630 VISIT_FOR_EFFECT(expr->expression()); 4631 ast_context()->ReturnValue(graph()->GetConstantTrue()); 4632 } else if (var != NULL && 4633 !var->is_global() && 4634 var->AsSlot() != NULL && 4635 var->AsSlot()->type() != Slot::LOOKUP) { 4636 // Result of deleting non-global, non-dynamic variables is false. 4637 // The subexpression does not have side effects. 4638 ast_context()->ReturnValue(graph()->GetConstantFalse()); 4639 } else if (prop != NULL) { 4640 if (prop->is_synthetic()) { 4641 // Result of deleting parameters is false, even when they rewrite 4642 // to accesses on the arguments object. 4643 ast_context()->ReturnValue(graph()->GetConstantFalse()); 4644 } else { 4645 VISIT_FOR_VALUE(prop->obj()); 4646 VISIT_FOR_VALUE(prop->key()); 4647 HValue* key = Pop(); 4648 HValue* obj = Pop(); 4649 HDeleteProperty* instr = new(zone()) HDeleteProperty(obj, key); 4650 ast_context()->ReturnInstruction(instr, expr->id()); 4651 } 4652 } else if (var->is_global()) { 4653 BAILOUT("delete with global variable"); 4654 } else { 4655 BAILOUT("delete with non-global variable"); 4656 } 4657 } else if (op == Token::NOT) { 4658 if (ast_context()->IsTest()) { 4659 TestContext* context = TestContext::cast(ast_context()); 4660 VisitForControl(expr->expression(), 4661 context->if_false(), 4662 context->if_true()); 4663 } else if (ast_context()->IsValue()) { 4664 HBasicBlock* materialize_false = graph()->CreateBasicBlock(); 4665 HBasicBlock* materialize_true = graph()->CreateBasicBlock(); 4666 VISIT_FOR_CONTROL(expr->expression(), 4667 materialize_false, 4668 materialize_true); 4669 materialize_false->SetJoinId(expr->expression()->id()); 4670 materialize_true->SetJoinId(expr->expression()->id()); 4671 4672 set_current_block(materialize_false); 4673 Push(graph()->GetConstantFalse()); 4674 set_current_block(materialize_true); 4675 Push(graph()->GetConstantTrue()); 4676 4677 HBasicBlock* join = 4678 CreateJoin(materialize_false, materialize_true, expr->id()); 4679 set_current_block(join); 4680 ast_context()->ReturnValue(Pop()); 4681 } else { 4682 ASSERT(ast_context()->IsEffect()); 4683 VisitForEffect(expr->expression()); 4684 } 4685 4686 } else if (op == Token::TYPEOF) { 4687 VisitForTypeOf(expr->expression()); 4688 if (HasStackOverflow()) return; 4689 HValue* value = Pop(); 4690 ast_context()->ReturnInstruction(new(zone()) HTypeof(value), expr->id()); 4691 4692 } else { 4693 VISIT_FOR_VALUE(expr->expression()); 4694 HValue* value = Pop(); 4695 HInstruction* instr = NULL; 4696 switch (op) { 4697 case Token::BIT_NOT: 4698 instr = new(zone()) HBitNot(value); 4699 break; 4700 case Token::SUB: 4701 instr = new(zone()) HMul(value, graph_->GetConstantMinus1()); 4702 break; 4703 case Token::ADD: 4704 instr = new(zone()) HMul(value, graph_->GetConstant1()); 4705 break; 4706 default: 4707 BAILOUT("Value: unsupported unary operation"); 4708 break; 4709 } 4710 ast_context()->ReturnInstruction(instr, expr->id()); 4711 } 4712 } 4713 4714 4715 HInstruction* HGraphBuilder::BuildIncrement(HValue* value, bool increment) { 4716 HConstant* delta = increment 4717 ? graph_->GetConstant1() 4718 : graph_->GetConstantMinus1(); 4719 HInstruction* instr = new(zone()) HAdd(value, delta); 4720 AssumeRepresentation(instr, Representation::Integer32()); 4721 return instr; 4722 } 4723 4724 4725 void HGraphBuilder::VisitCountOperation(CountOperation* expr) { 4726 Expression* target = expr->expression(); 4727 VariableProxy* proxy = target->AsVariableProxy(); 4728 Variable* var = proxy->AsVariable(); 4729 Property* prop = target->AsProperty(); 4730 ASSERT(var == NULL || prop == NULL); 4731 bool inc = expr->op() == Token::INC; 4732 4733 if (var != NULL) { 4734 VISIT_FOR_VALUE(target); 4735 4736 // Match the full code generator stack by simulating an extra stack 4737 // element for postfix operations in a non-effect context. 4738 bool has_extra = expr->is_postfix() && !ast_context()->IsEffect(); 4739 HValue* before = has_extra ? Top() : Pop(); 4740 HInstruction* after = BuildIncrement(before, inc); 4741 AddInstruction(after); 4742 Push(after); 4743 4744 if (var->is_global()) { 4745 HandleGlobalVariableAssignment(var, 4746 after, 4747 expr->position(), 4748 expr->AssignmentId()); 4749 } else if (var->IsStackAllocated()) { 4750 Bind(var, after); 4751 } else if (var->IsContextSlot()) { 4752 HValue* context = BuildContextChainWalk(var); 4753 int index = var->AsSlot()->index(); 4754 HStoreContextSlot* instr = 4755 new(zone()) HStoreContextSlot(context, index, after); 4756 AddInstruction(instr); 4757 if (instr->HasSideEffects()) AddSimulate(expr->AssignmentId()); 4758 } else { 4759 BAILOUT("lookup variable in count operation"); 4760 } 4761 Drop(has_extra ? 2 : 1); 4762 ast_context()->ReturnValue(expr->is_postfix() ? before : after); 4763 4764 } else if (prop != NULL) { 4765 prop->RecordTypeFeedback(oracle()); 4766 4767 if (prop->key()->IsPropertyName()) { 4768 // Named property. 4769 4770 // Match the full code generator stack by simulating an extra stack 4771 // element for postfix operations in a non-effect context. 4772 bool has_extra = expr->is_postfix() && !ast_context()->IsEffect(); 4773 if (has_extra) Push(graph_->GetConstantUndefined()); 4774 4775 VISIT_FOR_VALUE(prop->obj()); 4776 HValue* obj = Top(); 4777 4778 HInstruction* load = NULL; 4779 if (prop->IsMonomorphic()) { 4780 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); 4781 Handle<Map> map = prop->GetReceiverTypes()->first(); 4782 load = BuildLoadNamed(obj, prop, map, name); 4783 } else { 4784 load = BuildLoadNamedGeneric(obj, prop); 4785 } 4786 PushAndAdd(load); 4787 if (load->HasSideEffects()) AddSimulate(expr->CountId()); 4788 4789 HValue* before = Pop(); 4790 // There is no deoptimization to after the increment, so we don't need 4791 // to simulate the expression stack after this instruction. 4792 HInstruction* after = BuildIncrement(before, inc); 4793 AddInstruction(after); 4794 4795 HInstruction* store = BuildStoreNamed(obj, after, prop); 4796 AddInstruction(store); 4797 4798 // Overwrite the receiver in the bailout environment with the result 4799 // of the operation, and the placeholder with the original value if 4800 // necessary. 4801 environment()->SetExpressionStackAt(0, after); 4802 if (has_extra) environment()->SetExpressionStackAt(1, before); 4803 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); 4804 Drop(has_extra ? 2 : 1); 4805 4806 ast_context()->ReturnValue(expr->is_postfix() ? before : after); 4807 4808 } else { 4809 // Keyed property. 4810 4811 // Match the full code generator stack by simulate an extra stack element 4812 // for postfix operations in a non-effect context. 4813 bool has_extra = expr->is_postfix() && !ast_context()->IsEffect(); 4814 if (has_extra) Push(graph_->GetConstantUndefined()); 4815 4816 VISIT_FOR_VALUE(prop->obj()); 4817 VISIT_FOR_VALUE(prop->key()); 4818 HValue* obj = environment()->ExpressionStackAt(1); 4819 HValue* key = environment()->ExpressionStackAt(0); 4820 4821 HInstruction* load = BuildLoadKeyed(obj, key, prop); 4822 PushAndAdd(load); 4823 if (load->HasSideEffects()) AddSimulate(expr->CountId()); 4824 4825 HValue* before = Pop(); 4826 // There is no deoptimization to after the increment, so we don't need 4827 // to simulate the expression stack after this instruction. 4828 HInstruction* after = BuildIncrement(before, inc); 4829 AddInstruction(after); 4830 4831 expr->RecordTypeFeedback(oracle()); 4832 HInstruction* store = BuildStoreKeyed(obj, key, after, expr); 4833 AddInstruction(store); 4834 4835 // Drop the key from the bailout environment. Overwrite the receiver 4836 // with the result of the operation, and the placeholder with the 4837 // original value if necessary. 4838 Drop(1); 4839 environment()->SetExpressionStackAt(0, after); 4840 if (has_extra) environment()->SetExpressionStackAt(1, before); 4841 if (store->HasSideEffects()) AddSimulate(expr->AssignmentId()); 4842 Drop(has_extra ? 2 : 1); 4843 4844 ast_context()->ReturnValue(expr->is_postfix() ? before : after); 4845 } 4846 4847 } else { 4848 BAILOUT("invalid lhs in count operation"); 4849 } 4850 } 4851 4852 4853 HStringCharCodeAt* HGraphBuilder::BuildStringCharCodeAt(HValue* string, 4854 HValue* index) { 4855 AddInstruction(new(zone()) HCheckNonSmi(string)); 4856 AddInstruction(new(zone()) HCheckInstanceType( 4857 string, FIRST_STRING_TYPE, LAST_STRING_TYPE)); 4858 HStringLength* length = new(zone()) HStringLength(string); 4859 AddInstruction(length); 4860 HInstruction* checked_index = 4861 AddInstruction(new(zone()) HBoundsCheck(index, length)); 4862 return new(zone()) HStringCharCodeAt(string, checked_index); 4863 } 4864 4865 4866 HInstruction* HGraphBuilder::BuildBinaryOperation(BinaryOperation* expr, 4867 HValue* left, 4868 HValue* right) { 4869 HInstruction* instr = NULL; 4870 switch (expr->op()) { 4871 case Token::ADD: 4872 instr = new(zone()) HAdd(left, right); 4873 break; 4874 case Token::SUB: 4875 instr = new(zone()) HSub(left, right); 4876 break; 4877 case Token::MUL: 4878 instr = new(zone()) HMul(left, right); 4879 break; 4880 case Token::MOD: 4881 instr = new(zone()) HMod(left, right); 4882 break; 4883 case Token::DIV: 4884 instr = new(zone()) HDiv(left, right); 4885 break; 4886 case Token::BIT_XOR: 4887 instr = new(zone()) HBitXor(left, right); 4888 break; 4889 case Token::BIT_AND: 4890 instr = new(zone()) HBitAnd(left, right); 4891 break; 4892 case Token::BIT_OR: 4893 instr = new(zone()) HBitOr(left, right); 4894 break; 4895 case Token::SAR: 4896 instr = new(zone()) HSar(left, right); 4897 break; 4898 case Token::SHR: 4899 instr = new(zone()) HShr(left, right); 4900 break; 4901 case Token::SHL: 4902 instr = new(zone()) HShl(left, right); 4903 break; 4904 default: 4905 UNREACHABLE(); 4906 } 4907 TypeInfo info = oracle()->BinaryType(expr); 4908 // If we hit an uninitialized binary op stub we will get type info 4909 // for a smi operation. If one of the operands is a constant string 4910 // do not generate code assuming it is a smi operation. 4911 if (info.IsSmi() && 4912 ((left->IsConstant() && HConstant::cast(left)->HasStringValue()) || 4913 (right->IsConstant() && HConstant::cast(right)->HasStringValue()))) { 4914 return instr; 4915 } 4916 if (FLAG_trace_representation) { 4917 PrintF("Info: %s/%s\n", info.ToString(), ToRepresentation(info).Mnemonic()); 4918 } 4919 Representation rep = ToRepresentation(info); 4920 // We only generate either int32 or generic tagged bitwise operations. 4921 if (instr->IsBitwiseBinaryOperation() && rep.IsDouble()) { 4922 rep = Representation::Integer32(); 4923 } 4924 AssumeRepresentation(instr, rep); 4925 return instr; 4926 } 4927 4928 4929 // Check for the form (%_ClassOf(foo) === 'BarClass'). 4930 static bool IsClassOfTest(CompareOperation* expr) { 4931 if (expr->op() != Token::EQ_STRICT) return false; 4932 CallRuntime* call = expr->left()->AsCallRuntime(); 4933 if (call == NULL) return false; 4934 Literal* literal = expr->right()->AsLiteral(); 4935 if (literal == NULL) return false; 4936 if (!literal->handle()->IsString()) return false; 4937 if (!call->name()->IsEqualTo(CStrVector("_ClassOf"))) return false; 4938 ASSERT(call->arguments()->length() == 1); 4939 return true; 4940 } 4941 4942 4943 void HGraphBuilder::VisitBinaryOperation(BinaryOperation* expr) { 4944 if (expr->op() == Token::COMMA) { 4945 VISIT_FOR_EFFECT(expr->left()); 4946 // Visit the right subexpression in the same AST context as the entire 4947 // expression. 4948 Visit(expr->right()); 4949 4950 } else if (expr->op() == Token::AND || expr->op() == Token::OR) { 4951 bool is_logical_and = (expr->op() == Token::AND); 4952 if (ast_context()->IsTest()) { 4953 TestContext* context = TestContext::cast(ast_context()); 4954 // Translate left subexpression. 4955 HBasicBlock* eval_right = graph()->CreateBasicBlock(); 4956 if (is_logical_and) { 4957 VISIT_FOR_CONTROL(expr->left(), eval_right, context->if_false()); 4958 } else { 4959 VISIT_FOR_CONTROL(expr->left(), context->if_true(), eval_right); 4960 } 4961 eval_right->SetJoinId(expr->RightId()); 4962 4963 // Translate right subexpression by visiting it in the same AST 4964 // context as the entire expression. 4965 set_current_block(eval_right); 4966 Visit(expr->right()); 4967 4968 } else if (ast_context()->IsValue()) { 4969 VISIT_FOR_VALUE(expr->left()); 4970 ASSERT(current_block() != NULL); 4971 4972 // We need an extra block to maintain edge-split form. 4973 HBasicBlock* empty_block = graph()->CreateBasicBlock(); 4974 HBasicBlock* eval_right = graph()->CreateBasicBlock(); 4975 HTest* test = is_logical_and 4976 ? new(zone()) HTest(Top(), eval_right, empty_block) 4977 : new(zone()) HTest(Top(), empty_block, eval_right); 4978 current_block()->Finish(test); 4979 4980 set_current_block(eval_right); 4981 Drop(1); // Value of the left subexpression. 4982 VISIT_FOR_VALUE(expr->right()); 4983 4984 HBasicBlock* join_block = 4985 CreateJoin(empty_block, current_block(), expr->id()); 4986 set_current_block(join_block); 4987 ast_context()->ReturnValue(Pop()); 4988 4989 } else { 4990 ASSERT(ast_context()->IsEffect()); 4991 // In an effect context, we don't need the value of the left 4992 // subexpression, only its control flow and side effects. We need an 4993 // extra block to maintain edge-split form. 4994 HBasicBlock* empty_block = graph()->CreateBasicBlock(); 4995 HBasicBlock* right_block = graph()->CreateBasicBlock(); 4996 HBasicBlock* join_block = graph()->CreateBasicBlock(); 4997 if (is_logical_and) { 4998 VISIT_FOR_CONTROL(expr->left(), right_block, empty_block); 4999 } else { 5000 VISIT_FOR_CONTROL(expr->left(), empty_block, right_block); 5001 } 5002 // TODO(kmillikin): Find a way to fix this. It's ugly that there are 5003 // actually two empty blocks (one here and one inserted by 5004 // TestContext::BuildBranch, and that they both have an HSimulate 5005 // though the second one is not a merge node, and that we really have 5006 // no good AST ID to put on that first HSimulate. 5007 empty_block->SetJoinId(expr->id()); 5008 right_block->SetJoinId(expr->RightId()); 5009 set_current_block(right_block); 5010 VISIT_FOR_EFFECT(expr->right()); 5011 5012 empty_block->Goto(join_block); 5013 current_block()->Goto(join_block); 5014 join_block->SetJoinId(expr->id()); 5015 set_current_block(join_block); 5016 // We did not materialize any value in the predecessor environments, 5017 // so there is no need to handle it here. 5018 } 5019 5020 } else { 5021 VISIT_FOR_VALUE(expr->left()); 5022 VISIT_FOR_VALUE(expr->right()); 5023 5024 HValue* right = Pop(); 5025 HValue* left = Pop(); 5026 HInstruction* instr = BuildBinaryOperation(expr, left, right); 5027 instr->set_position(expr->position()); 5028 ast_context()->ReturnInstruction(instr, expr->id()); 5029 } 5030 } 5031 5032 5033 void HGraphBuilder::AssumeRepresentation(HValue* value, Representation r) { 5034 if (value->CheckFlag(HValue::kFlexibleRepresentation)) { 5035 if (FLAG_trace_representation) { 5036 PrintF("Assume representation for %s to be %s (%d)\n", 5037 value->Mnemonic(), 5038 r.Mnemonic(), 5039 graph_->GetMaximumValueID()); 5040 } 5041 value->ChangeRepresentation(r); 5042 // The representation of the value is dictated by type feedback and 5043 // will not be changed later. 5044 value->ClearFlag(HValue::kFlexibleRepresentation); 5045 } else if (FLAG_trace_representation) { 5046 PrintF("No representation assumed\n"); 5047 } 5048 } 5049 5050 5051 Representation HGraphBuilder::ToRepresentation(TypeInfo info) { 5052 if (info.IsSmi()) return Representation::Integer32(); 5053 if (info.IsInteger32()) return Representation::Integer32(); 5054 if (info.IsDouble()) return Representation::Double(); 5055 if (info.IsNumber()) return Representation::Double(); 5056 return Representation::Tagged(); 5057 } 5058 5059 5060 void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) { 5061 if (IsClassOfTest(expr)) { 5062 CallRuntime* call = expr->left()->AsCallRuntime(); 5063 VISIT_FOR_VALUE(call->arguments()->at(0)); 5064 HValue* value = Pop(); 5065 Literal* literal = expr->right()->AsLiteral(); 5066 Handle<String> rhs = Handle<String>::cast(literal->handle()); 5067 HInstruction* instr = new(zone()) HClassOfTest(value, rhs); 5068 instr->set_position(expr->position()); 5069 ast_context()->ReturnInstruction(instr, expr->id()); 5070 return; 5071 } 5072 5073 // Check for the pattern: typeof <expression> == <string literal>. 5074 UnaryOperation* left_unary = expr->left()->AsUnaryOperation(); 5075 Literal* right_literal = expr->right()->AsLiteral(); 5076 if ((expr->op() == Token::EQ || expr->op() == Token::EQ_STRICT) && 5077 left_unary != NULL && left_unary->op() == Token::TYPEOF && 5078 right_literal != NULL && right_literal->handle()->IsString()) { 5079 VisitForTypeOf(left_unary->expression()); 5080 if (HasStackOverflow()) return; 5081 HValue* left = Pop(); 5082 HInstruction* instr = new(zone()) HTypeofIs(left, 5083 Handle<String>::cast(right_literal->handle())); 5084 instr->set_position(expr->position()); 5085 ast_context()->ReturnInstruction(instr, expr->id()); 5086 return; 5087 } 5088 5089 VISIT_FOR_VALUE(expr->left()); 5090 VISIT_FOR_VALUE(expr->right()); 5091 5092 HValue* right = Pop(); 5093 HValue* left = Pop(); 5094 Token::Value op = expr->op(); 5095 5096 TypeInfo type_info = oracle()->CompareType(expr); 5097 HInstruction* instr = NULL; 5098 if (op == Token::INSTANCEOF) { 5099 // Check to see if the rhs of the instanceof is a global function not 5100 // residing in new space. If it is we assume that the function will stay the 5101 // same. 5102 Handle<JSFunction> target = Handle<JSFunction>::null(); 5103 Variable* var = expr->right()->AsVariableProxy()->AsVariable(); 5104 bool global_function = (var != NULL) && var->is_global() && !var->is_this(); 5105 if (global_function && 5106 info()->has_global_object() && 5107 !info()->global_object()->IsAccessCheckNeeded()) { 5108 Handle<String> name = var->name(); 5109 Handle<GlobalObject> global(info()->global_object()); 5110 LookupResult lookup; 5111 global->Lookup(*name, &lookup); 5112 if (lookup.IsProperty() && 5113 lookup.type() == NORMAL && 5114 lookup.GetValue()->IsJSFunction()) { 5115 Handle<JSFunction> candidate(JSFunction::cast(lookup.GetValue())); 5116 // If the function is in new space we assume it's more likely to 5117 // change and thus prefer the general IC code. 5118 if (!isolate()->heap()->InNewSpace(*candidate)) { 5119 target = candidate; 5120 } 5121 } 5122 } 5123 5124 // If the target is not null we have found a known global function that is 5125 // assumed to stay the same for this instanceof. 5126 if (target.is_null()) { 5127 HContext* context = new(zone()) HContext; 5128 AddInstruction(context); 5129 instr = new(zone()) HInstanceOf(context, left, right); 5130 } else { 5131 AddInstruction(new(zone()) HCheckFunction(right, target)); 5132 instr = new(zone()) HInstanceOfKnownGlobal(left, target); 5133 } 5134 } else if (op == Token::IN) { 5135 BAILOUT("Unsupported comparison: in"); 5136 } else if (type_info.IsNonPrimitive()) { 5137 switch (op) { 5138 case Token::EQ: 5139 case Token::EQ_STRICT: { 5140 AddInstruction(new(zone()) HCheckNonSmi(left)); 5141 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(left)); 5142 AddInstruction(new(zone()) HCheckNonSmi(right)); 5143 AddInstruction(HCheckInstanceType::NewIsJSObjectOrJSFunction(right)); 5144 instr = new(zone()) HCompareJSObjectEq(left, right); 5145 break; 5146 } 5147 default: 5148 BAILOUT("Unsupported non-primitive compare"); 5149 break; 5150 } 5151 } else { 5152 HCompare* compare = new(zone()) HCompare(left, right, op); 5153 Representation r = ToRepresentation(type_info); 5154 compare->SetInputRepresentation(r); 5155 instr = compare; 5156 } 5157 instr->set_position(expr->position()); 5158 ast_context()->ReturnInstruction(instr, expr->id()); 5159 } 5160 5161 5162 void HGraphBuilder::VisitCompareToNull(CompareToNull* expr) { 5163 VISIT_FOR_VALUE(expr->expression()); 5164 5165 HValue* value = Pop(); 5166 HIsNull* compare = new(zone()) HIsNull(value, expr->is_strict()); 5167 ast_context()->ReturnInstruction(compare, expr->id()); 5168 } 5169 5170 5171 void HGraphBuilder::VisitThisFunction(ThisFunction* expr) { 5172 BAILOUT("ThisFunction"); 5173 } 5174 5175 5176 void HGraphBuilder::VisitDeclaration(Declaration* decl) { 5177 // We allow only declarations that do not require code generation. 5178 // The following all require code generation: global variables and 5179 // functions, variables with slot type LOOKUP, declarations with 5180 // mode CONST, and functions. 5181 Variable* var = decl->proxy()->var(); 5182 Slot* slot = var->AsSlot(); 5183 if (var->is_global() || 5184 (slot != NULL && slot->type() == Slot::LOOKUP) || 5185 decl->mode() == Variable::CONST || 5186 decl->fun() != NULL) { 5187 BAILOUT("unsupported declaration"); 5188 } 5189 } 5190 5191 5192 // Generators for inline runtime functions. 5193 // Support for types. 5194 void HGraphBuilder::GenerateIsSmi(CallRuntime* call) { 5195 ASSERT(call->arguments()->length() == 1); 5196 VISIT_FOR_VALUE(call->arguments()->at(0)); 5197 HValue* value = Pop(); 5198 HIsSmi* result = new(zone()) HIsSmi(value); 5199 ast_context()->ReturnInstruction(result, call->id()); 5200 } 5201 5202 5203 void HGraphBuilder::GenerateIsSpecObject(CallRuntime* call) { 5204 ASSERT(call->arguments()->length() == 1); 5205 VISIT_FOR_VALUE(call->arguments()->at(0)); 5206 HValue* value = Pop(); 5207 HHasInstanceType* result = 5208 new(zone()) HHasInstanceType(value, FIRST_JS_OBJECT_TYPE, LAST_TYPE); 5209 ast_context()->ReturnInstruction(result, call->id()); 5210 } 5211 5212 5213 void HGraphBuilder::GenerateIsFunction(CallRuntime* call) { 5214 ASSERT(call->arguments()->length() == 1); 5215 VISIT_FOR_VALUE(call->arguments()->at(0)); 5216 HValue* value = Pop(); 5217 HHasInstanceType* result = 5218 new(zone()) HHasInstanceType(value, JS_FUNCTION_TYPE); 5219 ast_context()->ReturnInstruction(result, call->id()); 5220 } 5221 5222 5223 void HGraphBuilder::GenerateHasCachedArrayIndex(CallRuntime* call) { 5224 ASSERT(call->arguments()->length() == 1); 5225 VISIT_FOR_VALUE(call->arguments()->at(0)); 5226 HValue* value = Pop(); 5227 HHasCachedArrayIndex* result = new(zone()) HHasCachedArrayIndex(value); 5228 ast_context()->ReturnInstruction(result, call->id()); 5229 } 5230 5231 5232 void HGraphBuilder::GenerateIsArray(CallRuntime* call) { 5233 ASSERT(call->arguments()->length() == 1); 5234 VISIT_FOR_VALUE(call->arguments()->at(0)); 5235 HValue* value = Pop(); 5236 HHasInstanceType* result = new(zone()) HHasInstanceType(value, JS_ARRAY_TYPE); 5237 ast_context()->ReturnInstruction(result, call->id()); 5238 } 5239 5240 5241 void HGraphBuilder::GenerateIsRegExp(CallRuntime* call) { 5242 ASSERT(call->arguments()->length() == 1); 5243 VISIT_FOR_VALUE(call->arguments()->at(0)); 5244 HValue* value = Pop(); 5245 HHasInstanceType* result = 5246 new(zone()) HHasInstanceType(value, JS_REGEXP_TYPE); 5247 ast_context()->ReturnInstruction(result, call->id()); 5248 } 5249 5250 5251 void HGraphBuilder::GenerateIsObject(CallRuntime* call) { 5252 ASSERT(call->arguments()->length() == 1); 5253 VISIT_FOR_VALUE(call->arguments()->at(0)); 5254 HValue* value = Pop(); 5255 HIsObject* test = new(zone()) HIsObject(value); 5256 ast_context()->ReturnInstruction(test, call->id()); 5257 } 5258 5259 5260 void HGraphBuilder::GenerateIsNonNegativeSmi(CallRuntime* call) { 5261 BAILOUT("inlined runtime function: IsNonNegativeSmi"); 5262 } 5263 5264 5265 void HGraphBuilder::GenerateIsUndetectableObject(CallRuntime* call) { 5266 BAILOUT("inlined runtime function: IsUndetectableObject"); 5267 } 5268 5269 5270 void HGraphBuilder::GenerateIsStringWrapperSafeForDefaultValueOf( 5271 CallRuntime* call) { 5272 BAILOUT("inlined runtime function: IsStringWrapperSafeForDefaultValueOf"); 5273 } 5274 5275 5276 // Support for construct call checks. 5277 void HGraphBuilder::GenerateIsConstructCall(CallRuntime* call) { 5278 ASSERT(call->arguments()->length() == 0); 5279 if (function_state()->outer() != NULL) { 5280 // We are generating graph for inlined function. Currently 5281 // constructor inlining is not supported and we can just return 5282 // false from %_IsConstructCall(). 5283 ast_context()->ReturnValue(graph()->GetConstantFalse()); 5284 } else { 5285 ast_context()->ReturnInstruction(new(zone()) HIsConstructCall, call->id()); 5286 } 5287 } 5288 5289 5290 // Support for arguments.length and arguments[?]. 5291 void HGraphBuilder::GenerateArgumentsLength(CallRuntime* call) { 5292 // Our implementation of arguments (based on this stack frame or an 5293 // adapter below it) does not work for inlined functions. This runtime 5294 // function is blacklisted by AstNode::IsInlineable. 5295 ASSERT(function_state()->outer() == NULL); 5296 ASSERT(call->arguments()->length() == 0); 5297 HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); 5298 HArgumentsLength* result = new(zone()) HArgumentsLength(elements); 5299 ast_context()->ReturnInstruction(result, call->id()); 5300 } 5301 5302 5303 void HGraphBuilder::GenerateArguments(CallRuntime* call) { 5304 // Our implementation of arguments (based on this stack frame or an 5305 // adapter below it) does not work for inlined functions. This runtime 5306 // function is blacklisted by AstNode::IsInlineable. 5307 ASSERT(function_state()->outer() == NULL); 5308 ASSERT(call->arguments()->length() == 1); 5309 VISIT_FOR_VALUE(call->arguments()->at(0)); 5310 HValue* index = Pop(); 5311 HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements); 5312 HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements)); 5313 HAccessArgumentsAt* result = 5314 new(zone()) HAccessArgumentsAt(elements, length, index); 5315 ast_context()->ReturnInstruction(result, call->id()); 5316 } 5317 5318 5319 // Support for accessing the class and value fields of an object. 5320 void HGraphBuilder::GenerateClassOf(CallRuntime* call) { 5321 // The special form detected by IsClassOfTest is detected before we get here 5322 // and does not cause a bailout. 5323 BAILOUT("inlined runtime function: ClassOf"); 5324 } 5325 5326 5327 void HGraphBuilder::GenerateValueOf(CallRuntime* call) { 5328 ASSERT(call->arguments()->length() == 1); 5329 VISIT_FOR_VALUE(call->arguments()->at(0)); 5330 HValue* value = Pop(); 5331 HValueOf* result = new(zone()) HValueOf(value); 5332 ast_context()->ReturnInstruction(result, call->id()); 5333 } 5334 5335 5336 void HGraphBuilder::GenerateSetValueOf(CallRuntime* call) { 5337 BAILOUT("inlined runtime function: SetValueOf"); 5338 } 5339 5340 5341 // Fast support for charCodeAt(n). 5342 void HGraphBuilder::GenerateStringCharCodeAt(CallRuntime* call) { 5343 ASSERT(call->arguments()->length() == 2); 5344 VISIT_FOR_VALUE(call->arguments()->at(0)); 5345 VISIT_FOR_VALUE(call->arguments()->at(1)); 5346 HValue* index = Pop(); 5347 HValue* string = Pop(); 5348 HStringCharCodeAt* result = BuildStringCharCodeAt(string, index); 5349 ast_context()->ReturnInstruction(result, call->id()); 5350 } 5351 5352 5353 // Fast support for string.charAt(n) and string[n]. 5354 void HGraphBuilder::GenerateStringCharFromCode(CallRuntime* call) { 5355 ASSERT(call->arguments()->length() == 1); 5356 VISIT_FOR_VALUE(call->arguments()->at(0)); 5357 HValue* char_code = Pop(); 5358 HStringCharFromCode* result = new(zone()) HStringCharFromCode(char_code); 5359 ast_context()->ReturnInstruction(result, call->id()); 5360 } 5361 5362 5363 // Fast support for string.charAt(n) and string[n]. 5364 void HGraphBuilder::GenerateStringCharAt(CallRuntime* call) { 5365 ASSERT(call->arguments()->length() == 2); 5366 VISIT_FOR_VALUE(call->arguments()->at(0)); 5367 VISIT_FOR_VALUE(call->arguments()->at(1)); 5368 HValue* index = Pop(); 5369 HValue* string = Pop(); 5370 HStringCharCodeAt* char_code = BuildStringCharCodeAt(string, index); 5371 AddInstruction(char_code); 5372 HStringCharFromCode* result = new(zone()) HStringCharFromCode(char_code); 5373 ast_context()->ReturnInstruction(result, call->id()); 5374 } 5375 5376 5377 // Fast support for object equality testing. 5378 void HGraphBuilder::GenerateObjectEquals(CallRuntime* call) { 5379 ASSERT(call->arguments()->length() == 2); 5380 VISIT_FOR_VALUE(call->arguments()->at(0)); 5381 VISIT_FOR_VALUE(call->arguments()->at(1)); 5382 HValue* right = Pop(); 5383 HValue* left = Pop(); 5384 HCompareJSObjectEq* result = new(zone()) HCompareJSObjectEq(left, right); 5385 ast_context()->ReturnInstruction(result, call->id()); 5386 } 5387 5388 5389 void HGraphBuilder::GenerateLog(CallRuntime* call) { 5390 // %_Log is ignored in optimized code. 5391 ast_context()->ReturnValue(graph()->GetConstantUndefined()); 5392 } 5393 5394 5395 // Fast support for Math.random(). 5396 void HGraphBuilder::GenerateRandomHeapNumber(CallRuntime* call) { 5397 BAILOUT("inlined runtime function: RandomHeapNumber"); 5398 } 5399 5400 5401 // Fast support for StringAdd. 5402 void HGraphBuilder::GenerateStringAdd(CallRuntime* call) { 5403 ASSERT_EQ(2, call->arguments()->length()); 5404 VisitArgumentList(call->arguments()); 5405 CHECK_BAILOUT; 5406 HContext* context = new(zone()) HContext; 5407 AddInstruction(context); 5408 HCallStub* result = new(zone()) HCallStub(context, CodeStub::StringAdd, 2); 5409 Drop(2); 5410 ast_context()->ReturnInstruction(result, call->id()); 5411 } 5412 5413 5414 // Fast support for SubString. 5415 void HGraphBuilder::GenerateSubString(CallRuntime* call) { 5416 ASSERT_EQ(3, call->arguments()->length()); 5417 VisitArgumentList(call->arguments()); 5418 CHECK_BAILOUT; 5419 HContext* context = new(zone()) HContext; 5420 AddInstruction(context); 5421 HCallStub* result = new(zone()) HCallStub(context, CodeStub::SubString, 3); 5422 Drop(3); 5423 ast_context()->ReturnInstruction(result, call->id()); 5424 } 5425 5426 5427 // Fast support for StringCompare. 5428 void HGraphBuilder::GenerateStringCompare(CallRuntime* call) { 5429 ASSERT_EQ(2, call->arguments()->length()); 5430 VisitArgumentList(call->arguments()); 5431 CHECK_BAILOUT; 5432 HContext* context = new(zone()) HContext; 5433 AddInstruction(context); 5434 HCallStub* result = 5435 new(zone()) HCallStub(context, CodeStub::StringCompare, 2); 5436 Drop(2); 5437 ast_context()->ReturnInstruction(result, call->id()); 5438 } 5439 5440 5441 // Support for direct calls from JavaScript to native RegExp code. 5442 void HGraphBuilder::GenerateRegExpExec(CallRuntime* call) { 5443 ASSERT_EQ(4, call->arguments()->length()); 5444 VisitArgumentList(call->arguments()); 5445 CHECK_BAILOUT; 5446 HContext* context = new(zone()) HContext; 5447 AddInstruction(context); 5448 HCallStub* result = new(zone()) HCallStub(context, CodeStub::RegExpExec, 4); 5449 Drop(4); 5450 ast_context()->ReturnInstruction(result, call->id()); 5451 } 5452 5453 5454 // Construct a RegExp exec result with two in-object properties. 5455 void HGraphBuilder::GenerateRegExpConstructResult(CallRuntime* call) { 5456 ASSERT_EQ(3, call->arguments()->length()); 5457 VisitArgumentList(call->arguments()); 5458 CHECK_BAILOUT; 5459 HContext* context = new(zone()) HContext; 5460 AddInstruction(context); 5461 HCallStub* result = 5462 new(zone()) HCallStub(context, CodeStub::RegExpConstructResult, 3); 5463 Drop(3); 5464 ast_context()->ReturnInstruction(result, call->id()); 5465 } 5466 5467 5468 // Support for fast native caches. 5469 void HGraphBuilder::GenerateGetFromCache(CallRuntime* call) { 5470 BAILOUT("inlined runtime function: GetFromCache"); 5471 } 5472 5473 5474 // Fast support for number to string. 5475 void HGraphBuilder::GenerateNumberToString(CallRuntime* call) { 5476 ASSERT_EQ(1, call->arguments()->length()); 5477 VisitArgumentList(call->arguments()); 5478 CHECK_BAILOUT; 5479 HContext* context = new(zone()) HContext; 5480 AddInstruction(context); 5481 HCallStub* result = 5482 new(zone()) HCallStub(context, CodeStub::NumberToString, 1); 5483 Drop(1); 5484 ast_context()->ReturnInstruction(result, call->id()); 5485 } 5486 5487 5488 // Fast swapping of elements. Takes three expressions, the object and two 5489 // indices. This should only be used if the indices are known to be 5490 // non-negative and within bounds of the elements array at the call site. 5491 void HGraphBuilder::GenerateSwapElements(CallRuntime* call) { 5492 BAILOUT("inlined runtime function: SwapElements"); 5493 } 5494 5495 5496 // Fast call for custom callbacks. 5497 void HGraphBuilder::GenerateCallFunction(CallRuntime* call) { 5498 BAILOUT("inlined runtime function: CallFunction"); 5499 } 5500 5501 5502 // Fast call to math functions. 5503 void HGraphBuilder::GenerateMathPow(CallRuntime* call) { 5504 ASSERT_EQ(2, call->arguments()->length()); 5505 VISIT_FOR_VALUE(call->arguments()->at(0)); 5506 VISIT_FOR_VALUE(call->arguments()->at(1)); 5507 HValue* right = Pop(); 5508 HValue* left = Pop(); 5509 HPower* result = new(zone()) HPower(left, right); 5510 ast_context()->ReturnInstruction(result, call->id()); 5511 } 5512 5513 5514 void HGraphBuilder::GenerateMathSin(CallRuntime* call) { 5515 ASSERT_EQ(1, call->arguments()->length()); 5516 VisitArgumentList(call->arguments()); 5517 CHECK_BAILOUT; 5518 HContext* context = new(zone()) HContext; 5519 AddInstruction(context); 5520 HCallStub* result = 5521 new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1); 5522 result->set_transcendental_type(TranscendentalCache::SIN); 5523 Drop(1); 5524 ast_context()->ReturnInstruction(result, call->id()); 5525 } 5526 5527 5528 void HGraphBuilder::GenerateMathCos(CallRuntime* call) { 5529 ASSERT_EQ(1, call->arguments()->length()); 5530 VisitArgumentList(call->arguments()); 5531 CHECK_BAILOUT; 5532 HContext* context = new(zone()) HContext; 5533 AddInstruction(context); 5534 HCallStub* result = 5535 new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1); 5536 result->set_transcendental_type(TranscendentalCache::COS); 5537 Drop(1); 5538 ast_context()->ReturnInstruction(result, call->id()); 5539 } 5540 5541 5542 void HGraphBuilder::GenerateMathLog(CallRuntime* call) { 5543 ASSERT_EQ(1, call->arguments()->length()); 5544 VisitArgumentList(call->arguments()); 5545 CHECK_BAILOUT; 5546 HContext* context = new(zone()) HContext; 5547 AddInstruction(context); 5548 HCallStub* result = 5549 new(zone()) HCallStub(context, CodeStub::TranscendentalCache, 1); 5550 result->set_transcendental_type(TranscendentalCache::LOG); 5551 Drop(1); 5552 ast_context()->ReturnInstruction(result, call->id()); 5553 } 5554 5555 5556 void HGraphBuilder::GenerateMathSqrt(CallRuntime* call) { 5557 BAILOUT("inlined runtime function: MathSqrt"); 5558 } 5559 5560 5561 // Check whether two RegExps are equivalent 5562 void HGraphBuilder::GenerateIsRegExpEquivalent(CallRuntime* call) { 5563 BAILOUT("inlined runtime function: IsRegExpEquivalent"); 5564 } 5565 5566 5567 void HGraphBuilder::GenerateGetCachedArrayIndex(CallRuntime* call) { 5568 ASSERT(call->arguments()->length() == 1); 5569 VISIT_FOR_VALUE(call->arguments()->at(0)); 5570 HValue* value = Pop(); 5571 HGetCachedArrayIndex* result = new(zone()) HGetCachedArrayIndex(value); 5572 ast_context()->ReturnInstruction(result, call->id()); 5573 } 5574 5575 5576 void HGraphBuilder::GenerateFastAsciiArrayJoin(CallRuntime* call) { 5577 BAILOUT("inlined runtime function: FastAsciiArrayJoin"); 5578 } 5579 5580 5581 #undef BAILOUT 5582 #undef CHECK_BAILOUT 5583 #undef VISIT_FOR_EFFECT 5584 #undef VISIT_FOR_VALUE 5585 #undef ADD_TO_SUBGRAPH 5586 5587 5588 HEnvironment::HEnvironment(HEnvironment* outer, 5589 Scope* scope, 5590 Handle<JSFunction> closure) 5591 : closure_(closure), 5592 values_(0), 5593 assigned_variables_(4), 5594 parameter_count_(0), 5595 local_count_(0), 5596 outer_(outer), 5597 pop_count_(0), 5598 push_count_(0), 5599 ast_id_(AstNode::kNoNumber) { 5600 Initialize(scope->num_parameters() + 1, scope->num_stack_slots(), 0); 5601 } 5602 5603 5604 HEnvironment::HEnvironment(const HEnvironment* other) 5605 : values_(0), 5606 assigned_variables_(0), 5607 parameter_count_(0), 5608 local_count_(0), 5609 outer_(NULL), 5610 pop_count_(0), 5611 push_count_(0), 5612 ast_id_(other->ast_id()) { 5613 Initialize(other); 5614 } 5615 5616 5617 void HEnvironment::Initialize(int parameter_count, 5618 int local_count, 5619 int stack_height) { 5620 parameter_count_ = parameter_count; 5621 local_count_ = local_count; 5622 5623 // Avoid reallocating the temporaries' backing store on the first Push. 5624 int total = parameter_count + local_count + stack_height; 5625 values_.Initialize(total + 4); 5626 for (int i = 0; i < total; ++i) values_.Add(NULL); 5627 } 5628 5629 5630 void HEnvironment::Initialize(const HEnvironment* other) { 5631 closure_ = other->closure(); 5632 values_.AddAll(other->values_); 5633 assigned_variables_.AddAll(other->assigned_variables_); 5634 parameter_count_ = other->parameter_count_; 5635 local_count_ = other->local_count_; 5636 if (other->outer_ != NULL) outer_ = other->outer_->Copy(); // Deep copy. 5637 pop_count_ = other->pop_count_; 5638 push_count_ = other->push_count_; 5639 ast_id_ = other->ast_id_; 5640 } 5641 5642 5643 void HEnvironment::AddIncomingEdge(HBasicBlock* block, HEnvironment* other) { 5644 ASSERT(!block->IsLoopHeader()); 5645 ASSERT(values_.length() == other->values_.length()); 5646 5647 int length = values_.length(); 5648 for (int i = 0; i < length; ++i) { 5649 HValue* value = values_[i]; 5650 if (value != NULL && value->IsPhi() && value->block() == block) { 5651 // There is already a phi for the i'th value. 5652 HPhi* phi = HPhi::cast(value); 5653 // Assert index is correct and that we haven't missed an incoming edge. 5654 ASSERT(phi->merged_index() == i); 5655 ASSERT(phi->OperandCount() == block->predecessors()->length()); 5656 phi->AddInput(other->values_[i]); 5657 } else if (values_[i] != other->values_[i]) { 5658 // There is a fresh value on the incoming edge, a phi is needed. 5659 ASSERT(values_[i] != NULL && other->values_[i] != NULL); 5660 HPhi* phi = new(block->zone()) HPhi(i); 5661 HValue* old_value = values_[i]; 5662 for (int j = 0; j < block->predecessors()->length(); j++) { 5663 phi->AddInput(old_value); 5664 } 5665 phi->AddInput(other->values_[i]); 5666 this->values_[i] = phi; 5667 block->AddPhi(phi); 5668 } 5669 } 5670 } 5671 5672 5673 void HEnvironment::Bind(int index, HValue* value) { 5674 ASSERT(value != NULL); 5675 if (!assigned_variables_.Contains(index)) { 5676 assigned_variables_.Add(index); 5677 } 5678 values_[index] = value; 5679 } 5680 5681 5682 bool HEnvironment::HasExpressionAt(int index) const { 5683 return index >= parameter_count_ + local_count_; 5684 } 5685 5686 5687 bool HEnvironment::ExpressionStackIsEmpty() const { 5688 int first_expression = parameter_count() + local_count(); 5689 ASSERT(length() >= first_expression); 5690 return length() == first_expression; 5691 } 5692 5693 5694 void HEnvironment::SetExpressionStackAt(int index_from_top, HValue* value) { 5695 int count = index_from_top + 1; 5696 int index = values_.length() - count; 5697 ASSERT(HasExpressionAt(index)); 5698 // The push count must include at least the element in question or else 5699 // the new value will not be included in this environment's history. 5700 if (push_count_ < count) { 5701 // This is the same effect as popping then re-pushing 'count' elements. 5702 pop_count_ += (count - push_count_); 5703 push_count_ = count; 5704 } 5705 values_[index] = value; 5706 } 5707 5708 5709 void HEnvironment::Drop(int count) { 5710 for (int i = 0; i < count; ++i) { 5711 Pop(); 5712 } 5713 } 5714 5715 5716 HEnvironment* HEnvironment::Copy() const { 5717 return new(closure()->GetIsolate()->zone()) HEnvironment(this); 5718 } 5719 5720 5721 HEnvironment* HEnvironment::CopyWithoutHistory() const { 5722 HEnvironment* result = Copy(); 5723 result->ClearHistory(); 5724 return result; 5725 } 5726 5727 5728 HEnvironment* HEnvironment::CopyAsLoopHeader(HBasicBlock* loop_header) const { 5729 HEnvironment* new_env = Copy(); 5730 for (int i = 0; i < values_.length(); ++i) { 5731 HPhi* phi = new(loop_header->zone()) HPhi(i); 5732 phi->AddInput(values_[i]); 5733 new_env->values_[i] = phi; 5734 loop_header->AddPhi(phi); 5735 } 5736 new_env->ClearHistory(); 5737 return new_env; 5738 } 5739 5740 5741 HEnvironment* HEnvironment::CopyForInlining(Handle<JSFunction> target, 5742 FunctionLiteral* function, 5743 bool is_speculative, 5744 HConstant* undefined) const { 5745 // Outer environment is a copy of this one without the arguments. 5746 int arity = function->scope()->num_parameters(); 5747 HEnvironment* outer = Copy(); 5748 outer->Drop(arity + 1); // Including receiver. 5749 outer->ClearHistory(); 5750 Zone* zone = closure()->GetIsolate()->zone(); 5751 HEnvironment* inner = 5752 new(zone) HEnvironment(outer, function->scope(), target); 5753 // Get the argument values from the original environment. 5754 if (is_speculative) { 5755 for (int i = 0; i <= arity; ++i) { // Include receiver. 5756 HValue* push = ExpressionStackAt(arity - i); 5757 inner->SetValueAt(i, push); 5758 } 5759 } else { 5760 for (int i = 0; i <= arity; ++i) { // Include receiver. 5761 inner->SetValueAt(i, ExpressionStackAt(arity - i)); 5762 } 5763 } 5764 5765 // Initialize the stack-allocated locals to undefined. 5766 int local_base = arity + 1; 5767 int local_count = function->scope()->num_stack_slots(); 5768 for (int i = 0; i < local_count; ++i) { 5769 inner->SetValueAt(local_base + i, undefined); 5770 } 5771 5772 inner->set_ast_id(AstNode::kFunctionEntryId); 5773 return inner; 5774 } 5775 5776 5777 void HEnvironment::PrintTo(StringStream* stream) { 5778 for (int i = 0; i < length(); i++) { 5779 if (i == 0) stream->Add("parameters\n"); 5780 if (i == parameter_count()) stream->Add("locals\n"); 5781 if (i == parameter_count() + local_count()) stream->Add("expressions"); 5782 HValue* val = values_.at(i); 5783 stream->Add("%d: ", i); 5784 if (val != NULL) { 5785 val->PrintNameTo(stream); 5786 } else { 5787 stream->Add("NULL"); 5788 } 5789 stream->Add("\n"); 5790 } 5791 } 5792 5793 5794 void HEnvironment::PrintToStd() { 5795 HeapStringAllocator string_allocator; 5796 StringStream trace(&string_allocator); 5797 PrintTo(&trace); 5798 PrintF("%s", *trace.ToCString()); 5799 } 5800 5801 5802 void HTracer::TraceCompilation(FunctionLiteral* function) { 5803 Tag tag(this, "compilation"); 5804 Handle<String> name = function->debug_name(); 5805 PrintStringProperty("name", *name->ToCString()); 5806 PrintStringProperty("method", *name->ToCString()); 5807 PrintLongProperty("date", static_cast<int64_t>(OS::TimeCurrentMillis())); 5808 } 5809 5810 5811 void HTracer::TraceLithium(const char* name, LChunk* chunk) { 5812 Trace(name, chunk->graph(), chunk); 5813 } 5814 5815 5816 void HTracer::TraceHydrogen(const char* name, HGraph* graph) { 5817 Trace(name, graph, NULL); 5818 } 5819 5820 5821 void HTracer::Trace(const char* name, HGraph* graph, LChunk* chunk) { 5822 Tag tag(this, "cfg"); 5823 PrintStringProperty("name", name); 5824 const ZoneList<HBasicBlock*>* blocks = graph->blocks(); 5825 for (int i = 0; i < blocks->length(); i++) { 5826 HBasicBlock* current = blocks->at(i); 5827 Tag block_tag(this, "block"); 5828 PrintBlockProperty("name", current->block_id()); 5829 PrintIntProperty("from_bci", -1); 5830 PrintIntProperty("to_bci", -1); 5831 5832 if (!current->predecessors()->is_empty()) { 5833 PrintIndent(); 5834 trace_.Add("predecessors"); 5835 for (int j = 0; j < current->predecessors()->length(); ++j) { 5836 trace_.Add(" \"B%d\"", current->predecessors()->at(j)->block_id()); 5837 } 5838 trace_.Add("\n"); 5839 } else { 5840 PrintEmptyProperty("predecessors"); 5841 } 5842 5843 if (current->end() == NULL || current->end()->FirstSuccessor() == NULL) { 5844 PrintEmptyProperty("successors"); 5845 } else if (current->end()->SecondSuccessor() == NULL) { 5846 PrintBlockProperty("successors", 5847 current->end()->FirstSuccessor()->block_id()); 5848 } else { 5849 PrintBlockProperty("successors", 5850 current->end()->FirstSuccessor()->block_id(), 5851 current->end()->SecondSuccessor()->block_id()); 5852 } 5853 5854 PrintEmptyProperty("xhandlers"); 5855 PrintEmptyProperty("flags"); 5856 5857 if (current->dominator() != NULL) { 5858 PrintBlockProperty("dominator", current->dominator()->block_id()); 5859 } 5860 5861 if (chunk != NULL) { 5862 int first_index = current->first_instruction_index(); 5863 int last_index = current->last_instruction_index(); 5864 PrintIntProperty( 5865 "first_lir_id", 5866 LifetimePosition::FromInstructionIndex(first_index).Value()); 5867 PrintIntProperty( 5868 "last_lir_id", 5869 LifetimePosition::FromInstructionIndex(last_index).Value()); 5870 } 5871 5872 { 5873 Tag states_tag(this, "states"); 5874 Tag locals_tag(this, "locals"); 5875 int total = current->phis()->length(); 5876 trace_.Add("size %d\n", total); 5877 trace_.Add("method \"None\""); 5878 for (int j = 0; j < total; ++j) { 5879 HPhi* phi = current->phis()->at(j); 5880 trace_.Add("%d ", phi->merged_index()); 5881 phi->PrintNameTo(&trace_); 5882 trace_.Add(" "); 5883 phi->PrintTo(&trace_); 5884 trace_.Add("\n"); 5885 } 5886 } 5887 5888 { 5889 Tag HIR_tag(this, "HIR"); 5890 HInstruction* instruction = current->first(); 5891 while (instruction != NULL) { 5892 int bci = 0; 5893 int uses = instruction->uses()->length(); 5894 trace_.Add("%d %d ", bci, uses); 5895 instruction->PrintNameTo(&trace_); 5896 trace_.Add(" "); 5897 instruction->PrintTo(&trace_); 5898 trace_.Add(" <|@\n"); 5899 instruction = instruction->next(); 5900 } 5901 } 5902 5903 5904 if (chunk != NULL) { 5905 Tag LIR_tag(this, "LIR"); 5906 int first_index = current->first_instruction_index(); 5907 int last_index = current->last_instruction_index(); 5908 if (first_index != -1 && last_index != -1) { 5909 const ZoneList<LInstruction*>* instructions = chunk->instructions(); 5910 for (int i = first_index; i <= last_index; ++i) { 5911 LInstruction* linstr = instructions->at(i); 5912 if (linstr != NULL) { 5913 trace_.Add("%d ", 5914 LifetimePosition::FromInstructionIndex(i).Value()); 5915 linstr->PrintTo(&trace_); 5916 trace_.Add(" <|@\n"); 5917 } 5918 } 5919 } 5920 } 5921 } 5922 } 5923 5924 5925 void HTracer::TraceLiveRanges(const char* name, LAllocator* allocator) { 5926 Tag tag(this, "intervals"); 5927 PrintStringProperty("name", name); 5928 5929 const Vector<LiveRange*>* fixed_d = allocator->fixed_double_live_ranges(); 5930 for (int i = 0; i < fixed_d->length(); ++i) { 5931 TraceLiveRange(fixed_d->at(i), "fixed"); 5932 } 5933 5934 const Vector<LiveRange*>* fixed = allocator->fixed_live_ranges(); 5935 for (int i = 0; i < fixed->length(); ++i) { 5936 TraceLiveRange(fixed->at(i), "fixed"); 5937 } 5938 5939 const ZoneList<LiveRange*>* live_ranges = allocator->live_ranges(); 5940 for (int i = 0; i < live_ranges->length(); ++i) { 5941 TraceLiveRange(live_ranges->at(i), "object"); 5942 } 5943 } 5944 5945 5946 void HTracer::TraceLiveRange(LiveRange* range, const char* type) { 5947 if (range != NULL && !range->IsEmpty()) { 5948 trace_.Add("%d %s", range->id(), type); 5949 if (range->HasRegisterAssigned()) { 5950 LOperand* op = range->CreateAssignedOperand(); 5951 int assigned_reg = op->index(); 5952 if (op->IsDoubleRegister()) { 5953 trace_.Add(" \"%s\"", 5954 DoubleRegister::AllocationIndexToString(assigned_reg)); 5955 } else { 5956 ASSERT(op->IsRegister()); 5957 trace_.Add(" \"%s\"", Register::AllocationIndexToString(assigned_reg)); 5958 } 5959 } else if (range->IsSpilled()) { 5960 LOperand* op = range->TopLevel()->GetSpillOperand(); 5961 if (op->IsDoubleStackSlot()) { 5962 trace_.Add(" \"double_stack:%d\"", op->index()); 5963 } else { 5964 ASSERT(op->IsStackSlot()); 5965 trace_.Add(" \"stack:%d\"", op->index()); 5966 } 5967 } 5968 int parent_index = -1; 5969 if (range->IsChild()) { 5970 parent_index = range->parent()->id(); 5971 } else { 5972 parent_index = range->id(); 5973 } 5974 LOperand* op = range->FirstHint(); 5975 int hint_index = -1; 5976 if (op != NULL && op->IsUnallocated()) hint_index = op->VirtualRegister(); 5977 trace_.Add(" %d %d", parent_index, hint_index); 5978 UseInterval* cur_interval = range->first_interval(); 5979 while (cur_interval != NULL && range->Covers(cur_interval->start())) { 5980 trace_.Add(" [%d, %d[", 5981 cur_interval->start().Value(), 5982 cur_interval->end().Value()); 5983 cur_interval = cur_interval->next(); 5984 } 5985 5986 UsePosition* current_pos = range->first_pos(); 5987 while (current_pos != NULL) { 5988 if (current_pos->RegisterIsBeneficial() || FLAG_trace_all_uses) { 5989 trace_.Add(" %d M", current_pos->pos().Value()); 5990 } 5991 current_pos = current_pos->next(); 5992 } 5993 5994 trace_.Add(" \"\"\n"); 5995 } 5996 } 5997 5998 5999 void HTracer::FlushToFile() { 6000 AppendChars(filename_, *trace_.ToCString(), trace_.length(), false); 6001 trace_.Reset(); 6002 } 6003 6004 6005 void HStatistics::Initialize(CompilationInfo* info) { 6006 source_size_ += info->shared_info()->SourceSize(); 6007 } 6008 6009 6010 void HStatistics::Print() { 6011 PrintF("Timing results:\n"); 6012 int64_t sum = 0; 6013 for (int i = 0; i < timing_.length(); ++i) { 6014 sum += timing_[i]; 6015 } 6016 6017 for (int i = 0; i < names_.length(); ++i) { 6018 PrintF("%30s", names_[i]); 6019 double ms = static_cast<double>(timing_[i]) / 1000; 6020 double percent = static_cast<double>(timing_[i]) * 100 / sum; 6021 PrintF(" - %7.3f ms / %4.1f %% ", ms, percent); 6022 6023 unsigned size = sizes_[i]; 6024 double size_percent = static_cast<double>(size) * 100 / total_size_; 6025 PrintF(" %8u bytes / %4.1f %%\n", size, size_percent); 6026 } 6027 double source_size_in_kb = static_cast<double>(source_size_) / 1024; 6028 double normalized_time = source_size_in_kb > 0 6029 ? (static_cast<double>(sum) / 1000) / source_size_in_kb 6030 : 0; 6031 double normalized_bytes = source_size_in_kb > 0 6032 ? total_size_ / source_size_in_kb 6033 : 0; 6034 PrintF("%30s - %7.3f ms %7.3f bytes\n", "Sum", 6035 normalized_time, normalized_bytes); 6036 PrintF("---------------------------------------------------------------\n"); 6037 PrintF("%30s - %7.3f ms (%.1f times slower than full code gen)\n", 6038 "Total", 6039 static_cast<double>(total_) / 1000, 6040 static_cast<double>(total_) / full_code_gen_); 6041 } 6042 6043 6044 void HStatistics::SaveTiming(const char* name, int64_t ticks, unsigned size) { 6045 if (name == HPhase::kFullCodeGen) { 6046 full_code_gen_ += ticks; 6047 } else if (name == HPhase::kTotal) { 6048 total_ += ticks; 6049 } else { 6050 total_size_ += size; 6051 for (int i = 0; i < names_.length(); ++i) { 6052 if (names_[i] == name) { 6053 timing_[i] += ticks; 6054 sizes_[i] += size; 6055 return; 6056 } 6057 } 6058 names_.Add(name); 6059 timing_.Add(ticks); 6060 sizes_.Add(size); 6061 } 6062 } 6063 6064 6065 const char* const HPhase::kFullCodeGen = "Full code generator"; 6066 const char* const HPhase::kTotal = "Total"; 6067 6068 6069 void HPhase::Begin(const char* name, 6070 HGraph* graph, 6071 LChunk* chunk, 6072 LAllocator* allocator) { 6073 name_ = name; 6074 graph_ = graph; 6075 chunk_ = chunk; 6076 allocator_ = allocator; 6077 if (allocator != NULL && chunk_ == NULL) { 6078 chunk_ = allocator->chunk(); 6079 } 6080 if (FLAG_hydrogen_stats) start_ = OS::Ticks(); 6081 start_allocation_size_ = Zone::allocation_size_; 6082 } 6083 6084 6085 void HPhase::End() const { 6086 if (FLAG_hydrogen_stats) { 6087 int64_t end = OS::Ticks(); 6088 unsigned size = Zone::allocation_size_ - start_allocation_size_; 6089 HStatistics::Instance()->SaveTiming(name_, end - start_, size); 6090 } 6091 6092 if (FLAG_trace_hydrogen) { 6093 if (graph_ != NULL) HTracer::Instance()->TraceHydrogen(name_, graph_); 6094 if (chunk_ != NULL) HTracer::Instance()->TraceLithium(name_, chunk_); 6095 if (allocator_ != NULL) { 6096 HTracer::Instance()->TraceLiveRanges(name_, allocator_); 6097 } 6098 } 6099 6100 #ifdef DEBUG 6101 if (graph_ != NULL) graph_->Verify(); 6102 if (allocator_ != NULL) allocator_->Verify(); 6103 #endif 6104 } 6105 6106 } } // namespace v8::internal 6107