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