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