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