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