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