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