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