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