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