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