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