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