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