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