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 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 47 #ifdef DEBUG 48 void LInstruction::VerifyCall() { 49 // Call instructions can use only fixed registers as temporaries and 50 // outputs because all registers are blocked by the calling convention. 51 // Inputs operands must use a fixed register or use-at-start policy or 52 // a non-register policy. 53 ASSERT(Output() == NULL || 54 LUnallocated::cast(Output())->HasFixedPolicy() || 55 !LUnallocated::cast(Output())->HasRegisterPolicy()); 56 for (UseIterator it(this); !it.Done(); it.Advance()) { 57 LUnallocated* operand = LUnallocated::cast(it.Current()); 58 ASSERT(operand->HasFixedPolicy() || 59 operand->IsUsedAtStart()); 60 } 61 for (TempIterator it(this); !it.Done(); it.Advance()) { 62 LUnallocated* operand = LUnallocated::cast(it.Current()); 63 ASSERT(operand->HasFixedPolicy() ||!operand->HasRegisterPolicy()); 64 } 65 } 66 #endif 67 68 69 bool LInstruction::HasDoubleRegisterResult() { 70 return HasResult() && result()->IsDoubleRegister(); 71 } 72 73 74 bool LInstruction::HasDoubleRegisterInput() { 75 for (int i = 0; i < InputCount(); i++) { 76 LOperand* op = InputAt(i); 77 if (op != NULL && op->IsDoubleRegister()) { 78 return true; 79 } 80 } 81 return false; 82 } 83 84 85 bool LInstruction::IsDoubleInput(X87Register reg, LCodeGen* cgen) { 86 for (int i = 0; i < InputCount(); i++) { 87 LOperand* op = InputAt(i); 88 if (op != NULL && op->IsDoubleRegister()) { 89 if (cgen->ToX87Register(op).is(reg)) return true; 90 } 91 } 92 return false; 93 } 94 95 96 void LInstruction::PrintTo(StringStream* stream) { 97 stream->Add("%s ", this->Mnemonic()); 98 99 PrintOutputOperandTo(stream); 100 101 PrintDataTo(stream); 102 103 if (HasEnvironment()) { 104 stream->Add(" "); 105 environment()->PrintTo(stream); 106 } 107 108 if (HasPointerMap()) { 109 stream->Add(" "); 110 pointer_map()->PrintTo(stream); 111 } 112 } 113 114 115 void LInstruction::PrintDataTo(StringStream* stream) { 116 stream->Add("= "); 117 for (int i = 0; i < InputCount(); i++) { 118 if (i > 0) stream->Add(" "); 119 if (InputAt(i) == NULL) { 120 stream->Add("NULL"); 121 } else { 122 InputAt(i)->PrintTo(stream); 123 } 124 } 125 } 126 127 128 void LInstruction::PrintOutputOperandTo(StringStream* stream) { 129 if (HasResult()) result()->PrintTo(stream); 130 } 131 132 133 void LLabel::PrintDataTo(StringStream* stream) { 134 LGap::PrintDataTo(stream); 135 LLabel* rep = replacement(); 136 if (rep != NULL) { 137 stream->Add(" Dead block replaced with B%d", rep->block_id()); 138 } 139 } 140 141 142 bool LGap::IsRedundant() const { 143 for (int i = 0; i < 4; i++) { 144 if (parallel_moves_[i] != NULL && !parallel_moves_[i]->IsRedundant()) { 145 return false; 146 } 147 } 148 149 return true; 150 } 151 152 153 void LGap::PrintDataTo(StringStream* stream) { 154 for (int i = 0; i < 4; i++) { 155 stream->Add("("); 156 if (parallel_moves_[i] != NULL) { 157 parallel_moves_[i]->PrintDataTo(stream); 158 } 159 stream->Add(") "); 160 } 161 } 162 163 164 const char* LArithmeticD::Mnemonic() const { 165 switch (op()) { 166 case Token::ADD: return "add-d"; 167 case Token::SUB: return "sub-d"; 168 case Token::MUL: return "mul-d"; 169 case Token::DIV: return "div-d"; 170 case Token::MOD: return "mod-d"; 171 default: 172 UNREACHABLE(); 173 return NULL; 174 } 175 } 176 177 178 const char* LArithmeticT::Mnemonic() const { 179 switch (op()) { 180 case Token::ADD: return "add-t"; 181 case Token::SUB: return "sub-t"; 182 case Token::MUL: return "mul-t"; 183 case Token::MOD: return "mod-t"; 184 case Token::DIV: return "div-t"; 185 case Token::BIT_AND: return "bit-and-t"; 186 case Token::BIT_OR: return "bit-or-t"; 187 case Token::BIT_XOR: return "bit-xor-t"; 188 case Token::ROR: return "ror-t"; 189 case Token::SHL: return "sal-t"; 190 case Token::SAR: return "sar-t"; 191 case Token::SHR: return "shr-t"; 192 default: 193 UNREACHABLE(); 194 return NULL; 195 } 196 } 197 198 199 bool LGoto::HasInterestingComment(LCodeGen* gen) const { 200 return !gen->IsNextEmittedBlock(block_id()); 201 } 202 203 204 void LGoto::PrintDataTo(StringStream* stream) { 205 stream->Add("B%d", block_id()); 206 } 207 208 209 void LBranch::PrintDataTo(StringStream* stream) { 210 stream->Add("B%d | B%d on ", true_block_id(), false_block_id()); 211 value()->PrintTo(stream); 212 } 213 214 215 void LCompareNumericAndBranch::PrintDataTo(StringStream* stream) { 216 stream->Add("if "); 217 left()->PrintTo(stream); 218 stream->Add(" %s ", Token::String(op())); 219 right()->PrintTo(stream); 220 stream->Add(" then B%d else B%d", true_block_id(), false_block_id()); 221 } 222 223 224 void LIsObjectAndBranch::PrintDataTo(StringStream* stream) { 225 stream->Add("if is_object("); 226 value()->PrintTo(stream); 227 stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); 228 } 229 230 231 void LIsStringAndBranch::PrintDataTo(StringStream* stream) { 232 stream->Add("if is_string("); 233 value()->PrintTo(stream); 234 stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); 235 } 236 237 238 void LIsSmiAndBranch::PrintDataTo(StringStream* stream) { 239 stream->Add("if is_smi("); 240 value()->PrintTo(stream); 241 stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); 242 } 243 244 245 void LIsUndetectableAndBranch::PrintDataTo(StringStream* stream) { 246 stream->Add("if is_undetectable("); 247 value()->PrintTo(stream); 248 stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); 249 } 250 251 252 void LStringCompareAndBranch::PrintDataTo(StringStream* stream) { 253 stream->Add("if string_compare("); 254 left()->PrintTo(stream); 255 right()->PrintTo(stream); 256 stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); 257 } 258 259 260 void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) { 261 stream->Add("if has_instance_type("); 262 value()->PrintTo(stream); 263 stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); 264 } 265 266 267 void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) { 268 stream->Add("if has_cached_array_index("); 269 value()->PrintTo(stream); 270 stream->Add(") then B%d else B%d", true_block_id(), false_block_id()); 271 } 272 273 274 void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) { 275 stream->Add("if class_of_test("); 276 value()->PrintTo(stream); 277 stream->Add(", \"%o\") then B%d else B%d", 278 *hydrogen()->class_name(), 279 true_block_id(), 280 false_block_id()); 281 } 282 283 284 void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) { 285 stream->Add("if typeof "); 286 value()->PrintTo(stream); 287 stream->Add(" == \"%s\" then B%d else B%d", 288 *hydrogen()->type_literal()->ToCString(), 289 true_block_id(), false_block_id()); 290 } 291 292 293 void LInnerAllocatedObject::PrintDataTo(StringStream* stream) { 294 stream->Add(" = "); 295 base_object()->PrintTo(stream); 296 stream->Add(" + %d", offset()); 297 } 298 299 300 void LCallConstantFunction::PrintDataTo(StringStream* stream) { 301 stream->Add("#%d / ", arity()); 302 } 303 304 305 void LLoadContextSlot::PrintDataTo(StringStream* stream) { 306 context()->PrintTo(stream); 307 stream->Add("[%d]", slot_index()); 308 } 309 310 311 void LStoreContextSlot::PrintDataTo(StringStream* stream) { 312 context()->PrintTo(stream); 313 stream->Add("[%d] <- ", slot_index()); 314 value()->PrintTo(stream); 315 } 316 317 318 void LInvokeFunction::PrintDataTo(StringStream* stream) { 319 stream->Add("= "); 320 context()->PrintTo(stream); 321 stream->Add(" "); 322 function()->PrintTo(stream); 323 stream->Add(" #%d / ", arity()); 324 } 325 326 327 void LCallKeyed::PrintDataTo(StringStream* stream) { 328 stream->Add("[ecx] #%d / ", arity()); 329 } 330 331 332 void LCallNamed::PrintDataTo(StringStream* stream) { 333 SmartArrayPointer<char> name_string = name()->ToCString(); 334 stream->Add("%s #%d / ", *name_string, arity()); 335 } 336 337 338 void LCallGlobal::PrintDataTo(StringStream* stream) { 339 SmartArrayPointer<char> name_string = name()->ToCString(); 340 stream->Add("%s #%d / ", *name_string, arity()); 341 } 342 343 344 void LCallKnownGlobal::PrintDataTo(StringStream* stream) { 345 stream->Add("#%d / ", arity()); 346 } 347 348 349 void LCallNew::PrintDataTo(StringStream* stream) { 350 stream->Add("= "); 351 context()->PrintTo(stream); 352 stream->Add(" "); 353 constructor()->PrintTo(stream); 354 stream->Add(" #%d / ", arity()); 355 } 356 357 358 void LCallNewArray::PrintDataTo(StringStream* stream) { 359 stream->Add("= "); 360 context()->PrintTo(stream); 361 stream->Add(" "); 362 constructor()->PrintTo(stream); 363 stream->Add(" #%d / ", arity()); 364 ElementsKind kind = hydrogen()->elements_kind(); 365 stream->Add(" (%s) ", ElementsKindToString(kind)); 366 } 367 368 369 void LAccessArgumentsAt::PrintDataTo(StringStream* stream) { 370 arguments()->PrintTo(stream); 371 372 stream->Add(" length "); 373 length()->PrintTo(stream); 374 375 stream->Add(" index "); 376 index()->PrintTo(stream); 377 } 378 379 380 int LPlatformChunk::GetNextSpillIndex(bool is_double) { 381 // Skip a slot if for a double-width slot. 382 if (is_double) { 383 spill_slot_count_++; 384 spill_slot_count_ |= 1; 385 num_double_slots_++; 386 } 387 return spill_slot_count_++; 388 } 389 390 391 LOperand* LPlatformChunk::GetNextSpillSlot(bool is_double) { 392 int index = GetNextSpillIndex(is_double); 393 if (is_double) { 394 return LDoubleStackSlot::Create(index, zone()); 395 } else { 396 return LStackSlot::Create(index, zone()); 397 } 398 } 399 400 401 void LStoreNamedField::PrintDataTo(StringStream* stream) { 402 object()->PrintTo(stream); 403 hydrogen()->access().PrintTo(stream); 404 stream->Add(" <- "); 405 value()->PrintTo(stream); 406 } 407 408 409 void LStoreNamedGeneric::PrintDataTo(StringStream* stream) { 410 object()->PrintTo(stream); 411 stream->Add("."); 412 stream->Add(*String::cast(*name())->ToCString()); 413 stream->Add(" <- "); 414 value()->PrintTo(stream); 415 } 416 417 418 void LLoadKeyed::PrintDataTo(StringStream* stream) { 419 elements()->PrintTo(stream); 420 stream->Add("["); 421 key()->PrintTo(stream); 422 if (hydrogen()->IsDehoisted()) { 423 stream->Add(" + %d]", additional_index()); 424 } else { 425 stream->Add("]"); 426 } 427 } 428 429 430 void LStoreKeyed::PrintDataTo(StringStream* stream) { 431 elements()->PrintTo(stream); 432 stream->Add("["); 433 key()->PrintTo(stream); 434 if (hydrogen()->IsDehoisted()) { 435 stream->Add(" + %d] <-", additional_index()); 436 } else { 437 stream->Add("] <- "); 438 } 439 440 if (value() == NULL) { 441 ASSERT(hydrogen()->IsConstantHoleStore() && 442 hydrogen()->value()->representation().IsDouble()); 443 stream->Add("<the hole(nan)>"); 444 } else { 445 value()->PrintTo(stream); 446 } 447 } 448 449 450 void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) { 451 object()->PrintTo(stream); 452 stream->Add("["); 453 key()->PrintTo(stream); 454 stream->Add("] <- "); 455 value()->PrintTo(stream); 456 } 457 458 459 void LTransitionElementsKind::PrintDataTo(StringStream* stream) { 460 object()->PrintTo(stream); 461 stream->Add(" %p -> %p", *original_map(), *transitioned_map()); 462 } 463 464 465 LPlatformChunk* LChunkBuilder::Build() { 466 ASSERT(is_unused()); 467 chunk_ = new(zone()) LPlatformChunk(info(), graph()); 468 LPhase phase("L_Building chunk", chunk_); 469 status_ = BUILDING; 470 471 // Reserve the first spill slot for the state of dynamic alignment. 472 if (info()->IsOptimizing()) { 473 int alignment_state_index = chunk_->GetNextSpillIndex(false); 474 ASSERT_EQ(alignment_state_index, 0); 475 USE(alignment_state_index); 476 } 477 478 const ZoneList<HBasicBlock*>* blocks = graph()->blocks(); 479 for (int i = 0; i < blocks->length(); i++) { 480 HBasicBlock* next = NULL; 481 if (i < blocks->length() - 1) next = blocks->at(i + 1); 482 DoBasicBlock(blocks->at(i), next); 483 if (is_aborted()) return NULL; 484 } 485 status_ = DONE; 486 return chunk_; 487 } 488 489 490 void LChunkBuilder::Abort(BailoutReason reason) { 491 info()->set_bailout_reason(reason); 492 status_ = ABORTED; 493 } 494 495 496 LUnallocated* LChunkBuilder::ToUnallocated(Register reg) { 497 return new(zone()) LUnallocated(LUnallocated::FIXED_REGISTER, 498 Register::ToAllocationIndex(reg)); 499 } 500 501 502 LUnallocated* LChunkBuilder::ToUnallocated(XMMRegister reg) { 503 return new(zone()) LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER, 504 XMMRegister::ToAllocationIndex(reg)); 505 } 506 507 508 LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) { 509 return Use(value, ToUnallocated(fixed_register)); 510 } 511 512 513 LOperand* LChunkBuilder::UseFixedDouble(HValue* value, XMMRegister reg) { 514 return Use(value, ToUnallocated(reg)); 515 } 516 517 518 LOperand* LChunkBuilder::UseRegister(HValue* value) { 519 return Use(value, new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER)); 520 } 521 522 523 LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) { 524 return Use(value, 525 new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER, 526 LUnallocated::USED_AT_START)); 527 } 528 529 530 LOperand* LChunkBuilder::UseTempRegister(HValue* value) { 531 return Use(value, new(zone()) LUnallocated(LUnallocated::WRITABLE_REGISTER)); 532 } 533 534 535 LOperand* LChunkBuilder::Use(HValue* value) { 536 return Use(value, new(zone()) LUnallocated(LUnallocated::NONE)); 537 } 538 539 540 LOperand* LChunkBuilder::UseAtStart(HValue* value) { 541 return Use(value, new(zone()) LUnallocated(LUnallocated::NONE, 542 LUnallocated::USED_AT_START)); 543 } 544 545 546 LOperand* LChunkBuilder::UseOrConstant(HValue* value) { 547 return value->IsConstant() 548 ? chunk_->DefineConstantOperand(HConstant::cast(value)) 549 : Use(value); 550 } 551 552 553 LOperand* LChunkBuilder::UseOrConstantAtStart(HValue* value) { 554 return value->IsConstant() 555 ? chunk_->DefineConstantOperand(HConstant::cast(value)) 556 : UseAtStart(value); 557 } 558 559 560 LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) { 561 return value->IsConstant() 562 ? chunk_->DefineConstantOperand(HConstant::cast(value)) 563 : UseRegister(value); 564 } 565 566 567 LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) { 568 return value->IsConstant() 569 ? chunk_->DefineConstantOperand(HConstant::cast(value)) 570 : UseRegisterAtStart(value); 571 } 572 573 574 LOperand* LChunkBuilder::UseConstant(HValue* value) { 575 return chunk_->DefineConstantOperand(HConstant::cast(value)); 576 } 577 578 579 LOperand* LChunkBuilder::UseAny(HValue* value) { 580 return value->IsConstant() 581 ? chunk_->DefineConstantOperand(HConstant::cast(value)) 582 : Use(value, new(zone()) LUnallocated(LUnallocated::ANY)); 583 } 584 585 586 LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) { 587 if (value->EmitAtUses()) { 588 HInstruction* instr = HInstruction::cast(value); 589 VisitInstruction(instr); 590 } 591 operand->set_virtual_register(value->id()); 592 return operand; 593 } 594 595 596 template<int I, int T> 597 LInstruction* LChunkBuilder::Define(LTemplateInstruction<1, I, T>* instr, 598 LUnallocated* result) { 599 result->set_virtual_register(current_instruction_->id()); 600 instr->set_result(result); 601 return instr; 602 } 603 604 605 template<int I, int T> 606 LInstruction* LChunkBuilder::DefineAsRegister( 607 LTemplateInstruction<1, I, T>* instr) { 608 return Define(instr, 609 new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER)); 610 } 611 612 613 template<int I, int T> 614 LInstruction* LChunkBuilder::DefineAsSpilled( 615 LTemplateInstruction<1, I, T>* instr, 616 int index) { 617 return Define(instr, 618 new(zone()) LUnallocated(LUnallocated::FIXED_SLOT, index)); 619 } 620 621 622 template<int I, int T> 623 LInstruction* LChunkBuilder::DefineSameAsFirst( 624 LTemplateInstruction<1, I, T>* instr) { 625 return Define(instr, 626 new(zone()) LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT)); 627 } 628 629 630 template<int I, int T> 631 LInstruction* LChunkBuilder::DefineFixed(LTemplateInstruction<1, I, T>* instr, 632 Register reg) { 633 return Define(instr, ToUnallocated(reg)); 634 } 635 636 637 template<int I, int T> 638 LInstruction* LChunkBuilder::DefineFixedDouble( 639 LTemplateInstruction<1, I, T>* instr, 640 XMMRegister reg) { 641 return Define(instr, ToUnallocated(reg)); 642 } 643 644 645 LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) { 646 HEnvironment* hydrogen_env = current_block_->last_environment(); 647 int argument_index_accumulator = 0; 648 ZoneList<HValue*> objects_to_materialize(0, zone()); 649 instr->set_environment(CreateEnvironment(hydrogen_env, 650 &argument_index_accumulator, 651 &objects_to_materialize)); 652 return instr; 653 } 654 655 656 LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr, 657 HInstruction* hinstr, 658 CanDeoptimize can_deoptimize) { 659 info()->MarkAsNonDeferredCalling(); 660 661 #ifdef DEBUG 662 instr->VerifyCall(); 663 #endif 664 instr->MarkAsCall(); 665 instr = AssignPointerMap(instr); 666 667 if (hinstr->HasObservableSideEffects()) { 668 ASSERT(hinstr->next()->IsSimulate()); 669 HSimulate* sim = HSimulate::cast(hinstr->next()); 670 ASSERT(instruction_pending_deoptimization_environment_ == NULL); 671 ASSERT(pending_deoptimization_ast_id_.IsNone()); 672 instruction_pending_deoptimization_environment_ = instr; 673 pending_deoptimization_ast_id_ = sim->ast_id(); 674 } 675 676 // If instruction does not have side-effects lazy deoptimization 677 // after the call will try to deoptimize to the point before the call. 678 // Thus we still need to attach environment to this call even if 679 // call sequence can not deoptimize eagerly. 680 bool needs_environment = 681 (can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) || 682 !hinstr->HasObservableSideEffects(); 683 if (needs_environment && !instr->HasEnvironment()) { 684 instr = AssignEnvironment(instr); 685 } 686 687 return instr; 688 } 689 690 691 LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) { 692 ASSERT(!instr->HasPointerMap()); 693 instr->set_pointer_map(new(zone()) LPointerMap(position_, zone())); 694 return instr; 695 } 696 697 698 LUnallocated* LChunkBuilder::TempRegister() { 699 LUnallocated* operand = 700 new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER); 701 int vreg = allocator_->GetVirtualRegister(); 702 if (!allocator_->AllocationOk()) { 703 Abort(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister); 704 vreg = 0; 705 } 706 operand->set_virtual_register(vreg); 707 return operand; 708 } 709 710 711 LOperand* LChunkBuilder::FixedTemp(Register reg) { 712 LUnallocated* operand = ToUnallocated(reg); 713 ASSERT(operand->HasFixedPolicy()); 714 return operand; 715 } 716 717 718 LOperand* LChunkBuilder::FixedTemp(XMMRegister reg) { 719 LUnallocated* operand = ToUnallocated(reg); 720 ASSERT(operand->HasFixedPolicy()); 721 return operand; 722 } 723 724 725 LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) { 726 return new(zone()) LLabel(instr->block()); 727 } 728 729 730 LInstruction* LChunkBuilder::DoDummyUse(HDummyUse* instr) { 731 return DefineAsRegister(new(zone()) LDummyUse(UseAny(instr->value()))); 732 } 733 734 735 LInstruction* LChunkBuilder::DoEnvironmentMarker(HEnvironmentMarker* instr) { 736 UNREACHABLE(); 737 return NULL; 738 } 739 740 741 LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) { 742 return AssignEnvironment(new(zone()) LDeoptimize); 743 } 744 745 746 LInstruction* LChunkBuilder::DoShift(Token::Value op, 747 HBitwiseBinaryOperation* instr) { 748 if (instr->representation().IsTagged()) { 749 ASSERT(instr->left()->representation().IsSmiOrTagged()); 750 ASSERT(instr->right()->representation().IsSmiOrTagged()); 751 752 LOperand* context = UseFixed(instr->context(), esi); 753 LOperand* left = UseFixed(instr->left(), edx); 754 LOperand* right = UseFixed(instr->right(), eax); 755 LArithmeticT* result = new(zone()) LArithmeticT(op, context, left, right); 756 return MarkAsCall(DefineFixed(result, eax), instr); 757 } 758 759 ASSERT(instr->representation().IsSmiOrInteger32()); 760 ASSERT(instr->left()->representation().Equals(instr->representation())); 761 ASSERT(instr->right()->representation().Equals(instr->representation())); 762 LOperand* left = UseRegisterAtStart(instr->left()); 763 764 HValue* right_value = instr->right(); 765 LOperand* right = NULL; 766 int constant_value = 0; 767 bool does_deopt = false; 768 if (right_value->IsConstant()) { 769 HConstant* constant = HConstant::cast(right_value); 770 right = chunk_->DefineConstantOperand(constant); 771 constant_value = constant->Integer32Value() & 0x1f; 772 // Left shifts can deoptimize if we shift by > 0 and the result cannot be 773 // truncated to smi. 774 if (instr->representation().IsSmi() && constant_value > 0) { 775 for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) { 776 if (!it.value()->CheckFlag(HValue::kTruncatingToSmi)) { 777 does_deopt = true; 778 break; 779 } 780 } 781 } 782 } else { 783 right = UseFixed(right_value, ecx); 784 } 785 786 // Shift operations can only deoptimize if we do a logical shift by 0 and 787 // the result cannot be truncated to int32. 788 if (op == Token::SHR && constant_value == 0) { 789 if (FLAG_opt_safe_uint32_operations) { 790 does_deopt = !instr->CheckFlag(HInstruction::kUint32); 791 } else { 792 for (HUseIterator it(instr->uses()); !it.Done(); it.Advance()) { 793 if (!it.value()->CheckFlag(HValue::kTruncatingToInt32)) { 794 does_deopt = true; 795 break; 796 } 797 } 798 } 799 } 800 801 LInstruction* result = 802 DefineSameAsFirst(new(zone()) LShiftI(op, left, right, does_deopt)); 803 return does_deopt ? AssignEnvironment(result) : result; 804 } 805 806 807 LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op, 808 HArithmeticBinaryOperation* instr) { 809 ASSERT(instr->representation().IsDouble()); 810 ASSERT(instr->left()->representation().IsDouble()); 811 ASSERT(instr->right()->representation().IsDouble()); 812 ASSERT(op != Token::MOD); 813 LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand()); 814 LOperand* right = UseRegisterAtStart(instr->BetterRightOperand()); 815 LArithmeticD* result = new(zone()) LArithmeticD(op, left, right); 816 return DefineSameAsFirst(result); 817 } 818 819 820 LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op, 821 HArithmeticBinaryOperation* instr) { 822 ASSERT(op == Token::ADD || 823 op == Token::DIV || 824 op == Token::MOD || 825 op == Token::MUL || 826 op == Token::SUB); 827 HValue* left = instr->left(); 828 HValue* right = instr->right(); 829 ASSERT(left->representation().IsTagged()); 830 ASSERT(right->representation().IsTagged()); 831 LOperand* context = UseFixed(instr->context(), esi); 832 LOperand* left_operand = UseFixed(left, edx); 833 LOperand* right_operand = UseFixed(right, eax); 834 LArithmeticT* result = 835 new(zone()) LArithmeticT(op, context, left_operand, right_operand); 836 return MarkAsCall(DefineFixed(result, eax), instr); 837 } 838 839 840 void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) { 841 ASSERT(is_building()); 842 current_block_ = block; 843 next_block_ = next_block; 844 if (block->IsStartBlock()) { 845 block->UpdateEnvironment(graph_->start_environment()); 846 argument_count_ = 0; 847 } else if (block->predecessors()->length() == 1) { 848 // We have a single predecessor => copy environment and outgoing 849 // argument count from the predecessor. 850 ASSERT(block->phis()->length() == 0); 851 HBasicBlock* pred = block->predecessors()->at(0); 852 HEnvironment* last_environment = pred->last_environment(); 853 ASSERT(last_environment != NULL); 854 // Only copy the environment, if it is later used again. 855 if (pred->end()->SecondSuccessor() == NULL) { 856 ASSERT(pred->end()->FirstSuccessor() == block); 857 } else { 858 if (pred->end()->FirstSuccessor()->block_id() > block->block_id() || 859 pred->end()->SecondSuccessor()->block_id() > block->block_id()) { 860 last_environment = last_environment->Copy(); 861 } 862 } 863 block->UpdateEnvironment(last_environment); 864 ASSERT(pred->argument_count() >= 0); 865 argument_count_ = pred->argument_count(); 866 } else { 867 // We are at a state join => process phis. 868 HBasicBlock* pred = block->predecessors()->at(0); 869 // No need to copy the environment, it cannot be used later. 870 HEnvironment* last_environment = pred->last_environment(); 871 for (int i = 0; i < block->phis()->length(); ++i) { 872 HPhi* phi = block->phis()->at(i); 873 if (phi->HasMergedIndex()) { 874 last_environment->SetValueAt(phi->merged_index(), phi); 875 } 876 } 877 for (int i = 0; i < block->deleted_phis()->length(); ++i) { 878 if (block->deleted_phis()->at(i) < last_environment->length()) { 879 last_environment->SetValueAt(block->deleted_phis()->at(i), 880 graph_->GetConstantUndefined()); 881 } 882 } 883 block->UpdateEnvironment(last_environment); 884 // Pick up the outgoing argument count of one of the predecessors. 885 argument_count_ = pred->argument_count(); 886 } 887 HInstruction* current = block->first(); 888 int start = chunk_->instructions()->length(); 889 while (current != NULL && !is_aborted()) { 890 // Code for constants in registers is generated lazily. 891 if (!current->EmitAtUses()) { 892 VisitInstruction(current); 893 } 894 current = current->next(); 895 } 896 int end = chunk_->instructions()->length() - 1; 897 if (end >= start) { 898 block->set_first_instruction_index(start); 899 block->set_last_instruction_index(end); 900 } 901 block->set_argument_count(argument_count_); 902 next_block_ = NULL; 903 current_block_ = NULL; 904 } 905 906 907 void LChunkBuilder::VisitInstruction(HInstruction* current) { 908 HInstruction* old_current = current_instruction_; 909 current_instruction_ = current; 910 if (current->has_position()) position_ = current->position(); 911 LInstruction* instr = current->CompileToLithium(this); 912 913 if (instr != NULL) { 914 #if DEBUG 915 // Make sure that the lithium instruction has either no fixed register 916 // constraints in temps or the result OR no uses that are only used at 917 // start. If this invariant doesn't hold, the register allocator can decide 918 // to insert a split of a range immediately before the instruction due to an 919 // already allocated register needing to be used for the instruction's fixed 920 // register constraint. In this case, The register allocator won't see an 921 // interference between the split child and the use-at-start (it would if 922 // the it was just a plain use), so it is free to move the split child into 923 // the same register that is used for the use-at-start. 924 // See https://code.google.com/p/chromium/issues/detail?id=201590 925 if (!(instr->ClobbersRegisters() && instr->ClobbersDoubleRegisters())) { 926 int fixed = 0; 927 int used_at_start = 0; 928 for (UseIterator it(instr); !it.Done(); it.Advance()) { 929 LUnallocated* operand = LUnallocated::cast(it.Current()); 930 if (operand->IsUsedAtStart()) ++used_at_start; 931 } 932 if (instr->Output() != NULL) { 933 if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed; 934 } 935 for (TempIterator it(instr); !it.Done(); it.Advance()) { 936 LUnallocated* operand = LUnallocated::cast(it.Current()); 937 if (operand->HasFixedPolicy()) ++fixed; 938 } 939 ASSERT(fixed == 0 || used_at_start == 0); 940 } 941 #endif 942 943 instr->set_position(position_); 944 if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) { 945 instr = AssignPointerMap(instr); 946 } 947 if (FLAG_stress_environments && !instr->HasEnvironment()) { 948 instr = AssignEnvironment(instr); 949 } 950 instr->set_hydrogen_value(current); 951 chunk_->AddInstruction(instr, current_block_); 952 } 953 current_instruction_ = old_current; 954 } 955 956 957 LEnvironment* LChunkBuilder::CreateEnvironment( 958 HEnvironment* hydrogen_env, 959 int* argument_index_accumulator, 960 ZoneList<HValue*>* objects_to_materialize) { 961 if (hydrogen_env == NULL) return NULL; 962 963 LEnvironment* outer = CreateEnvironment(hydrogen_env->outer(), 964 argument_index_accumulator, 965 objects_to_materialize); 966 BailoutId ast_id = hydrogen_env->ast_id(); 967 ASSERT(!ast_id.IsNone() || 968 hydrogen_env->frame_type() != JS_FUNCTION); 969 int value_count = hydrogen_env->length() - hydrogen_env->specials_count(); 970 LEnvironment* result = 971 new(zone()) LEnvironment(hydrogen_env->closure(), 972 hydrogen_env->frame_type(), 973 ast_id, 974 hydrogen_env->parameter_count(), 975 argument_count_, 976 value_count, 977 outer, 978 hydrogen_env->entry(), 979 zone()); 980 int argument_index = *argument_index_accumulator; 981 int object_index = objects_to_materialize->length(); 982 for (int i = 0; i < hydrogen_env->length(); ++i) { 983 if (hydrogen_env->is_special_index(i)) continue; 984 985 LOperand* op; 986 HValue* value = hydrogen_env->values()->at(i); 987 if (value->IsArgumentsObject() || value->IsCapturedObject()) { 988 objects_to_materialize->Add(value, zone()); 989 op = LEnvironment::materialization_marker(); 990 } else if (value->IsPushArgument()) { 991 op = new(zone()) LArgument(argument_index++); 992 } else { 993 op = UseAny(value); 994 } 995 result->AddValue(op, 996 value->representation(), 997 value->CheckFlag(HInstruction::kUint32)); 998 } 999 1000 for (int i = object_index; i < objects_to_materialize->length(); ++i) { 1001 HValue* object_to_materialize = objects_to_materialize->at(i); 1002 int previously_materialized_object = -1; 1003 for (int prev = 0; prev < i; ++prev) { 1004 if (objects_to_materialize->at(prev) == objects_to_materialize->at(i)) { 1005 previously_materialized_object = prev; 1006 break; 1007 } 1008 } 1009 int length = object_to_materialize->OperandCount(); 1010 bool is_arguments = object_to_materialize->IsArgumentsObject(); 1011 if (previously_materialized_object >= 0) { 1012 result->AddDuplicateObject(previously_materialized_object); 1013 continue; 1014 } else { 1015 result->AddNewObject(is_arguments ? length - 1 : length, is_arguments); 1016 } 1017 for (int i = is_arguments ? 1 : 0; i < length; ++i) { 1018 LOperand* op; 1019 HValue* value = object_to_materialize->OperandAt(i); 1020 if (value->IsArgumentsObject() || value->IsCapturedObject()) { 1021 objects_to_materialize->Add(value, zone()); 1022 op = LEnvironment::materialization_marker(); 1023 } else { 1024 ASSERT(!value->IsPushArgument()); 1025 op = UseAny(value); 1026 } 1027 result->AddValue(op, 1028 value->representation(), 1029 value->CheckFlag(HInstruction::kUint32)); 1030 } 1031 } 1032 1033 if (hydrogen_env->frame_type() == JS_FUNCTION) { 1034 *argument_index_accumulator = argument_index; 1035 } 1036 1037 return result; 1038 } 1039 1040 1041 LInstruction* LChunkBuilder::DoGoto(HGoto* instr) { 1042 return new(zone()) LGoto(instr->FirstSuccessor()->block_id()); 1043 } 1044 1045 1046 LInstruction* LChunkBuilder::DoBranch(HBranch* instr) { 1047 HValue* value = instr->value(); 1048 if (value->EmitAtUses()) { 1049 ASSERT(value->IsConstant()); 1050 ASSERT(!value->representation().IsDouble()); 1051 HBasicBlock* successor = HConstant::cast(value)->BooleanValue() 1052 ? instr->FirstSuccessor() 1053 : instr->SecondSuccessor(); 1054 return new(zone()) LGoto(successor->block_id()); 1055 } 1056 1057 ToBooleanStub::Types expected = instr->expected_input_types(); 1058 1059 // Tagged values that are not known smis or booleans require a 1060 // deoptimization environment. If the instruction is generic no 1061 // environment is needed since all cases are handled. 1062 Representation rep = value->representation(); 1063 HType type = value->type(); 1064 if (!rep.IsTagged() || type.IsSmi() || type.IsBoolean()) { 1065 return new(zone()) LBranch(UseRegister(value), NULL); 1066 } 1067 1068 bool needs_temp = expected.NeedsMap() || expected.IsEmpty(); 1069 LOperand* temp = needs_temp ? TempRegister() : NULL; 1070 1071 // The Generic stub does not have a deopt, so we need no environment. 1072 if (expected.IsGeneric()) { 1073 return new(zone()) LBranch(UseRegister(value), temp); 1074 } 1075 1076 // We need a temporary register when we have to access the map *or* we have 1077 // no type info yet, in which case we handle all cases (including the ones 1078 // involving maps). 1079 return AssignEnvironment(new(zone()) LBranch(UseRegister(value), temp)); 1080 } 1081 1082 1083 LInstruction* LChunkBuilder::DoDebugBreak(HDebugBreak* instr) { 1084 return new(zone()) LDebugBreak(); 1085 } 1086 1087 1088 LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) { 1089 ASSERT(instr->value()->representation().IsTagged()); 1090 LOperand* value = UseRegisterAtStart(instr->value()); 1091 return new(zone()) LCmpMapAndBranch(value); 1092 } 1093 1094 1095 LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* length) { 1096 info()->MarkAsRequiresFrame(); 1097 return DefineAsRegister(new(zone()) LArgumentsLength(Use(length->value()))); 1098 } 1099 1100 1101 LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* elems) { 1102 info()->MarkAsRequiresFrame(); 1103 return DefineAsRegister(new(zone()) LArgumentsElements); 1104 } 1105 1106 1107 LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) { 1108 LOperand* left = UseFixed(instr->left(), InstanceofStub::left()); 1109 LOperand* right = UseFixed(instr->right(), InstanceofStub::right()); 1110 LOperand* context = UseFixed(instr->context(), esi); 1111 LInstanceOf* result = new(zone()) LInstanceOf(context, left, right); 1112 return MarkAsCall(DefineFixed(result, eax), instr); 1113 } 1114 1115 1116 LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal( 1117 HInstanceOfKnownGlobal* instr) { 1118 LInstanceOfKnownGlobal* result = 1119 new(zone()) LInstanceOfKnownGlobal( 1120 UseFixed(instr->context(), esi), 1121 UseFixed(instr->left(), InstanceofStub::left()), 1122 FixedTemp(edi)); 1123 return MarkAsCall(DefineFixed(result, eax), instr); 1124 } 1125 1126 1127 LInstruction* LChunkBuilder::DoInstanceSize(HInstanceSize* instr) { 1128 LOperand* object = UseRegisterAtStart(instr->object()); 1129 return DefineAsRegister(new(zone()) LInstanceSize(object)); 1130 } 1131 1132 1133 LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) { 1134 LOperand* receiver = UseRegister(instr->receiver()); 1135 LOperand* function = UseRegisterAtStart(instr->function()); 1136 LOperand* temp = TempRegister(); 1137 LWrapReceiver* result = 1138 new(zone()) LWrapReceiver(receiver, function, temp); 1139 return AssignEnvironment(DefineSameAsFirst(result)); 1140 } 1141 1142 1143 LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) { 1144 LOperand* function = UseFixed(instr->function(), edi); 1145 LOperand* receiver = UseFixed(instr->receiver(), eax); 1146 LOperand* length = UseFixed(instr->length(), ebx); 1147 LOperand* elements = UseFixed(instr->elements(), ecx); 1148 LApplyArguments* result = new(zone()) LApplyArguments(function, 1149 receiver, 1150 length, 1151 elements); 1152 return MarkAsCall(DefineFixed(result, eax), instr, CAN_DEOPTIMIZE_EAGERLY); 1153 } 1154 1155 1156 LInstruction* LChunkBuilder::DoPushArgument(HPushArgument* instr) { 1157 ++argument_count_; 1158 LOperand* argument = UseAny(instr->argument()); 1159 return new(zone()) LPushArgument(argument); 1160 } 1161 1162 1163 LInstruction* LChunkBuilder::DoInnerAllocatedObject( 1164 HInnerAllocatedObject* inner_object) { 1165 LOperand* base_object = UseRegisterAtStart(inner_object->base_object()); 1166 LInnerAllocatedObject* result = 1167 new(zone()) LInnerAllocatedObject(base_object); 1168 return DefineAsRegister(result); 1169 } 1170 1171 1172 LInstruction* LChunkBuilder::DoThisFunction(HThisFunction* instr) { 1173 return instr->HasNoUses() 1174 ? NULL 1175 : DefineAsRegister(new(zone()) LThisFunction); 1176 } 1177 1178 1179 LInstruction* LChunkBuilder::DoContext(HContext* instr) { 1180 if (instr->HasNoUses()) return NULL; 1181 1182 if (info()->IsStub()) { 1183 return DefineFixed(new(zone()) LContext, esi); 1184 } 1185 1186 return DefineAsRegister(new(zone()) LContext); 1187 } 1188 1189 1190 LInstruction* LChunkBuilder::DoOuterContext(HOuterContext* instr) { 1191 LOperand* context = UseRegisterAtStart(instr->value()); 1192 return DefineAsRegister(new(zone()) LOuterContext(context)); 1193 } 1194 1195 1196 LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) { 1197 LOperand* context = UseFixed(instr->context(), esi); 1198 return MarkAsCall(new(zone()) LDeclareGlobals(context), instr); 1199 } 1200 1201 1202 LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) { 1203 LOperand* context = UseRegisterAtStart(instr->value()); 1204 return DefineAsRegister(new(zone()) LGlobalObject(context)); 1205 } 1206 1207 1208 LInstruction* LChunkBuilder::DoGlobalReceiver(HGlobalReceiver* instr) { 1209 LOperand* global_object = UseRegisterAtStart(instr->value()); 1210 return DefineAsRegister(new(zone()) LGlobalReceiver(global_object)); 1211 } 1212 1213 1214 LInstruction* LChunkBuilder::DoCallConstantFunction( 1215 HCallConstantFunction* instr) { 1216 argument_count_ -= instr->argument_count(); 1217 return MarkAsCall(DefineFixed(new(zone()) LCallConstantFunction, eax), instr); 1218 } 1219 1220 1221 LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) { 1222 LOperand* context = UseFixed(instr->context(), esi); 1223 LOperand* function = UseFixed(instr->function(), edi); 1224 argument_count_ -= instr->argument_count(); 1225 LInvokeFunction* result = new(zone()) LInvokeFunction(context, function); 1226 return MarkAsCall(DefineFixed(result, eax), instr, CANNOT_DEOPTIMIZE_EAGERLY); 1227 } 1228 1229 1230 LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) { 1231 switch (instr->op()) { 1232 case kMathFloor: return DoMathFloor(instr); 1233 case kMathRound: return DoMathRound(instr); 1234 case kMathAbs: return DoMathAbs(instr); 1235 case kMathLog: return DoMathLog(instr); 1236 case kMathSin: return DoMathSin(instr); 1237 case kMathCos: return DoMathCos(instr); 1238 case kMathTan: return DoMathTan(instr); 1239 case kMathExp: return DoMathExp(instr); 1240 case kMathSqrt: return DoMathSqrt(instr); 1241 case kMathPowHalf: return DoMathPowHalf(instr); 1242 default: 1243 UNREACHABLE(); 1244 return NULL; 1245 } 1246 } 1247 1248 1249 LInstruction* LChunkBuilder::DoMathFloor(HUnaryMathOperation* instr) { 1250 LOperand* input = UseRegisterAtStart(instr->value()); 1251 LMathFloor* result = new(zone()) LMathFloor(input); 1252 return AssignEnvironment(DefineAsRegister(result)); 1253 } 1254 1255 1256 LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) { 1257 LOperand* context = UseAny(instr->context()); 1258 LOperand* input = UseRegister(instr->value()); 1259 LOperand* temp = FixedTemp(xmm4); 1260 LMathRound* result = new(zone()) LMathRound(context, input, temp); 1261 return AssignEnvironment(DefineAsRegister(result)); 1262 } 1263 1264 1265 LInstruction* LChunkBuilder::DoMathAbs(HUnaryMathOperation* instr) { 1266 LOperand* context = UseAny(instr->context()); // Deferred use. 1267 LOperand* input = UseRegisterAtStart(instr->value()); 1268 LMathAbs* result = new(zone()) LMathAbs(context, input); 1269 return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result))); 1270 } 1271 1272 1273 LInstruction* LChunkBuilder::DoMathLog(HUnaryMathOperation* instr) { 1274 ASSERT(instr->representation().IsDouble()); 1275 ASSERT(instr->value()->representation().IsDouble()); 1276 LOperand* input = UseRegisterAtStart(instr->value()); 1277 LMathLog* result = new(zone()) LMathLog(input); 1278 return DefineSameAsFirst(result); 1279 } 1280 1281 1282 LInstruction* LChunkBuilder::DoMathSin(HUnaryMathOperation* instr) { 1283 LOperand* input = UseFixedDouble(instr->value(), xmm1); 1284 LMathSin* result = new(zone()) LMathSin(input); 1285 return MarkAsCall(DefineFixedDouble(result, xmm1), instr); 1286 } 1287 1288 1289 LInstruction* LChunkBuilder::DoMathCos(HUnaryMathOperation* instr) { 1290 LOperand* input = UseFixedDouble(instr->value(), xmm1); 1291 LMathCos* result = new(zone()) LMathCos(input); 1292 return MarkAsCall(DefineFixedDouble(result, xmm1), instr); 1293 } 1294 1295 1296 LInstruction* LChunkBuilder::DoMathTan(HUnaryMathOperation* instr) { 1297 LOperand* input = UseFixedDouble(instr->value(), xmm1); 1298 LMathTan* result = new(zone()) LMathTan(input); 1299 return MarkAsCall(DefineFixedDouble(result, xmm1), instr); 1300 } 1301 1302 1303 LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) { 1304 ASSERT(instr->representation().IsDouble()); 1305 ASSERT(instr->value()->representation().IsDouble()); 1306 LOperand* value = UseTempRegister(instr->value()); 1307 LOperand* temp1 = TempRegister(); 1308 LOperand* temp2 = TempRegister(); 1309 LMathExp* result = new(zone()) LMathExp(value, temp1, temp2); 1310 return DefineAsRegister(result); 1311 } 1312 1313 1314 LInstruction* LChunkBuilder::DoMathSqrt(HUnaryMathOperation* instr) { 1315 LOperand* input = UseRegisterAtStart(instr->value()); 1316 LMathSqrt* result = new(zone()) LMathSqrt(input); 1317 return DefineSameAsFirst(result); 1318 } 1319 1320 1321 LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) { 1322 LOperand* context = UseAny(instr->context()); 1323 LOperand* input = UseRegisterAtStart(instr->value()); 1324 LOperand* temp = TempRegister(); 1325 LMathPowHalf* result = new(zone()) LMathPowHalf(context, input, temp); 1326 return DefineSameAsFirst(result); 1327 } 1328 1329 1330 LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) { 1331 ASSERT(instr->key()->representation().IsTagged()); 1332 LOperand* context = UseFixed(instr->context(), esi); 1333 LOperand* key = UseFixed(instr->key(), ecx); 1334 argument_count_ -= instr->argument_count(); 1335 LCallKeyed* result = new(zone()) LCallKeyed(context, key); 1336 return MarkAsCall(DefineFixed(result, eax), instr); 1337 } 1338 1339 1340 LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) { 1341 LOperand* context = UseFixed(instr->context(), esi); 1342 argument_count_ -= instr->argument_count(); 1343 LCallNamed* result = new(zone()) LCallNamed(context); 1344 return MarkAsCall(DefineFixed(result, eax), instr); 1345 } 1346 1347 1348 LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) { 1349 LOperand* context = UseFixed(instr->context(), esi); 1350 argument_count_ -= instr->argument_count(); 1351 LCallGlobal* result = new(zone()) LCallGlobal(context); 1352 return MarkAsCall(DefineFixed(result, eax), instr); 1353 } 1354 1355 1356 LInstruction* LChunkBuilder::DoCallKnownGlobal(HCallKnownGlobal* instr) { 1357 argument_count_ -= instr->argument_count(); 1358 return MarkAsCall(DefineFixed(new(zone()) LCallKnownGlobal, eax), instr); 1359 } 1360 1361 1362 LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) { 1363 LOperand* context = UseFixed(instr->context(), esi); 1364 LOperand* constructor = UseFixed(instr->constructor(), edi); 1365 argument_count_ -= instr->argument_count(); 1366 LCallNew* result = new(zone()) LCallNew(context, constructor); 1367 return MarkAsCall(DefineFixed(result, eax), instr); 1368 } 1369 1370 1371 LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) { 1372 LOperand* context = UseFixed(instr->context(), esi); 1373 LOperand* constructor = UseFixed(instr->constructor(), edi); 1374 argument_count_ -= instr->argument_count(); 1375 LCallNewArray* result = new(zone()) LCallNewArray(context, constructor); 1376 return MarkAsCall(DefineFixed(result, eax), instr); 1377 } 1378 1379 1380 LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) { 1381 LOperand* context = UseFixed(instr->context(), esi); 1382 LOperand* function = UseFixed(instr->function(), edi); 1383 argument_count_ -= instr->argument_count(); 1384 LCallFunction* result = new(zone()) LCallFunction(context, function); 1385 return MarkAsCall(DefineFixed(result, eax), instr); 1386 } 1387 1388 1389 LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) { 1390 argument_count_ -= instr->argument_count(); 1391 LOperand* context = UseFixed(instr->context(), esi); 1392 return MarkAsCall(DefineFixed(new(zone()) LCallRuntime(context), eax), instr); 1393 } 1394 1395 1396 LInstruction* LChunkBuilder::DoRor(HRor* instr) { 1397 return DoShift(Token::ROR, instr); 1398 } 1399 1400 1401 LInstruction* LChunkBuilder::DoShr(HShr* instr) { 1402 return DoShift(Token::SHR, instr); 1403 } 1404 1405 1406 LInstruction* LChunkBuilder::DoSar(HSar* instr) { 1407 return DoShift(Token::SAR, instr); 1408 } 1409 1410 1411 LInstruction* LChunkBuilder::DoShl(HShl* instr) { 1412 return DoShift(Token::SHL, instr); 1413 } 1414 1415 1416 LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) { 1417 if (instr->representation().IsSmiOrInteger32()) { 1418 ASSERT(instr->left()->representation().Equals(instr->representation())); 1419 ASSERT(instr->right()->representation().Equals(instr->representation())); 1420 1421 LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand()); 1422 LOperand* right = UseOrConstantAtStart(instr->BetterRightOperand()); 1423 return DefineSameAsFirst(new(zone()) LBitI(left, right)); 1424 } else { 1425 ASSERT(instr->representation().IsSmiOrTagged()); 1426 ASSERT(instr->left()->representation().IsSmiOrTagged()); 1427 ASSERT(instr->right()->representation().IsSmiOrTagged()); 1428 1429 LOperand* context = UseFixed(instr->context(), esi); 1430 LOperand* left = UseFixed(instr->left(), edx); 1431 LOperand* right = UseFixed(instr->right(), eax); 1432 LArithmeticT* result = 1433 new(zone()) LArithmeticT(instr->op(), context, left, right); 1434 return MarkAsCall(DefineFixed(result, eax), instr); 1435 } 1436 } 1437 1438 1439 LInstruction* LChunkBuilder::DoDiv(HDiv* instr) { 1440 if (instr->representation().IsDouble()) { 1441 return DoArithmeticD(Token::DIV, instr); 1442 } else if (instr->representation().IsSmiOrInteger32()) { 1443 ASSERT(instr->left()->representation().Equals(instr->representation())); 1444 ASSERT(instr->right()->representation().Equals(instr->representation())); 1445 if (instr->HasPowerOf2Divisor()) { 1446 ASSERT(!instr->CheckFlag(HValue::kCanBeDivByZero)); 1447 LOperand* value = UseRegisterAtStart(instr->left()); 1448 LDivI* div = 1449 new(zone()) LDivI(value, UseOrConstant(instr->right()), NULL); 1450 return AssignEnvironment(DefineSameAsFirst(div)); 1451 } 1452 // The temporary operand is necessary to ensure that right is not allocated 1453 // into edx. 1454 LOperand* temp = FixedTemp(edx); 1455 LOperand* dividend = UseFixed(instr->left(), eax); 1456 LOperand* divisor = UseRegister(instr->right()); 1457 LDivI* result = new(zone()) LDivI(dividend, divisor, temp); 1458 return AssignEnvironment(DefineFixed(result, eax)); 1459 } else { 1460 ASSERT(instr->representation().IsTagged()); 1461 return DoArithmeticT(Token::DIV, instr); 1462 } 1463 } 1464 1465 1466 HValue* LChunkBuilder::SimplifiedDivisorForMathFloorOfDiv(HValue* divisor) { 1467 if (divisor->IsConstant() && 1468 HConstant::cast(divisor)->HasInteger32Value()) { 1469 HConstant* constant_val = HConstant::cast(divisor); 1470 return constant_val->CopyToRepresentation(Representation::Integer32(), 1471 divisor->block()->zone()); 1472 } 1473 // A value with an integer representation does not need to be transformed. 1474 if (divisor->representation().IsInteger32()) { 1475 return divisor; 1476 // A change from an integer32 can be replaced by the integer32 value. 1477 } else if (divisor->IsChange() && 1478 HChange::cast(divisor)->from().IsInteger32()) { 1479 return HChange::cast(divisor)->value(); 1480 } 1481 return NULL; 1482 } 1483 1484 1485 LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) { 1486 HValue* right = instr->right(); 1487 if (!right->IsConstant()) { 1488 ASSERT(right->representation().IsInteger32()); 1489 // The temporary operand is necessary to ensure that right is not allocated 1490 // into edx. 1491 LOperand* temp = FixedTemp(edx); 1492 LOperand* dividend = UseFixed(instr->left(), eax); 1493 LOperand* divisor = UseRegister(instr->right()); 1494 LDivI* flooring_div = new(zone()) LDivI(dividend, divisor, temp); 1495 return AssignEnvironment(DefineFixed(flooring_div, eax)); 1496 } 1497 1498 ASSERT(right->IsConstant() && HConstant::cast(right)->HasInteger32Value()); 1499 LOperand* divisor = chunk_->DefineConstantOperand(HConstant::cast(right)); 1500 int32_t divisor_si = HConstant::cast(right)->Integer32Value(); 1501 if (divisor_si == 0) { 1502 LOperand* dividend = UseRegister(instr->left()); 1503 return AssignEnvironment(DefineAsRegister( 1504 new(zone()) LMathFloorOfDiv(dividend, divisor, NULL))); 1505 } else if (IsPowerOf2(abs(divisor_si))) { 1506 // use dividend as temp if divisor < 0 && divisor != -1 1507 LOperand* dividend = divisor_si < -1 ? UseTempRegister(instr->left()) : 1508 UseRegisterAtStart(instr->left()); 1509 LInstruction* result = DefineAsRegister( 1510 new(zone()) LMathFloorOfDiv(dividend, divisor, NULL)); 1511 return divisor_si < 0 ? AssignEnvironment(result) : result; 1512 } else { 1513 // needs edx:eax, plus a temp 1514 LOperand* dividend = UseFixed(instr->left(), eax); 1515 LOperand* temp = TempRegister(); 1516 LInstruction* result = DefineFixed( 1517 new(zone()) LMathFloorOfDiv(dividend, divisor, temp), edx); 1518 return divisor_si < 0 ? AssignEnvironment(result) : result; 1519 } 1520 } 1521 1522 1523 LInstruction* LChunkBuilder::DoMod(HMod* instr) { 1524 HValue* left = instr->left(); 1525 HValue* right = instr->right(); 1526 if (instr->representation().IsSmiOrInteger32()) { 1527 ASSERT(instr->left()->representation().Equals(instr->representation())); 1528 ASSERT(instr->right()->representation().Equals(instr->representation())); 1529 1530 if (instr->HasPowerOf2Divisor()) { 1531 ASSERT(!right->CanBeZero()); 1532 LModI* mod = new(zone()) LModI(UseRegisterAtStart(left), 1533 UseOrConstant(right), 1534 NULL); 1535 LInstruction* result = DefineSameAsFirst(mod); 1536 return (left->CanBeNegative() && 1537 instr->CheckFlag(HValue::kBailoutOnMinusZero)) 1538 ? AssignEnvironment(result) 1539 : result; 1540 } else if (instr->fixed_right_arg().has_value) { 1541 LModI* mod = new(zone()) LModI(UseRegister(left), 1542 UseRegisterAtStart(right), 1543 NULL); 1544 return AssignEnvironment(DefineSameAsFirst(mod)); 1545 } else { 1546 // The temporary operand is necessary to ensure that right is not 1547 // allocated into edx. 1548 LModI* mod = new(zone()) LModI(UseFixed(left, eax), 1549 UseRegister(right), 1550 FixedTemp(edx)); 1551 LInstruction* result = DefineFixed(mod, edx); 1552 return (right->CanBeZero() || 1553 (left->RangeCanInclude(kMinInt) && 1554 right->RangeCanInclude(-1) && 1555 instr->CheckFlag(HValue::kBailoutOnMinusZero)) || 1556 (left->CanBeNegative() && 1557 instr->CanBeZero() && 1558 instr->CheckFlag(HValue::kBailoutOnMinusZero))) 1559 ? AssignEnvironment(result) 1560 : result; 1561 } 1562 } else if (instr->representation().IsSmiOrTagged()) { 1563 return DoArithmeticT(Token::MOD, instr); 1564 } else { 1565 ASSERT(instr->representation().IsDouble()); 1566 // We call a C function for double modulo. It can't trigger a GC. We need 1567 // to use fixed result register for the call. 1568 // TODO(fschneider): Allow any register as input registers. 1569 LArithmeticD* mod = new(zone()) LArithmeticD(Token::MOD, 1570 UseFixedDouble(left, xmm2), 1571 UseFixedDouble(right, xmm1)); 1572 return MarkAsCall(DefineFixedDouble(mod, xmm1), instr); 1573 } 1574 } 1575 1576 1577 LInstruction* LChunkBuilder::DoMul(HMul* instr) { 1578 if (instr->representation().IsSmiOrInteger32()) { 1579 ASSERT(instr->left()->representation().Equals(instr->representation())); 1580 ASSERT(instr->right()->representation().Equals(instr->representation())); 1581 LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand()); 1582 LOperand* right = UseOrConstant(instr->BetterRightOperand()); 1583 LOperand* temp = NULL; 1584 if (instr->CheckFlag(HValue::kBailoutOnMinusZero)) { 1585 temp = TempRegister(); 1586 } 1587 LMulI* mul = new(zone()) LMulI(left, right, temp); 1588 if (instr->CheckFlag(HValue::kCanOverflow) || 1589 instr->CheckFlag(HValue::kBailoutOnMinusZero)) { 1590 AssignEnvironment(mul); 1591 } 1592 return DefineSameAsFirst(mul); 1593 } else if (instr->representation().IsDouble()) { 1594 return DoArithmeticD(Token::MUL, instr); 1595 } else { 1596 ASSERT(instr->representation().IsTagged()); 1597 return DoArithmeticT(Token::MUL, instr); 1598 } 1599 } 1600 1601 1602 LInstruction* LChunkBuilder::DoSub(HSub* instr) { 1603 if (instr->representation().IsSmiOrInteger32()) { 1604 ASSERT(instr->left()->representation().Equals(instr->representation())); 1605 ASSERT(instr->right()->representation().Equals(instr->representation())); 1606 LOperand* left = UseRegisterAtStart(instr->left()); 1607 LOperand* right = UseOrConstantAtStart(instr->right()); 1608 LSubI* sub = new(zone()) LSubI(left, right); 1609 LInstruction* result = DefineSameAsFirst(sub); 1610 if (instr->CheckFlag(HValue::kCanOverflow)) { 1611 result = AssignEnvironment(result); 1612 } 1613 return result; 1614 } else if (instr->representation().IsDouble()) { 1615 return DoArithmeticD(Token::SUB, instr); 1616 } else { 1617 ASSERT(instr->representation().IsSmiOrTagged()); 1618 return DoArithmeticT(Token::SUB, instr); 1619 } 1620 } 1621 1622 1623 LInstruction* LChunkBuilder::DoAdd(HAdd* instr) { 1624 if (instr->representation().IsSmiOrInteger32()) { 1625 ASSERT(instr->left()->representation().Equals(instr->representation())); 1626 ASSERT(instr->right()->representation().Equals(instr->representation())); 1627 // Check to see if it would be advantageous to use an lea instruction rather 1628 // than an add. This is the case when no overflow check is needed and there 1629 // are multiple uses of the add's inputs, so using a 3-register add will 1630 // preserve all input values for later uses. 1631 bool use_lea = LAddI::UseLea(instr); 1632 LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand()); 1633 HValue* right_candidate = instr->BetterRightOperand(); 1634 LOperand* right = use_lea 1635 ? UseRegisterOrConstantAtStart(right_candidate) 1636 : UseOrConstantAtStart(right_candidate); 1637 LAddI* add = new(zone()) LAddI(left, right); 1638 bool can_overflow = instr->CheckFlag(HValue::kCanOverflow); 1639 LInstruction* result = use_lea 1640 ? DefineAsRegister(add) 1641 : DefineSameAsFirst(add); 1642 if (can_overflow) { 1643 result = AssignEnvironment(result); 1644 } 1645 return result; 1646 } else if (instr->representation().IsDouble()) { 1647 return DoArithmeticD(Token::ADD, instr); 1648 } else { 1649 ASSERT(instr->representation().IsSmiOrTagged()); 1650 return DoArithmeticT(Token::ADD, instr); 1651 } 1652 } 1653 1654 1655 LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) { 1656 LOperand* left = NULL; 1657 LOperand* right = NULL; 1658 if (instr->representation().IsSmiOrInteger32()) { 1659 ASSERT(instr->left()->representation().Equals(instr->representation())); 1660 ASSERT(instr->right()->representation().Equals(instr->representation())); 1661 left = UseRegisterAtStart(instr->BetterLeftOperand()); 1662 right = UseOrConstantAtStart(instr->BetterRightOperand()); 1663 } else { 1664 ASSERT(instr->representation().IsDouble()); 1665 ASSERT(instr->left()->representation().IsDouble()); 1666 ASSERT(instr->right()->representation().IsDouble()); 1667 left = UseRegisterAtStart(instr->left()); 1668 right = UseRegisterAtStart(instr->right()); 1669 } 1670 LMathMinMax* minmax = new(zone()) LMathMinMax(left, right); 1671 return DefineSameAsFirst(minmax); 1672 } 1673 1674 1675 LInstruction* LChunkBuilder::DoPower(HPower* instr) { 1676 ASSERT(instr->representation().IsDouble()); 1677 // We call a C function for double power. It can't trigger a GC. 1678 // We need to use fixed result register for the call. 1679 Representation exponent_type = instr->right()->representation(); 1680 ASSERT(instr->left()->representation().IsDouble()); 1681 LOperand* left = UseFixedDouble(instr->left(), xmm2); 1682 LOperand* right = exponent_type.IsDouble() ? 1683 UseFixedDouble(instr->right(), xmm1) : 1684 UseFixed(instr->right(), eax); 1685 LPower* result = new(zone()) LPower(left, right); 1686 return MarkAsCall(DefineFixedDouble(result, xmm3), instr, 1687 CAN_DEOPTIMIZE_EAGERLY); 1688 } 1689 1690 1691 LInstruction* LChunkBuilder::DoRandom(HRandom* instr) { 1692 ASSERT(instr->representation().IsDouble()); 1693 ASSERT(instr->global_object()->representation().IsSmiOrTagged()); 1694 LOperand* global_object = UseFixed(instr->global_object(), eax); 1695 LRandom* result = new(zone()) LRandom(global_object); 1696 return MarkAsCall(DefineFixedDouble(result, xmm1), instr); 1697 } 1698 1699 1700 LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) { 1701 ASSERT(instr->left()->representation().IsSmiOrTagged()); 1702 ASSERT(instr->right()->representation().IsSmiOrTagged()); 1703 LOperand* context = UseFixed(instr->context(), esi); 1704 LOperand* left = UseFixed(instr->left(), edx); 1705 LOperand* right = UseFixed(instr->right(), eax); 1706 LCmpT* result = new(zone()) LCmpT(context, left, right); 1707 return MarkAsCall(DefineFixed(result, eax), instr); 1708 } 1709 1710 1711 LInstruction* LChunkBuilder::DoCompareNumericAndBranch( 1712 HCompareNumericAndBranch* instr) { 1713 Representation r = instr->representation(); 1714 if (r.IsSmiOrInteger32()) { 1715 ASSERT(instr->left()->representation().Equals(r)); 1716 ASSERT(instr->right()->representation().Equals(r)); 1717 LOperand* left = UseRegisterOrConstantAtStart(instr->left()); 1718 LOperand* right = UseOrConstantAtStart(instr->right()); 1719 return new(zone()) LCompareNumericAndBranch(left, right); 1720 } else { 1721 ASSERT(r.IsDouble()); 1722 ASSERT(instr->left()->representation().IsDouble()); 1723 ASSERT(instr->right()->representation().IsDouble()); 1724 LOperand* left; 1725 LOperand* right; 1726 if (instr->left()->IsConstant() && instr->right()->IsConstant()) { 1727 left = UseRegisterOrConstantAtStart(instr->left()); 1728 right = UseRegisterOrConstantAtStart(instr->right()); 1729 } else { 1730 left = UseRegisterAtStart(instr->left()); 1731 right = UseRegisterAtStart(instr->right()); 1732 } 1733 return new(zone()) LCompareNumericAndBranch(left, right); 1734 } 1735 } 1736 1737 1738 LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch( 1739 HCompareObjectEqAndBranch* instr) { 1740 LOperand* left = UseRegisterAtStart(instr->left()); 1741 LOperand* right = UseOrConstantAtStart(instr->right()); 1742 return new(zone()) LCmpObjectEqAndBranch(left, right); 1743 } 1744 1745 1746 LInstruction* LChunkBuilder::DoCompareHoleAndBranch( 1747 HCompareHoleAndBranch* instr) { 1748 LOperand* object = UseRegisterAtStart(instr->object()); 1749 return new(zone()) LCmpHoleAndBranch(object); 1750 } 1751 1752 1753 LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) { 1754 ASSERT(instr->value()->representation().IsSmiOrTagged()); 1755 LOperand* temp = TempRegister(); 1756 return new(zone()) LIsObjectAndBranch(UseRegister(instr->value()), temp); 1757 } 1758 1759 1760 LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) { 1761 ASSERT(instr->value()->representation().IsTagged()); 1762 LOperand* temp = TempRegister(); 1763 return new(zone()) LIsStringAndBranch(UseRegister(instr->value()), temp); 1764 } 1765 1766 1767 LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) { 1768 ASSERT(instr->value()->representation().IsTagged()); 1769 return new(zone()) LIsSmiAndBranch(Use(instr->value())); 1770 } 1771 1772 1773 LInstruction* LChunkBuilder::DoIsUndetectableAndBranch( 1774 HIsUndetectableAndBranch* instr) { 1775 ASSERT(instr->value()->representation().IsTagged()); 1776 return new(zone()) LIsUndetectableAndBranch( 1777 UseRegisterAtStart(instr->value()), TempRegister()); 1778 } 1779 1780 1781 LInstruction* LChunkBuilder::DoStringCompareAndBranch( 1782 HStringCompareAndBranch* instr) { 1783 ASSERT(instr->left()->representation().IsTagged()); 1784 ASSERT(instr->right()->representation().IsTagged()); 1785 LOperand* context = UseFixed(instr->context(), esi); 1786 LOperand* left = UseFixed(instr->left(), edx); 1787 LOperand* right = UseFixed(instr->right(), eax); 1788 1789 LStringCompareAndBranch* result = new(zone()) 1790 LStringCompareAndBranch(context, left, right); 1791 1792 return MarkAsCall(result, instr); 1793 } 1794 1795 1796 LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch( 1797 HHasInstanceTypeAndBranch* instr) { 1798 ASSERT(instr->value()->representation().IsTagged()); 1799 return new(zone()) LHasInstanceTypeAndBranch( 1800 UseRegisterAtStart(instr->value()), 1801 TempRegister()); 1802 } 1803 1804 1805 LInstruction* LChunkBuilder::DoGetCachedArrayIndex( 1806 HGetCachedArrayIndex* instr) { 1807 ASSERT(instr->value()->representation().IsTagged()); 1808 LOperand* value = UseRegisterAtStart(instr->value()); 1809 1810 return DefineAsRegister(new(zone()) LGetCachedArrayIndex(value)); 1811 } 1812 1813 1814 LInstruction* LChunkBuilder::DoHasCachedArrayIndexAndBranch( 1815 HHasCachedArrayIndexAndBranch* instr) { 1816 ASSERT(instr->value()->representation().IsTagged()); 1817 return new(zone()) LHasCachedArrayIndexAndBranch( 1818 UseRegisterAtStart(instr->value())); 1819 } 1820 1821 1822 LInstruction* LChunkBuilder::DoClassOfTestAndBranch( 1823 HClassOfTestAndBranch* instr) { 1824 ASSERT(instr->value()->representation().IsTagged()); 1825 return new(zone()) LClassOfTestAndBranch(UseRegister(instr->value()), 1826 TempRegister(), 1827 TempRegister()); 1828 } 1829 1830 1831 LInstruction* LChunkBuilder::DoMapEnumLength(HMapEnumLength* instr) { 1832 LOperand* map = UseRegisterAtStart(instr->value()); 1833 return DefineAsRegister(new(zone()) LMapEnumLength(map)); 1834 } 1835 1836 1837 LInstruction* LChunkBuilder::DoElementsKind(HElementsKind* instr) { 1838 LOperand* object = UseRegisterAtStart(instr->value()); 1839 return DefineAsRegister(new(zone()) LElementsKind(object)); 1840 } 1841 1842 1843 LInstruction* LChunkBuilder::DoValueOf(HValueOf* instr) { 1844 LOperand* object = UseRegister(instr->value()); 1845 LValueOf* result = new(zone()) LValueOf(object, TempRegister()); 1846 return DefineSameAsFirst(result); 1847 } 1848 1849 1850 LInstruction* LChunkBuilder::DoDateField(HDateField* instr) { 1851 LOperand* date = UseFixed(instr->value(), eax); 1852 LDateField* result = 1853 new(zone()) LDateField(date, FixedTemp(ecx), instr->index()); 1854 return MarkAsCall(DefineFixed(result, eax), instr, CAN_DEOPTIMIZE_EAGERLY); 1855 } 1856 1857 1858 LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) { 1859 LOperand* string = UseRegister(instr->string()); 1860 LOperand* index = UseRegister(instr->index()); 1861 ASSERT(ecx.is_byte_register()); 1862 LOperand* value = UseFixed(instr->value(), ecx); 1863 LSeqStringSetChar* result = 1864 new(zone()) LSeqStringSetChar(instr->encoding(), string, index, value); 1865 return DefineSameAsFirst(result); 1866 } 1867 1868 1869 LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) { 1870 return AssignEnvironment(new(zone()) LBoundsCheck( 1871 UseRegisterOrConstantAtStart(instr->index()), 1872 UseAtStart(instr->length()))); 1873 } 1874 1875 1876 LInstruction* LChunkBuilder::DoBoundsCheckBaseIndexInformation( 1877 HBoundsCheckBaseIndexInformation* instr) { 1878 UNREACHABLE(); 1879 return NULL; 1880 } 1881 1882 1883 LInstruction* LChunkBuilder::DoThrow(HThrow* instr) { 1884 LOperand* context = UseFixed(instr->context(), esi); 1885 LOperand* value = UseFixed(instr->value(), eax); 1886 return MarkAsCall(new(zone()) LThrow(context, value), instr); 1887 } 1888 1889 1890 LInstruction* LChunkBuilder::DoUseConst(HUseConst* instr) { 1891 return NULL; 1892 } 1893 1894 1895 LInstruction* LChunkBuilder::DoForceRepresentation(HForceRepresentation* bad) { 1896 // All HForceRepresentation instructions should be eliminated in the 1897 // representation change phase of Hydrogen. 1898 UNREACHABLE(); 1899 return NULL; 1900 } 1901 1902 1903 LInstruction* LChunkBuilder::DoChange(HChange* instr) { 1904 Representation from = instr->from(); 1905 Representation to = instr->to(); 1906 if (from.IsSmi()) { 1907 if (to.IsTagged()) { 1908 LOperand* value = UseRegister(instr->value()); 1909 return DefineSameAsFirst(new(zone()) LDummyUse(value)); 1910 } 1911 from = Representation::Tagged(); 1912 } 1913 // Only mark conversions that might need to allocate as calling rather than 1914 // all changes. This makes simple, non-allocating conversion not have to force 1915 // building a stack frame. 1916 if (from.IsTagged()) { 1917 if (to.IsDouble()) { 1918 info()->MarkAsDeferredCalling(); 1919 LOperand* value = UseRegister(instr->value()); 1920 // Temp register only necessary for minus zero check. 1921 LOperand* temp = instr->deoptimize_on_minus_zero() 1922 ? TempRegister() 1923 : NULL; 1924 LNumberUntagD* res = new(zone()) LNumberUntagD(value, temp); 1925 return AssignEnvironment(DefineAsRegister(res)); 1926 } else if (to.IsSmi()) { 1927 HValue* val = instr->value(); 1928 LOperand* value = UseRegister(val); 1929 if (val->type().IsSmi()) { 1930 return DefineSameAsFirst(new(zone()) LDummyUse(value)); 1931 } 1932 return AssignEnvironment(DefineSameAsFirst(new(zone()) LCheckSmi(value))); 1933 } else { 1934 ASSERT(to.IsInteger32()); 1935 if (instr->value()->type().IsSmi()) { 1936 LOperand* value = UseRegister(instr->value()); 1937 return DefineSameAsFirst(new(zone()) LSmiUntag(value, false)); 1938 } else { 1939 bool truncating = instr->CanTruncateToInt32(); 1940 if (CpuFeatures::IsSafeForSnapshot(SSE2)) { 1941 LOperand* value = UseRegister(instr->value()); 1942 LOperand* xmm_temp = 1943 (truncating && CpuFeatures::IsSupported(SSE3)) 1944 ? NULL 1945 : FixedTemp(xmm1); 1946 LTaggedToI* res = new(zone()) LTaggedToI(value, xmm_temp); 1947 return AssignEnvironment(DefineSameAsFirst(res)); 1948 } else { 1949 LOperand* value = UseFixed(instr->value(), ecx); 1950 LTaggedToINoSSE2* res = 1951 new(zone()) LTaggedToINoSSE2(value, TempRegister(), 1952 TempRegister(), TempRegister()); 1953 return AssignEnvironment(DefineFixed(res, ecx)); 1954 } 1955 } 1956 } 1957 } else if (from.IsDouble()) { 1958 if (to.IsTagged()) { 1959 info()->MarkAsDeferredCalling(); 1960 LOperand* value = UseRegisterAtStart(instr->value()); 1961 LOperand* temp = FLAG_inline_new ? TempRegister() : NULL; 1962 1963 // Make sure that temp and result_temp are different registers. 1964 LUnallocated* result_temp = TempRegister(); 1965 LNumberTagD* result = new(zone()) LNumberTagD(value, temp); 1966 return AssignPointerMap(Define(result, result_temp)); 1967 } else if (to.IsSmi()) { 1968 LOperand* value = UseRegister(instr->value()); 1969 return AssignEnvironment( 1970 DefineAsRegister(new(zone()) LDoubleToSmi(value))); 1971 } else { 1972 ASSERT(to.IsInteger32()); 1973 bool truncating = instr->CanTruncateToInt32(); 1974 bool needs_temp = truncating && !CpuFeatures::IsSupported(SSE3); 1975 LOperand* value = needs_temp ? 1976 UseTempRegister(instr->value()) : UseRegister(instr->value()); 1977 LOperand* temp = needs_temp ? TempRegister() : NULL; 1978 return AssignEnvironment( 1979 DefineAsRegister(new(zone()) LDoubleToI(value, temp))); 1980 } 1981 } else if (from.IsInteger32()) { 1982 info()->MarkAsDeferredCalling(); 1983 if (to.IsTagged()) { 1984 HValue* val = instr->value(); 1985 LOperand* value = UseRegister(val); 1986 if (val->HasRange() && val->range()->IsInSmiRange()) { 1987 return DefineSameAsFirst(new(zone()) LSmiTag(value)); 1988 } else if (val->CheckFlag(HInstruction::kUint32)) { 1989 LOperand* temp = CpuFeatures::IsSupported(SSE2) ? FixedTemp(xmm1) 1990 : NULL; 1991 LNumberTagU* result = new(zone()) LNumberTagU(value, temp); 1992 return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result))); 1993 } else { 1994 LNumberTagI* result = new(zone()) LNumberTagI(value); 1995 return AssignEnvironment(AssignPointerMap(DefineSameAsFirst(result))); 1996 } 1997 } else if (to.IsSmi()) { 1998 HValue* val = instr->value(); 1999 LOperand* value = UseRegister(val); 2000 LInstruction* result = 2001 DefineSameAsFirst(new(zone()) LInteger32ToSmi(value)); 2002 if (val->HasRange() && val->range()->IsInSmiRange()) { 2003 return result; 2004 } 2005 return AssignEnvironment(result); 2006 } else { 2007 ASSERT(to.IsDouble()); 2008 if (instr->value()->CheckFlag(HInstruction::kUint32)) { 2009 LOperand* temp = FixedTemp(xmm1); 2010 return DefineAsRegister( 2011 new(zone()) LUint32ToDouble(UseRegister(instr->value()), temp)); 2012 } else { 2013 return DefineAsRegister( 2014 new(zone()) LInteger32ToDouble(Use(instr->value()))); 2015 } 2016 } 2017 } 2018 UNREACHABLE(); 2019 return NULL; 2020 } 2021 2022 2023 LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) { 2024 LOperand* value = UseAtStart(instr->value()); 2025 return AssignEnvironment(new(zone()) LCheckNonSmi(value)); 2026 } 2027 2028 2029 LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) { 2030 LOperand* value = UseRegisterAtStart(instr->value()); 2031 return AssignEnvironment(new(zone()) LCheckSmi(value)); 2032 } 2033 2034 2035 LInstruction* LChunkBuilder::DoIsNumberAndBranch(HIsNumberAndBranch* instr) { 2036 return new(zone()) 2037 LIsNumberAndBranch(UseRegisterOrConstantAtStart(instr->value())); 2038 } 2039 2040 2041 LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) { 2042 LOperand* value = UseRegisterAtStart(instr->value()); 2043 LOperand* temp = TempRegister(); 2044 LCheckInstanceType* result = new(zone()) LCheckInstanceType(value, temp); 2045 return AssignEnvironment(result); 2046 } 2047 2048 2049 LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) { 2050 // If the target is in new space, we'll emit a global cell compare and so 2051 // want the value in a register. If the target gets promoted before we 2052 // emit code, we will still get the register but will do an immediate 2053 // compare instead of the cell compare. This is safe. 2054 LOperand* value = instr->target_in_new_space() 2055 ? UseRegisterAtStart(instr->value()) : UseAtStart(instr->value()); 2056 return AssignEnvironment(new(zone()) LCheckFunction(value)); 2057 } 2058 2059 2060 LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) { 2061 LOperand* value = NULL; 2062 if (!instr->CanOmitMapChecks()) { 2063 value = UseRegisterAtStart(instr->value()); 2064 if (instr->has_migration_target()) info()->MarkAsDeferredCalling(); 2065 } 2066 LCheckMaps* result = new(zone()) LCheckMaps(value); 2067 if (!instr->CanOmitMapChecks()) { 2068 AssignEnvironment(result); 2069 if (instr->has_migration_target()) return AssignPointerMap(result); 2070 } 2071 return result; 2072 } 2073 2074 2075 LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) { 2076 HValue* value = instr->value(); 2077 Representation input_rep = value->representation(); 2078 if (input_rep.IsDouble()) { 2079 LOperand* reg = UseRegister(value); 2080 return DefineFixed(new(zone()) LClampDToUint8(reg), eax); 2081 } else if (input_rep.IsInteger32()) { 2082 LOperand* reg = UseFixed(value, eax); 2083 return DefineFixed(new(zone()) LClampIToUint8(reg), eax); 2084 } else { 2085 ASSERT(input_rep.IsSmiOrTagged()); 2086 if (CpuFeatures::IsSupported(SSE2)) { 2087 LOperand* reg = UseFixed(value, eax); 2088 // Register allocator doesn't (yet) support allocation of double 2089 // temps. Reserve xmm1 explicitly. 2090 LOperand* temp = FixedTemp(xmm1); 2091 LClampTToUint8* result = new(zone()) LClampTToUint8(reg, temp); 2092 return AssignEnvironment(DefineFixed(result, eax)); 2093 } else { 2094 LOperand* value = UseRegister(instr->value()); 2095 LClampTToUint8NoSSE2* res = 2096 new(zone()) LClampTToUint8NoSSE2(value, TempRegister(), 2097 TempRegister(), TempRegister()); 2098 return AssignEnvironment(DefineFixed(res, ecx)); 2099 } 2100 } 2101 } 2102 2103 2104 LInstruction* LChunkBuilder::DoReturn(HReturn* instr) { 2105 LOperand* context = info()->IsStub() 2106 ? UseFixed(instr->context(), esi) 2107 : NULL; 2108 LOperand* parameter_count = UseRegisterOrConstant(instr->parameter_count()); 2109 return new(zone()) LReturn(UseFixed(instr->value(), eax), context, 2110 parameter_count); 2111 } 2112 2113 2114 LInstruction* LChunkBuilder::DoConstant(HConstant* instr) { 2115 Representation r = instr->representation(); 2116 if (r.IsSmi()) { 2117 return DefineAsRegister(new(zone()) LConstantS); 2118 } else if (r.IsInteger32()) { 2119 return DefineAsRegister(new(zone()) LConstantI); 2120 } else if (r.IsDouble()) { 2121 double value = instr->DoubleValue(); 2122 bool value_is_zero = BitCast<uint64_t, double>(value) == 0; 2123 LOperand* temp = value_is_zero ? NULL : TempRegister(); 2124 return DefineAsRegister(new(zone()) LConstantD(temp)); 2125 } else if (r.IsExternal()) { 2126 return DefineAsRegister(new(zone()) LConstantE); 2127 } else if (r.IsTagged()) { 2128 return DefineAsRegister(new(zone()) LConstantT); 2129 } else { 2130 UNREACHABLE(); 2131 return NULL; 2132 } 2133 } 2134 2135 2136 LInstruction* LChunkBuilder::DoLoadGlobalCell(HLoadGlobalCell* instr) { 2137 LLoadGlobalCell* result = new(zone()) LLoadGlobalCell; 2138 return instr->RequiresHoleCheck() 2139 ? AssignEnvironment(DefineAsRegister(result)) 2140 : DefineAsRegister(result); 2141 } 2142 2143 2144 LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) { 2145 LOperand* context = UseFixed(instr->context(), esi); 2146 LOperand* global_object = UseFixed(instr->global_object(), edx); 2147 LLoadGlobalGeneric* result = 2148 new(zone()) LLoadGlobalGeneric(context, global_object); 2149 return MarkAsCall(DefineFixed(result, eax), instr); 2150 } 2151 2152 2153 LInstruction* LChunkBuilder::DoStoreGlobalCell(HStoreGlobalCell* instr) { 2154 LStoreGlobalCell* result = 2155 new(zone()) LStoreGlobalCell(UseRegister(instr->value())); 2156 return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result; 2157 } 2158 2159 2160 LInstruction* LChunkBuilder::DoStoreGlobalGeneric(HStoreGlobalGeneric* instr) { 2161 LOperand* context = UseFixed(instr->context(), esi); 2162 LOperand* global_object = UseFixed(instr->global_object(), edx); 2163 LOperand* value = UseFixed(instr->value(), eax); 2164 LStoreGlobalGeneric* result = 2165 new(zone()) LStoreGlobalGeneric(context, global_object, value); 2166 return MarkAsCall(result, instr); 2167 } 2168 2169 2170 LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) { 2171 LOperand* context = UseRegisterAtStart(instr->value()); 2172 LInstruction* result = 2173 DefineAsRegister(new(zone()) LLoadContextSlot(context)); 2174 return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result; 2175 } 2176 2177 2178 LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) { 2179 LOperand* value; 2180 LOperand* temp; 2181 LOperand* context = UseRegister(instr->context()); 2182 if (instr->NeedsWriteBarrier()) { 2183 value = UseTempRegister(instr->value()); 2184 temp = TempRegister(); 2185 } else { 2186 value = UseRegister(instr->value()); 2187 temp = NULL; 2188 } 2189 LInstruction* result = new(zone()) LStoreContextSlot(context, value, temp); 2190 return instr->RequiresHoleCheck() ? AssignEnvironment(result) : result; 2191 } 2192 2193 2194 LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) { 2195 LOperand* obj = (instr->access().IsExternalMemory() && 2196 instr->access().offset() == 0) 2197 ? UseRegisterOrConstantAtStart(instr->object()) 2198 : UseRegisterAtStart(instr->object()); 2199 return DefineAsRegister(new(zone()) LLoadNamedField(obj)); 2200 } 2201 2202 2203 LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) { 2204 LOperand* context = UseFixed(instr->context(), esi); 2205 LOperand* object = UseFixed(instr->object(), edx); 2206 LLoadNamedGeneric* result = new(zone()) LLoadNamedGeneric(context, object); 2207 return MarkAsCall(DefineFixed(result, eax), instr); 2208 } 2209 2210 2211 LInstruction* LChunkBuilder::DoLoadFunctionPrototype( 2212 HLoadFunctionPrototype* instr) { 2213 return AssignEnvironment(DefineAsRegister( 2214 new(zone()) LLoadFunctionPrototype(UseRegister(instr->function()), 2215 TempRegister()))); 2216 } 2217 2218 2219 LInstruction* LChunkBuilder::DoLoadExternalArrayPointer( 2220 HLoadExternalArrayPointer* instr) { 2221 LOperand* input = UseRegisterAtStart(instr->value()); 2222 return DefineAsRegister(new(zone()) LLoadExternalArrayPointer(input)); 2223 } 2224 2225 2226 LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) { 2227 ASSERT(instr->key()->representation().IsSmiOrInteger32()); 2228 ElementsKind elements_kind = instr->elements_kind(); 2229 bool clobbers_key = ExternalArrayOpRequiresTemp( 2230 instr->key()->representation(), elements_kind); 2231 LOperand* key = clobbers_key 2232 ? UseTempRegister(instr->key()) 2233 : UseRegisterOrConstantAtStart(instr->key()); 2234 LLoadKeyed* result = NULL; 2235 2236 if (!instr->is_external()) { 2237 LOperand* obj = UseRegisterAtStart(instr->elements()); 2238 result = new(zone()) LLoadKeyed(obj, key); 2239 } else { 2240 ASSERT( 2241 (instr->representation().IsInteger32() && 2242 (elements_kind != EXTERNAL_FLOAT_ELEMENTS) && 2243 (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) || 2244 (instr->representation().IsDouble() && 2245 ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) || 2246 (elements_kind == EXTERNAL_DOUBLE_ELEMENTS)))); 2247 LOperand* external_pointer = UseRegister(instr->elements()); 2248 result = new(zone()) LLoadKeyed(external_pointer, key); 2249 } 2250 2251 DefineAsRegister(result); 2252 bool can_deoptimize = instr->RequiresHoleCheck() || 2253 (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS); 2254 // An unsigned int array load might overflow and cause a deopt, make sure it 2255 // has an environment. 2256 return can_deoptimize ? AssignEnvironment(result) : result; 2257 } 2258 2259 2260 LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) { 2261 LOperand* context = UseFixed(instr->context(), esi); 2262 LOperand* object = UseFixed(instr->object(), edx); 2263 LOperand* key = UseFixed(instr->key(), ecx); 2264 2265 LLoadKeyedGeneric* result = 2266 new(zone()) LLoadKeyedGeneric(context, object, key); 2267 return MarkAsCall(DefineFixed(result, eax), instr); 2268 } 2269 2270 2271 LOperand* LChunkBuilder::GetStoreKeyedValueOperand(HStoreKeyed* instr) { 2272 ElementsKind elements_kind = instr->elements_kind(); 2273 2274 // Determine if we need a byte register in this case for the value. 2275 bool val_is_fixed_register = 2276 elements_kind == EXTERNAL_BYTE_ELEMENTS || 2277 elements_kind == EXTERNAL_UNSIGNED_BYTE_ELEMENTS || 2278 elements_kind == EXTERNAL_PIXEL_ELEMENTS; 2279 if (val_is_fixed_register) { 2280 return UseFixed(instr->value(), eax); 2281 } 2282 2283 if (!CpuFeatures::IsSafeForSnapshot(SSE2) && 2284 IsDoubleOrFloatElementsKind(elements_kind)) { 2285 return UseRegisterAtStart(instr->value()); 2286 } 2287 2288 return UseRegister(instr->value()); 2289 } 2290 2291 2292 LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) { 2293 if (!instr->is_external()) { 2294 ASSERT(instr->elements()->representation().IsTagged()); 2295 ASSERT(instr->key()->representation().IsInteger32() || 2296 instr->key()->representation().IsSmi()); 2297 2298 if (instr->value()->representation().IsDouble()) { 2299 LOperand* object = UseRegisterAtStart(instr->elements()); 2300 LOperand* val = NULL; 2301 val = UseRegisterAtStart(instr->value()); 2302 LOperand* key = UseRegisterOrConstantAtStart(instr->key()); 2303 return new(zone()) LStoreKeyed(object, key, val); 2304 } else { 2305 ASSERT(instr->value()->representation().IsSmiOrTagged()); 2306 bool needs_write_barrier = instr->NeedsWriteBarrier(); 2307 2308 LOperand* obj = UseRegister(instr->elements()); 2309 LOperand* val; 2310 LOperand* key; 2311 if (needs_write_barrier) { 2312 val = UseTempRegister(instr->value()); 2313 key = UseTempRegister(instr->key()); 2314 } else { 2315 val = UseRegisterOrConstantAtStart(instr->value()); 2316 key = UseRegisterOrConstantAtStart(instr->key()); 2317 } 2318 return new(zone()) LStoreKeyed(obj, key, val); 2319 } 2320 } 2321 2322 ElementsKind elements_kind = instr->elements_kind(); 2323 ASSERT( 2324 (instr->value()->representation().IsInteger32() && 2325 (elements_kind != EXTERNAL_FLOAT_ELEMENTS) && 2326 (elements_kind != EXTERNAL_DOUBLE_ELEMENTS)) || 2327 (instr->value()->representation().IsDouble() && 2328 ((elements_kind == EXTERNAL_FLOAT_ELEMENTS) || 2329 (elements_kind == EXTERNAL_DOUBLE_ELEMENTS)))); 2330 ASSERT(instr->elements()->representation().IsExternal()); 2331 2332 LOperand* external_pointer = UseRegister(instr->elements()); 2333 LOperand* val = GetStoreKeyedValueOperand(instr); 2334 bool clobbers_key = ExternalArrayOpRequiresTemp( 2335 instr->key()->representation(), elements_kind); 2336 LOperand* key = clobbers_key 2337 ? UseTempRegister(instr->key()) 2338 : UseRegisterOrConstantAtStart(instr->key()); 2339 return new(zone()) LStoreKeyed(external_pointer, 2340 key, 2341 val); 2342 } 2343 2344 2345 LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) { 2346 LOperand* context = UseFixed(instr->context(), esi); 2347 LOperand* object = UseFixed(instr->object(), edx); 2348 LOperand* key = UseFixed(instr->key(), ecx); 2349 LOperand* value = UseFixed(instr->value(), eax); 2350 2351 ASSERT(instr->object()->representation().IsTagged()); 2352 ASSERT(instr->key()->representation().IsTagged()); 2353 ASSERT(instr->value()->representation().IsTagged()); 2354 2355 LStoreKeyedGeneric* result = 2356 new(zone()) LStoreKeyedGeneric(context, object, key, value); 2357 return MarkAsCall(result, instr); 2358 } 2359 2360 2361 LInstruction* LChunkBuilder::DoTransitionElementsKind( 2362 HTransitionElementsKind* instr) { 2363 LOperand* object = UseRegister(instr->object()); 2364 if (IsSimpleMapChangeTransition(instr->from_kind(), instr->to_kind())) { 2365 LOperand* object = UseRegister(instr->object()); 2366 LOperand* new_map_reg = TempRegister(); 2367 LOperand* temp_reg = TempRegister(); 2368 LTransitionElementsKind* result = 2369 new(zone()) LTransitionElementsKind(object, NULL, 2370 new_map_reg, temp_reg); 2371 return result; 2372 } else { 2373 LOperand* context = UseRegister(instr->context()); 2374 LTransitionElementsKind* result = 2375 new(zone()) LTransitionElementsKind(object, context, NULL, NULL); 2376 return AssignPointerMap(result); 2377 } 2378 } 2379 2380 2381 LInstruction* LChunkBuilder::DoTrapAllocationMemento( 2382 HTrapAllocationMemento* instr) { 2383 LOperand* object = UseRegister(instr->object()); 2384 LOperand* temp = TempRegister(); 2385 LTrapAllocationMemento* result = 2386 new(zone()) LTrapAllocationMemento(object, temp); 2387 return AssignEnvironment(result); 2388 } 2389 2390 2391 LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) { 2392 bool is_in_object = instr->access().IsInobject(); 2393 bool is_external_location = instr->access().IsExternalMemory() && 2394 instr->access().offset() == 0; 2395 bool needs_write_barrier = instr->NeedsWriteBarrier(); 2396 bool needs_write_barrier_for_map = instr->has_transition() && 2397 instr->NeedsWriteBarrierForMap(); 2398 2399 LOperand* obj; 2400 if (needs_write_barrier) { 2401 obj = is_in_object 2402 ? UseRegister(instr->object()) 2403 : UseTempRegister(instr->object()); 2404 } else if (is_external_location) { 2405 ASSERT(!is_in_object); 2406 ASSERT(!needs_write_barrier); 2407 ASSERT(!needs_write_barrier_for_map); 2408 obj = UseRegisterOrConstant(instr->object()); 2409 } else { 2410 obj = needs_write_barrier_for_map 2411 ? UseRegister(instr->object()) 2412 : UseRegisterAtStart(instr->object()); 2413 } 2414 2415 bool can_be_constant = instr->value()->IsConstant() && 2416 HConstant::cast(instr->value())->NotInNewSpace() && 2417 !(FLAG_track_double_fields && instr->field_representation().IsDouble()); 2418 2419 LOperand* val; 2420 if (needs_write_barrier) { 2421 val = UseTempRegister(instr->value()); 2422 } else if (can_be_constant) { 2423 val = UseRegisterOrConstant(instr->value()); 2424 } else if (FLAG_track_fields && instr->field_representation().IsSmi()) { 2425 val = UseTempRegister(instr->value()); 2426 } else if (FLAG_track_double_fields && 2427 instr->field_representation().IsDouble()) { 2428 val = UseRegisterAtStart(instr->value()); 2429 } else { 2430 val = UseRegister(instr->value()); 2431 } 2432 2433 // We only need a scratch register if we have a write barrier or we 2434 // have a store into the properties array (not in-object-property). 2435 LOperand* temp = (!is_in_object || needs_write_barrier || 2436 needs_write_barrier_for_map) ? TempRegister() : NULL; 2437 2438 // We need a temporary register for write barrier of the map field. 2439 LOperand* temp_map = needs_write_barrier_for_map ? TempRegister() : NULL; 2440 2441 LStoreNamedField* result = 2442 new(zone()) LStoreNamedField(obj, val, temp, temp_map); 2443 if (FLAG_track_heap_object_fields && 2444 instr->field_representation().IsHeapObject()) { 2445 if (!instr->value()->type().IsHeapObject()) { 2446 return AssignEnvironment(result); 2447 } 2448 } 2449 return result; 2450 } 2451 2452 2453 LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) { 2454 LOperand* context = UseFixed(instr->context(), esi); 2455 LOperand* object = UseFixed(instr->object(), edx); 2456 LOperand* value = UseFixed(instr->value(), eax); 2457 2458 LStoreNamedGeneric* result = 2459 new(zone()) LStoreNamedGeneric(context, object, value); 2460 return MarkAsCall(result, instr); 2461 } 2462 2463 2464 LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) { 2465 LOperand* context = UseFixed(instr->context(), esi); 2466 LOperand* left = UseOrConstantAtStart(instr->left()); 2467 LOperand* right = UseOrConstantAtStart(instr->right()); 2468 LStringAdd* string_add = new(zone()) LStringAdd(context, left, right); 2469 return MarkAsCall(DefineFixed(string_add, eax), instr); 2470 } 2471 2472 2473 LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) { 2474 LOperand* string = UseTempRegister(instr->string()); 2475 LOperand* index = UseTempRegister(instr->index()); 2476 LOperand* context = UseAny(instr->context()); 2477 LStringCharCodeAt* result = 2478 new(zone()) LStringCharCodeAt(context, string, index); 2479 return AssignEnvironment(AssignPointerMap(DefineAsRegister(result))); 2480 } 2481 2482 2483 LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) { 2484 LOperand* char_code = UseRegister(instr->value()); 2485 LOperand* context = UseAny(instr->context()); 2486 LStringCharFromCode* result = 2487 new(zone()) LStringCharFromCode(context, char_code); 2488 return AssignPointerMap(DefineAsRegister(result)); 2489 } 2490 2491 2492 LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) { 2493 info()->MarkAsDeferredCalling(); 2494 LOperand* context = UseAny(instr->context()); 2495 LOperand* size = instr->size()->IsConstant() 2496 ? UseConstant(instr->size()) 2497 : UseTempRegister(instr->size()); 2498 LOperand* temp = TempRegister(); 2499 LAllocate* result = new(zone()) LAllocate(context, size, temp); 2500 return AssignPointerMap(DefineAsRegister(result)); 2501 } 2502 2503 2504 LInstruction* LChunkBuilder::DoRegExpLiteral(HRegExpLiteral* instr) { 2505 LOperand* context = UseFixed(instr->context(), esi); 2506 return MarkAsCall( 2507 DefineFixed(new(zone()) LRegExpLiteral(context), eax), instr); 2508 } 2509 2510 2511 LInstruction* LChunkBuilder::DoFunctionLiteral(HFunctionLiteral* instr) { 2512 LOperand* context = UseFixed(instr->context(), esi); 2513 return MarkAsCall( 2514 DefineFixed(new(zone()) LFunctionLiteral(context), eax), instr); 2515 } 2516 2517 2518 LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) { 2519 ASSERT(argument_count_ == 0); 2520 allocator_->MarkAsOsrEntry(); 2521 current_block_->last_environment()->set_ast_id(instr->ast_id()); 2522 return AssignEnvironment(new(zone()) LOsrEntry); 2523 } 2524 2525 2526 LInstruction* LChunkBuilder::DoParameter(HParameter* instr) { 2527 LParameter* result = new(zone()) LParameter; 2528 if (instr->kind() == HParameter::STACK_PARAMETER) { 2529 int spill_index = chunk()->GetParameterStackSlot(instr->index()); 2530 return DefineAsSpilled(result, spill_index); 2531 } else { 2532 ASSERT(info()->IsStub()); 2533 CodeStubInterfaceDescriptor* descriptor = 2534 info()->code_stub()->GetInterfaceDescriptor(info()->isolate()); 2535 int index = static_cast<int>(instr->index()); 2536 Register reg = DESCRIPTOR_GET_PARAMETER_REGISTER(descriptor, index); 2537 return DefineFixed(result, reg); 2538 } 2539 } 2540 2541 2542 LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) { 2543 int spill_index = chunk()->GetNextSpillIndex(false); // Not double-width. 2544 if (spill_index > LUnallocated::kMaxFixedSlotIndex) { 2545 Abort(kTooManySpillSlotsNeededForOSR); 2546 spill_index = 0; 2547 } 2548 return DefineAsSpilled(new(zone()) LUnknownOSRValue, spill_index); 2549 } 2550 2551 2552 LInstruction* LChunkBuilder::DoCallStub(HCallStub* instr) { 2553 LOperand* context = UseFixed(instr->context(), esi); 2554 argument_count_ -= instr->argument_count(); 2555 LCallStub* result = new(zone()) LCallStub(context); 2556 return MarkAsCall(DefineFixed(result, eax), instr); 2557 } 2558 2559 2560 LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) { 2561 // There are no real uses of the arguments object. 2562 // arguments.length and element access are supported directly on 2563 // stack arguments, and any real arguments object use causes a bailout. 2564 // So this value is never used. 2565 return NULL; 2566 } 2567 2568 2569 LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) { 2570 // There are no real uses of a captured object. 2571 return NULL; 2572 } 2573 2574 2575 LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) { 2576 info()->MarkAsRequiresFrame(); 2577 LOperand* args = UseRegister(instr->arguments()); 2578 LOperand* length; 2579 LOperand* index; 2580 if (instr->length()->IsConstant() && instr->index()->IsConstant()) { 2581 length = UseRegisterOrConstant(instr->length()); 2582 index = UseOrConstant(instr->index()); 2583 } else { 2584 length = UseTempRegister(instr->length()); 2585 index = Use(instr->index()); 2586 } 2587 return DefineAsRegister(new(zone()) LAccessArgumentsAt(args, length, index)); 2588 } 2589 2590 2591 LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) { 2592 LOperand* object = UseFixed(instr->value(), eax); 2593 LToFastProperties* result = new(zone()) LToFastProperties(object); 2594 return MarkAsCall(DefineFixed(result, eax), instr); 2595 } 2596 2597 2598 LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) { 2599 LOperand* context = UseFixed(instr->context(), esi); 2600 LOperand* value = UseAtStart(instr->value()); 2601 LTypeof* result = new(zone()) LTypeof(context, value); 2602 return MarkAsCall(DefineFixed(result, eax), instr); 2603 } 2604 2605 2606 LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) { 2607 return new(zone()) LTypeofIsAndBranch(UseTempRegister(instr->value())); 2608 } 2609 2610 2611 LInstruction* LChunkBuilder::DoIsConstructCallAndBranch( 2612 HIsConstructCallAndBranch* instr) { 2613 return new(zone()) LIsConstructCallAndBranch(TempRegister()); 2614 } 2615 2616 2617 LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) { 2618 HEnvironment* env = current_block_->last_environment(); 2619 ASSERT(env != NULL); 2620 2621 env->set_ast_id(instr->ast_id()); 2622 2623 env->Drop(instr->pop_count()); 2624 for (int i = instr->values()->length() - 1; i >= 0; --i) { 2625 HValue* value = instr->values()->at(i); 2626 if (instr->HasAssignedIndexAt(i)) { 2627 env->Bind(instr->GetAssignedIndexAt(i), value); 2628 } else { 2629 env->Push(value); 2630 } 2631 } 2632 2633 // If there is an instruction pending deoptimization environment create a 2634 // lazy bailout instruction to capture the environment. 2635 if (!pending_deoptimization_ast_id_.IsNone()) { 2636 ASSERT(pending_deoptimization_ast_id_ == instr->ast_id()); 2637 LLazyBailout* lazy_bailout = new(zone()) LLazyBailout; 2638 LInstruction* result = AssignEnvironment(lazy_bailout); 2639 // Store the lazy deopt environment with the instruction if needed. Right 2640 // now it is only used for LInstanceOfKnownGlobal. 2641 instruction_pending_deoptimization_environment_-> 2642 SetDeferredLazyDeoptimizationEnvironment(result->environment()); 2643 instruction_pending_deoptimization_environment_ = NULL; 2644 pending_deoptimization_ast_id_ = BailoutId::None(); 2645 return result; 2646 } 2647 2648 return NULL; 2649 } 2650 2651 2652 LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) { 2653 info()->MarkAsDeferredCalling(); 2654 if (instr->is_function_entry()) { 2655 LOperand* context = UseFixed(instr->context(), esi); 2656 return MarkAsCall(new(zone()) LStackCheck(context), instr); 2657 } else { 2658 ASSERT(instr->is_backwards_branch()); 2659 LOperand* context = UseAny(instr->context()); 2660 return AssignEnvironment( 2661 AssignPointerMap(new(zone()) LStackCheck(context))); 2662 } 2663 } 2664 2665 2666 LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) { 2667 HEnvironment* outer = current_block_->last_environment(); 2668 HConstant* undefined = graph()->GetConstantUndefined(); 2669 HEnvironment* inner = outer->CopyForInlining(instr->closure(), 2670 instr->arguments_count(), 2671 instr->function(), 2672 undefined, 2673 instr->inlining_kind(), 2674 instr->undefined_receiver()); 2675 // Only replay binding of arguments object if it wasn't removed from graph. 2676 if (instr->arguments_var() != NULL && instr->arguments_object()->IsLinked()) { 2677 inner->Bind(instr->arguments_var(), instr->arguments_object()); 2678 } 2679 inner->set_entry(instr); 2680 current_block_->UpdateEnvironment(inner); 2681 chunk_->AddInlinedClosure(instr->closure()); 2682 return NULL; 2683 } 2684 2685 2686 LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) { 2687 LInstruction* pop = NULL; 2688 2689 HEnvironment* env = current_block_->last_environment(); 2690 2691 if (env->entry()->arguments_pushed()) { 2692 int argument_count = env->arguments_environment()->parameter_count(); 2693 pop = new(zone()) LDrop(argument_count); 2694 argument_count_ -= argument_count; 2695 } 2696 2697 HEnvironment* outer = current_block_->last_environment()-> 2698 DiscardInlined(false); 2699 current_block_->UpdateEnvironment(outer); 2700 return pop; 2701 } 2702 2703 2704 LInstruction* LChunkBuilder::DoForInPrepareMap(HForInPrepareMap* instr) { 2705 LOperand* context = UseFixed(instr->context(), esi); 2706 LOperand* object = UseFixed(instr->enumerable(), eax); 2707 LForInPrepareMap* result = new(zone()) LForInPrepareMap(context, object); 2708 return MarkAsCall(DefineFixed(result, eax), instr, CAN_DEOPTIMIZE_EAGERLY); 2709 } 2710 2711 2712 LInstruction* LChunkBuilder::DoForInCacheArray(HForInCacheArray* instr) { 2713 LOperand* map = UseRegister(instr->map()); 2714 return AssignEnvironment(DefineAsRegister( 2715 new(zone()) LForInCacheArray(map))); 2716 } 2717 2718 2719 LInstruction* LChunkBuilder::DoCheckMapValue(HCheckMapValue* instr) { 2720 LOperand* value = UseRegisterAtStart(instr->value()); 2721 LOperand* map = UseRegisterAtStart(instr->map()); 2722 return AssignEnvironment(new(zone()) LCheckMapValue(value, map)); 2723 } 2724 2725 2726 LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) { 2727 LOperand* object = UseRegister(instr->object()); 2728 LOperand* index = UseTempRegister(instr->index()); 2729 return DefineSameAsFirst(new(zone()) LLoadFieldByIndex(object, index)); 2730 } 2731 2732 2733 } } // namespace v8::internal 2734 2735 #endif // V8_TARGET_ARCH_IA32 2736