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