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