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