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