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