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