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