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