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