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