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