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