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 30#include "lithium-allocator-inl.h" 31#include "arm/lithium-arm.h" 32#include "arm/lithium-codegen-arm.h" 33 34namespace v8 { 35namespace internal { 36 37#define DEFINE_COMPILE(type) \ 38 void L##type::CompileToNative(LCodeGen* generator) { \ 39 generator->Do##type(this); \ 40 } 41LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE) 42#undef DEFINE_COMPILE 43 44LOsrEntry::LOsrEntry() { 45 for (int i = 0; i < Register::kNumAllocatableRegisters; ++i) { 46 register_spills_[i] = NULL; 47 } 48 for (int i = 0; i < DoubleRegister::kNumAllocatableRegisters; ++i) { 49 double_register_spills_[i] = NULL; 50 } 51} 52 53 54void LOsrEntry::MarkSpilledRegister(int allocation_index, 55 LOperand* spill_operand) { 56 ASSERT(spill_operand->IsStackSlot()); 57 ASSERT(register_spills_[allocation_index] == NULL); 58 register_spills_[allocation_index] = spill_operand; 59} 60 61 62#ifdef DEBUG 63void LInstruction::VerifyCall() { 64 // Call instructions can use only fixed registers as 65 // temporaries and outputs because all registers 66 // are blocked by the calling convention. 67 // Inputs must use a fixed register. 68 ASSERT(Output() == NULL || 69 LUnallocated::cast(Output())->HasFixedPolicy() || 70 !LUnallocated::cast(Output())->HasRegisterPolicy()); 71 for (UseIterator it(this); it.HasNext(); it.Advance()) { 72 LOperand* operand = it.Next(); 73 ASSERT(LUnallocated::cast(operand)->HasFixedPolicy() || 74 !LUnallocated::cast(operand)->HasRegisterPolicy()); 75 } 76 for (TempIterator it(this); it.HasNext(); it.Advance()) { 77 LOperand* operand = it.Next(); 78 ASSERT(LUnallocated::cast(operand)->HasFixedPolicy() || 79 !LUnallocated::cast(operand)->HasRegisterPolicy()); 80 } 81} 82#endif 83 84 85void LOsrEntry::MarkSpilledDoubleRegister(int allocation_index, 86 LOperand* spill_operand) { 87 ASSERT(spill_operand->IsDoubleStackSlot()); 88 ASSERT(double_register_spills_[allocation_index] == NULL); 89 double_register_spills_[allocation_index] = spill_operand; 90} 91 92 93void LInstruction::PrintTo(StringStream* stream) { 94 stream->Add("%s ", this->Mnemonic()); 95 96 PrintOutputOperandTo(stream); 97 98 PrintDataTo(stream); 99 100 if (HasEnvironment()) { 101 stream->Add(" "); 102 environment()->PrintTo(stream); 103 } 104 105 if (HasPointerMap()) { 106 stream->Add(" "); 107 pointer_map()->PrintTo(stream); 108 } 109} 110 111 112template<int R, int I, int T> 113void LTemplateInstruction<R, I, T>::PrintDataTo(StringStream* stream) { 114 stream->Add("= "); 115 inputs_.PrintOperandsTo(stream); 116} 117 118 119template<int R, int I, int T> 120void LTemplateInstruction<R, I, T>::PrintOutputOperandTo(StringStream* stream) { 121 results_.PrintOperandsTo(stream); 122} 123 124 125template<typename T, int N> 126void OperandContainer<T, N>::PrintOperandsTo(StringStream* stream) { 127 for (int i = 0; i < N; i++) { 128 if (i > 0) stream->Add(" "); 129 elems_[i]->PrintTo(stream); 130 } 131} 132 133 134void LLabel::PrintDataTo(StringStream* stream) { 135 LGap::PrintDataTo(stream); 136 LLabel* rep = replacement(); 137 if (rep != NULL) { 138 stream->Add(" Dead block replaced with B%d", rep->block_id()); 139 } 140} 141 142 143bool LGap::IsRedundant() const { 144 for (int i = 0; i < 4; i++) { 145 if (parallel_moves_[i] != NULL && !parallel_moves_[i]->IsRedundant()) { 146 return false; 147 } 148 } 149 150 return true; 151} 152 153 154void LGap::PrintDataTo(StringStream* stream) const { 155 for (int i = 0; i < 4; i++) { 156 stream->Add("("); 157 if (parallel_moves_[i] != NULL) { 158 parallel_moves_[i]->PrintDataTo(stream); 159 } 160 stream->Add(") "); 161 } 162} 163 164 165const char* LArithmeticD::Mnemonic() const { 166 switch (op()) { 167 case Token::ADD: return "add-d"; 168 case Token::SUB: return "sub-d"; 169 case Token::MUL: return "mul-d"; 170 case Token::DIV: return "div-d"; 171 case Token::MOD: return "mod-d"; 172 default: 173 UNREACHABLE(); 174 return NULL; 175 } 176} 177 178 179const char* LArithmeticT::Mnemonic() const { 180 switch (op()) { 181 case Token::ADD: return "add-t"; 182 case Token::SUB: return "sub-t"; 183 case Token::MUL: return "mul-t"; 184 case Token::MOD: return "mod-t"; 185 case Token::DIV: return "div-t"; 186 case Token::BIT_AND: return "bit-and-t"; 187 case Token::BIT_OR: return "bit-or-t"; 188 case Token::BIT_XOR: return "bit-xor-t"; 189 case Token::SHL: return "shl-t"; 190 case Token::SAR: return "sar-t"; 191 case Token::SHR: return "shr-t"; 192 default: 193 UNREACHABLE(); 194 return NULL; 195 } 196} 197 198 199void LGoto::PrintDataTo(StringStream* stream) { 200 stream->Add("B%d", block_id()); 201} 202 203 204void LBranch::PrintDataTo(StringStream* stream) { 205 stream->Add("B%d | B%d on ", true_block_id(), false_block_id()); 206 InputAt(0)->PrintTo(stream); 207} 208 209 210void LCmpIDAndBranch::PrintDataTo(StringStream* stream) { 211 stream->Add("if "); 212 InputAt(0)->PrintTo(stream); 213 stream->Add(" %s ", Token::String(op())); 214 InputAt(1)->PrintTo(stream); 215 stream->Add(" then B%d else B%d", true_block_id(), false_block_id()); 216} 217 218 219void LIsNullAndBranch::PrintDataTo(StringStream* stream) { 220 stream->Add("if "); 221 InputAt(0)->PrintTo(stream); 222 stream->Add(is_strict() ? " === null" : " == null"); 223 stream->Add(" then B%d else B%d", true_block_id(), false_block_id()); 224} 225 226 227void LIsObjectAndBranch::PrintDataTo(StringStream* stream) { 228 stream->Add("if is_object("); 229 InputAt(0)->PrintTo(stream); 230 stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); 231} 232 233 234void LIsSmiAndBranch::PrintDataTo(StringStream* stream) { 235 stream->Add("if is_smi("); 236 InputAt(0)->PrintTo(stream); 237 stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); 238} 239 240 241void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) { 242 stream->Add("if has_instance_type("); 243 InputAt(0)->PrintTo(stream); 244 stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); 245} 246 247 248void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) { 249 stream->Add("if has_cached_array_index("); 250 InputAt(0)->PrintTo(stream); 251 stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); 252} 253 254 255void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) { 256 stream->Add("if class_of_test("); 257 InputAt(0)->PrintTo(stream); 258 stream->Add(", \"%o\") then B%d else B%d", 259 *hydrogen()->class_name(), 260 true_block_id(), 261 false_block_id()); 262} 263 264 265void LTypeofIs::PrintDataTo(StringStream* stream) { 266 InputAt(0)->PrintTo(stream); 267 stream->Add(" == \"%s\"", *hydrogen()->type_literal()->ToCString()); 268} 269 270 271void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) { 272 stream->Add("if typeof "); 273 InputAt(0)->PrintTo(stream); 274 stream->Add(" == \"%s\" then B%d else B%d", 275 *hydrogen()->type_literal()->ToCString(), 276 true_block_id(), false_block_id()); 277} 278 279 280void LCallConstantFunction::PrintDataTo(StringStream* stream) { 281 stream->Add("#%d / ", arity()); 282} 283 284 285void LUnaryMathOperation::PrintDataTo(StringStream* stream) { 286 stream->Add("/%s ", hydrogen()->OpName()); 287 InputAt(0)->PrintTo(stream); 288} 289 290 291void LLoadContextSlot::PrintDataTo(StringStream* stream) { 292 InputAt(0)->PrintTo(stream); 293 stream->Add("[%d]", slot_index()); 294} 295 296 297void LStoreContextSlot::PrintDataTo(StringStream* stream) { 298 InputAt(0)->PrintTo(stream); 299 stream->Add("[%d] <- ", slot_index()); 300 InputAt(1)->PrintTo(stream); 301} 302 303 304void LCallKeyed::PrintDataTo(StringStream* stream) { 305 stream->Add("[r2] #%d / ", arity()); 306} 307 308 309void LCallNamed::PrintDataTo(StringStream* stream) { 310 SmartPointer<char> name_string = name()->ToCString(); 311 stream->Add("%s #%d / ", *name_string, arity()); 312} 313 314 315void LCallGlobal::PrintDataTo(StringStream* stream) { 316 SmartPointer<char> name_string = name()->ToCString(); 317 stream->Add("%s #%d / ", *name_string, arity()); 318} 319 320 321void LCallKnownGlobal::PrintDataTo(StringStream* stream) { 322 stream->Add("#%d / ", arity()); 323} 324 325 326void LCallNew::PrintDataTo(StringStream* stream) { 327 stream->Add("= "); 328 InputAt(0)->PrintTo(stream); 329 stream->Add(" #%d / ", arity()); 330} 331 332 333void LClassOfTest::PrintDataTo(StringStream* stream) { 334 stream->Add("= class_of_test("); 335 InputAt(0)->PrintTo(stream); 336 stream->Add(", \"%o\")", *hydrogen()->class_name()); 337} 338 339 340void LAccessArgumentsAt::PrintDataTo(StringStream* stream) { 341 arguments()->PrintTo(stream); 342 343 stream->Add(" length "); 344 length()->PrintTo(stream); 345 346 stream->Add(" index "); 347 index()->PrintTo(stream); 348} 349 350 351void LStoreNamedField::PrintDataTo(StringStream* stream) { 352 object()->PrintTo(stream); 353 stream->Add("."); 354 stream->Add(*String::cast(*name())->ToCString()); 355 stream->Add(" <- "); 356 value()->PrintTo(stream); 357} 358 359 360void LStoreNamedGeneric::PrintDataTo(StringStream* stream) { 361 object()->PrintTo(stream); 362 stream->Add("."); 363 stream->Add(*String::cast(*name())->ToCString()); 364 stream->Add(" <- "); 365 value()->PrintTo(stream); 366} 367 368 369void LStoreKeyedFastElement::PrintDataTo(StringStream* stream) { 370 object()->PrintTo(stream); 371 stream->Add("["); 372 key()->PrintTo(stream); 373 stream->Add("] <- "); 374 value()->PrintTo(stream); 375} 376 377 378void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) { 379 object()->PrintTo(stream); 380 stream->Add("["); 381 key()->PrintTo(stream); 382 stream->Add("] <- "); 383 value()->PrintTo(stream); 384} 385 386 387LChunk::LChunk(CompilationInfo* info, HGraph* graph) 388 : spill_slot_count_(0), 389 info_(info), 390 graph_(graph), 391 instructions_(32), 392 pointer_maps_(8), 393 inlined_closures_(1) { 394} 395 396 397int LChunk::GetNextSpillIndex(bool is_double) { 398 // Skip a slot if for a double-width slot. 399 if (is_double) spill_slot_count_++; 400 return spill_slot_count_++; 401} 402 403 404LOperand* LChunk::GetNextSpillSlot(bool is_double) { 405 int index = GetNextSpillIndex(is_double); 406 if (is_double) { 407 return LDoubleStackSlot::Create(index); 408 } else { 409 return LStackSlot::Create(index); 410 } 411} 412 413 414void LChunk::MarkEmptyBlocks() { 415 HPhase phase("Mark empty blocks", this); 416 for (int i = 0; i < graph()->blocks()->length(); ++i) { 417 HBasicBlock* block = graph()->blocks()->at(i); 418 int first = block->first_instruction_index(); 419 int last = block->last_instruction_index(); 420 LInstruction* first_instr = instructions()->at(first); 421 LInstruction* last_instr = instructions()->at(last); 422 423 LLabel* label = LLabel::cast(first_instr); 424 if (last_instr->IsGoto()) { 425 LGoto* goto_instr = LGoto::cast(last_instr); 426 if (!goto_instr->include_stack_check() && 427 label->IsRedundant() && 428 !label->is_loop_header()) { 429 bool can_eliminate = true; 430 for (int i = first + 1; i < last && can_eliminate; ++i) { 431 LInstruction* cur = instructions()->at(i); 432 if (cur->IsGap()) { 433 LGap* gap = LGap::cast(cur); 434 if (!gap->IsRedundant()) { 435 can_eliminate = false; 436 } 437 } else { 438 can_eliminate = false; 439 } 440 } 441 442 if (can_eliminate) { 443 label->set_replacement(GetLabel(goto_instr->block_id())); 444 } 445 } 446 } 447 } 448} 449 450 451void LChunk::AddInstruction(LInstruction* instr, HBasicBlock* block) { 452 LGap* gap = new LGap(block); 453 int index = -1; 454 if (instr->IsControl()) { 455 instructions_.Add(gap); 456 index = instructions_.length(); 457 instructions_.Add(instr); 458 } else { 459 index = instructions_.length(); 460 instructions_.Add(instr); 461 instructions_.Add(gap); 462 } 463 if (instr->HasPointerMap()) { 464 pointer_maps_.Add(instr->pointer_map()); 465 instr->pointer_map()->set_lithium_position(index); 466 } 467} 468 469 470LConstantOperand* LChunk::DefineConstantOperand(HConstant* constant) { 471 return LConstantOperand::Create(constant->id()); 472} 473 474 475int LChunk::GetParameterStackSlot(int index) const { 476 // The receiver is at index 0, the first parameter at index 1, so we 477 // shift all parameter indexes down by the number of parameters, and 478 // make sure they end up negative so they are distinguishable from 479 // spill slots. 480 int result = index - info()->scope()->num_parameters() - 1; 481 ASSERT(result < 0); 482 return result; 483} 484 485// A parameter relative to ebp in the arguments stub. 486int LChunk::ParameterAt(int index) { 487 ASSERT(-1 <= index); // -1 is the receiver. 488 return (1 + info()->scope()->num_parameters() - index) * 489 kPointerSize; 490} 491 492 493LGap* LChunk::GetGapAt(int index) const { 494 return LGap::cast(instructions_[index]); 495} 496 497 498bool LChunk::IsGapAt(int index) const { 499 return instructions_[index]->IsGap(); 500} 501 502 503int LChunk::NearestGapPos(int index) const { 504 while (!IsGapAt(index)) index--; 505 return index; 506} 507 508 509void LChunk::AddGapMove(int index, LOperand* from, LOperand* to) { 510 GetGapAt(index)->GetOrCreateParallelMove(LGap::START)->AddMove(from, to); 511} 512 513 514Handle<Object> LChunk::LookupLiteral(LConstantOperand* operand) const { 515 return HConstant::cast(graph_->LookupValue(operand->index()))->handle(); 516} 517 518 519Representation LChunk::LookupLiteralRepresentation( 520 LConstantOperand* operand) const { 521 return graph_->LookupValue(operand->index())->representation(); 522} 523 524 525LChunk* LChunkBuilder::Build() { 526 ASSERT(is_unused()); 527 chunk_ = new LChunk(info(), graph()); 528 HPhase phase("Building chunk", chunk_); 529 status_ = BUILDING; 530 const ZoneList<HBasicBlock*>* blocks = graph()->blocks(); 531 for (int i = 0; i < blocks->length(); i++) { 532 HBasicBlock* next = NULL; 533 if (i < blocks->length() - 1) next = blocks->at(i + 1); 534 DoBasicBlock(blocks->at(i), next); 535 if (is_aborted()) return NULL; 536 } 537 status_ = DONE; 538 return chunk_; 539} 540 541 542void LChunkBuilder::Abort(const char* format, ...) { 543 if (FLAG_trace_bailout) { 544 SmartPointer<char> name(info()->shared_info()->DebugName()->ToCString()); 545 PrintF("Aborting LChunk building in @\"%s\": ", *name); 546 va_list arguments; 547 va_start(arguments, format); 548 OS::VPrint(format, arguments); 549 va_end(arguments); 550 PrintF("\n"); 551 } 552 status_ = ABORTED; 553} 554 555 556LRegister* LChunkBuilder::ToOperand(Register reg) { 557 return LRegister::Create(Register::ToAllocationIndex(reg)); 558} 559 560 561LUnallocated* LChunkBuilder::ToUnallocated(Register reg) { 562 return new LUnallocated(LUnallocated::FIXED_REGISTER, 563 Register::ToAllocationIndex(reg)); 564} 565 566 567LUnallocated* LChunkBuilder::ToUnallocated(DoubleRegister reg) { 568 return new LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER, 569 DoubleRegister::ToAllocationIndex(reg)); 570} 571 572 573LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) { 574 return Use(value, ToUnallocated(fixed_register)); 575} 576 577 578LOperand* LChunkBuilder::UseFixedDouble(HValue* value, DoubleRegister reg) { 579 return Use(value, ToUnallocated(reg)); 580} 581 582 583LOperand* LChunkBuilder::UseRegister(HValue* value) { 584 return Use(value, new LUnallocated(LUnallocated::MUST_HAVE_REGISTER)); 585} 586 587 588LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) { 589 return Use(value, 590 new LUnallocated(LUnallocated::MUST_HAVE_REGISTER, 591 LUnallocated::USED_AT_START)); 592} 593 594 595LOperand* LChunkBuilder::UseTempRegister(HValue* value) { 596 return Use(value, new LUnallocated(LUnallocated::WRITABLE_REGISTER)); 597} 598 599 600LOperand* LChunkBuilder::Use(HValue* value) { 601 return Use(value, new LUnallocated(LUnallocated::NONE)); 602} 603 604 605LOperand* LChunkBuilder::UseAtStart(HValue* value) { 606 return Use(value, new LUnallocated(LUnallocated::NONE, 607 LUnallocated::USED_AT_START)); 608} 609 610 611LOperand* LChunkBuilder::UseOrConstant(HValue* value) { 612 return value->IsConstant() 613 ? chunk_->DefineConstantOperand(HConstant::cast(value)) 614 : Use(value); 615} 616 617 618LOperand* LChunkBuilder::UseOrConstantAtStart(HValue* value) { 619 return value->IsConstant() 620 ? chunk_->DefineConstantOperand(HConstant::cast(value)) 621 : UseAtStart(value); 622} 623 624 625LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) { 626 return value->IsConstant() 627 ? chunk_->DefineConstantOperand(HConstant::cast(value)) 628 : UseRegister(value); 629} 630 631 632LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) { 633 return value->IsConstant() 634 ? chunk_->DefineConstantOperand(HConstant::cast(value)) 635 : UseRegisterAtStart(value); 636} 637 638 639LOperand* LChunkBuilder::UseAny(HValue* value) { 640 return value->IsConstant() 641 ? chunk_->DefineConstantOperand(HConstant::cast(value)) 642 : Use(value, new LUnallocated(LUnallocated::ANY)); 643} 644 645 646LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) { 647 if (value->EmitAtUses()) { 648 HInstruction* instr = HInstruction::cast(value); 649 VisitInstruction(instr); 650 } 651 allocator_->RecordUse(value, operand); 652 return operand; 653} 654 655 656template<int I, int T> 657LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr, 658 LUnallocated* result) { 659 allocator_->RecordDefinition(current_instruction_, result); 660 instr->set_result(result); 661 return instr; 662} 663 664 665template<int I, int T> 666LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr) { 667 return Define(instr, new LUnallocated(LUnallocated::NONE)); 668} 669 670 671template<int I, int T> 672LInstruction* LChunkBuilder::DefineAsRegister( 673 LTemplateInstruction<1, I, T>* instr) { 674 return Define(instr, new LUnallocated(LUnallocated::MUST_HAVE_REGISTER)); 675} 676 677 678template<int I, int T> 679LInstruction* LChunkBuilder::DefineAsSpilled( 680 LTemplateInstruction<1, I, T>* instr, int index) { 681 return Define(instr, new LUnallocated(LUnallocated::FIXED_SLOT, index)); 682} 683 684 685template<int I, int T> 686LInstruction* LChunkBuilder::DefineSameAsFirst( 687 LTemplateInstruction<1, I, T>* instr) { 688 return Define(instr, new LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT)); 689} 690 691 692template<int I, int T> 693LInstruction* LChunkBuilder::DefineFixed( 694 LTemplateInstruction<1, I, T>* instr, Register reg) { 695 return Define(instr, ToUnallocated(reg)); 696} 697 698 699template<int I, int T> 700LInstruction* LChunkBuilder::DefineFixedDouble( 701 LTemplateInstruction<1, I, T>* instr, DoubleRegister reg) { 702 return Define(instr, ToUnallocated(reg)); 703} 704 705 706LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) { 707 HEnvironment* hydrogen_env = current_block_->last_environment(); 708 instr->set_environment(CreateEnvironment(hydrogen_env)); 709 return instr; 710} 711 712 713LInstruction* LChunkBuilder::SetInstructionPendingDeoptimizationEnvironment( 714 LInstruction* instr, int ast_id) { 715 ASSERT(instruction_pending_deoptimization_environment_ == NULL); 716 ASSERT(pending_deoptimization_ast_id_ == AstNode::kNoNumber); 717 instruction_pending_deoptimization_environment_ = instr; 718 pending_deoptimization_ast_id_ = ast_id; 719 return instr; 720} 721 722 723void LChunkBuilder::ClearInstructionPendingDeoptimizationEnvironment() { 724 instruction_pending_deoptimization_environment_ = NULL; 725 pending_deoptimization_ast_id_ = AstNode::kNoNumber; 726} 727 728 729LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr, 730 HInstruction* hinstr, 731 CanDeoptimize can_deoptimize) { 732#ifdef DEBUG 733 instr->VerifyCall(); 734#endif 735 instr->MarkAsCall(); 736 instr = AssignPointerMap(instr); 737 738 if (hinstr->HasSideEffects()) { 739 ASSERT(hinstr->next()->IsSimulate()); 740 HSimulate* sim = HSimulate::cast(hinstr->next()); 741 instr = SetInstructionPendingDeoptimizationEnvironment( 742 instr, sim->ast_id()); 743 } 744 745 // If instruction does not have side-effects lazy deoptimization 746 // after the call will try to deoptimize to the point before the call. 747 // Thus we still need to attach environment to this call even if 748 // call sequence can not deoptimize eagerly. 749 bool needs_environment = 750 (can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) || !hinstr->HasSideEffects(); 751 if (needs_environment && !instr->HasEnvironment()) { 752 instr = AssignEnvironment(instr); 753 } 754 755 return instr; 756} 757 758 759LInstruction* LChunkBuilder::MarkAsSaveDoubles(LInstruction* instr) { 760 instr->MarkAsSaveDoubles(); 761 return instr; 762} 763 764 765LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) { 766 ASSERT(!instr->HasPointerMap()); 767 instr->set_pointer_map(new LPointerMap(position_)); 768 return instr; 769} 770 771 772LUnallocated* LChunkBuilder::TempRegister() { 773 LUnallocated* operand = new LUnallocated(LUnallocated::MUST_HAVE_REGISTER); 774 allocator_->RecordTemporary(operand); 775 return operand; 776} 777 778 779LOperand* LChunkBuilder::FixedTemp(Register reg) { 780 LUnallocated* operand = ToUnallocated(reg); 781 allocator_->RecordTemporary(operand); 782 return operand; 783} 784 785 786LOperand* LChunkBuilder::FixedTemp(DoubleRegister reg) { 787 LUnallocated* operand = ToUnallocated(reg); 788 allocator_->RecordTemporary(operand); 789 return operand; 790} 791 792 793LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) { 794 return new LLabel(instr->block()); 795} 796 797 798LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) { 799 return AssignEnvironment(new LDeoptimize); 800} 801 802 803LInstruction* LChunkBuilder::DoBit(Token::Value op, 804 HBitwiseBinaryOperation* instr) { 805 if (instr->representation().IsInteger32()) { 806 ASSERT(instr->left()->representation().IsInteger32()); 807 ASSERT(instr->right()->representation().IsInteger32()); 808 809 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand()); 810 LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand()); 811 return DefineSameAsFirst(new LBitI(op, left, right)); 812 } else { 813 ASSERT(instr->representation().IsTagged()); 814 ASSERT(instr->left()->representation().IsTagged()); 815 ASSERT(instr->right()->representation().IsTagged()); 816 817 LOperand* left = UseFixed(instr->left(), r1); 818 LOperand* right = UseFixed(instr->right(), r0); 819 LArithmeticT* result = new LArithmeticT(op, left, right); 820 return MarkAsCall(DefineFixed(result, r0), instr); 821 } 822} 823 824 825LInstruction* LChunkBuilder::DoShift(Token::Value op, 826 HBitwiseBinaryOperation* instr) { 827 if (instr->representation().IsTagged()) { 828 ASSERT(instr->left()->representation().IsTagged()); 829 ASSERT(instr->right()->representation().IsTagged()); 830 831 LOperand* left = UseFixed(instr->left(), r1); 832 LOperand* right = UseFixed(instr->right(), r0); 833 LArithmeticT* result = new LArithmeticT(op, left, right); 834 return MarkAsCall(DefineFixed(result, r0), instr); 835 } 836 837 ASSERT(instr->representation().IsInteger32()); 838 ASSERT(instr->OperandAt(0)->representation().IsInteger32()); 839 ASSERT(instr->OperandAt(1)->representation().IsInteger32()); 840 LOperand* left = UseRegisterAtStart(instr->OperandAt(0)); 841 842 HValue* right_value = instr->OperandAt(1); 843 LOperand* right = NULL; 844 int constant_value = 0; 845 if (right_value->IsConstant()) { 846 HConstant* constant = HConstant::cast(right_value); 847 right = chunk_->DefineConstantOperand(constant); 848 constant_value = constant->Integer32Value() & 0x1f; 849 } else { 850 right = UseRegister(right_value); 851 } 852 853 // Shift operations can only deoptimize if we do a logical shift 854 // by 0 and the result cannot be truncated to int32. 855 bool can_deopt = (op == Token::SHR && constant_value == 0); 856 if (can_deopt) { 857 bool can_truncate = true; 858 for (int i = 0; i < instr->uses()->length(); i++) { 859 if (!instr->uses()->at(i)->CheckFlag(HValue::kTruncatingToInt32)) { 860 can_truncate = false; 861 break; 862 } 863 } 864 can_deopt = !can_truncate; 865 } 866 867 LInstruction* result = 868 DefineSameAsFirst(new LShiftI(op, left, right, can_deopt)); 869 if (can_deopt) AssignEnvironment(result); 870 return result; 871} 872 873 874LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op, 875 HArithmeticBinaryOperation* instr) { 876 ASSERT(instr->representation().IsDouble()); 877 ASSERT(instr->left()->representation().IsDouble()); 878 ASSERT(instr->right()->representation().IsDouble()); 879 ASSERT(op != Token::MOD); 880 LOperand* left = UseRegisterAtStart(instr->left()); 881 LOperand* right = UseRegisterAtStart(instr->right()); 882 LArithmeticD* result = new LArithmeticD(op, left, right); 883 return DefineSameAsFirst(result); 884} 885 886 887LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op, 888 HArithmeticBinaryOperation* instr) { 889 ASSERT(op == Token::ADD || 890 op == Token::DIV || 891 op == Token::MOD || 892 op == Token::MUL || 893 op == Token::SUB); 894 HValue* left = instr->left(); 895 HValue* right = instr->right(); 896 ASSERT(left->representation().IsTagged()); 897 ASSERT(right->representation().IsTagged()); 898 LOperand* left_operand = UseFixed(left, r1); 899 LOperand* right_operand = UseFixed(right, r0); 900 LArithmeticT* result = new LArithmeticT(op, left_operand, right_operand); 901 return MarkAsCall(DefineFixed(result, r0), instr); 902} 903 904 905void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) { 906 ASSERT(is_building()); 907 current_block_ = block; 908 next_block_ = next_block; 909 if (block->IsStartBlock()) { 910 block->UpdateEnvironment(graph_->start_environment()); 911 argument_count_ = 0; 912 } else if (block->predecessors()->length() == 1) { 913 // We have a single predecessor => copy environment and outgoing 914 // argument count from the predecessor. 915 ASSERT(block->phis()->length() == 0); 916 HBasicBlock* pred = block->predecessors()->at(0); 917 HEnvironment* last_environment = pred->last_environment(); 918 ASSERT(last_environment != NULL); 919 // Only copy the environment, if it is later used again. 920 if (pred->end()->SecondSuccessor() == NULL) { 921 ASSERT(pred->end()->FirstSuccessor() == block); 922 } else { 923 if (pred->end()->FirstSuccessor()->block_id() > block->block_id() || 924 pred->end()->SecondSuccessor()->block_id() > block->block_id()) { 925 last_environment = last_environment->Copy(); 926 } 927 } 928 block->UpdateEnvironment(last_environment); 929 ASSERT(pred->argument_count() >= 0); 930 argument_count_ = pred->argument_count(); 931 } else { 932 // We are at a state join => process phis. 933 HBasicBlock* pred = block->predecessors()->at(0); 934 // No need to copy the environment, it cannot be used later. 935 HEnvironment* last_environment = pred->last_environment(); 936 for (int i = 0; i < block->phis()->length(); ++i) { 937 HPhi* phi = block->phis()->at(i); 938 last_environment->SetValueAt(phi->merged_index(), phi); 939 } 940 for (int i = 0; i < block->deleted_phis()->length(); ++i) { 941 last_environment->SetValueAt(block->deleted_phis()->at(i), 942 graph_->GetConstantUndefined()); 943 } 944 block->UpdateEnvironment(last_environment); 945 // Pick up the outgoing argument count of one of the predecessors. 946 argument_count_ = pred->argument_count(); 947 } 948 HInstruction* current = block->first(); 949 int start = chunk_->instructions()->length(); 950 while (current != NULL && !is_aborted()) { 951 // Code for constants in registers is generated lazily. 952 if (!current->EmitAtUses()) { 953 VisitInstruction(current); 954 } 955 current = current->next(); 956 } 957 int end = chunk_->instructions()->length() - 1; 958 if (end >= start) { 959 block->set_first_instruction_index(start); 960 block->set_last_instruction_index(end); 961 } 962 block->set_argument_count(argument_count_); 963 next_block_ = NULL; 964 current_block_ = NULL; 965} 966 967 968void LChunkBuilder::VisitInstruction(HInstruction* current) { 969 HInstruction* old_current = current_instruction_; 970 current_instruction_ = current; 971 if (current->has_position()) position_ = current->position(); 972 LInstruction* instr = current->CompileToLithium(this); 973 974 if (instr != NULL) { 975 if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) { 976 instr = AssignPointerMap(instr); 977 } 978 if (FLAG_stress_environments && !instr->HasEnvironment()) { 979 instr = AssignEnvironment(instr); 980 } 981 if (current->IsTest() && !instr->IsGoto()) { 982 ASSERT(instr->IsControl()); 983 HTest* test = HTest::cast(current); 984 instr->set_hydrogen_value(test->value()); 985 HBasicBlock* first = test->FirstSuccessor(); 986 HBasicBlock* second = test->SecondSuccessor(); 987 ASSERT(first != NULL && second != NULL); 988 instr->SetBranchTargets(first->block_id(), second->block_id()); 989 } else { 990 instr->set_hydrogen_value(current); 991 } 992 993 chunk_->AddInstruction(instr, current_block_); 994 } 995 current_instruction_ = old_current; 996} 997 998 999LEnvironment* LChunkBuilder::CreateEnvironment(HEnvironment* hydrogen_env) { 1000 if (hydrogen_env == NULL) return NULL; 1001 1002 LEnvironment* outer = CreateEnvironment(hydrogen_env->outer()); 1003 int ast_id = hydrogen_env->ast_id(); 1004 ASSERT(ast_id != AstNode::kNoNumber); 1005 int value_count = hydrogen_env->length(); 1006 LEnvironment* result = new LEnvironment(hydrogen_env->closure(), 1007 ast_id, 1008 hydrogen_env->parameter_count(), 1009 argument_count_, 1010 value_count, 1011 outer); 1012 int argument_index = 0; 1013 for (int i = 0; i < value_count; ++i) { 1014 HValue* value = hydrogen_env->values()->at(i); 1015 LOperand* op = NULL; 1016 if (value->IsArgumentsObject()) { 1017 op = NULL; 1018 } else if (value->IsPushArgument()) { 1019 op = new LArgument(argument_index++); 1020 } else { 1021 op = UseAny(value); 1022 } 1023 result->AddValue(op, value->representation()); 1024 } 1025 1026 return result; 1027} 1028 1029 1030LInstruction* LChunkBuilder::DoGoto(HGoto* instr) { 1031 LInstruction* result = new LGoto(instr->FirstSuccessor()->block_id(), 1032 instr->include_stack_check()); 1033 if (instr->include_stack_check()) result = AssignPointerMap(result); 1034 return result; 1035} 1036 1037 1038LInstruction* LChunkBuilder::DoTest(HTest* instr) { 1039 HValue* v = instr->value(); 1040 if (v->EmitAtUses()) { 1041 if (v->IsClassOfTest()) { 1042 HClassOfTest* compare = HClassOfTest::cast(v); 1043 ASSERT(compare->value()->representation().IsTagged()); 1044 1045 return new LClassOfTestAndBranch(UseTempRegister(compare->value()), 1046 TempRegister()); 1047 } else if (v->IsCompare()) { 1048 HCompare* compare = HCompare::cast(v); 1049 Token::Value op = compare->token(); 1050 HValue* left = compare->left(); 1051 HValue* right = compare->right(); 1052 Representation r = compare->GetInputRepresentation(); 1053 if (r.IsInteger32()) { 1054 ASSERT(left->representation().IsInteger32()); 1055 ASSERT(right->representation().IsInteger32()); 1056 return new LCmpIDAndBranch(UseRegisterAtStart(left), 1057 UseRegisterAtStart(right)); 1058 } else if (r.IsDouble()) { 1059 ASSERT(left->representation().IsDouble()); 1060 ASSERT(right->representation().IsDouble()); 1061 return new LCmpIDAndBranch(UseRegisterAtStart(left), 1062 UseRegisterAtStart(right)); 1063 } else { 1064 ASSERT(left->representation().IsTagged()); 1065 ASSERT(right->representation().IsTagged()); 1066 bool reversed = op == Token::GT || op == Token::LTE; 1067 LOperand* left_operand = UseFixed(left, reversed ? r0 : r1); 1068 LOperand* right_operand = UseFixed(right, reversed ? r1 : r0); 1069 LInstruction* result = new LCmpTAndBranch(left_operand, 1070 right_operand); 1071 return MarkAsCall(result, instr); 1072 } 1073 } else if (v->IsIsSmi()) { 1074 HIsSmi* compare = HIsSmi::cast(v); 1075 ASSERT(compare->value()->representation().IsTagged()); 1076 1077 return new LIsSmiAndBranch(Use(compare->value())); 1078 } else if (v->IsHasInstanceType()) { 1079 HHasInstanceType* compare = HHasInstanceType::cast(v); 1080 ASSERT(compare->value()->representation().IsTagged()); 1081 return new LHasInstanceTypeAndBranch( 1082 UseRegisterAtStart(compare->value())); 1083 } else if (v->IsHasCachedArrayIndex()) { 1084 HHasCachedArrayIndex* compare = HHasCachedArrayIndex::cast(v); 1085 ASSERT(compare->value()->representation().IsTagged()); 1086 1087 return new LHasCachedArrayIndexAndBranch( 1088 UseRegisterAtStart(compare->value())); 1089 } else if (v->IsIsNull()) { 1090 HIsNull* compare = HIsNull::cast(v); 1091 ASSERT(compare->value()->representation().IsTagged()); 1092 1093 return new LIsNullAndBranch(UseRegisterAtStart(compare->value())); 1094 } else if (v->IsIsObject()) { 1095 HIsObject* compare = HIsObject::cast(v); 1096 ASSERT(compare->value()->representation().IsTagged()); 1097 1098 LOperand* temp = TempRegister(); 1099 return new LIsObjectAndBranch(UseRegister(compare->value()), temp); 1100 } else if (v->IsCompareJSObjectEq()) { 1101 HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v); 1102 return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()), 1103 UseRegisterAtStart(compare->right())); 1104 } else if (v->IsInstanceOf()) { 1105 HInstanceOf* instance_of = HInstanceOf::cast(v); 1106 LInstruction* result = 1107 new LInstanceOfAndBranch(UseFixed(instance_of->left(), r0), 1108 UseFixed(instance_of->right(), r1)); 1109 return MarkAsCall(result, instr); 1110 } else if (v->IsTypeofIs()) { 1111 HTypeofIs* typeof_is = HTypeofIs::cast(v); 1112 return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value())); 1113 } else if (v->IsIsConstructCall()) { 1114 return new LIsConstructCallAndBranch(TempRegister()); 1115 } else { 1116 if (v->IsConstant()) { 1117 if (HConstant::cast(v)->ToBoolean()) { 1118 return new LGoto(instr->FirstSuccessor()->block_id()); 1119 } else { 1120 return new LGoto(instr->SecondSuccessor()->block_id()); 1121 } 1122 } 1123 Abort("Undefined compare before branch"); 1124 return NULL; 1125 } 1126 } 1127 return new LBranch(UseRegisterAtStart(v)); 1128} 1129 1130 1131LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) { 1132 ASSERT(instr->value()->representation().IsTagged()); 1133 LOperand* value = UseRegisterAtStart(instr->value()); 1134 LOperand* temp = TempRegister(); 1135 return new LCmpMapAndBranch(value, temp); 1136} 1137 1138 1139LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* length) { 1140 return DefineAsRegister(new LArgumentsLength(UseRegister(length->value()))); 1141} 1142 1143 1144LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) { 1145 return DefineAsRegister(new LArgumentsElements); 1146} 1147 1148 1149LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) { 1150 LInstanceOf* result = 1151 new LInstanceOf(UseFixed(instr->left(), r0), 1152 UseFixed(instr->right(), r1)); 1153 return MarkAsCall(DefineFixed(result, r0), instr); 1154} 1155 1156 1157LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal( 1158 HInstanceOfKnownGlobal* instr) { 1159 LInstanceOfKnownGlobal* result = 1160 new LInstanceOfKnownGlobal(UseFixed(instr->value(), r0), FixedTemp(r4)); 1161 return MarkAsCall(DefineFixed(result, r0), instr); 1162} 1163 1164 1165LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) { 1166 LOperand* function = UseFixed(instr->function(), r1); 1167 LOperand* receiver = UseFixed(instr->receiver(), r0); 1168 LOperand* length = UseFixed(instr->length(), r2); 1169 LOperand* elements = UseFixed(instr->elements(), r3); 1170 LApplyArguments* result = new LApplyArguments(function, 1171 receiver, 1172 length, 1173 elements); 1174 return MarkAsCall(DefineFixed(result, r0), instr, CAN_DEOPTIMIZE_EAGERLY); 1175} 1176 1177 1178LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) { 1179 ++argument_count_; 1180 LOperand* argument = Use(instr->argument()); 1181 return new LPushArgument(argument); 1182} 1183 1184 1185LInstruction* LChunkBuilder::DoContext(HContext* instr) { 1186 return DefineAsRegister(new LContext); 1187} 1188 1189 1190LInstruction* LChunkBuilder::DoOuterContext(HOuterContext* instr) { 1191 LOperand* context = UseRegisterAtStart(instr->value()); 1192 return DefineAsRegister(new LOuterContext(context)); 1193} 1194 1195 1196LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) { 1197 LOperand* context = UseRegisterAtStart(instr->value()); 1198 return DefineAsRegister(new LGlobalObject(context)); 1199} 1200 1201 1202LInstruction* LChunkBuilder::DoGlobalReceiver(HGlobalReceiver* instr) { 1203 LOperand* global_object = UseRegisterAtStart(instr->value()); 1204 return DefineAsRegister(new LGlobalReceiver(global_object)); 1205} 1206 1207 1208LInstruction* LChunkBuilder::DoCallConstantFunction( 1209 HCallConstantFunction* instr) { 1210 argument_count_ -= instr->argument_count(); 1211 return MarkAsCall(DefineFixed(new LCallConstantFunction, r0), instr); 1212} 1213 1214 1215LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) { 1216 BuiltinFunctionId op = instr->op(); 1217 if (op == kMathLog || op == kMathSin || op == kMathCos) { 1218 LOperand* input = UseFixedDouble(instr->value(), d2); 1219 LUnaryMathOperation* result = new LUnaryMathOperation(input, NULL); 1220 return MarkAsCall(DefineFixedDouble(result, d2), instr); 1221 } else { 1222 LOperand* input = UseRegisterAtStart(instr->value()); 1223 LOperand* temp = (op == kMathFloor) ? TempRegister() : NULL; 1224 LUnaryMathOperation* result = new LUnaryMathOperation(input, temp); 1225 switch (op) { 1226 case kMathAbs: 1227 return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result))); 1228 case kMathFloor: 1229 return AssignEnvironment(AssignPointerMap(DefineAsRegister(result))); 1230 case kMathSqrt: 1231 return DefineSameAsFirst(result); 1232 case kMathRound: 1233 return AssignEnvironment(DefineAsRegister(result)); 1234 case kMathPowHalf: 1235 return DefineSameAsFirst(result); 1236 default: 1237 UNREACHABLE(); 1238 return NULL; 1239 } 1240 } 1241} 1242 1243 1244LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) { 1245 ASSERT(instr->key()->representation().IsTagged()); 1246 argument_count_ -= instr->argument_count(); 1247 LOperand* key = UseFixed(instr->key(), r2); 1248 return MarkAsCall(DefineFixed(new LCallKeyed(key), r0), instr); 1249} 1250 1251 1252LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) { 1253 argument_count_ -= instr->argument_count(); 1254 return MarkAsCall(DefineFixed(new LCallNamed, r0), instr); 1255} 1256 1257 1258LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) { 1259 argument_count_ -= instr->argument_count(); 1260 return MarkAsCall(DefineFixed(new LCallGlobal, r0), instr); 1261} 1262 1263 1264LInstruction* LChunkBuilder::DoCallKnownGlobal(HCallKnownGlobal* instr) { 1265 argument_count_ -= instr->argument_count(); 1266 return MarkAsCall(DefineFixed(new LCallKnownGlobal, r0), instr); 1267} 1268 1269 1270LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) { 1271 LOperand* constructor = UseFixed(instr->constructor(), r1); 1272 argument_count_ -= instr->argument_count(); 1273 LCallNew* result = new LCallNew(constructor); 1274 return MarkAsCall(DefineFixed(result, r0), instr); 1275} 1276 1277 1278LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) { 1279 argument_count_ -= instr->argument_count(); 1280 return MarkAsCall(DefineFixed(new LCallFunction, r0), instr); 1281} 1282 1283 1284LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) { 1285 argument_count_ -= instr->argument_count(); 1286 return MarkAsCall(DefineFixed(new LCallRuntime, r0), instr); 1287} 1288 1289 1290LInstruction* LChunkBuilder::DoShr(HShr* instr) { 1291 return DoShift(Token::SHR, instr); 1292} 1293 1294 1295LInstruction* LChunkBuilder::DoSar(HSar* instr) { 1296 return DoShift(Token::SAR, instr); 1297} 1298 1299 1300LInstruction* LChunkBuilder::DoShl(HShl* instr) { 1301 return DoShift(Token::SHL, instr); 1302} 1303 1304 1305LInstruction* LChunkBuilder::DoBitAnd(HBitAnd* instr) { 1306 return DoBit(Token::BIT_AND, instr); 1307} 1308 1309 1310LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) { 1311 ASSERT(instr->value()->representation().IsInteger32()); 1312 ASSERT(instr->representation().IsInteger32()); 1313 return DefineSameAsFirst(new LBitNotI(UseRegisterAtStart(instr->value()))); 1314} 1315 1316 1317LInstruction* LChunkBuilder::DoBitOr(HBitOr* instr) { 1318 return DoBit(Token::BIT_OR, instr); 1319} 1320 1321 1322LInstruction* LChunkBuilder::DoBitXor(HBitXor* instr) { 1323 return DoBit(Token::BIT_XOR, instr); 1324} 1325 1326 1327LInstruction* LChunkBuilder::DoDiv(HDiv* instr) { 1328 if (instr->representation().IsDouble()) { 1329 return DoArithmeticD(Token::DIV, instr); 1330 } else if (instr->representation().IsInteger32()) { 1331 // TODO(1042) The fixed register allocation 1332 // is needed because we call TypeRecordingBinaryOpStub from 1333 // the generated code, which requires registers r0 1334 // and r1 to be used. We should remove that 1335 // when we provide a native implementation. 1336 LOperand* dividend = UseFixed(instr->left(), r0); 1337 LOperand* divisor = UseFixed(instr->right(), r1); 1338 return AssignEnvironment(AssignPointerMap( 1339 DefineFixed(new LDivI(dividend, divisor), r0))); 1340 } else { 1341 return DoArithmeticT(Token::DIV, instr); 1342 } 1343} 1344 1345 1346LInstruction* LChunkBuilder::DoMod(HMod* instr) { 1347 if (instr->representation().IsInteger32()) { 1348 ASSERT(instr->left()->representation().IsInteger32()); 1349 ASSERT(instr->right()->representation().IsInteger32()); 1350 1351 LModI* mod; 1352 if (instr->HasPowerOf2Divisor()) { 1353 ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero)); 1354 LOperand* value = UseRegisterAtStart(instr->left()); 1355 mod = new LModI(value, UseOrConstant(instr->right())); 1356 } else { 1357 LOperand* dividend = UseRegister(instr->left()); 1358 LOperand* divisor = UseRegisterAtStart(instr->right()); 1359 mod = new LModI(dividend, 1360 divisor, 1361 TempRegister(), 1362 FixedTemp(d1), 1363 FixedTemp(d2)); 1364 } 1365 1366 return AssignEnvironment(DefineSameAsFirst(mod)); 1367 } else if (instr->representation().IsTagged()) { 1368 return DoArithmeticT(Token::MOD, instr); 1369 } else { 1370 ASSERT(instr->representation().IsDouble()); 1371 // We call a C function for double modulo. It can't trigger a GC. 1372 // We need to use fixed result register for the call. 1373 // TODO(fschneider): Allow any register as input registers. 1374 LOperand* left = UseFixedDouble(instr->left(), d1); 1375 LOperand* right = UseFixedDouble(instr->right(), d2); 1376 LArithmeticD* result = new LArithmeticD(Token::MOD, left, right); 1377 return MarkAsCall(DefineFixedDouble(result, d1), instr); 1378 } 1379} 1380 1381 1382LInstruction* LChunkBuilder::DoMul(HMul* instr) { 1383 if (instr->representation().IsInteger32()) { 1384 ASSERT(instr->left()->representation().IsInteger32()); 1385 ASSERT(instr->right()->representation().IsInteger32()); 1386 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand()); 1387 LOperand* right = UseOrConstant(instr->MostConstantOperand()); 1388 LOperand* temp = NULL; 1389 if (instr->CheckFlag(HValue::kBailoutOnMinusZero)) { 1390 temp = TempRegister(); 1391 } 1392 LMulI* mul = new LMulI(left, right, temp); 1393 return AssignEnvironment(DefineSameAsFirst(mul)); 1394 } else if (instr->representation().IsDouble()) { 1395 return DoArithmeticD(Token::MUL, instr); 1396 } else { 1397 return DoArithmeticT(Token::MUL, instr); 1398 } 1399} 1400 1401 1402LInstruction* LChunkBuilder::DoSub(HSub* instr) { 1403 if (instr->representation().IsInteger32()) { 1404 ASSERT(instr->left()->representation().IsInteger32()); 1405 ASSERT(instr->right()->representation().IsInteger32()); 1406 LOperand* left = UseRegisterAtStart(instr->left()); 1407 LOperand* right = UseOrConstantAtStart(instr->right()); 1408 LSubI* sub = new LSubI(left, right); 1409 LInstruction* result = DefineSameAsFirst(sub); 1410 if (instr->CheckFlag(HValue::kCanOverflow)) { 1411 result = AssignEnvironment(result); 1412 } 1413 return result; 1414 } else if (instr->representation().IsDouble()) { 1415 return DoArithmeticD(Token::SUB, instr); 1416 } else { 1417 return DoArithmeticT(Token::SUB, instr); 1418 } 1419} 1420 1421 1422LInstruction* LChunkBuilder::DoAdd(HAdd* instr) { 1423 if (instr->representation().IsInteger32()) { 1424 ASSERT(instr->left()->representation().IsInteger32()); 1425 ASSERT(instr->right()->representation().IsInteger32()); 1426 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand()); 1427 LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand()); 1428 LAddI* add = new LAddI(left, right); 1429 LInstruction* result = DefineSameAsFirst(add); 1430 if (instr->CheckFlag(HValue::kCanOverflow)) { 1431 result = AssignEnvironment(result); 1432 } 1433 return result; 1434 } else if (instr->representation().IsDouble()) { 1435 return DoArithmeticD(Token::ADD, instr); 1436 } else { 1437 ASSERT(instr->representation().IsTagged()); 1438 return DoArithmeticT(Token::ADD, instr); 1439 } 1440} 1441 1442 1443LInstruction* LChunkBuilder::DoPower(HPower* instr) { 1444 ASSERT(instr->representation().IsDouble()); 1445 // We call a C function for double power. It can't trigger a GC. 1446 // We need to use fixed result register for the call. 1447 Representation exponent_type = instr->right()->representation(); 1448 ASSERT(instr->left()->representation().IsDouble()); 1449 LOperand* left = UseFixedDouble(instr->left(), d1); 1450 LOperand* right = exponent_type.IsDouble() ? 1451 UseFixedDouble(instr->right(), d2) : 1452 UseFixed(instr->right(), r0); 1453 LPower* result = new LPower(left, right); 1454 return MarkAsCall(DefineFixedDouble(result, d3), 1455 instr, 1456 CAN_DEOPTIMIZE_EAGERLY); 1457} 1458 1459 1460LInstruction* LChunkBuilder::DoCompare(HCompare* instr) { 1461 Token::Value op = instr->token(); 1462 Representation r = instr->GetInputRepresentation(); 1463 if (r.IsInteger32()) { 1464 ASSERT(instr->left()->representation().IsInteger32()); 1465 ASSERT(instr->right()->representation().IsInteger32()); 1466 LOperand* left = UseRegisterAtStart(instr->left()); 1467 LOperand* right = UseRegisterAtStart(instr->right()); 1468 return DefineAsRegister(new LCmpID(left, right)); 1469 } else if (r.IsDouble()) { 1470 ASSERT(instr->left()->representation().IsDouble()); 1471 ASSERT(instr->right()->representation().IsDouble()); 1472 LOperand* left = UseRegisterAtStart(instr->left()); 1473 LOperand* right = UseRegisterAtStart(instr->right()); 1474 return DefineAsRegister(new LCmpID(left, right)); 1475 } else { 1476 ASSERT(instr->left()->representation().IsTagged()); 1477 ASSERT(instr->right()->representation().IsTagged()); 1478 bool reversed = (op == Token::GT || op == Token::LTE); 1479 LOperand* left = UseFixed(instr->left(), reversed ? r0 : r1); 1480 LOperand* right = UseFixed(instr->right(), reversed ? r1 : r0); 1481 LCmpT* result = new LCmpT(left, right); 1482 return MarkAsCall(DefineFixed(result, r0), instr); 1483 } 1484} 1485 1486 1487LInstruction* LChunkBuilder::DoCompareJSObjectEq( 1488 HCompareJSObjectEq* instr) { 1489 LOperand* left = UseRegisterAtStart(instr->left()); 1490 LOperand* right = UseRegisterAtStart(instr->right()); 1491 LCmpJSObjectEq* result = new LCmpJSObjectEq(left, right); 1492 return DefineAsRegister(result); 1493} 1494 1495 1496LInstruction* LChunkBuilder::DoIsNull(HIsNull* instr) { 1497 ASSERT(instr->value()->representation().IsTagged()); 1498 LOperand* value = UseRegisterAtStart(instr->value()); 1499 1500 return DefineAsRegister(new LIsNull(value)); 1501} 1502 1503 1504LInstruction* LChunkBuilder::DoIsObject(HIsObject* instr) { 1505 ASSERT(instr->value()->representation().IsTagged()); 1506 LOperand* value = UseRegisterAtStart(instr->value()); 1507 1508 return DefineAsRegister(new LIsObject(value)); 1509} 1510 1511 1512LInstruction* LChunkBuilder::DoIsSmi(HIsSmi* instr) { 1513 ASSERT(instr->value()->representation().IsTagged()); 1514 LOperand* value = UseAtStart(instr->value()); 1515 1516 return DefineAsRegister(new LIsSmi(value)); 1517} 1518 1519 1520LInstruction* LChunkBuilder::DoHasInstanceType(HHasInstanceType* instr) { 1521 ASSERT(instr->value()->representation().IsTagged()); 1522 LOperand* value = UseRegisterAtStart(instr->value()); 1523 1524 return DefineAsRegister(new LHasInstanceType(value)); 1525} 1526 1527 1528LInstruction* LChunkBuilder::DoGetCachedArrayIndex( 1529 HGetCachedArrayIndex* instr) { 1530 ASSERT(instr->value()->representation().IsTagged()); 1531 LOperand* value = UseRegisterAtStart(instr->value()); 1532 1533 return DefineAsRegister(new LGetCachedArrayIndex(value)); 1534} 1535 1536 1537LInstruction* LChunkBuilder::DoHasCachedArrayIndex( 1538 HHasCachedArrayIndex* instr) { 1539 ASSERT(instr->value()->representation().IsTagged()); 1540 LOperand* value = UseRegister(instr->value()); 1541 1542 return DefineAsRegister(new LHasCachedArrayIndex(value)); 1543} 1544 1545 1546LInstruction* LChunkBuilder::DoClassOfTest(HClassOfTest* instr) { 1547 ASSERT(instr->value()->representation().IsTagged()); 1548 LOperand* value = UseTempRegister(instr->value()); 1549 return DefineSameAsFirst(new LClassOfTest(value)); 1550} 1551 1552 1553LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) { 1554 LOperand* array = UseRegisterAtStart(instr->value()); 1555 return DefineAsRegister(new LJSArrayLength(array)); 1556} 1557 1558 1559LInstruction* LChunkBuilder::DoExternalArrayLength( 1560 HExternalArrayLength* instr) { 1561 LOperand* array = UseRegisterAtStart(instr->value()); 1562 return DefineAsRegister(new LExternalArrayLength(array)); 1563} 1564 1565 1566LInstruction* LChunkBuilder::DoFixedArrayLength(HFixedArrayLength* instr) { 1567 LOperand* array = UseRegisterAtStart(instr->value()); 1568 return DefineAsRegister(new LFixedArrayLength(array)); 1569} 1570 1571 1572LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) { 1573 LOperand* object = UseRegister(instr->value()); 1574 LValueOf* result = new LValueOf(object, TempRegister()); 1575 return AssignEnvironment(DefineSameAsFirst(result)); 1576} 1577 1578 1579LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) { 1580 return AssignEnvironment(new LBoundsCheck(UseRegisterAtStart(instr->index()), 1581 UseRegister(instr->length()))); 1582} 1583 1584 1585LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) { 1586 // The control instruction marking the end of a block that completed 1587 // abruptly (e.g., threw an exception). There is nothing specific to do. 1588 return NULL; 1589} 1590 1591 1592LInstruction* LChunkBuilder::DoThrow(HThrow* instr) { 1593 LOperand* value = UseFixed(instr->value(), r0); 1594 return MarkAsCall(new LThrow(value), instr); 1595} 1596 1597 1598LInstruction* LChunkBuilder::DoChange(HChange* instr) { 1599 Representation from = instr->from(); 1600 Representation to = instr->to(); 1601 if (from.IsTagged()) { 1602 if (to.IsDouble()) { 1603 LOperand* value = UseRegister(instr->value()); 1604 LNumberUntagD* res = new LNumberUntagD(value); 1605 return AssignEnvironment(DefineAsRegister(res)); 1606 } else { 1607 ASSERT(to.IsInteger32()); 1608 LOperand* value = UseRegister(instr->value()); 1609 bool needs_check = !instr->value()->type().IsSmi(); 1610 LInstruction* res = NULL; 1611 if (!needs_check) { 1612 res = DefineSameAsFirst(new LSmiUntag(value, needs_check)); 1613 } else { 1614 LOperand* temp1 = TempRegister(); 1615 LOperand* temp2 = instr->CanTruncateToInt32() ? TempRegister() 1616 : NULL; 1617 LOperand* temp3 = instr->CanTruncateToInt32() ? FixedTemp(d3) 1618 : NULL; 1619 res = DefineSameAsFirst(new LTaggedToI(value, temp1, temp2, temp3)); 1620 res = AssignEnvironment(res); 1621 } 1622 return res; 1623 } 1624 } else if (from.IsDouble()) { 1625 if (to.IsTagged()) { 1626 LOperand* value = UseRegister(instr->value()); 1627 LOperand* temp1 = TempRegister(); 1628 LOperand* temp2 = TempRegister(); 1629 1630 // Make sure that the temp and result_temp registers are 1631 // different. 1632 LUnallocated* result_temp = TempRegister(); 1633 LNumberTagD* result = new LNumberTagD(value, temp1, temp2); 1634 Define(result, result_temp); 1635 return AssignPointerMap(result); 1636 } else { 1637 ASSERT(to.IsInteger32()); 1638 LOperand* value = UseRegister(instr->value()); 1639 LDoubleToI* res = 1640 new LDoubleToI(value, 1641 TempRegister(), 1642 instr->CanTruncateToInt32() ? TempRegister() : NULL); 1643 return AssignEnvironment(DefineAsRegister(res)); 1644 } 1645 } else if (from.IsInteger32()) { 1646 if (to.IsTagged()) { 1647 HValue* val = instr->value(); 1648 LOperand* value = UseRegister(val); 1649 if (val->HasRange() && val->range()->IsInSmiRange()) { 1650 return DefineSameAsFirst(new LSmiTag(value)); 1651 } else { 1652 LNumberTagI* result = new LNumberTagI(value); 1653 return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result))); 1654 } 1655 } else { 1656 ASSERT(to.IsDouble()); 1657 LOperand* value = Use(instr->value()); 1658 return DefineAsRegister(new LInteger32ToDouble(value)); 1659 } 1660 } 1661 UNREACHABLE(); 1662 return NULL; 1663} 1664 1665 1666LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) { 1667 LOperand* value = UseRegisterAtStart(instr->value()); 1668 return AssignEnvironment(new LCheckNonSmi(value)); 1669} 1670 1671 1672LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) { 1673 LOperand* value = UseRegisterAtStart(instr->value()); 1674 LInstruction* result = new LCheckInstanceType(value); 1675 return AssignEnvironment(result); 1676} 1677 1678 1679LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) { 1680 LOperand* temp1 = TempRegister(); 1681 LOperand* temp2 = TempRegister(); 1682 LInstruction* result = new LCheckPrototypeMaps(temp1, temp2); 1683 return AssignEnvironment(result); 1684} 1685 1686 1687LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) { 1688 LOperand* value = UseRegisterAtStart(instr->value()); 1689 return AssignEnvironment(new LCheckSmi(value)); 1690} 1691 1692 1693LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) { 1694 LOperand* value = UseRegisterAtStart(instr->value()); 1695 return AssignEnvironment(new LCheckFunction(value)); 1696} 1697 1698 1699LInstruction* LChunkBuilder::DoCheckMap(HCheckMap* instr) { 1700 LOperand* value = UseRegisterAtStart(instr->value()); 1701 LInstruction* result = new LCheckMap(value); 1702 return AssignEnvironment(result); 1703} 1704 1705 1706LInstruction* LChunkBuilder::DoReturn(HReturn* instr) { 1707 return new LReturn(UseFixed(instr->value(), r0)); 1708} 1709 1710 1711LInstruction* LChunkBuilder::DoConstant(HConstant* instr) { 1712 Representation r = instr->representation(); 1713 if (r.IsInteger32()) { 1714 return DefineAsRegister(new LConstantI); 1715 } else if (r.IsDouble()) { 1716 return DefineAsRegister(new LConstantD); 1717 } else if (r.IsTagged()) { 1718 return DefineAsRegister(new LConstantT); 1719 } else { 1720 UNREACHABLE(); 1721 return NULL; 1722 } 1723} 1724 1725 1726LInstruction* LChunkBuilder::DoLoadGlobalCell(HLoadGlobalCell* instr) { 1727 LLoadGlobalCell* result = new LLoadGlobalCell; 1728 return instr->check_hole_value() 1729 ? AssignEnvironment(DefineAsRegister(result)) 1730 : DefineAsRegister(result); 1731} 1732 1733 1734LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) { 1735 LOperand* global_object = UseFixed(instr->global_object(), r0); 1736 LLoadGlobalGeneric* result = new LLoadGlobalGeneric(global_object); 1737 return MarkAsCall(DefineFixed(result, r0), instr); 1738} 1739 1740 1741LInstruction* LChunkBuilder::DoStoreGlobalCell(HStoreGlobalCell* instr) { 1742 if (instr->check_hole_value()) { 1743 LOperand* temp = TempRegister(); 1744 LOperand* value = UseRegister(instr->value()); 1745 return AssignEnvironment(new LStoreGlobalCell(value, temp)); 1746 } else { 1747 LOperand* value = UseRegisterAtStart(instr->value()); 1748 return new LStoreGlobalCell(value, NULL); 1749 } 1750} 1751 1752 1753LInstruction* LChunkBuilder::DoStoreGlobalGeneric(HStoreGlobalGeneric* instr) { 1754 LOperand* global_object = UseFixed(instr->global_object(), r1); 1755 LOperand* value = UseFixed(instr->value(), r0); 1756 LStoreGlobalGeneric* result = 1757 new LStoreGlobalGeneric(global_object, value); 1758 return MarkAsCall(result, instr); 1759} 1760 1761 1762LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) { 1763 LOperand* context = UseRegisterAtStart(instr->value()); 1764 return DefineAsRegister(new LLoadContextSlot(context)); 1765} 1766 1767 1768LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) { 1769 LOperand* context; 1770 LOperand* value; 1771 if (instr->NeedsWriteBarrier()) { 1772 context = UseTempRegister(instr->context()); 1773 value = UseTempRegister(instr->value()); 1774 } else { 1775 context = UseRegister(instr->context()); 1776 value = UseRegister(instr->value()); 1777 } 1778 return new LStoreContextSlot(context, value); 1779} 1780 1781 1782LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) { 1783 return DefineAsRegister( 1784 new LLoadNamedField(UseRegisterAtStart(instr->object()))); 1785} 1786 1787 1788LInstruction* LChunkBuilder::DoLoadNamedFieldPolymorphic( 1789 HLoadNamedFieldPolymorphic* instr) { 1790 ASSERT(instr->representation().IsTagged()); 1791 if (instr->need_generic()) { 1792 LOperand* obj = UseFixed(instr->object(), r0); 1793 LLoadNamedFieldPolymorphic* result = new LLoadNamedFieldPolymorphic(obj); 1794 return MarkAsCall(DefineFixed(result, r0), instr); 1795 } else { 1796 LOperand* obj = UseRegisterAtStart(instr->object()); 1797 LLoadNamedFieldPolymorphic* result = new LLoadNamedFieldPolymorphic(obj); 1798 return AssignEnvironment(DefineAsRegister(result)); 1799 } 1800} 1801 1802 1803LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) { 1804 LOperand* object = UseFixed(instr->object(), r0); 1805 LInstruction* result = DefineFixed(new LLoadNamedGeneric(object), r0); 1806 return MarkAsCall(result, instr); 1807} 1808 1809 1810LInstruction* LChunkBuilder::DoLoadFunctionPrototype( 1811 HLoadFunctionPrototype* instr) { 1812 return AssignEnvironment(DefineAsRegister( 1813 new LLoadFunctionPrototype(UseRegister(instr->function())))); 1814} 1815 1816 1817LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) { 1818 LOperand* input = UseRegisterAtStart(instr->value()); 1819 return DefineAsRegister(new LLoadElements(input)); 1820} 1821 1822 1823LInstruction* LChunkBuilder::DoLoadExternalArrayPointer( 1824 HLoadExternalArrayPointer* instr) { 1825 LOperand* input = UseRegisterAtStart(instr->value()); 1826 return DefineAsRegister(new LLoadExternalArrayPointer(input)); 1827} 1828 1829 1830LInstruction* LChunkBuilder::DoLoadKeyedFastElement( 1831 HLoadKeyedFastElement* instr) { 1832 ASSERT(instr->representation().IsTagged()); 1833 ASSERT(instr->key()->representation().IsInteger32()); 1834 LOperand* obj = UseRegisterAtStart(instr->object()); 1835 LOperand* key = UseRegisterAtStart(instr->key()); 1836 LLoadKeyedFastElement* result = new LLoadKeyedFastElement(obj, key); 1837 return AssignEnvironment(DefineSameAsFirst(result)); 1838} 1839 1840 1841LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement( 1842 HLoadKeyedSpecializedArrayElement* instr) { 1843 ExternalArrayType array_type = instr->array_type(); 1844 Representation representation(instr->representation()); 1845 ASSERT((representation.IsInteger32() && array_type != kExternalFloatArray) || 1846 (representation.IsDouble() && array_type == kExternalFloatArray)); 1847 ASSERT(instr->key()->representation().IsInteger32()); 1848 LOperand* external_pointer = UseRegister(instr->external_pointer()); 1849 LOperand* key = UseRegister(instr->key()); 1850 LLoadKeyedSpecializedArrayElement* result = 1851 new LLoadKeyedSpecializedArrayElement(external_pointer, key); 1852 LInstruction* load_instr = DefineAsRegister(result); 1853 // An unsigned int array load might overflow and cause a deopt, make sure it 1854 // has an environment. 1855 return (array_type == kExternalUnsignedIntArray) ? 1856 AssignEnvironment(load_instr) : load_instr; 1857} 1858 1859 1860LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) { 1861 LOperand* object = UseFixed(instr->object(), r1); 1862 LOperand* key = UseFixed(instr->key(), r0); 1863 1864 LInstruction* result = 1865 DefineFixed(new LLoadKeyedGeneric(object, key), r0); 1866 return MarkAsCall(result, instr); 1867} 1868 1869 1870LInstruction* LChunkBuilder::DoStoreKeyedFastElement( 1871 HStoreKeyedFastElement* instr) { 1872 bool needs_write_barrier = instr->NeedsWriteBarrier(); 1873 ASSERT(instr->value()->representation().IsTagged()); 1874 ASSERT(instr->object()->representation().IsTagged()); 1875 ASSERT(instr->key()->representation().IsInteger32()); 1876 1877 LOperand* obj = UseTempRegister(instr->object()); 1878 LOperand* val = needs_write_barrier 1879 ? UseTempRegister(instr->value()) 1880 : UseRegisterAtStart(instr->value()); 1881 LOperand* key = needs_write_barrier 1882 ? UseTempRegister(instr->key()) 1883 : UseRegisterOrConstantAtStart(instr->key()); 1884 1885 return AssignEnvironment(new LStoreKeyedFastElement(obj, key, val)); 1886} 1887 1888 1889LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement( 1890 HStoreKeyedSpecializedArrayElement* instr) { 1891 Representation representation(instr->value()->representation()); 1892 ExternalArrayType array_type = instr->array_type(); 1893 ASSERT((representation.IsInteger32() && array_type != kExternalFloatArray) || 1894 (representation.IsDouble() && array_type == kExternalFloatArray)); 1895 ASSERT(instr->external_pointer()->representation().IsExternal()); 1896 ASSERT(instr->key()->representation().IsInteger32()); 1897 1898 LOperand* external_pointer = UseRegister(instr->external_pointer()); 1899 bool val_is_temp_register = array_type == kExternalPixelArray || 1900 array_type == kExternalFloatArray; 1901 LOperand* val = val_is_temp_register 1902 ? UseTempRegister(instr->value()) 1903 : UseRegister(instr->value()); 1904 LOperand* key = UseRegister(instr->key()); 1905 1906 return new LStoreKeyedSpecializedArrayElement(external_pointer, 1907 key, 1908 val); 1909} 1910 1911 1912LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) { 1913 LOperand* obj = UseFixed(instr->object(), r2); 1914 LOperand* key = UseFixed(instr->key(), r1); 1915 LOperand* val = UseFixed(instr->value(), r0); 1916 1917 ASSERT(instr->object()->representation().IsTagged()); 1918 ASSERT(instr->key()->representation().IsTagged()); 1919 ASSERT(instr->value()->representation().IsTagged()); 1920 1921 return MarkAsCall(new LStoreKeyedGeneric(obj, key, val), instr); 1922} 1923 1924 1925LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) { 1926 bool needs_write_barrier = instr->NeedsWriteBarrier(); 1927 1928 LOperand* obj = needs_write_barrier 1929 ? UseTempRegister(instr->object()) 1930 : UseRegisterAtStart(instr->object()); 1931 1932 LOperand* val = needs_write_barrier 1933 ? UseTempRegister(instr->value()) 1934 : UseRegister(instr->value()); 1935 1936 return new LStoreNamedField(obj, val); 1937} 1938 1939 1940LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) { 1941 LOperand* obj = UseFixed(instr->object(), r1); 1942 LOperand* val = UseFixed(instr->value(), r0); 1943 1944 LInstruction* result = new LStoreNamedGeneric(obj, val); 1945 return MarkAsCall(result, instr); 1946} 1947 1948 1949LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) { 1950 LOperand* string = UseRegister(instr->string()); 1951 LOperand* index = UseRegisterOrConstant(instr->index()); 1952 LStringCharCodeAt* result = new LStringCharCodeAt(string, index); 1953 return AssignEnvironment(AssignPointerMap(DefineAsRegister(result))); 1954} 1955 1956 1957LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) { 1958 LOperand* char_code = UseRegister(instr->value()); 1959 LStringCharFromCode* result = new LStringCharFromCode(char_code); 1960 return AssignPointerMap(DefineAsRegister(result)); 1961} 1962 1963 1964LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) { 1965 LOperand* string = UseRegisterAtStart(instr->value()); 1966 return DefineAsRegister(new LStringLength(string)); 1967} 1968 1969 1970LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) { 1971 return MarkAsCall(DefineFixed(new LArrayLiteral, r0), instr); 1972} 1973 1974 1975LInstruction* LChunkBuilder::DoObjectLiteral(HObjectLiteral* instr) { 1976 return MarkAsCall(DefineFixed(new LObjectLiteral, r0), instr); 1977} 1978 1979 1980LInstruction* LChunkBuilder::DoRegExpLiteral(HRegExpLiteral* instr) { 1981 return MarkAsCall(DefineFixed(new LRegExpLiteral, r0), instr); 1982} 1983 1984 1985LInstruction* LChunkBuilder::DoFunctionLiteral(HFunctionLiteral* instr) { 1986 return MarkAsCall(DefineFixed(new LFunctionLiteral, r0), instr); 1987} 1988 1989 1990LInstruction* LChunkBuilder::DoDeleteProperty(HDeleteProperty* instr) { 1991 LOperand* object = UseFixed(instr->object(), r0); 1992 LOperand* key = UseFixed(instr->key(), r1); 1993 LDeleteProperty* result = new LDeleteProperty(object, key); 1994 return MarkAsCall(DefineFixed(result, r0), instr); 1995} 1996 1997 1998LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) { 1999 allocator_->MarkAsOsrEntry(); 2000 current_block_->last_environment()->set_ast_id(instr->ast_id()); 2001 return AssignEnvironment(new LOsrEntry); 2002} 2003 2004 2005LInstruction* LChunkBuilder::DoParameter(HParameter* instr) { 2006 int spill_index = chunk()->GetParameterStackSlot(instr->index()); 2007 return DefineAsSpilled(new LParameter, spill_index); 2008} 2009 2010 2011LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) { 2012 int spill_index = chunk()->GetNextSpillIndex(false); // Not double-width. 2013 if (spill_index > LUnallocated::kMaxFixedIndex) { 2014 Abort("Too many spill slots needed for OSR"); 2015 spill_index = 0; 2016 } 2017 return DefineAsSpilled(new LUnknownOSRValue, spill_index); 2018} 2019 2020 2021LInstruction* LChunkBuilder::DoCallStub(HCallStub* instr) { 2022 argument_count_ -= instr->argument_count(); 2023 return MarkAsCall(DefineFixed(new LCallStub, r0), instr); 2024} 2025 2026 2027LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) { 2028 // There are no real uses of the arguments object. 2029 // arguments.length and element access are supported directly on 2030 // stack arguments, and any real arguments object use causes a bailout. 2031 // So this value is never used. 2032 return NULL; 2033} 2034 2035 2036LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) { 2037 LOperand* arguments = UseRegister(instr->arguments()); 2038 LOperand* length = UseTempRegister(instr->length()); 2039 LOperand* index = UseRegister(instr->index()); 2040 LAccessArgumentsAt* result = new LAccessArgumentsAt(arguments, length, index); 2041 return AssignEnvironment(DefineAsRegister(result)); 2042} 2043 2044 2045LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) { 2046 LOperand* object = UseFixed(instr->value(), r0); 2047 LToFastProperties* result = new LToFastProperties(object); 2048 return MarkAsCall(DefineFixed(result, r0), instr); 2049} 2050 2051 2052LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) { 2053 LTypeof* result = new LTypeof(UseFixed(instr->value(), r0)); 2054 return MarkAsCall(DefineFixed(result, r0), instr); 2055} 2056 2057 2058LInstruction* LChunkBuilder::DoTypeofIs(HTypeofIs* instr) { 2059 return DefineSameAsFirst(new LTypeofIs(UseRegister(instr->value()))); 2060} 2061 2062 2063LInstruction* LChunkBuilder::DoIsConstructCall(HIsConstructCall* instr) { 2064 return DefineAsRegister(new LIsConstructCall()); 2065} 2066 2067 2068LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) { 2069 HEnvironment* env = current_block_->last_environment(); 2070 ASSERT(env != NULL); 2071 2072 env->set_ast_id(instr->ast_id()); 2073 2074 env->Drop(instr->pop_count()); 2075 for (int i = 0; i < instr->values()->length(); ++i) { 2076 HValue* value = instr->values()->at(i); 2077 if (instr->HasAssignedIndexAt(i)) { 2078 env->Bind(instr->GetAssignedIndexAt(i), value); 2079 } else { 2080 env->Push(value); 2081 } 2082 } 2083 2084 // If there is an instruction pending deoptimization environment create a 2085 // lazy bailout instruction to capture the environment. 2086 if (pending_deoptimization_ast_id_ == instr->ast_id()) { 2087 LInstruction* result = new LLazyBailout; 2088 result = AssignEnvironment(result); 2089 instruction_pending_deoptimization_environment_-> 2090 set_deoptimization_environment(result->environment()); 2091 ClearInstructionPendingDeoptimizationEnvironment(); 2092 return result; 2093 } 2094 2095 return NULL; 2096} 2097 2098 2099LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) { 2100 return MarkAsCall(new LStackCheck, instr); 2101} 2102 2103 2104LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) { 2105 HEnvironment* outer = current_block_->last_environment(); 2106 HConstant* undefined = graph()->GetConstantUndefined(); 2107 HEnvironment* inner = outer->CopyForInlining(instr->closure(), 2108 instr->function(), 2109 false, 2110 undefined); 2111 current_block_->UpdateEnvironment(inner); 2112 chunk_->AddInlinedClosure(instr->closure()); 2113 return NULL; 2114} 2115 2116 2117LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) { 2118 HEnvironment* outer = current_block_->last_environment()->outer(); 2119 current_block_->UpdateEnvironment(outer); 2120 return NULL; 2121} 2122 2123 2124} } // namespace v8::internal 2125