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