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