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