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