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