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