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