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