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