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