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