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