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