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 "arm/lithium-arm.h" 32 #include "arm/lithium-codegen-arm.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 "shl-t"; 186 case Token::SAR: return "sar-t"; 187 case Token::SHR: return "shr-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("[r2] #%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(), r1); 840 LOperand* right = UseFixed(instr->right(), r0); 841 LArithmeticT* result = new(zone()) LArithmeticT(op, left, right); 842 return MarkAsCall(DefineFixed(result, r0), 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, r1); 905 LOperand* right_operand = UseFixed(right, r0); 906 LArithmeticT* result = 907 new(zone()) LArithmeticT(op, left_operand, right_operand); 908 return MarkAsCall(DefineFixed(result, r0), 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 1065 LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) { 1066 ASSERT(instr->value()->representation().IsTagged()); 1067 LOperand* value = UseRegisterAtStart(instr->value()); 1068 LOperand* temp = TempRegister(); 1069 return new(zone()) LCmpMapAndBranch(value, temp); 1070 } 1071 1072 1073 LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* instr) { 1074 LOperand* value = UseRegister(instr->value()); 1075 return DefineAsRegister(new(zone()) LArgumentsLength(value)); 1076 } 1077 1078 1079 LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) { 1080 return DefineAsRegister(new(zone()) LArgumentsElements); 1081 } 1082 1083 1084 LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) { 1085 LInstanceOf* result = 1086 new(zone()) LInstanceOf(UseFixed(instr->left(), r0), 1087 UseFixed(instr->right(), r1)); 1088 return MarkAsCall(DefineFixed(result, r0), instr); 1089 } 1090 1091 1092 LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal( 1093 HInstanceOfKnownGlobal* instr) { 1094 LInstanceOfKnownGlobal* result = 1095 new(zone()) LInstanceOfKnownGlobal(UseFixed(instr->left(), r0), 1096 FixedTemp(r4)); 1097 return MarkAsCall(DefineFixed(result, r0), instr); 1098 } 1099 1100 1101 LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) { 1102 LOperand* receiver = UseRegisterAtStart(instr->receiver()); 1103 LOperand* function = UseRegisterAtStart(instr->function()); 1104 LWrapReceiver* result = new(zone()) LWrapReceiver(receiver, function); 1105 return AssignEnvironment(DefineSameAsFirst(result)); 1106 } 1107 1108 1109 LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) { 1110 LOperand* function = UseFixed(instr->function(), r1); 1111 LOperand* receiver = UseFixed(instr->receiver(), r0); 1112 LOperand* length = UseFixed(instr->length(), r2); 1113 LOperand* elements = UseFixed(instr->elements(), r3); 1114 LApplyArguments* result = new(zone()) LApplyArguments(function, 1115 receiver, 1116 length, 1117 elements); 1118 return MarkAsCall(DefineFixed(result, r0), instr, CAN_DEOPTIMIZE_EAGERLY); 1119 } 1120 1121 1122 LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) { 1123 ++argument_count_; 1124 LOperand* argument = Use(instr->argument()); 1125 return new(zone()) LPushArgument(argument); 1126 } 1127 1128 1129 LInstruction* LChunkBuilder::DoThisFunction(HThisFunction* instr) { 1130 return instr->HasNoUses() 1131 ? NULL 1132 : DefineAsRegister(new(zone()) LThisFunction); 1133 } 1134 1135 1136 LInstruction* LChunkBuilder::DoContext(HContext* instr) { 1137 return instr->HasNoUses() ? NULL : DefineAsRegister(new(zone()) LContext); 1138 } 1139 1140 1141 LInstruction* LChunkBuilder::DoOuterContext(HOuterContext* instr) { 1142 LOperand* context = UseRegisterAtStart(instr->value()); 1143 return DefineAsRegister(new(zone()) LOuterContext(context)); 1144 } 1145 1146 1147 LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) { 1148 return MarkAsCall(new(zone()) LDeclareGlobals, instr); 1149 } 1150 1151 1152 LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) { 1153 LOperand* context = UseRegisterAtStart(instr->value()); 1154 return DefineAsRegister(new(zone()) LGlobalObject(context)); 1155 } 1156 1157 1158 LInstruction* LChunkBuilder::DoGlobalReceiver(HGlobalReceiver* instr) { 1159 LOperand* global_object = UseRegisterAtStart(instr->value()); 1160 return DefineAsRegister(new(zone()) LGlobalReceiver(global_object)); 1161 } 1162 1163 1164 LInstruction* LChunkBuilder::DoCallConstantFunction( 1165 HCallConstantFunction* instr) { 1166 argument_count_ -= instr->argument_count(); 1167 return MarkAsCall(DefineFixed(new(zone()) LCallConstantFunction, r0), instr); 1168 } 1169 1170 1171 LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) { 1172 LOperand* function = UseFixed(instr->function(), r1); 1173 argument_count_ -= instr->argument_count(); 1174 LInvokeFunction* result = new(zone()) LInvokeFunction(function); 1175 return MarkAsCall(DefineFixed(result, r0), instr, CANNOT_DEOPTIMIZE_EAGERLY); 1176 } 1177 1178 1179 LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) { 1180 BuiltinFunctionId op = instr->op(); 1181 if (op == kMathLog || op == kMathSin || op == kMathCos || op == kMathTan) { 1182 LOperand* input = UseFixedDouble(instr->value(), d2); 1183 LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, NULL); 1184 return MarkAsCall(DefineFixedDouble(result, d2), instr); 1185 } else if (op == kMathPowHalf) { 1186 LOperand* input = UseFixedDouble(instr->value(), d2); 1187 LOperand* temp = FixedTemp(d3); 1188 LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, temp); 1189 return DefineFixedDouble(result, d2); 1190 } else { 1191 LOperand* input = UseRegisterAtStart(instr->value()); 1192 LOperand* temp = (op == kMathFloor) ? TempRegister() : NULL; 1193 LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, temp); 1194 switch (op) { 1195 case kMathAbs: 1196 return AssignEnvironment(AssignPointerMap(DefineAsRegister(result))); 1197 case kMathFloor: 1198 return AssignEnvironment(AssignPointerMap(DefineAsRegister(result))); 1199 case kMathSqrt: 1200 return DefineAsRegister(result); 1201 case kMathRound: 1202 return AssignEnvironment(DefineAsRegister(result)); 1203 default: 1204 UNREACHABLE(); 1205 return NULL; 1206 } 1207 } 1208 } 1209 1210 1211 LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) { 1212 ASSERT(instr->key()->representation().IsTagged()); 1213 argument_count_ -= instr->argument_count(); 1214 LOperand* key = UseFixed(instr->key(), r2); 1215 return MarkAsCall(DefineFixed(new(zone()) LCallKeyed(key), r0), instr); 1216 } 1217 1218 1219 LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) { 1220 argument_count_ -= instr->argument_count(); 1221 return MarkAsCall(DefineFixed(new(zone()) LCallNamed, r0), instr); 1222 } 1223 1224 1225 LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) { 1226 argument_count_ -= instr->argument_count(); 1227 return MarkAsCall(DefineFixed(new(zone()) LCallGlobal, r0), instr); 1228 } 1229 1230 1231 LInstruction* LChunkBuilder::DoCallKnownGlobal(HCallKnownGlobal* instr) { 1232 argument_count_ -= instr->argument_count(); 1233 return MarkAsCall(DefineFixed(new(zone()) LCallKnownGlobal, r0), instr); 1234 } 1235 1236 1237 LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) { 1238 LOperand* constructor = UseFixed(instr->constructor(), r1); 1239 argument_count_ -= instr->argument_count(); 1240 LCallNew* result = new(zone()) LCallNew(constructor); 1241 return MarkAsCall(DefineFixed(result, r0), instr); 1242 } 1243 1244 1245 LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) { 1246 LOperand* function = UseFixed(instr->function(), r1); 1247 argument_count_ -= instr->argument_count(); 1248 return MarkAsCall(DefineFixed(new(zone()) LCallFunction(function), r0), 1249 instr); 1250 } 1251 1252 1253 LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) { 1254 argument_count_ -= instr->argument_count(); 1255 return MarkAsCall(DefineFixed(new(zone()) LCallRuntime, r0), instr); 1256 } 1257 1258 1259 LInstruction* LChunkBuilder::DoShr(HShr* instr) { 1260 return DoShift(Token::SHR, instr); 1261 } 1262 1263 1264 LInstruction* LChunkBuilder::DoSar(HSar* instr) { 1265 return DoShift(Token::SAR, instr); 1266 } 1267 1268 1269 LInstruction* LChunkBuilder::DoShl(HShl* instr) { 1270 return DoShift(Token::SHL, instr); 1271 } 1272 1273 1274 LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) { 1275 if (instr->representation().IsInteger32()) { 1276 ASSERT(instr->left()->representation().IsInteger32()); 1277 ASSERT(instr->right()->representation().IsInteger32()); 1278 1279 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand()); 1280 LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand()); 1281 return DefineAsRegister(new(zone()) LBitI(left, right)); 1282 } else { 1283 ASSERT(instr->representation().IsTagged()); 1284 ASSERT(instr->left()->representation().IsTagged()); 1285 ASSERT(instr->right()->representation().IsTagged()); 1286 1287 LOperand* left = UseFixed(instr->left(), r1); 1288 LOperand* right = UseFixed(instr->right(), r0); 1289 LArithmeticT* result = new(zone()) LArithmeticT(instr->op(), left, right); 1290 return MarkAsCall(DefineFixed(result, r0), instr); 1291 } 1292 } 1293 1294 1295 LInstruction* LChunkBuilder::DoBitNot(HBitNot* instr) { 1296 ASSERT(instr->value()->representation().IsInteger32()); 1297 ASSERT(instr->representation().IsInteger32()); 1298 LOperand* value = UseRegisterAtStart(instr->value()); 1299 return DefineAsRegister(new(zone()) LBitNotI(value)); 1300 } 1301 1302 1303 LInstruction* LChunkBuilder::DoDiv(HDiv* instr) { 1304 if (instr->representation().IsDouble()) { 1305 return DoArithmeticD(Token::DIV, instr); 1306 } else if (instr->representation().IsInteger32()) { 1307 // TODO(1042) The fixed register allocation 1308 // is needed because we call TypeRecordingBinaryOpStub from 1309 // the generated code, which requires registers r0 1310 // and r1 to be used. We should remove that 1311 // when we provide a native implementation. 1312 LOperand* dividend = UseFixed(instr->left(), r0); 1313 LOperand* divisor = UseFixed(instr->right(), r1); 1314 return AssignEnvironment(AssignPointerMap( 1315 DefineFixed(new(zone()) LDivI(dividend, divisor), r0))); 1316 } else { 1317 return DoArithmeticT(Token::DIV, instr); 1318 } 1319 } 1320 1321 1322 LInstruction* LChunkBuilder::DoMod(HMod* instr) { 1323 if (instr->representation().IsInteger32()) { 1324 ASSERT(instr->left()->representation().IsInteger32()); 1325 ASSERT(instr->right()->representation().IsInteger32()); 1326 1327 LModI* mod; 1328 if (instr->HasPowerOf2Divisor()) { 1329 ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero)); 1330 LOperand* value = UseRegisterAtStart(instr->left()); 1331 mod = new(zone()) LModI(value, UseOrConstant(instr->right())); 1332 } else { 1333 LOperand* dividend = UseRegister(instr->left()); 1334 LOperand* divisor = UseRegister(instr->right()); 1335 mod = new(zone()) LModI(dividend, 1336 divisor, 1337 TempRegister(), 1338 FixedTemp(d10), 1339 FixedTemp(d11)); 1340 } 1341 1342 if (instr->CheckFlag(HValue::kBailoutOnMinusZero) || 1343 instr->CheckFlag(HValue::kCanBeDivByZero)) { 1344 return AssignEnvironment(DefineAsRegister(mod)); 1345 } else { 1346 return DefineAsRegister(mod); 1347 } 1348 } else if (instr->representation().IsTagged()) { 1349 return DoArithmeticT(Token::MOD, instr); 1350 } else { 1351 ASSERT(instr->representation().IsDouble()); 1352 // We call a C function for double modulo. It can't trigger a GC. 1353 // We need to use fixed result register for the call. 1354 // TODO(fschneider): Allow any register as input registers. 1355 LOperand* left = UseFixedDouble(instr->left(), d1); 1356 LOperand* right = UseFixedDouble(instr->right(), d2); 1357 LArithmeticD* result = new(zone()) LArithmeticD(Token::MOD, left, right); 1358 return MarkAsCall(DefineFixedDouble(result, d1), instr); 1359 } 1360 } 1361 1362 1363 LInstruction* LChunkBuilder::DoMul(HMul* instr) { 1364 if (instr->representation().IsInteger32()) { 1365 ASSERT(instr->left()->representation().IsInteger32()); 1366 ASSERT(instr->right()->representation().IsInteger32()); 1367 LOperand* left; 1368 LOperand* right = UseOrConstant(instr->MostConstantOperand()); 1369 LOperand* temp = NULL; 1370 if (instr->CheckFlag(HValue::kBailoutOnMinusZero) && 1371 (instr->CheckFlag(HValue::kCanOverflow) || 1372 !right->IsConstantOperand())) { 1373 left = UseRegister(instr->LeastConstantOperand()); 1374 temp = TempRegister(); 1375 } else { 1376 left = UseRegisterAtStart(instr->LeastConstantOperand()); 1377 } 1378 LMulI* mul = new(zone()) LMulI(left, right, temp); 1379 if (instr->CheckFlag(HValue::kCanOverflow) || 1380 instr->CheckFlag(HValue::kBailoutOnMinusZero)) { 1381 AssignEnvironment(mul); 1382 } 1383 return DefineAsRegister(mul); 1384 1385 } else if (instr->representation().IsDouble()) { 1386 return DoArithmeticD(Token::MUL, instr); 1387 1388 } else { 1389 return DoArithmeticT(Token::MUL, instr); 1390 } 1391 } 1392 1393 1394 LInstruction* LChunkBuilder::DoSub(HSub* instr) { 1395 if (instr->representation().IsInteger32()) { 1396 ASSERT(instr->left()->representation().IsInteger32()); 1397 ASSERT(instr->right()->representation().IsInteger32()); 1398 LOperand* left = UseRegisterAtStart(instr->left()); 1399 LOperand* right = UseOrConstantAtStart(instr->right()); 1400 LSubI* sub = new(zone()) LSubI(left, right); 1401 LInstruction* result = DefineAsRegister(sub); 1402 if (instr->CheckFlag(HValue::kCanOverflow)) { 1403 result = AssignEnvironment(result); 1404 } 1405 return result; 1406 } else if (instr->representation().IsDouble()) { 1407 return DoArithmeticD(Token::SUB, instr); 1408 } else { 1409 return DoArithmeticT(Token::SUB, instr); 1410 } 1411 } 1412 1413 1414 LInstruction* LChunkBuilder::DoAdd(HAdd* instr) { 1415 if (instr->representation().IsInteger32()) { 1416 ASSERT(instr->left()->representation().IsInteger32()); 1417 ASSERT(instr->right()->representation().IsInteger32()); 1418 LOperand* left = UseRegisterAtStart(instr->LeastConstantOperand()); 1419 LOperand* right = UseOrConstantAtStart(instr->MostConstantOperand()); 1420 LAddI* add = new(zone()) LAddI(left, right); 1421 LInstruction* result = DefineAsRegister(add); 1422 if (instr->CheckFlag(HValue::kCanOverflow)) { 1423 result = AssignEnvironment(result); 1424 } 1425 return result; 1426 } else if (instr->representation().IsDouble()) { 1427 return DoArithmeticD(Token::ADD, instr); 1428 } else { 1429 ASSERT(instr->representation().IsTagged()); 1430 return DoArithmeticT(Token::ADD, instr); 1431 } 1432 } 1433 1434 1435 LInstruction* LChunkBuilder::DoPower(HPower* instr) { 1436 ASSERT(instr->representation().IsDouble()); 1437 // We call a C function for double power. It can't trigger a GC. 1438 // We need to use fixed result register for the call. 1439 Representation exponent_type = instr->right()->representation(); 1440 ASSERT(instr->left()->representation().IsDouble()); 1441 LOperand* left = UseFixedDouble(instr->left(), d1); 1442 LOperand* right = exponent_type.IsDouble() ? 1443 UseFixedDouble(instr->right(), d2) : 1444 UseFixed(instr->right(), r2); 1445 LPower* result = new(zone()) LPower(left, right); 1446 return MarkAsCall(DefineFixedDouble(result, d3), 1447 instr, 1448 CAN_DEOPTIMIZE_EAGERLY); 1449 } 1450 1451 1452 LInstruction* LChunkBuilder::DoRandom(HRandom* instr) { 1453 ASSERT(instr->representation().IsDouble()); 1454 ASSERT(instr->global_object()->representation().IsTagged()); 1455 LOperand* global_object = UseFixed(instr->global_object(), r0); 1456 LRandom* result = new(zone()) LRandom(global_object); 1457 return MarkAsCall(DefineFixedDouble(result, d7), instr); 1458 } 1459 1460 1461 LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) { 1462 ASSERT(instr->left()->representation().IsTagged()); 1463 ASSERT(instr->right()->representation().IsTagged()); 1464 LOperand* left = UseFixed(instr->left(), r1); 1465 LOperand* right = UseFixed(instr->right(), r0); 1466 LCmpT* result = new(zone()) LCmpT(left, right); 1467 return MarkAsCall(DefineFixed(result, r0), instr); 1468 } 1469 1470 1471 LInstruction* LChunkBuilder::DoCompareIDAndBranch( 1472 HCompareIDAndBranch* instr) { 1473 Representation r = instr->GetInputRepresentation(); 1474 if (r.IsInteger32()) { 1475 ASSERT(instr->left()->representation().IsInteger32()); 1476 ASSERT(instr->right()->representation().IsInteger32()); 1477 LOperand* left = UseRegisterOrConstantAtStart(instr->left()); 1478 LOperand* right = UseRegisterOrConstantAtStart(instr->right()); 1479 return new(zone()) LCmpIDAndBranch(left, right); 1480 } else { 1481 ASSERT(r.IsDouble()); 1482 ASSERT(instr->left()->representation().IsDouble()); 1483 ASSERT(instr->right()->representation().IsDouble()); 1484 LOperand* left = UseRegisterAtStart(instr->left()); 1485 LOperand* right = UseRegisterAtStart(instr->right()); 1486 return new(zone()) LCmpIDAndBranch(left, right); 1487 } 1488 } 1489 1490 1491 LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch( 1492 HCompareObjectEqAndBranch* instr) { 1493 LOperand* left = UseRegisterAtStart(instr->left()); 1494 LOperand* right = UseRegisterAtStart(instr->right()); 1495 return new(zone()) LCmpObjectEqAndBranch(left, right); 1496 } 1497 1498 1499 LInstruction* LChunkBuilder::DoCompareConstantEqAndBranch( 1500 HCompareConstantEqAndBranch* instr) { 1501 LOperand* value = UseRegisterAtStart(instr->value()); 1502 return new(zone()) LCmpConstantEqAndBranch(value); 1503 } 1504 1505 1506 LInstruction* LChunkBuilder::DoIsNilAndBranch(HIsNilAndBranch* instr) { 1507 ASSERT(instr->value()->representation().IsTagged()); 1508 return new(zone()) LIsNilAndBranch(UseRegisterAtStart(instr->value())); 1509 } 1510 1511 1512 LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) { 1513 ASSERT(instr->value()->representation().IsTagged()); 1514 LOperand* value = UseRegisterAtStart(instr->value()); 1515 LOperand* temp = TempRegister(); 1516 return new(zone()) LIsObjectAndBranch(value, temp); 1517 } 1518 1519 1520 LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) { 1521 ASSERT(instr->value()->representation().IsTagged()); 1522 LOperand* value = UseRegisterAtStart(instr->value()); 1523 LOperand* temp = TempRegister(); 1524 return new(zone()) LIsStringAndBranch(value, temp); 1525 } 1526 1527 1528 LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) { 1529 ASSERT(instr->value()->representation().IsTagged()); 1530 return new(zone()) LIsSmiAndBranch(Use(instr->value())); 1531 } 1532 1533 1534 LInstruction* LChunkBuilder::DoIsUndetectableAndBranch( 1535 HIsUndetectableAndBranch* instr) { 1536 ASSERT(instr->value()->representation().IsTagged()); 1537 LOperand* value = UseRegisterAtStart(instr->value()); 1538 return new(zone()) LIsUndetectableAndBranch(value, TempRegister()); 1539 } 1540 1541 1542 LInstruction* LChunkBuilder::DoStringCompareAndBranch( 1543 HStringCompareAndBranch* instr) { 1544 ASSERT(instr->left()->representation().IsTagged()); 1545 ASSERT(instr->right()->representation().IsTagged()); 1546 LOperand* left = UseFixed(instr->left(), r1); 1547 LOperand* right = UseFixed(instr->right(), r0); 1548 LStringCompareAndBranch* result = 1549 new(zone()) LStringCompareAndBranch(left, right); 1550 return MarkAsCall(result, instr); 1551 } 1552 1553 1554 LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch( 1555 HHasInstanceTypeAndBranch* instr) { 1556 ASSERT(instr->value()->representation().IsTagged()); 1557 LOperand* value = UseRegisterAtStart(instr->value()); 1558 return new(zone()) LHasInstanceTypeAndBranch(value); 1559 } 1560 1561 1562 LInstruction* LChunkBuilder::DoGetCachedArrayIndex( 1563 HGetCachedArrayIndex* instr) { 1564 ASSERT(instr->value()->representation().IsTagged()); 1565 LOperand* value = UseRegisterAtStart(instr->value()); 1566 1567 return DefineAsRegister(new(zone()) LGetCachedArrayIndex(value)); 1568 } 1569 1570 1571 LInstruction* LChunkBuilder::DoHasCachedArrayIndexAndBranch( 1572 HHasCachedArrayIndexAndBranch* instr) { 1573 ASSERT(instr->value()->representation().IsTagged()); 1574 return new(zone()) LHasCachedArrayIndexAndBranch( 1575 UseRegisterAtStart(instr->value())); 1576 } 1577 1578 1579 LInstruction* LChunkBuilder::DoClassOfTestAndBranch( 1580 HClassOfTestAndBranch* instr) { 1581 ASSERT(instr->value()->representation().IsTagged()); 1582 LOperand* value = UseRegister(instr->value()); 1583 return new(zone()) LClassOfTestAndBranch(value, TempRegister()); 1584 } 1585 1586 1587 LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) { 1588 LOperand* array = UseRegisterAtStart(instr->value()); 1589 return DefineAsRegister(new(zone()) LJSArrayLength(array)); 1590 } 1591 1592 1593 LInstruction* LChunkBuilder::DoFixedArrayBaseLength( 1594 HFixedArrayBaseLength* instr) { 1595 LOperand* array = UseRegisterAtStart(instr->value()); 1596 return DefineAsRegister(new(zone()) LFixedArrayBaseLength(array)); 1597 } 1598 1599 1600 LInstruction* LChunkBuilder::DoElementsKind(HElementsKind* instr) { 1601 LOperand* object = UseRegisterAtStart(instr->value()); 1602 return DefineAsRegister(new(zone()) LElementsKind(object)); 1603 } 1604 1605 1606 LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) { 1607 LOperand* object = UseRegister(instr->value()); 1608 LValueOf* result = new(zone()) LValueOf(object, TempRegister()); 1609 return DefineAsRegister(result); 1610 } 1611 1612 1613 LInstruction* LChunkBuilder::DoDateField(HDateField* instr) { 1614 LOperand* object = UseFixed(instr->value(), r0); 1615 LDateField* result = new LDateField(object, FixedTemp(r1), instr->index()); 1616 return MarkAsCall(DefineFixed(result, r0), instr); 1617 } 1618 1619 1620 LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) { 1621 LOperand* value = UseRegisterAtStart(instr->index()); 1622 LOperand* length = UseRegister(instr->length()); 1623 return AssignEnvironment(new(zone()) LBoundsCheck(value, length)); 1624 } 1625 1626 1627 LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) { 1628 // The control instruction marking the end of a block that completed 1629 // abruptly (e.g., threw an exception). There is nothing specific to do. 1630 return NULL; 1631 } 1632 1633 1634 LInstruction* LChunkBuilder::DoThrow(HThrow* instr) { 1635 LOperand* value = UseFixed(instr->value(), r0); 1636 return MarkAsCall(new(zone()) LThrow(value), instr); 1637 } 1638 1639 1640 LInstruction* LChunkBuilder::DoUseConst(HUseConst* instr) { 1641 return NULL; 1642 } 1643 1644 1645 LInstruction* LChunkBuilder::DoForceRepresentation(HForceRepresentation* bad) { 1646 // All HForceRepresentation instructions should be eliminated in the 1647 // representation change phase of Hydrogen. 1648 UNREACHABLE(); 1649 return NULL; 1650 } 1651 1652 1653 LInstruction* LChunkBuilder::DoChange(HChange* instr) { 1654 Representation from = instr->from(); 1655 Representation to = instr->to(); 1656 if (from.IsTagged()) { 1657 if (to.IsDouble()) { 1658 LOperand* value = UseRegister(instr->value()); 1659 LNumberUntagD* res = new(zone()) LNumberUntagD(value); 1660 return AssignEnvironment(DefineAsRegister(res)); 1661 } else { 1662 ASSERT(to.IsInteger32()); 1663 LOperand* value = UseRegisterAtStart(instr->value()); 1664 bool needs_check = !instr->value()->type().IsSmi(); 1665 LInstruction* res = NULL; 1666 if (!needs_check) { 1667 res = DefineAsRegister(new(zone()) LSmiUntag(value, needs_check)); 1668 } else { 1669 LOperand* temp1 = TempRegister(); 1670 LOperand* temp2 = instr->CanTruncateToInt32() ? TempRegister() 1671 : NULL; 1672 LOperand* temp3 = instr->CanTruncateToInt32() ? FixedTemp(d11) 1673 : NULL; 1674 res = DefineSameAsFirst(new(zone()) LTaggedToI(value, 1675 temp1, 1676 temp2, 1677 temp3)); 1678 res = AssignEnvironment(res); 1679 } 1680 return res; 1681 } 1682 } else if (from.IsDouble()) { 1683 if (to.IsTagged()) { 1684 LOperand* value = UseRegister(instr->value()); 1685 LOperand* temp1 = TempRegister(); 1686 LOperand* temp2 = TempRegister(); 1687 1688 // Make sure that the temp and result_temp registers are 1689 // different. 1690 LUnallocated* result_temp = TempRegister(); 1691 LNumberTagD* result = new(zone()) LNumberTagD(value, temp1, temp2); 1692 Define(result, result_temp); 1693 return AssignPointerMap(result); 1694 } else { 1695 ASSERT(to.IsInteger32()); 1696 LOperand* value = UseRegister(instr->value()); 1697 LOperand* temp1 = TempRegister(); 1698 LOperand* temp2 = instr->CanTruncateToInt32() ? TempRegister() : NULL; 1699 LDoubleToI* res = new(zone()) LDoubleToI(value, temp1, temp2); 1700 return AssignEnvironment(DefineAsRegister(res)); 1701 } 1702 } else if (from.IsInteger32()) { 1703 if (to.IsTagged()) { 1704 HValue* val = instr->value(); 1705 LOperand* value = UseRegisterAtStart(val); 1706 if (val->HasRange() && val->range()->IsInSmiRange()) { 1707 return DefineAsRegister(new(zone()) LSmiTag(value)); 1708 } else { 1709 LNumberTagI* result = new(zone()) LNumberTagI(value); 1710 return AssignEnvironment(AssignPointerMap(DefineAsRegister(result))); 1711 } 1712 } else { 1713 ASSERT(to.IsDouble()); 1714 LOperand* value = Use(instr->value()); 1715 return DefineAsRegister(new(zone()) LInteger32ToDouble(value)); 1716 } 1717 } 1718 UNREACHABLE(); 1719 return NULL; 1720 } 1721 1722 1723 LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) { 1724 LOperand* value = UseRegisterAtStart(instr->value()); 1725 return AssignEnvironment(new(zone()) LCheckNonSmi(value)); 1726 } 1727 1728 1729 LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) { 1730 LOperand* value = UseRegisterAtStart(instr->value()); 1731 LInstruction* result = new(zone()) LCheckInstanceType(value); 1732 return AssignEnvironment(result); 1733 } 1734 1735 1736 LInstruction* LChunkBuilder::DoCheckPrototypeMaps(HCheckPrototypeMaps* instr) { 1737 LOperand* temp1 = TempRegister(); 1738 LOperand* temp2 = TempRegister(); 1739 LInstruction* result = new(zone()) LCheckPrototypeMaps(temp1, temp2); 1740 return AssignEnvironment(result); 1741 } 1742 1743 1744 LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) { 1745 LOperand* value = UseRegisterAtStart(instr->value()); 1746 return AssignEnvironment(new(zone()) LCheckSmi(value)); 1747 } 1748 1749 1750 LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) { 1751 LOperand* value = UseRegisterAtStart(instr->value()); 1752 return AssignEnvironment(new(zone()) LCheckFunction(value)); 1753 } 1754 1755 1756 LInstruction* LChunkBuilder::DoCheckMap(HCheckMap* instr) { 1757 LOperand* value = UseRegisterAtStart(instr->value()); 1758 LInstruction* result = new(zone()) LCheckMap(value); 1759 return AssignEnvironment(result); 1760 } 1761 1762 1763 LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) { 1764 HValue* value = instr->value(); 1765 Representation input_rep = value->representation(); 1766 LOperand* reg = UseRegister(value); 1767 if (input_rep.IsDouble()) { 1768 return DefineAsRegister(new(zone()) LClampDToUint8(reg, FixedTemp(d11))); 1769 } else if (input_rep.IsInteger32()) { 1770 return DefineAsRegister(new(zone()) LClampIToUint8(reg)); 1771 } else { 1772 ASSERT(input_rep.IsTagged()); 1773 // Register allocator doesn't (yet) support allocation of double 1774 // temps. Reserve d1 explicitly. 1775 LClampTToUint8* result = new(zone()) LClampTToUint8(reg, FixedTemp(d11)); 1776 return AssignEnvironment(DefineAsRegister(result)); 1777 } 1778 } 1779 1780 1781 LInstruction* LChunkBuilder::DoReturn(HReturn* instr) { 1782 return new(zone()) LReturn(UseFixed(instr->value(), r0)); 1783 } 1784 1785 1786 LInstruction* LChunkBuilder::DoConstant(HConstant* instr) { 1787 Representation r = instr->representation(); 1788 if (r.IsInteger32()) { 1789 return DefineAsRegister(new(zone()) LConstantI); 1790 } else if (r.IsDouble()) { 1791 return DefineAsRegister(new(zone()) LConstantD); 1792 } else if (r.IsTagged()) { 1793 return DefineAsRegister(new(zone()) LConstantT); 1794 } else { 1795 UNREACHABLE(); 1796 return NULL; 1797 } 1798 } 1799 1800 1801 LInstruction* LChunkBuilder::DoLoadGlobalCell(HLoadGlobalCell* instr) { 1802 LLoadGlobalCell* result = new(zone()) LLoadGlobalCell; 1803 return instr->RequiresHoleCheck() 1804 ? AssignEnvironment(DefineAsRegister(result)) 1805 : DefineAsRegister(result); 1806 } 1807 1808 1809 LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) { 1810 LOperand* global_object = UseFixed(instr->global_object(), r0); 1811 LLoadGlobalGeneric* result = new(zone()) LLoadGlobalGeneric(global_object); 1812 return MarkAsCall(DefineFixed(result, r0), instr); 1813 } 1814 1815 1816 LInstruction* LChunkBuilder::DoStoreGlobalCell(HStoreGlobalCell* instr) { 1817 LOperand* value = UseRegister(instr->value()); 1818 // Use a temp to check the value in the cell in the case where we perform 1819 // a hole check. 1820 return instr->RequiresHoleCheck() 1821 ? AssignEnvironment(new(zone()) LStoreGlobalCell(value, TempRegister())) 1822 : new(zone()) LStoreGlobalCell(value, NULL); 1823 } 1824 1825 1826 LInstruction* LChunkBuilder::DoStoreGlobalGeneric(HStoreGlobalGeneric* instr) { 1827 LOperand* global_object = UseFixed(instr->global_object(), r1); 1828 LOperand* value = UseFixed(instr->value(), r0); 1829 LStoreGlobalGeneric* result = 1830 new(zone()) LStoreGlobalGeneric(global_object, value); 1831 return MarkAsCall(result, instr); 1832 } 1833 1834 1835 LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) { 1836 LOperand* context = UseRegisterAtStart(instr->value()); 1837 LInstruction* result = 1838 DefineAsRegister(new(zone()) LLoadContextSlot(context)); 1839 return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result; 1840 } 1841 1842 1843 LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) { 1844 LOperand* context; 1845 LOperand* value; 1846 if (instr->NeedsWriteBarrier()) { 1847 context = UseTempRegister(instr->context()); 1848 value = UseTempRegister(instr->value()); 1849 } else { 1850 context = UseRegister(instr->context()); 1851 value = UseRegister(instr->value()); 1852 } 1853 LInstruction* result = new(zone()) LStoreContextSlot(context, value); 1854 return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result; 1855 } 1856 1857 1858 LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) { 1859 return DefineAsRegister( 1860 new(zone()) LLoadNamedField(UseRegisterAtStart(instr->object()))); 1861 } 1862 1863 1864 LInstruction* LChunkBuilder::DoLoadNamedFieldPolymorphic( 1865 HLoadNamedFieldPolymorphic* instr) { 1866 ASSERT(instr->representation().IsTagged()); 1867 if (instr->need_generic()) { 1868 LOperand* obj = UseFixed(instr->object(), r0); 1869 LLoadNamedFieldPolymorphic* result = 1870 new(zone()) LLoadNamedFieldPolymorphic(obj); 1871 return MarkAsCall(DefineFixed(result, r0), instr); 1872 } else { 1873 LOperand* obj = UseRegisterAtStart(instr->object()); 1874 LLoadNamedFieldPolymorphic* result = 1875 new(zone()) LLoadNamedFieldPolymorphic(obj); 1876 return AssignEnvironment(DefineAsRegister(result)); 1877 } 1878 } 1879 1880 1881 LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) { 1882 LOperand* object = UseFixed(instr->object(), r0); 1883 LInstruction* result = DefineFixed(new(zone()) LLoadNamedGeneric(object), r0); 1884 return MarkAsCall(result, instr); 1885 } 1886 1887 1888 LInstruction* LChunkBuilder::DoLoadFunctionPrototype( 1889 HLoadFunctionPrototype* instr) { 1890 return AssignEnvironment(DefineAsRegister( 1891 new(zone()) LLoadFunctionPrototype(UseRegister(instr->function())))); 1892 } 1893 1894 1895 LInstruction* LChunkBuilder::DoLoadElements(HLoadElements* instr) { 1896 LOperand* input = UseRegisterAtStart(instr->value()); 1897 return DefineAsRegister(new(zone()) LLoadElements(input)); 1898 } 1899 1900 1901 LInstruction* LChunkBuilder::DoLoadExternalArrayPointer( 1902 HLoadExternalArrayPointer* instr) { 1903 LOperand* input = UseRegisterAtStart(instr->value()); 1904 return DefineAsRegister(new(zone()) LLoadExternalArrayPointer(input)); 1905 } 1906 1907 1908 LInstruction* LChunkBuilder::DoLoadKeyedFastElement( 1909 HLoadKeyedFastElement* instr) { 1910 ASSERT(instr->representation().IsTagged()); 1911 ASSERT(instr->key()->representation().IsInteger32()); 1912 LOperand* obj = UseRegisterAtStart(instr->object()); 1913 LOperand* key = UseRegisterAtStart(instr->key()); 1914 LLoadKeyedFastElement* result = new(zone()) LLoadKeyedFastElement(obj, key); 1915 if (instr->RequiresHoleCheck()) AssignEnvironment(result); 1916 return DefineAsRegister(result); 1917 } 1918 1919 1920 LInstruction* LChunkBuilder::DoLoadKeyedFastDoubleElement( 1921 HLoadKeyedFastDoubleElement* instr) { 1922 ASSERT(instr->representation().IsDouble()); 1923 ASSERT(instr->key()->representation().IsInteger32()); 1924 LOperand* elements = UseTempRegister(instr->elements()); 1925 LOperand* key = UseRegisterOrConstantAtStart(instr->key()); 1926 LLoadKeyedFastDoubleElement* result = 1927 new(zone()) LLoadKeyedFastDoubleElement(elements, key); 1928 return AssignEnvironment(DefineAsRegister(result)); 1929 } 1930 1931 1932 LInstruction* LChunkBuilder::DoLoadKeyedSpecializedArrayElement( 1933 HLoadKeyedSpecializedArrayElement* instr) { 1934 ElementsKind elements_kind = instr->elements_kind(); 1935 ASSERT( 1936 (instr->representation().IsInteger32() && 1937 (elements_kind != EXTERNAL_FLOAT_ELEMENTS) && 1938 (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) || 1939 (instr->representation().IsDouble() && 1940 ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) || 1941 (elements_kind == EXTERNAL_DOUBLE_ELEMENTS)))); 1942 ASSERT(instr->key()->representation().IsInteger32()); 1943 LOperand* external_pointer = UseRegister(instr->external_pointer()); 1944 LOperand* key = UseRegisterOrConstant(instr->key()); 1945 LLoadKeyedSpecializedArrayElement* result = 1946 new(zone()) LLoadKeyedSpecializedArrayElement(external_pointer, key); 1947 LInstruction* load_instr = DefineAsRegister(result); 1948 // An unsigned int array load might overflow and cause a deopt, make sure it 1949 // has an environment. 1950 return (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) ? 1951 AssignEnvironment(load_instr) : load_instr; 1952 } 1953 1954 1955 LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) { 1956 LOperand* object = UseFixed(instr->object(), r1); 1957 LOperand* key = UseFixed(instr->key(), r0); 1958 1959 LInstruction* result = 1960 DefineFixed(new(zone()) LLoadKeyedGeneric(object, key), r0); 1961 return MarkAsCall(result, instr); 1962 } 1963 1964 1965 LInstruction* LChunkBuilder::DoStoreKeyedFastElement( 1966 HStoreKeyedFastElement* instr) { 1967 bool needs_write_barrier = instr->NeedsWriteBarrier(); 1968 ASSERT(instr->value()->representation().IsTagged()); 1969 ASSERT(instr->object()->representation().IsTagged()); 1970 ASSERT(instr->key()->representation().IsInteger32()); 1971 1972 LOperand* obj = UseTempRegister(instr->object()); 1973 LOperand* val = needs_write_barrier 1974 ? UseTempRegister(instr->value()) 1975 : UseRegisterAtStart(instr->value()); 1976 LOperand* key = needs_write_barrier 1977 ? UseTempRegister(instr->key()) 1978 : UseRegisterOrConstantAtStart(instr->key()); 1979 return new(zone()) LStoreKeyedFastElement(obj, key, val); 1980 } 1981 1982 1983 LInstruction* LChunkBuilder::DoStoreKeyedFastDoubleElement( 1984 HStoreKeyedFastDoubleElement* instr) { 1985 ASSERT(instr->value()->representation().IsDouble()); 1986 ASSERT(instr->elements()->representation().IsTagged()); 1987 ASSERT(instr->key()->representation().IsInteger32()); 1988 1989 LOperand* elements = UseRegisterAtStart(instr->elements()); 1990 LOperand* val = UseTempRegister(instr->value()); 1991 LOperand* key = UseRegisterOrConstantAtStart(instr->key()); 1992 1993 return new(zone()) LStoreKeyedFastDoubleElement(elements, key, val); 1994 } 1995 1996 1997 LInstruction* LChunkBuilder::DoStoreKeyedSpecializedArrayElement( 1998 HStoreKeyedSpecializedArrayElement* instr) { 1999 ElementsKind elements_kind = instr->elements_kind(); 2000 ASSERT( 2001 (instr->value()->representation().IsInteger32() && 2002 (elements_kind != EXTERNAL_FLOAT_ELEMENTS) && 2003 (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) || 2004 (instr->value()->representation().IsDouble() && 2005 ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) || 2006 (elements_kind == EXTERNAL_DOUBLE_ELEMENTS)))); 2007 ASSERT(instr->external_pointer()->representation().IsExternal()); 2008 ASSERT(instr->key()->representation().IsInteger32()); 2009 2010 LOperand* external_pointer = UseRegister(instr->external_pointer()); 2011 bool val_is_temp_register = 2012 elements_kind == EXTERNAL_PIXEL_ELEMENTS || 2013 elements_kind == EXTERNAL_FLOAT_ELEMENTS; 2014 LOperand* val = val_is_temp_register 2015 ? UseTempRegister(instr->value()) 2016 : UseRegister(instr->value()); 2017 LOperand* key = UseRegisterOrConstant(instr->key()); 2018 2019 return new(zone()) LStoreKeyedSpecializedArrayElement(external_pointer, 2020 key, 2021 val); 2022 } 2023 2024 2025 LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) { 2026 LOperand* obj = UseFixed(instr->object(), r2); 2027 LOperand* key = UseFixed(instr->key(), r1); 2028 LOperand* val = UseFixed(instr->value(), r0); 2029 2030 ASSERT(instr->object()->representation().IsTagged()); 2031 ASSERT(instr->key()->representation().IsTagged()); 2032 ASSERT(instr->value()->representation().IsTagged()); 2033 2034 return MarkAsCall(new(zone()) LStoreKeyedGeneric(obj, key, val), instr); 2035 } 2036 2037 2038 LInstruction* LChunkBuilder::DoTransitionElementsKind( 2039 HTransitionElementsKind* instr) { 2040 if (instr->original_map()->elements_kind() == FAST_SMI_ONLY_ELEMENTS && 2041 instr->transitioned_map()->elements_kind() == FAST_ELEMENTS) { 2042 LOperand* object = UseRegister(instr->object()); 2043 LOperand* new_map_reg = TempRegister(); 2044 LTransitionElementsKind* result = 2045 new(zone()) LTransitionElementsKind(object, new_map_reg, NULL); 2046 return DefineSameAsFirst(result); 2047 } else { 2048 LOperand* object = UseFixed(instr->object(), r0); 2049 LOperand* fixed_object_reg = FixedTemp(r2); 2050 LOperand* new_map_reg = FixedTemp(r3); 2051 LTransitionElementsKind* result = 2052 new(zone()) LTransitionElementsKind(object, 2053 new_map_reg, 2054 fixed_object_reg); 2055 return MarkAsCall(DefineFixed(result, r0), instr); 2056 } 2057 } 2058 2059 2060 LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) { 2061 bool needs_write_barrier = instr->NeedsWriteBarrier(); 2062 2063 LOperand* obj = needs_write_barrier 2064 ? UseTempRegister(instr->object()) 2065 : UseRegisterAtStart(instr->object()); 2066 2067 LOperand* val = needs_write_barrier 2068 ? UseTempRegister(instr->value()) 2069 : UseRegister(instr->value()); 2070 2071 return new(zone()) LStoreNamedField(obj, val); 2072 } 2073 2074 2075 LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) { 2076 LOperand* obj = UseFixed(instr->object(), r1); 2077 LOperand* val = UseFixed(instr->value(), r0); 2078 2079 LInstruction* result = new(zone()) LStoreNamedGeneric(obj, val); 2080 return MarkAsCall(result, instr); 2081 } 2082 2083 2084 LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) { 2085 LOperand* left = UseRegisterAtStart(instr->left()); 2086 LOperand* right = UseRegisterAtStart(instr->right()); 2087 return MarkAsCall(DefineFixed(new(zone()) LStringAdd(left, right), r0), 2088 instr); 2089 } 2090 2091 2092 LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) { 2093 LOperand* string = UseTempRegister(instr->string()); 2094 LOperand* index = UseTempRegister(instr->index()); 2095 LStringCharCodeAt* result = new(zone()) LStringCharCodeAt(string, index); 2096 return AssignEnvironment(AssignPointerMap(DefineAsRegister(result))); 2097 } 2098 2099 2100 LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) { 2101 LOperand* char_code = UseRegister(instr->value()); 2102 LStringCharFromCode* result = new(zone()) LStringCharFromCode(char_code); 2103 return AssignPointerMap(DefineAsRegister(result)); 2104 } 2105 2106 2107 LInstruction* LChunkBuilder::DoStringLength(HStringLength* instr) { 2108 LOperand* string = UseRegisterAtStart(instr->value()); 2109 return DefineAsRegister(new(zone()) LStringLength(string)); 2110 } 2111 2112 2113 LInstruction* LChunkBuilder::DoAllocateObject(HAllocateObject* instr) { 2114 LAllocateObject* result = new LAllocateObject(TempRegister(), TempRegister()); 2115 return AssignPointerMap(DefineAsRegister(result)); 2116 } 2117 2118 2119 LInstruction* LChunkBuilder::DoFastLiteral(HFastLiteral* instr) { 2120 return MarkAsCall(DefineFixed(new(zone()) LFastLiteral, r0), instr); 2121 } 2122 2123 2124 LInstruction* LChunkBuilder::DoArrayLiteral(HArrayLiteral* instr) { 2125 return MarkAsCall(DefineFixed(new(zone()) LArrayLiteral, r0), instr); 2126 } 2127 2128 2129 LInstruction* LChunkBuilder::DoObjectLiteral(HObjectLiteral* instr) { 2130 return MarkAsCall(DefineFixed(new(zone()) LObjectLiteral, r0), instr); 2131 } 2132 2133 2134 LInstruction* LChunkBuilder::DoRegExpLiteral(HRegExpLiteral* instr) { 2135 return MarkAsCall(DefineFixed(new(zone()) LRegExpLiteral, r0), instr); 2136 } 2137 2138 2139 LInstruction* LChunkBuilder::DoFunctionLiteral(HFunctionLiteral* instr) { 2140 return MarkAsCall(DefineFixed(new(zone()) LFunctionLiteral, r0), instr); 2141 } 2142 2143 2144 LInstruction* LChunkBuilder::DoDeleteProperty(HDeleteProperty* instr) { 2145 LOperand* object = UseFixed(instr->object(), r0); 2146 LOperand* key = UseFixed(instr->key(), r1); 2147 LDeleteProperty* result = new(zone()) LDeleteProperty(object, key); 2148 return MarkAsCall(DefineFixed(result, r0), instr); 2149 } 2150 2151 2152 LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) { 2153 allocator_->MarkAsOsrEntry(); 2154 current_block_->last_environment()->set_ast_id(instr->ast_id()); 2155 return AssignEnvironment(new(zone()) LOsrEntry); 2156 } 2157 2158 2159 LInstruction* LChunkBuilder::DoParameter(HParameter* instr) { 2160 int spill_index = chunk()->GetParameterStackSlot(instr->index()); 2161 return DefineAsSpilled(new(zone()) LParameter, spill_index); 2162 } 2163 2164 2165 LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) { 2166 int spill_index = chunk()->GetNextSpillIndex(false); // Not double-width. 2167 if (spill_index > LUnallocated::kMaxFixedIndex) { 2168 Abort("Too many spill slots needed for OSR"); 2169 spill_index = 0; 2170 } 2171 return DefineAsSpilled(new(zone()) LUnknownOSRValue, spill_index); 2172 } 2173 2174 2175 LInstruction* LChunkBuilder::DoCallStub(HCallStub* instr) { 2176 argument_count_ -= instr->argument_count(); 2177 return MarkAsCall(DefineFixed(new(zone()) LCallStub, r0), instr); 2178 } 2179 2180 2181 LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) { 2182 // There are no real uses of the arguments object. 2183 // arguments.length and element access are supported directly on 2184 // stack arguments, and any real arguments object use causes a bailout. 2185 // So this value is never used. 2186 return NULL; 2187 } 2188 2189 2190 LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) { 2191 LOperand* arguments = UseRegister(instr->arguments()); 2192 LOperand* length = UseTempRegister(instr->length()); 2193 LOperand* index = UseRegister(instr->index()); 2194 LAccessArgumentsAt* result = 2195 new(zone()) LAccessArgumentsAt(arguments, length, index); 2196 return AssignEnvironment(DefineAsRegister(result)); 2197 } 2198 2199 2200 LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) { 2201 LOperand* object = UseFixed(instr->value(), r0); 2202 LToFastProperties* result = new(zone()) LToFastProperties(object); 2203 return MarkAsCall(DefineFixed(result, r0), instr); 2204 } 2205 2206 2207 LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) { 2208 LTypeof* result = new(zone()) LTypeof(UseFixed(instr->value(), r0)); 2209 return MarkAsCall(DefineFixed(result, r0), instr); 2210 } 2211 2212 2213 LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) { 2214 return new(zone()) LTypeofIsAndBranch(UseTempRegister(instr->value())); 2215 } 2216 2217 2218 LInstruction* LChunkBuilder::DoIsConstructCallAndBranch( 2219 HIsConstructCallAndBranch* instr) { 2220 return new(zone()) LIsConstructCallAndBranch(TempRegister()); 2221 } 2222 2223 2224 LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) { 2225 HEnvironment* env = current_block_->last_environment(); 2226 ASSERT(env != NULL); 2227 2228 env->set_ast_id(instr->ast_id()); 2229 2230 env->Drop(instr->pop_count()); 2231 for (int i = 0; i < instr->values()->length(); ++i) { 2232 HValue* value = instr->values()->at(i); 2233 if (instr->HasAssignedIndexAt(i)) { 2234 env->Bind(instr->GetAssignedIndexAt(i), value); 2235 } else { 2236 env->Push(value); 2237 } 2238 } 2239 2240 // If there is an instruction pending deoptimization environment create a 2241 // lazy bailout instruction to capture the environment. 2242 if (pending_deoptimization_ast_id_ == instr->ast_id()) { 2243 LInstruction* result = new(zone()) LLazyBailout; 2244 result = AssignEnvironment(result); 2245 instruction_pending_deoptimization_environment_-> 2246 set_deoptimization_environment(result->environment()); 2247 ClearInstructionPendingDeoptimizationEnvironment(); 2248 return result; 2249 } 2250 2251 return NULL; 2252 } 2253 2254 2255 LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) { 2256 if (instr->is_function_entry()) { 2257 return MarkAsCall(new(zone()) LStackCheck, instr); 2258 } else { 2259 ASSERT(instr->is_backwards_branch()); 2260 return AssignEnvironment(AssignPointerMap(new(zone()) LStackCheck)); 2261 } 2262 } 2263 2264 2265 LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) { 2266 HEnvironment* outer = current_block_->last_environment(); 2267 HConstant* undefined = graph()->GetConstantUndefined(); 2268 HEnvironment* inner = outer->CopyForInlining(instr->closure(), 2269 instr->arguments_count(), 2270 instr->function(), 2271 undefined, 2272 instr->call_kind(), 2273 instr->is_construct()); 2274 if (instr->arguments() != NULL) { 2275 inner->Bind(instr->arguments(), graph()->GetArgumentsObject()); 2276 } 2277 current_block_->UpdateEnvironment(inner); 2278 chunk_->AddInlinedClosure(instr->closure()); 2279 return NULL; 2280 } 2281 2282 2283 LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) { 2284 HEnvironment* outer = current_block_->last_environment()-> 2285 DiscardInlined(false); 2286 current_block_->UpdateEnvironment(outer); 2287 return NULL; 2288 } 2289 2290 2291 LInstruction* LChunkBuilder::DoIn(HIn* instr) { 2292 LOperand* key = UseRegisterAtStart(instr->key()); 2293 LOperand* object = UseRegisterAtStart(instr->object()); 2294 LIn* result = new(zone()) LIn(key, object); 2295 return MarkAsCall(DefineFixed(result, r0), instr); 2296 } 2297 2298 2299 LInstruction* LChunkBuilder::DoForInPrepareMap(HForInPrepareMap* instr) { 2300 LOperand* object = UseFixed(instr->enumerable(), r0); 2301 LForInPrepareMap* result = new(zone()) LForInPrepareMap(object); 2302 return MarkAsCall(DefineFixed(result, r0), instr, CAN_DEOPTIMIZE_EAGERLY); 2303 } 2304 2305 2306 LInstruction* LChunkBuilder::DoForInCacheArray(HForInCacheArray* instr) { 2307 LOperand* map = UseRegister(instr->map()); 2308 return AssignEnvironment(DefineAsRegister( 2309 new(zone()) LForInCacheArray(map))); 2310 } 2311 2312 2313 LInstruction* LChunkBuilder::DoCheckMapValue(HCheckMapValue* instr) { 2314 LOperand* value = UseRegisterAtStart(instr->value()); 2315 LOperand* map = UseRegisterAtStart(instr->map()); 2316 return AssignEnvironment(new(zone()) LCheckMapValue(value, map)); 2317 } 2318 2319 2320 LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) { 2321 LOperand* object = UseRegister(instr->object()); 2322 LOperand* index = UseRegister(instr->index()); 2323 return DefineAsRegister(new(zone()) LLoadFieldByIndex(object, index)); 2324 } 2325 2326 2327 } } // namespace v8::internal 2328