1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "src/crankshaft/hydrogen-instructions.h" 6 7 #include "src/base/bits.h" 8 #include "src/base/ieee754.h" 9 #include "src/base/safe_math.h" 10 #include "src/codegen.h" 11 #include "src/crankshaft/hydrogen-infer-representation.h" 12 #include "src/double.h" 13 #include "src/elements.h" 14 #include "src/factory.h" 15 16 #if V8_TARGET_ARCH_IA32 17 #include "src/crankshaft/ia32/lithium-ia32.h" // NOLINT 18 #elif V8_TARGET_ARCH_X64 19 #include "src/crankshaft/x64/lithium-x64.h" // NOLINT 20 #elif V8_TARGET_ARCH_ARM64 21 #include "src/crankshaft/arm64/lithium-arm64.h" // NOLINT 22 #elif V8_TARGET_ARCH_ARM 23 #include "src/crankshaft/arm/lithium-arm.h" // NOLINT 24 #elif V8_TARGET_ARCH_PPC 25 #include "src/crankshaft/ppc/lithium-ppc.h" // NOLINT 26 #elif V8_TARGET_ARCH_MIPS 27 #include "src/crankshaft/mips/lithium-mips.h" // NOLINT 28 #elif V8_TARGET_ARCH_MIPS64 29 #include "src/crankshaft/mips64/lithium-mips64.h" // NOLINT 30 #elif V8_TARGET_ARCH_S390 31 #include "src/crankshaft/s390/lithium-s390.h" // NOLINT 32 #elif V8_TARGET_ARCH_X87 33 #include "src/crankshaft/x87/lithium-x87.h" // NOLINT 34 #else 35 #error Unsupported target architecture. 36 #endif 37 38 namespace v8 { 39 namespace internal { 40 41 #define DEFINE_COMPILE(type) \ 42 LInstruction* H##type::CompileToLithium(LChunkBuilder* builder) { \ 43 return builder->Do##type(this); \ 44 } 45 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE) 46 #undef DEFINE_COMPILE 47 48 Representation RepresentationFromMachineType(MachineType type) { 49 if (type == MachineType::Int32()) { 50 return Representation::Integer32(); 51 } 52 53 if (type == MachineType::TaggedSigned()) { 54 return Representation::Smi(); 55 } 56 57 if (type == MachineType::Pointer()) { 58 return Representation::External(); 59 } 60 61 return Representation::Tagged(); 62 } 63 64 Isolate* HValue::isolate() const { 65 DCHECK(block() != NULL); 66 return block()->isolate(); 67 } 68 69 70 void HValue::AssumeRepresentation(Representation r) { 71 if (CheckFlag(kFlexibleRepresentation)) { 72 ChangeRepresentation(r); 73 // The representation of the value is dictated by type feedback and 74 // will not be changed later. 75 ClearFlag(kFlexibleRepresentation); 76 } 77 } 78 79 80 void HValue::InferRepresentation(HInferRepresentationPhase* h_infer) { 81 DCHECK(CheckFlag(kFlexibleRepresentation)); 82 Representation new_rep = RepresentationFromInputs(); 83 UpdateRepresentation(new_rep, h_infer, "inputs"); 84 new_rep = RepresentationFromUses(); 85 UpdateRepresentation(new_rep, h_infer, "uses"); 86 if (representation().IsSmi() && HasNonSmiUse()) { 87 UpdateRepresentation( 88 Representation::Integer32(), h_infer, "use requirements"); 89 } 90 } 91 92 93 Representation HValue::RepresentationFromUses() { 94 if (HasNoUses()) return Representation::None(); 95 Representation result = Representation::None(); 96 97 for (HUseIterator it(uses()); !it.Done(); it.Advance()) { 98 HValue* use = it.value(); 99 Representation rep = use->observed_input_representation(it.index()); 100 result = result.generalize(rep); 101 102 if (FLAG_trace_representation) { 103 PrintF("#%d %s is used by #%d %s as %s%s\n", 104 id(), Mnemonic(), use->id(), use->Mnemonic(), rep.Mnemonic(), 105 (use->CheckFlag(kTruncatingToInt32) ? "-trunc" : "")); 106 } 107 } 108 if (IsPhi()) { 109 result = result.generalize( 110 HPhi::cast(this)->representation_from_indirect_uses()); 111 } 112 113 // External representations are dealt with separately. 114 return result.IsExternal() ? Representation::None() : result; 115 } 116 117 118 void HValue::UpdateRepresentation(Representation new_rep, 119 HInferRepresentationPhase* h_infer, 120 const char* reason) { 121 Representation r = representation(); 122 if (new_rep.is_more_general_than(r)) { 123 if (CheckFlag(kCannotBeTagged) && new_rep.IsTagged()) return; 124 if (FLAG_trace_representation) { 125 PrintF("Changing #%d %s representation %s -> %s based on %s\n", 126 id(), Mnemonic(), r.Mnemonic(), new_rep.Mnemonic(), reason); 127 } 128 ChangeRepresentation(new_rep); 129 AddDependantsToWorklist(h_infer); 130 } 131 } 132 133 134 void HValue::AddDependantsToWorklist(HInferRepresentationPhase* h_infer) { 135 for (HUseIterator it(uses()); !it.Done(); it.Advance()) { 136 h_infer->AddToWorklist(it.value()); 137 } 138 for (int i = 0; i < OperandCount(); ++i) { 139 h_infer->AddToWorklist(OperandAt(i)); 140 } 141 } 142 143 144 static int32_t ConvertAndSetOverflow(Representation r, 145 int64_t result, 146 bool* overflow) { 147 if (r.IsSmi()) { 148 if (result > Smi::kMaxValue) { 149 *overflow = true; 150 return Smi::kMaxValue; 151 } 152 if (result < Smi::kMinValue) { 153 *overflow = true; 154 return Smi::kMinValue; 155 } 156 } else { 157 if (result > kMaxInt) { 158 *overflow = true; 159 return kMaxInt; 160 } 161 if (result < kMinInt) { 162 *overflow = true; 163 return kMinInt; 164 } 165 } 166 return static_cast<int32_t>(result); 167 } 168 169 170 static int32_t AddWithoutOverflow(Representation r, 171 int32_t a, 172 int32_t b, 173 bool* overflow) { 174 int64_t result = static_cast<int64_t>(a) + static_cast<int64_t>(b); 175 return ConvertAndSetOverflow(r, result, overflow); 176 } 177 178 179 static int32_t SubWithoutOverflow(Representation r, 180 int32_t a, 181 int32_t b, 182 bool* overflow) { 183 int64_t result = static_cast<int64_t>(a) - static_cast<int64_t>(b); 184 return ConvertAndSetOverflow(r, result, overflow); 185 } 186 187 188 static int32_t MulWithoutOverflow(const Representation& r, 189 int32_t a, 190 int32_t b, 191 bool* overflow) { 192 int64_t result = static_cast<int64_t>(a) * static_cast<int64_t>(b); 193 return ConvertAndSetOverflow(r, result, overflow); 194 } 195 196 197 int32_t Range::Mask() const { 198 if (lower_ == upper_) return lower_; 199 if (lower_ >= 0) { 200 int32_t res = 1; 201 while (res < upper_) { 202 res = (res << 1) | 1; 203 } 204 return res; 205 } 206 return 0xffffffff; 207 } 208 209 210 void Range::AddConstant(int32_t value) { 211 if (value == 0) return; 212 bool may_overflow = false; // Overflow is ignored here. 213 Representation r = Representation::Integer32(); 214 lower_ = AddWithoutOverflow(r, lower_, value, &may_overflow); 215 upper_ = AddWithoutOverflow(r, upper_, value, &may_overflow); 216 #ifdef DEBUG 217 Verify(); 218 #endif 219 } 220 221 222 void Range::Intersect(Range* other) { 223 upper_ = Min(upper_, other->upper_); 224 lower_ = Max(lower_, other->lower_); 225 bool b = CanBeMinusZero() && other->CanBeMinusZero(); 226 set_can_be_minus_zero(b); 227 } 228 229 230 void Range::Union(Range* other) { 231 upper_ = Max(upper_, other->upper_); 232 lower_ = Min(lower_, other->lower_); 233 bool b = CanBeMinusZero() || other->CanBeMinusZero(); 234 set_can_be_minus_zero(b); 235 } 236 237 238 void Range::CombinedMax(Range* other) { 239 upper_ = Max(upper_, other->upper_); 240 lower_ = Max(lower_, other->lower_); 241 set_can_be_minus_zero(CanBeMinusZero() || other->CanBeMinusZero()); 242 } 243 244 245 void Range::CombinedMin(Range* other) { 246 upper_ = Min(upper_, other->upper_); 247 lower_ = Min(lower_, other->lower_); 248 set_can_be_minus_zero(CanBeMinusZero() || other->CanBeMinusZero()); 249 } 250 251 252 void Range::Sar(int32_t value) { 253 int32_t bits = value & 0x1F; 254 lower_ = lower_ >> bits; 255 upper_ = upper_ >> bits; 256 set_can_be_minus_zero(false); 257 } 258 259 260 void Range::Shl(int32_t value) { 261 int32_t bits = value & 0x1F; 262 int old_lower = lower_; 263 int old_upper = upper_; 264 lower_ = lower_ << bits; 265 upper_ = upper_ << bits; 266 if (old_lower != lower_ >> bits || old_upper != upper_ >> bits) { 267 upper_ = kMaxInt; 268 lower_ = kMinInt; 269 } 270 set_can_be_minus_zero(false); 271 } 272 273 274 bool Range::AddAndCheckOverflow(const Representation& r, Range* other) { 275 bool may_overflow = false; 276 lower_ = AddWithoutOverflow(r, lower_, other->lower(), &may_overflow); 277 upper_ = AddWithoutOverflow(r, upper_, other->upper(), &may_overflow); 278 if (may_overflow) { 279 Clear(); 280 } else { 281 KeepOrder(); 282 } 283 #ifdef DEBUG 284 Verify(); 285 #endif 286 return may_overflow; 287 } 288 289 290 bool Range::SubAndCheckOverflow(const Representation& r, Range* other) { 291 bool may_overflow = false; 292 lower_ = SubWithoutOverflow(r, lower_, other->upper(), &may_overflow); 293 upper_ = SubWithoutOverflow(r, upper_, other->lower(), &may_overflow); 294 if (may_overflow) { 295 Clear(); 296 } else { 297 KeepOrder(); 298 } 299 #ifdef DEBUG 300 Verify(); 301 #endif 302 return may_overflow; 303 } 304 305 void Range::Clear() { 306 lower_ = kMinInt; 307 upper_ = kMaxInt; 308 } 309 310 void Range::KeepOrder() { 311 if (lower_ > upper_) { 312 int32_t tmp = lower_; 313 lower_ = upper_; 314 upper_ = tmp; 315 } 316 } 317 318 319 #ifdef DEBUG 320 void Range::Verify() const { 321 DCHECK(lower_ <= upper_); 322 } 323 #endif 324 325 326 bool Range::MulAndCheckOverflow(const Representation& r, Range* other) { 327 bool may_overflow = false; 328 int v1 = MulWithoutOverflow(r, lower_, other->lower(), &may_overflow); 329 int v2 = MulWithoutOverflow(r, lower_, other->upper(), &may_overflow); 330 int v3 = MulWithoutOverflow(r, upper_, other->lower(), &may_overflow); 331 int v4 = MulWithoutOverflow(r, upper_, other->upper(), &may_overflow); 332 if (may_overflow) { 333 Clear(); 334 } else { 335 lower_ = Min(Min(v1, v2), Min(v3, v4)); 336 upper_ = Max(Max(v1, v2), Max(v3, v4)); 337 } 338 #ifdef DEBUG 339 Verify(); 340 #endif 341 return may_overflow; 342 } 343 344 345 bool HValue::IsDefinedAfter(HBasicBlock* other) const { 346 return block()->block_id() > other->block_id(); 347 } 348 349 350 HUseListNode* HUseListNode::tail() { 351 // Skip and remove dead items in the use list. 352 while (tail_ != NULL && tail_->value()->CheckFlag(HValue::kIsDead)) { 353 tail_ = tail_->tail_; 354 } 355 return tail_; 356 } 357 358 359 bool HValue::CheckUsesForFlag(Flag f) const { 360 for (HUseIterator it(uses()); !it.Done(); it.Advance()) { 361 if (it.value()->IsSimulate()) continue; 362 if (!it.value()->CheckFlag(f)) return false; 363 } 364 return true; 365 } 366 367 368 bool HValue::CheckUsesForFlag(Flag f, HValue** value) const { 369 for (HUseIterator it(uses()); !it.Done(); it.Advance()) { 370 if (it.value()->IsSimulate()) continue; 371 if (!it.value()->CheckFlag(f)) { 372 *value = it.value(); 373 return false; 374 } 375 } 376 return true; 377 } 378 379 380 bool HValue::HasAtLeastOneUseWithFlagAndNoneWithout(Flag f) const { 381 bool return_value = false; 382 for (HUseIterator it(uses()); !it.Done(); it.Advance()) { 383 if (it.value()->IsSimulate()) continue; 384 if (!it.value()->CheckFlag(f)) return false; 385 return_value = true; 386 } 387 return return_value; 388 } 389 390 391 HUseIterator::HUseIterator(HUseListNode* head) : next_(head) { 392 Advance(); 393 } 394 395 396 void HUseIterator::Advance() { 397 current_ = next_; 398 if (current_ != NULL) { 399 next_ = current_->tail(); 400 value_ = current_->value(); 401 index_ = current_->index(); 402 } 403 } 404 405 406 int HValue::UseCount() const { 407 int count = 0; 408 for (HUseIterator it(uses()); !it.Done(); it.Advance()) ++count; 409 return count; 410 } 411 412 413 HUseListNode* HValue::RemoveUse(HValue* value, int index) { 414 HUseListNode* previous = NULL; 415 HUseListNode* current = use_list_; 416 while (current != NULL) { 417 if (current->value() == value && current->index() == index) { 418 if (previous == NULL) { 419 use_list_ = current->tail(); 420 } else { 421 previous->set_tail(current->tail()); 422 } 423 break; 424 } 425 426 previous = current; 427 current = current->tail(); 428 } 429 430 #ifdef DEBUG 431 // Do not reuse use list nodes in debug mode, zap them. 432 if (current != NULL) { 433 HUseListNode* temp = 434 new(block()->zone()) 435 HUseListNode(current->value(), current->index(), NULL); 436 current->Zap(); 437 current = temp; 438 } 439 #endif 440 return current; 441 } 442 443 444 bool HValue::Equals(HValue* other) { 445 if (other->opcode() != opcode()) return false; 446 if (!other->representation().Equals(representation())) return false; 447 if (!other->type_.Equals(type_)) return false; 448 if (other->flags() != flags()) return false; 449 if (OperandCount() != other->OperandCount()) return false; 450 for (int i = 0; i < OperandCount(); ++i) { 451 if (OperandAt(i)->id() != other->OperandAt(i)->id()) return false; 452 } 453 bool result = DataEquals(other); 454 DCHECK(!result || Hashcode() == other->Hashcode()); 455 return result; 456 } 457 458 459 intptr_t HValue::Hashcode() { 460 intptr_t result = opcode(); 461 int count = OperandCount(); 462 for (int i = 0; i < count; ++i) { 463 result = result * 19 + OperandAt(i)->id() + (result >> 7); 464 } 465 return result; 466 } 467 468 469 const char* HValue::Mnemonic() const { 470 switch (opcode()) { 471 #define MAKE_CASE(type) case k##type: return #type; 472 HYDROGEN_CONCRETE_INSTRUCTION_LIST(MAKE_CASE) 473 #undef MAKE_CASE 474 case kPhi: return "Phi"; 475 default: return ""; 476 } 477 } 478 479 480 bool HValue::CanReplaceWithDummyUses() { 481 return FLAG_unreachable_code_elimination && 482 !(block()->IsReachable() || 483 IsBlockEntry() || 484 IsControlInstruction() || 485 IsArgumentsObject() || 486 IsCapturedObject() || 487 IsSimulate() || 488 IsEnterInlined() || 489 IsLeaveInlined()); 490 } 491 492 493 bool HValue::IsInteger32Constant() { 494 return IsConstant() && HConstant::cast(this)->HasInteger32Value(); 495 } 496 497 498 int32_t HValue::GetInteger32Constant() { 499 return HConstant::cast(this)->Integer32Value(); 500 } 501 502 503 bool HValue::EqualsInteger32Constant(int32_t value) { 504 return IsInteger32Constant() && GetInteger32Constant() == value; 505 } 506 507 508 void HValue::SetOperandAt(int index, HValue* value) { 509 RegisterUse(index, value); 510 InternalSetOperandAt(index, value); 511 } 512 513 514 void HValue::DeleteAndReplaceWith(HValue* other) { 515 // We replace all uses first, so Delete can assert that there are none. 516 if (other != NULL) ReplaceAllUsesWith(other); 517 Kill(); 518 DeleteFromGraph(); 519 } 520 521 522 void HValue::ReplaceAllUsesWith(HValue* other) { 523 while (use_list_ != NULL) { 524 HUseListNode* list_node = use_list_; 525 HValue* value = list_node->value(); 526 DCHECK(!value->block()->IsStartBlock()); 527 value->InternalSetOperandAt(list_node->index(), other); 528 use_list_ = list_node->tail(); 529 list_node->set_tail(other->use_list_); 530 other->use_list_ = list_node; 531 } 532 } 533 534 535 void HValue::Kill() { 536 // Instead of going through the entire use list of each operand, we only 537 // check the first item in each use list and rely on the tail() method to 538 // skip dead items, removing them lazily next time we traverse the list. 539 SetFlag(kIsDead); 540 for (int i = 0; i < OperandCount(); ++i) { 541 HValue* operand = OperandAt(i); 542 if (operand == NULL) continue; 543 HUseListNode* first = operand->use_list_; 544 if (first != NULL && first->value()->CheckFlag(kIsDead)) { 545 operand->use_list_ = first->tail(); 546 } 547 } 548 } 549 550 551 void HValue::SetBlock(HBasicBlock* block) { 552 DCHECK(block_ == NULL || block == NULL); 553 block_ = block; 554 if (id_ == kNoNumber && block != NULL) { 555 id_ = block->graph()->GetNextValueID(this); 556 } 557 } 558 559 560 std::ostream& operator<<(std::ostream& os, const HValue& v) { 561 return v.PrintTo(os); 562 } 563 564 565 std::ostream& operator<<(std::ostream& os, const TypeOf& t) { 566 if (t.value->representation().IsTagged() && 567 !t.value->type().Equals(HType::Tagged())) 568 return os; 569 return os << " type:" << t.value->type(); 570 } 571 572 573 std::ostream& operator<<(std::ostream& os, const ChangesOf& c) { 574 GVNFlagSet changes_flags = c.value->ChangesFlags(); 575 if (changes_flags.IsEmpty()) return os; 576 os << " changes["; 577 if (changes_flags == c.value->AllSideEffectsFlagSet()) { 578 os << "*"; 579 } else { 580 bool add_comma = false; 581 #define PRINT_DO(Type) \ 582 if (changes_flags.Contains(k##Type)) { \ 583 if (add_comma) os << ","; \ 584 add_comma = true; \ 585 os << #Type; \ 586 } 587 GVN_TRACKED_FLAG_LIST(PRINT_DO); 588 GVN_UNTRACKED_FLAG_LIST(PRINT_DO); 589 #undef PRINT_DO 590 } 591 return os << "]"; 592 } 593 594 595 bool HValue::HasMonomorphicJSObjectType() { 596 return !GetMonomorphicJSObjectMap().is_null(); 597 } 598 599 600 bool HValue::UpdateInferredType() { 601 HType type = CalculateInferredType(); 602 bool result = (!type.Equals(type_)); 603 type_ = type; 604 return result; 605 } 606 607 608 void HValue::RegisterUse(int index, HValue* new_value) { 609 HValue* old_value = OperandAt(index); 610 if (old_value == new_value) return; 611 612 HUseListNode* removed = NULL; 613 if (old_value != NULL) { 614 removed = old_value->RemoveUse(this, index); 615 } 616 617 if (new_value != NULL) { 618 if (removed == NULL) { 619 new_value->use_list_ = new(new_value->block()->zone()) HUseListNode( 620 this, index, new_value->use_list_); 621 } else { 622 removed->set_tail(new_value->use_list_); 623 new_value->use_list_ = removed; 624 } 625 } 626 } 627 628 629 void HValue::AddNewRange(Range* r, Zone* zone) { 630 if (!HasRange()) ComputeInitialRange(zone); 631 if (!HasRange()) range_ = new(zone) Range(); 632 DCHECK(HasRange()); 633 r->StackUpon(range_); 634 range_ = r; 635 } 636 637 638 void HValue::RemoveLastAddedRange() { 639 DCHECK(HasRange()); 640 DCHECK(range_->next() != NULL); 641 range_ = range_->next(); 642 } 643 644 645 void HValue::ComputeInitialRange(Zone* zone) { 646 DCHECK(!HasRange()); 647 range_ = InferRange(zone); 648 DCHECK(HasRange()); 649 } 650 651 652 std::ostream& HInstruction::PrintTo(std::ostream& os) const { // NOLINT 653 os << Mnemonic() << " "; 654 PrintDataTo(os) << ChangesOf(this) << TypeOf(this); 655 if (CheckFlag(HValue::kHasNoObservableSideEffects)) os << " [noOSE]"; 656 if (CheckFlag(HValue::kIsDead)) os << " [dead]"; 657 return os; 658 } 659 660 661 std::ostream& HInstruction::PrintDataTo(std::ostream& os) const { // NOLINT 662 for (int i = 0; i < OperandCount(); ++i) { 663 if (i > 0) os << " "; 664 os << NameOf(OperandAt(i)); 665 } 666 return os; 667 } 668 669 670 void HInstruction::Unlink() { 671 DCHECK(IsLinked()); 672 DCHECK(!IsControlInstruction()); // Must never move control instructions. 673 DCHECK(!IsBlockEntry()); // Doesn't make sense to delete these. 674 DCHECK(previous_ != NULL); 675 previous_->next_ = next_; 676 if (next_ == NULL) { 677 DCHECK(block()->last() == this); 678 block()->set_last(previous_); 679 } else { 680 next_->previous_ = previous_; 681 } 682 clear_block(); 683 } 684 685 686 void HInstruction::InsertBefore(HInstruction* next) { 687 DCHECK(!IsLinked()); 688 DCHECK(!next->IsBlockEntry()); 689 DCHECK(!IsControlInstruction()); 690 DCHECK(!next->block()->IsStartBlock()); 691 DCHECK(next->previous_ != NULL); 692 HInstruction* prev = next->previous(); 693 prev->next_ = this; 694 next->previous_ = this; 695 next_ = next; 696 previous_ = prev; 697 SetBlock(next->block()); 698 if (!has_position() && next->has_position()) { 699 set_position(next->position()); 700 } 701 } 702 703 704 void HInstruction::InsertAfter(HInstruction* previous) { 705 DCHECK(!IsLinked()); 706 DCHECK(!previous->IsControlInstruction()); 707 DCHECK(!IsControlInstruction() || previous->next_ == NULL); 708 HBasicBlock* block = previous->block(); 709 // Never insert anything except constants into the start block after finishing 710 // it. 711 if (block->IsStartBlock() && block->IsFinished() && !IsConstant()) { 712 DCHECK(block->end()->SecondSuccessor() == NULL); 713 InsertAfter(block->end()->FirstSuccessor()->first()); 714 return; 715 } 716 717 // If we're inserting after an instruction with side-effects that is 718 // followed by a simulate instruction, we need to insert after the 719 // simulate instruction instead. 720 HInstruction* next = previous->next_; 721 if (previous->HasObservableSideEffects() && next != NULL) { 722 DCHECK(next->IsSimulate()); 723 previous = next; 724 next = previous->next_; 725 } 726 727 previous_ = previous; 728 next_ = next; 729 SetBlock(block); 730 previous->next_ = this; 731 if (next != NULL) next->previous_ = this; 732 if (block->last() == previous) { 733 block->set_last(this); 734 } 735 if (!has_position() && previous->has_position()) { 736 set_position(previous->position()); 737 } 738 } 739 740 741 bool HInstruction::Dominates(HInstruction* other) { 742 if (block() != other->block()) { 743 return block()->Dominates(other->block()); 744 } 745 // Both instructions are in the same basic block. This instruction 746 // should precede the other one in order to dominate it. 747 for (HInstruction* instr = next(); instr != NULL; instr = instr->next()) { 748 if (instr == other) { 749 return true; 750 } 751 } 752 return false; 753 } 754 755 756 #ifdef DEBUG 757 void HInstruction::Verify() { 758 // Verify that input operands are defined before use. 759 HBasicBlock* cur_block = block(); 760 for (int i = 0; i < OperandCount(); ++i) { 761 HValue* other_operand = OperandAt(i); 762 if (other_operand == NULL) continue; 763 HBasicBlock* other_block = other_operand->block(); 764 if (cur_block == other_block) { 765 if (!other_operand->IsPhi()) { 766 HInstruction* cur = this->previous(); 767 while (cur != NULL) { 768 if (cur == other_operand) break; 769 cur = cur->previous(); 770 } 771 // Must reach other operand in the same block! 772 DCHECK(cur == other_operand); 773 } 774 } else { 775 // If the following assert fires, you may have forgotten an 776 // AddInstruction. 777 DCHECK(other_block->Dominates(cur_block)); 778 } 779 } 780 781 // Verify that instructions that may have side-effects are followed 782 // by a simulate instruction. 783 if (HasObservableSideEffects() && !IsOsrEntry()) { 784 DCHECK(next()->IsSimulate()); 785 } 786 787 // Verify that instructions that can be eliminated by GVN have overridden 788 // HValue::DataEquals. The default implementation is UNREACHABLE. We 789 // don't actually care whether DataEquals returns true or false here. 790 if (CheckFlag(kUseGVN)) DataEquals(this); 791 792 // Verify that all uses are in the graph. 793 for (HUseIterator use = uses(); !use.Done(); use.Advance()) { 794 if (use.value()->IsInstruction()) { 795 DCHECK(HInstruction::cast(use.value())->IsLinked()); 796 } 797 } 798 } 799 #endif 800 801 802 bool HInstruction::CanDeoptimize() { 803 switch (opcode()) { 804 case HValue::kAbnormalExit: 805 case HValue::kAccessArgumentsAt: 806 case HValue::kAllocate: 807 case HValue::kArgumentsElements: 808 case HValue::kArgumentsLength: 809 case HValue::kArgumentsObject: 810 case HValue::kBlockEntry: 811 case HValue::kCallNewArray: 812 case HValue::kCapturedObject: 813 case HValue::kClassOfTestAndBranch: 814 case HValue::kCompareGeneric: 815 case HValue::kCompareHoleAndBranch: 816 case HValue::kCompareMap: 817 case HValue::kCompareNumericAndBranch: 818 case HValue::kCompareObjectEqAndBranch: 819 case HValue::kConstant: 820 case HValue::kContext: 821 case HValue::kDebugBreak: 822 case HValue::kDeclareGlobals: 823 case HValue::kDummyUse: 824 case HValue::kEnterInlined: 825 case HValue::kEnvironmentMarker: 826 case HValue::kForceRepresentation: 827 case HValue::kGoto: 828 case HValue::kHasInstanceTypeAndBranch: 829 case HValue::kInnerAllocatedObject: 830 case HValue::kIsSmiAndBranch: 831 case HValue::kIsStringAndBranch: 832 case HValue::kIsUndetectableAndBranch: 833 case HValue::kLeaveInlined: 834 case HValue::kLoadFieldByIndex: 835 case HValue::kLoadNamedField: 836 case HValue::kLoadRoot: 837 case HValue::kMathMinMax: 838 case HValue::kParameter: 839 case HValue::kPhi: 840 case HValue::kPushArguments: 841 case HValue::kReturn: 842 case HValue::kSeqStringGetChar: 843 case HValue::kStoreCodeEntry: 844 case HValue::kStoreKeyed: 845 case HValue::kStoreNamedField: 846 case HValue::kStringCharCodeAt: 847 case HValue::kStringCharFromCode: 848 case HValue::kThisFunction: 849 case HValue::kTypeofIsAndBranch: 850 case HValue::kUnknownOSRValue: 851 case HValue::kUseConst: 852 return false; 853 854 case HValue::kAdd: 855 case HValue::kApplyArguments: 856 case HValue::kBitwise: 857 case HValue::kBoundsCheck: 858 case HValue::kBranch: 859 case HValue::kCallRuntime: 860 case HValue::kCallWithDescriptor: 861 case HValue::kChange: 862 case HValue::kCheckArrayBufferNotNeutered: 863 case HValue::kCheckHeapObject: 864 case HValue::kCheckInstanceType: 865 case HValue::kCheckMapValue: 866 case HValue::kCheckMaps: 867 case HValue::kCheckSmi: 868 case HValue::kCheckValue: 869 case HValue::kClampToUint8: 870 case HValue::kDeoptimize: 871 case HValue::kDiv: 872 case HValue::kForInCacheArray: 873 case HValue::kForInPrepareMap: 874 case HValue::kHasInPrototypeChainAndBranch: 875 case HValue::kInvokeFunction: 876 case HValue::kLoadContextSlot: 877 case HValue::kLoadFunctionPrototype: 878 case HValue::kLoadKeyed: 879 case HValue::kMathFloorOfDiv: 880 case HValue::kMaybeGrowElements: 881 case HValue::kMod: 882 case HValue::kMul: 883 case HValue::kOsrEntry: 884 case HValue::kPower: 885 case HValue::kPrologue: 886 case HValue::kRor: 887 case HValue::kSar: 888 case HValue::kSeqStringSetChar: 889 case HValue::kShl: 890 case HValue::kShr: 891 case HValue::kSimulate: 892 case HValue::kStackCheck: 893 case HValue::kStoreContextSlot: 894 case HValue::kStringAdd: 895 case HValue::kStringCompareAndBranch: 896 case HValue::kSub: 897 case HValue::kTransitionElementsKind: 898 case HValue::kTrapAllocationMemento: 899 case HValue::kTypeof: 900 case HValue::kUnaryMathOperation: 901 case HValue::kWrapReceiver: 902 return true; 903 } 904 UNREACHABLE(); 905 return true; 906 } 907 908 909 std::ostream& operator<<(std::ostream& os, const NameOf& v) { 910 return os << v.value->representation().Mnemonic() << v.value->id(); 911 } 912 913 std::ostream& HDummyUse::PrintDataTo(std::ostream& os) const { // NOLINT 914 return os << NameOf(value()); 915 } 916 917 918 std::ostream& HEnvironmentMarker::PrintDataTo( 919 std::ostream& os) const { // NOLINT 920 return os << (kind() == BIND ? "bind" : "lookup") << " var[" << index() 921 << "]"; 922 } 923 924 925 std::ostream& HUnaryCall::PrintDataTo(std::ostream& os) const { // NOLINT 926 return os << NameOf(value()) << " #" << argument_count(); 927 } 928 929 930 std::ostream& HBinaryCall::PrintDataTo(std::ostream& os) const { // NOLINT 931 return os << NameOf(first()) << " " << NameOf(second()) << " #" 932 << argument_count(); 933 } 934 935 std::ostream& HInvokeFunction::PrintTo(std::ostream& os) const { // NOLINT 936 if (tail_call_mode() == TailCallMode::kAllow) os << "Tail"; 937 return HBinaryCall::PrintTo(os); 938 } 939 940 std::ostream& HInvokeFunction::PrintDataTo(std::ostream& os) const { // NOLINT 941 HBinaryCall::PrintDataTo(os); 942 if (syntactic_tail_call_mode() == TailCallMode::kAllow) { 943 os << ", JSTailCall"; 944 } 945 return os; 946 } 947 948 std::ostream& HBoundsCheck::PrintDataTo(std::ostream& os) const { // NOLINT 949 os << NameOf(index()) << " " << NameOf(length()); 950 if (base() != NULL && (offset() != 0 || scale() != 0)) { 951 os << " base: (("; 952 if (base() != index()) { 953 os << NameOf(index()); 954 } else { 955 os << "index"; 956 } 957 os << " + " << offset() << ") >> " << scale() << ")"; 958 } 959 if (skip_check()) os << " [DISABLED]"; 960 return os; 961 } 962 963 964 void HBoundsCheck::InferRepresentation(HInferRepresentationPhase* h_infer) { 965 DCHECK(CheckFlag(kFlexibleRepresentation)); 966 HValue* actual_index = index()->ActualValue(); 967 HValue* actual_length = length()->ActualValue(); 968 Representation index_rep = actual_index->representation(); 969 Representation length_rep = actual_length->representation(); 970 if (index_rep.IsTagged() && actual_index->type().IsSmi()) { 971 index_rep = Representation::Smi(); 972 } 973 if (length_rep.IsTagged() && actual_length->type().IsSmi()) { 974 length_rep = Representation::Smi(); 975 } 976 Representation r = index_rep.generalize(length_rep); 977 if (r.is_more_general_than(Representation::Integer32())) { 978 r = Representation::Integer32(); 979 } 980 UpdateRepresentation(r, h_infer, "boundscheck"); 981 } 982 983 984 Range* HBoundsCheck::InferRange(Zone* zone) { 985 Representation r = representation(); 986 if (r.IsSmiOrInteger32() && length()->HasRange()) { 987 int upper = length()->range()->upper() - (allow_equality() ? 0 : 1); 988 int lower = 0; 989 990 Range* result = new(zone) Range(lower, upper); 991 if (index()->HasRange()) { 992 result->Intersect(index()->range()); 993 } 994 995 // In case of Smi representation, clamp result to Smi::kMaxValue. 996 if (r.IsSmi()) result->ClampToSmi(); 997 return result; 998 } 999 return HValue::InferRange(zone); 1000 } 1001 1002 1003 std::ostream& HCallWithDescriptor::PrintDataTo( 1004 std::ostream& os) const { // NOLINT 1005 for (int i = 0; i < OperandCount(); i++) { 1006 os << NameOf(OperandAt(i)) << " "; 1007 } 1008 os << "#" << argument_count(); 1009 if (syntactic_tail_call_mode() == TailCallMode::kAllow) { 1010 os << ", JSTailCall"; 1011 } 1012 return os; 1013 } 1014 1015 1016 std::ostream& HCallNewArray::PrintDataTo(std::ostream& os) const { // NOLINT 1017 os << ElementsKindToString(elements_kind()) << " "; 1018 return HBinaryCall::PrintDataTo(os); 1019 } 1020 1021 1022 std::ostream& HCallRuntime::PrintDataTo(std::ostream& os) const { // NOLINT 1023 os << function()->name << " "; 1024 if (save_doubles() == kSaveFPRegs) os << "[save doubles] "; 1025 return os << "#" << argument_count(); 1026 } 1027 1028 1029 std::ostream& HClassOfTestAndBranch::PrintDataTo( 1030 std::ostream& os) const { // NOLINT 1031 return os << "class_of_test(" << NameOf(value()) << ", \"" 1032 << class_name()->ToCString().get() << "\")"; 1033 } 1034 1035 1036 std::ostream& HWrapReceiver::PrintDataTo(std::ostream& os) const { // NOLINT 1037 return os << NameOf(receiver()) << " " << NameOf(function()); 1038 } 1039 1040 1041 std::ostream& HAccessArgumentsAt::PrintDataTo( 1042 std::ostream& os) const { // NOLINT 1043 return os << NameOf(arguments()) << "[" << NameOf(index()) << "], length " 1044 << NameOf(length()); 1045 } 1046 1047 1048 std::ostream& HControlInstruction::PrintDataTo( 1049 std::ostream& os) const { // NOLINT 1050 os << " goto ("; 1051 bool first_block = true; 1052 for (HSuccessorIterator it(this); !it.Done(); it.Advance()) { 1053 if (!first_block) os << ", "; 1054 os << *it.Current(); 1055 first_block = false; 1056 } 1057 return os << ")"; 1058 } 1059 1060 1061 std::ostream& HUnaryControlInstruction::PrintDataTo( 1062 std::ostream& os) const { // NOLINT 1063 os << NameOf(value()); 1064 return HControlInstruction::PrintDataTo(os); 1065 } 1066 1067 1068 std::ostream& HReturn::PrintDataTo(std::ostream& os) const { // NOLINT 1069 return os << NameOf(value()) << " (pop " << NameOf(parameter_count()) 1070 << " values)"; 1071 } 1072 1073 1074 Representation HBranch::observed_input_representation(int index) { 1075 if (expected_input_types_ & (ToBooleanHint::kNull | ToBooleanHint::kReceiver | 1076 ToBooleanHint::kString | ToBooleanHint::kSymbol | 1077 ToBooleanHint::kSimdValue)) { 1078 return Representation::Tagged(); 1079 } 1080 if (expected_input_types_ & ToBooleanHint::kUndefined) { 1081 if (expected_input_types_ & ToBooleanHint::kHeapNumber) { 1082 return Representation::Double(); 1083 } 1084 return Representation::Tagged(); 1085 } 1086 if (expected_input_types_ & ToBooleanHint::kHeapNumber) { 1087 return Representation::Double(); 1088 } 1089 if (expected_input_types_ & ToBooleanHint::kSmallInteger) { 1090 return Representation::Smi(); 1091 } 1092 return Representation::None(); 1093 } 1094 1095 1096 bool HBranch::KnownSuccessorBlock(HBasicBlock** block) { 1097 HValue* value = this->value(); 1098 if (value->EmitAtUses()) { 1099 DCHECK(value->IsConstant()); 1100 DCHECK(!value->representation().IsDouble()); 1101 *block = HConstant::cast(value)->BooleanValue() 1102 ? FirstSuccessor() 1103 : SecondSuccessor(); 1104 return true; 1105 } 1106 *block = NULL; 1107 return false; 1108 } 1109 1110 1111 std::ostream& HBranch::PrintDataTo(std::ostream& os) const { // NOLINT 1112 return HUnaryControlInstruction::PrintDataTo(os) << " " 1113 << expected_input_types(); 1114 } 1115 1116 1117 std::ostream& HCompareMap::PrintDataTo(std::ostream& os) const { // NOLINT 1118 os << NameOf(value()) << " (" << *map().handle() << ")"; 1119 HControlInstruction::PrintDataTo(os); 1120 if (known_successor_index() == 0) { 1121 os << " [true]"; 1122 } else if (known_successor_index() == 1) { 1123 os << " [false]"; 1124 } 1125 return os; 1126 } 1127 1128 1129 const char* HUnaryMathOperation::OpName() const { 1130 switch (op()) { 1131 case kMathFloor: 1132 return "floor"; 1133 case kMathFround: 1134 return "fround"; 1135 case kMathRound: 1136 return "round"; 1137 case kMathAbs: 1138 return "abs"; 1139 case kMathCos: 1140 return "cos"; 1141 case kMathLog: 1142 return "log"; 1143 case kMathExp: 1144 return "exp"; 1145 case kMathSin: 1146 return "sin"; 1147 case kMathSqrt: 1148 return "sqrt"; 1149 case kMathPowHalf: 1150 return "pow-half"; 1151 case kMathClz32: 1152 return "clz32"; 1153 default: 1154 UNREACHABLE(); 1155 return NULL; 1156 } 1157 } 1158 1159 1160 Range* HUnaryMathOperation::InferRange(Zone* zone) { 1161 Representation r = representation(); 1162 if (op() == kMathClz32) return new(zone) Range(0, 32); 1163 if (r.IsSmiOrInteger32() && value()->HasRange()) { 1164 if (op() == kMathAbs) { 1165 int upper = value()->range()->upper(); 1166 int lower = value()->range()->lower(); 1167 bool spans_zero = value()->range()->CanBeZero(); 1168 // Math.abs(kMinInt) overflows its representation, on which the 1169 // instruction deopts. Hence clamp it to kMaxInt. 1170 int abs_upper = upper == kMinInt ? kMaxInt : abs(upper); 1171 int abs_lower = lower == kMinInt ? kMaxInt : abs(lower); 1172 Range* result = 1173 new(zone) Range(spans_zero ? 0 : Min(abs_lower, abs_upper), 1174 Max(abs_lower, abs_upper)); 1175 // In case of Smi representation, clamp Math.abs(Smi::kMinValue) to 1176 // Smi::kMaxValue. 1177 if (r.IsSmi()) result->ClampToSmi(); 1178 return result; 1179 } 1180 } 1181 return HValue::InferRange(zone); 1182 } 1183 1184 1185 std::ostream& HUnaryMathOperation::PrintDataTo( 1186 std::ostream& os) const { // NOLINT 1187 return os << OpName() << " " << NameOf(value()); 1188 } 1189 1190 1191 std::ostream& HUnaryOperation::PrintDataTo(std::ostream& os) const { // NOLINT 1192 return os << NameOf(value()); 1193 } 1194 1195 1196 std::ostream& HHasInstanceTypeAndBranch::PrintDataTo( 1197 std::ostream& os) const { // NOLINT 1198 os << NameOf(value()); 1199 switch (from_) { 1200 case FIRST_JS_RECEIVER_TYPE: 1201 if (to_ == LAST_TYPE) os << " spec_object"; 1202 break; 1203 case JS_REGEXP_TYPE: 1204 if (to_ == JS_REGEXP_TYPE) os << " reg_exp"; 1205 break; 1206 case JS_ARRAY_TYPE: 1207 if (to_ == JS_ARRAY_TYPE) os << " array"; 1208 break; 1209 case JS_FUNCTION_TYPE: 1210 if (to_ == JS_FUNCTION_TYPE) os << " function"; 1211 break; 1212 default: 1213 break; 1214 } 1215 return os; 1216 } 1217 1218 1219 std::ostream& HTypeofIsAndBranch::PrintDataTo( 1220 std::ostream& os) const { // NOLINT 1221 os << NameOf(value()) << " == " << type_literal()->ToCString().get(); 1222 return HControlInstruction::PrintDataTo(os); 1223 } 1224 1225 1226 namespace { 1227 1228 String* TypeOfString(HConstant* constant, Isolate* isolate) { 1229 Heap* heap = isolate->heap(); 1230 if (constant->HasNumberValue()) return heap->number_string(); 1231 if (constant->HasStringValue()) return heap->string_string(); 1232 switch (constant->GetInstanceType()) { 1233 case ODDBALL_TYPE: { 1234 Unique<Object> unique = constant->GetUnique(); 1235 if (unique.IsKnownGlobal(heap->true_value()) || 1236 unique.IsKnownGlobal(heap->false_value())) { 1237 return heap->boolean_string(); 1238 } 1239 if (unique.IsKnownGlobal(heap->null_value())) { 1240 return heap->object_string(); 1241 } 1242 DCHECK(unique.IsKnownGlobal(heap->undefined_value())); 1243 return heap->undefined_string(); 1244 } 1245 case SYMBOL_TYPE: 1246 return heap->symbol_string(); 1247 case SIMD128_VALUE_TYPE: { 1248 Unique<Map> map = constant->ObjectMap(); 1249 #define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type) \ 1250 if (map.IsKnownGlobal(heap->type##_map())) { \ 1251 return heap->type##_string(); \ 1252 } 1253 SIMD128_TYPES(SIMD128_TYPE) 1254 #undef SIMD128_TYPE 1255 UNREACHABLE(); 1256 return nullptr; 1257 } 1258 default: 1259 if (constant->IsUndetectable()) return heap->undefined_string(); 1260 if (constant->IsCallable()) return heap->function_string(); 1261 return heap->object_string(); 1262 } 1263 } 1264 1265 } // namespace 1266 1267 1268 bool HTypeofIsAndBranch::KnownSuccessorBlock(HBasicBlock** block) { 1269 if (FLAG_fold_constants && value()->IsConstant()) { 1270 HConstant* constant = HConstant::cast(value()); 1271 String* type_string = TypeOfString(constant, isolate()); 1272 bool same_type = type_literal_.IsKnownGlobal(type_string); 1273 *block = same_type ? FirstSuccessor() : SecondSuccessor(); 1274 return true; 1275 } else if (value()->representation().IsSpecialization()) { 1276 bool number_type = 1277 type_literal_.IsKnownGlobal(isolate()->heap()->number_string()); 1278 *block = number_type ? FirstSuccessor() : SecondSuccessor(); 1279 return true; 1280 } 1281 *block = NULL; 1282 return false; 1283 } 1284 1285 1286 std::ostream& HCheckMapValue::PrintDataTo(std::ostream& os) const { // NOLINT 1287 return os << NameOf(value()) << " " << NameOf(map()); 1288 } 1289 1290 1291 HValue* HCheckMapValue::Canonicalize() { 1292 if (map()->IsConstant()) { 1293 HConstant* c_map = HConstant::cast(map()); 1294 return HCheckMaps::CreateAndInsertAfter( 1295 block()->graph()->zone(), value(), c_map->MapValue(), 1296 c_map->HasStableMapValue(), this); 1297 } 1298 return this; 1299 } 1300 1301 1302 std::ostream& HForInPrepareMap::PrintDataTo(std::ostream& os) const { // NOLINT 1303 return os << NameOf(enumerable()); 1304 } 1305 1306 1307 std::ostream& HForInCacheArray::PrintDataTo(std::ostream& os) const { // NOLINT 1308 return os << NameOf(enumerable()) << " " << NameOf(map()) << "[" << idx_ 1309 << "]"; 1310 } 1311 1312 1313 std::ostream& HLoadFieldByIndex::PrintDataTo( 1314 std::ostream& os) const { // NOLINT 1315 return os << NameOf(object()) << " " << NameOf(index()); 1316 } 1317 1318 1319 static bool MatchLeftIsOnes(HValue* l, HValue* r, HValue** negated) { 1320 if (!l->EqualsInteger32Constant(~0)) return false; 1321 *negated = r; 1322 return true; 1323 } 1324 1325 1326 static bool MatchNegationViaXor(HValue* instr, HValue** negated) { 1327 if (!instr->IsBitwise()) return false; 1328 HBitwise* b = HBitwise::cast(instr); 1329 return (b->op() == Token::BIT_XOR) && 1330 (MatchLeftIsOnes(b->left(), b->right(), negated) || 1331 MatchLeftIsOnes(b->right(), b->left(), negated)); 1332 } 1333 1334 1335 static bool MatchDoubleNegation(HValue* instr, HValue** arg) { 1336 HValue* negated; 1337 return MatchNegationViaXor(instr, &negated) && 1338 MatchNegationViaXor(negated, arg); 1339 } 1340 1341 1342 HValue* HBitwise::Canonicalize() { 1343 if (!representation().IsSmiOrInteger32()) return this; 1344 // If x is an int32, then x & -1 == x, x | 0 == x and x ^ 0 == x. 1345 int32_t nop_constant = (op() == Token::BIT_AND) ? -1 : 0; 1346 if (left()->EqualsInteger32Constant(nop_constant) && 1347 !right()->CheckFlag(kUint32)) { 1348 return right(); 1349 } 1350 if (right()->EqualsInteger32Constant(nop_constant) && 1351 !left()->CheckFlag(kUint32)) { 1352 return left(); 1353 } 1354 // Optimize double negation, a common pattern used for ToInt32(x). 1355 HValue* arg; 1356 if (MatchDoubleNegation(this, &arg) && !arg->CheckFlag(kUint32)) { 1357 return arg; 1358 } 1359 return this; 1360 } 1361 1362 1363 // static 1364 HInstruction* HAdd::New(Isolate* isolate, Zone* zone, HValue* context, 1365 HValue* left, HValue* right, 1366 ExternalAddType external_add_type) { 1367 // For everything else, you should use the other factory method without 1368 // ExternalAddType. 1369 DCHECK_EQ(external_add_type, AddOfExternalAndTagged); 1370 return new (zone) HAdd(context, left, right, external_add_type); 1371 } 1372 1373 1374 Representation HAdd::RepresentationFromInputs() { 1375 Representation left_rep = left()->representation(); 1376 if (left_rep.IsExternal()) { 1377 return Representation::External(); 1378 } 1379 return HArithmeticBinaryOperation::RepresentationFromInputs(); 1380 } 1381 1382 1383 Representation HAdd::RequiredInputRepresentation(int index) { 1384 if (index == 2) { 1385 Representation left_rep = left()->representation(); 1386 if (left_rep.IsExternal()) { 1387 if (external_add_type_ == AddOfExternalAndTagged) { 1388 return Representation::Tagged(); 1389 } else { 1390 return Representation::Integer32(); 1391 } 1392 } 1393 } 1394 return HArithmeticBinaryOperation::RequiredInputRepresentation(index); 1395 } 1396 1397 1398 static bool IsIdentityOperation(HValue* arg1, HValue* arg2, int32_t identity) { 1399 return arg1->representation().IsSpecialization() && 1400 arg2->EqualsInteger32Constant(identity); 1401 } 1402 1403 1404 HValue* HAdd::Canonicalize() { 1405 // Adding 0 is an identity operation except in case of -0: -0 + 0 = +0 1406 if (IsIdentityOperation(left(), right(), 0) && 1407 !left()->representation().IsDouble()) { // Left could be -0. 1408 return left(); 1409 } 1410 if (IsIdentityOperation(right(), left(), 0) && 1411 !left()->representation().IsDouble()) { // Right could be -0. 1412 return right(); 1413 } 1414 return this; 1415 } 1416 1417 1418 HValue* HSub::Canonicalize() { 1419 if (IsIdentityOperation(left(), right(), 0)) return left(); 1420 return this; 1421 } 1422 1423 1424 HValue* HMul::Canonicalize() { 1425 if (IsIdentityOperation(left(), right(), 1)) return left(); 1426 if (IsIdentityOperation(right(), left(), 1)) return right(); 1427 return this; 1428 } 1429 1430 1431 bool HMul::MulMinusOne() { 1432 if (left()->EqualsInteger32Constant(-1) || 1433 right()->EqualsInteger32Constant(-1)) { 1434 return true; 1435 } 1436 1437 return false; 1438 } 1439 1440 1441 HValue* HMod::Canonicalize() { 1442 return this; 1443 } 1444 1445 1446 HValue* HDiv::Canonicalize() { 1447 if (IsIdentityOperation(left(), right(), 1)) return left(); 1448 return this; 1449 } 1450 1451 1452 HValue* HChange::Canonicalize() { 1453 return (from().Equals(to())) ? value() : this; 1454 } 1455 1456 1457 HValue* HWrapReceiver::Canonicalize() { 1458 if (HasNoUses()) return NULL; 1459 if (receiver()->type().IsJSReceiver()) { 1460 return receiver(); 1461 } 1462 return this; 1463 } 1464 1465 1466 std::ostream& HTypeof::PrintDataTo(std::ostream& os) const { // NOLINT 1467 return os << NameOf(value()); 1468 } 1469 1470 1471 HInstruction* HForceRepresentation::New(Isolate* isolate, Zone* zone, 1472 HValue* context, HValue* value, 1473 Representation representation) { 1474 if (FLAG_fold_constants && value->IsConstant()) { 1475 HConstant* c = HConstant::cast(value); 1476 c = c->CopyToRepresentation(representation, zone); 1477 if (c != NULL) return c; 1478 } 1479 return new(zone) HForceRepresentation(value, representation); 1480 } 1481 1482 1483 std::ostream& HForceRepresentation::PrintDataTo( 1484 std::ostream& os) const { // NOLINT 1485 return os << representation().Mnemonic() << " " << NameOf(value()); 1486 } 1487 1488 1489 std::ostream& HChange::PrintDataTo(std::ostream& os) const { // NOLINT 1490 HUnaryOperation::PrintDataTo(os); 1491 os << " " << from().Mnemonic() << " to " << to().Mnemonic(); 1492 1493 if (CanTruncateToSmi()) os << " truncating-smi"; 1494 if (CanTruncateToInt32()) os << " truncating-int32"; 1495 if (CanTruncateToNumber()) os << " truncating-number"; 1496 if (CheckFlag(kBailoutOnMinusZero)) os << " -0?"; 1497 return os; 1498 } 1499 1500 1501 HValue* HUnaryMathOperation::Canonicalize() { 1502 if (op() == kMathRound || op() == kMathFloor) { 1503 HValue* val = value(); 1504 if (val->IsChange()) val = HChange::cast(val)->value(); 1505 if (val->representation().IsSmiOrInteger32()) { 1506 if (val->representation().Equals(representation())) return val; 1507 return Prepend(new (block()->zone()) 1508 HChange(val, representation(), false, false, true)); 1509 } 1510 } 1511 if (op() == kMathFloor && representation().IsSmiOrInteger32() && 1512 value()->IsDiv() && value()->HasOneUse()) { 1513 HDiv* hdiv = HDiv::cast(value()); 1514 1515 HValue* left = hdiv->left(); 1516 if (left->representation().IsInteger32() && !left->CheckFlag(kUint32)) { 1517 // A value with an integer representation does not need to be transformed. 1518 } else if (left->IsChange() && HChange::cast(left)->from().IsInteger32() && 1519 !HChange::cast(left)->value()->CheckFlag(kUint32)) { 1520 // A change from an integer32 can be replaced by the integer32 value. 1521 left = HChange::cast(left)->value(); 1522 } else if (hdiv->observed_input_representation(1).IsSmiOrInteger32()) { 1523 left = Prepend(new (block()->zone()) HChange( 1524 left, Representation::Integer32(), false, false, true)); 1525 } else { 1526 return this; 1527 } 1528 1529 HValue* right = hdiv->right(); 1530 if (right->IsInteger32Constant()) { 1531 right = Prepend(HConstant::cast(right)->CopyToRepresentation( 1532 Representation::Integer32(), right->block()->zone())); 1533 } else if (right->representation().IsInteger32() && 1534 !right->CheckFlag(kUint32)) { 1535 // A value with an integer representation does not need to be transformed. 1536 } else if (right->IsChange() && 1537 HChange::cast(right)->from().IsInteger32() && 1538 !HChange::cast(right)->value()->CheckFlag(kUint32)) { 1539 // A change from an integer32 can be replaced by the integer32 value. 1540 right = HChange::cast(right)->value(); 1541 } else if (hdiv->observed_input_representation(2).IsSmiOrInteger32()) { 1542 right = Prepend(new (block()->zone()) HChange( 1543 right, Representation::Integer32(), false, false, true)); 1544 } else { 1545 return this; 1546 } 1547 1548 return Prepend(HMathFloorOfDiv::New( 1549 block()->graph()->isolate(), block()->zone(), context(), left, right)); 1550 } 1551 return this; 1552 } 1553 1554 1555 HValue* HCheckInstanceType::Canonicalize() { 1556 if ((check_ == IS_JS_RECEIVER && value()->type().IsJSReceiver()) || 1557 (check_ == IS_JS_ARRAY && value()->type().IsJSArray()) || 1558 (check_ == IS_STRING && value()->type().IsString())) { 1559 return value(); 1560 } 1561 1562 if (check_ == IS_INTERNALIZED_STRING && value()->IsConstant()) { 1563 if (HConstant::cast(value())->HasInternalizedStringValue()) { 1564 return value(); 1565 } 1566 } 1567 return this; 1568 } 1569 1570 1571 void HCheckInstanceType::GetCheckInterval(InstanceType* first, 1572 InstanceType* last) { 1573 DCHECK(is_interval_check()); 1574 switch (check_) { 1575 case IS_JS_RECEIVER: 1576 *first = FIRST_JS_RECEIVER_TYPE; 1577 *last = LAST_JS_RECEIVER_TYPE; 1578 return; 1579 case IS_JS_ARRAY: 1580 *first = *last = JS_ARRAY_TYPE; 1581 return; 1582 case IS_JS_FUNCTION: 1583 *first = *last = JS_FUNCTION_TYPE; 1584 return; 1585 case IS_JS_DATE: 1586 *first = *last = JS_DATE_TYPE; 1587 return; 1588 default: 1589 UNREACHABLE(); 1590 } 1591 } 1592 1593 1594 void HCheckInstanceType::GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag) { 1595 DCHECK(!is_interval_check()); 1596 switch (check_) { 1597 case IS_STRING: 1598 *mask = kIsNotStringMask; 1599 *tag = kStringTag; 1600 return; 1601 case IS_INTERNALIZED_STRING: 1602 *mask = kIsNotStringMask | kIsNotInternalizedMask; 1603 *tag = kInternalizedTag; 1604 return; 1605 default: 1606 UNREACHABLE(); 1607 } 1608 } 1609 1610 1611 std::ostream& HCheckMaps::PrintDataTo(std::ostream& os) const { // NOLINT 1612 os << NameOf(value()) << " [" << *maps()->at(0).handle(); 1613 for (int i = 1; i < maps()->size(); ++i) { 1614 os << "," << *maps()->at(i).handle(); 1615 } 1616 os << "]"; 1617 if (IsStabilityCheck()) os << "(stability-check)"; 1618 return os; 1619 } 1620 1621 1622 HValue* HCheckMaps::Canonicalize() { 1623 if (!IsStabilityCheck() && maps_are_stable() && value()->IsConstant()) { 1624 HConstant* c_value = HConstant::cast(value()); 1625 if (c_value->HasObjectMap()) { 1626 for (int i = 0; i < maps()->size(); ++i) { 1627 if (c_value->ObjectMap() == maps()->at(i)) { 1628 if (maps()->size() > 1) { 1629 set_maps(new(block()->graph()->zone()) UniqueSet<Map>( 1630 maps()->at(i), block()->graph()->zone())); 1631 } 1632 MarkAsStabilityCheck(); 1633 break; 1634 } 1635 } 1636 } 1637 } 1638 return this; 1639 } 1640 1641 1642 std::ostream& HCheckValue::PrintDataTo(std::ostream& os) const { // NOLINT 1643 return os << NameOf(value()) << " " << Brief(*object().handle()); 1644 } 1645 1646 1647 HValue* HCheckValue::Canonicalize() { 1648 return (value()->IsConstant() && 1649 HConstant::cast(value())->EqualsUnique(object_)) ? NULL : this; 1650 } 1651 1652 1653 const char* HCheckInstanceType::GetCheckName() const { 1654 switch (check_) { 1655 case IS_JS_RECEIVER: return "object"; 1656 case IS_JS_ARRAY: return "array"; 1657 case IS_JS_FUNCTION: 1658 return "function"; 1659 case IS_JS_DATE: 1660 return "date"; 1661 case IS_STRING: return "string"; 1662 case IS_INTERNALIZED_STRING: return "internalized_string"; 1663 } 1664 UNREACHABLE(); 1665 return ""; 1666 } 1667 1668 1669 std::ostream& HCheckInstanceType::PrintDataTo( 1670 std::ostream& os) const { // NOLINT 1671 os << GetCheckName() << " "; 1672 return HUnaryOperation::PrintDataTo(os); 1673 } 1674 1675 1676 std::ostream& HUnknownOSRValue::PrintDataTo(std::ostream& os) const { // NOLINT 1677 const char* type = "expression"; 1678 if (environment_->is_local_index(index_)) type = "local"; 1679 if (environment_->is_special_index(index_)) type = "special"; 1680 if (environment_->is_parameter_index(index_)) type = "parameter"; 1681 return os << type << " @ " << index_; 1682 } 1683 1684 1685 Range* HValue::InferRange(Zone* zone) { 1686 Range* result; 1687 if (representation().IsSmi() || type().IsSmi()) { 1688 result = new(zone) Range(Smi::kMinValue, Smi::kMaxValue); 1689 result->set_can_be_minus_zero(false); 1690 } else { 1691 result = new(zone) Range(); 1692 result->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToInt32)); 1693 // TODO(jkummerow): The range cannot be minus zero when the upper type 1694 // bound is Integer32. 1695 } 1696 return result; 1697 } 1698 1699 1700 Range* HChange::InferRange(Zone* zone) { 1701 Range* input_range = value()->range(); 1702 if (from().IsInteger32() && !value()->CheckFlag(HInstruction::kUint32) && 1703 (to().IsSmi() || 1704 (to().IsTagged() && 1705 input_range != NULL && 1706 input_range->IsInSmiRange()))) { 1707 set_type(HType::Smi()); 1708 ClearChangesFlag(kNewSpacePromotion); 1709 } 1710 if (to().IsSmiOrTagged() && 1711 input_range != NULL && 1712 input_range->IsInSmiRange() && 1713 (!SmiValuesAre32Bits() || 1714 !value()->CheckFlag(HValue::kUint32) || 1715 input_range->upper() != kMaxInt)) { 1716 // The Range class can't express upper bounds in the (kMaxInt, kMaxUint32] 1717 // interval, so we treat kMaxInt as a sentinel for this entire interval. 1718 ClearFlag(kCanOverflow); 1719 } 1720 Range* result = (input_range != NULL) 1721 ? input_range->Copy(zone) 1722 : HValue::InferRange(zone); 1723 result->set_can_be_minus_zero(!to().IsSmiOrInteger32() || 1724 !(CheckFlag(kAllUsesTruncatingToInt32) || 1725 CheckFlag(kAllUsesTruncatingToSmi))); 1726 if (to().IsSmi()) result->ClampToSmi(); 1727 return result; 1728 } 1729 1730 1731 Range* HConstant::InferRange(Zone* zone) { 1732 if (HasInteger32Value()) { 1733 Range* result = new(zone) Range(int32_value_, int32_value_); 1734 result->set_can_be_minus_zero(false); 1735 return result; 1736 } 1737 return HValue::InferRange(zone); 1738 } 1739 1740 1741 SourcePosition HPhi::position() const { return block()->first()->position(); } 1742 1743 1744 Range* HPhi::InferRange(Zone* zone) { 1745 Representation r = representation(); 1746 if (r.IsSmiOrInteger32()) { 1747 if (block()->IsLoopHeader()) { 1748 Range* range = r.IsSmi() 1749 ? new(zone) Range(Smi::kMinValue, Smi::kMaxValue) 1750 : new(zone) Range(kMinInt, kMaxInt); 1751 return range; 1752 } else { 1753 Range* range = OperandAt(0)->range()->Copy(zone); 1754 for (int i = 1; i < OperandCount(); ++i) { 1755 range->Union(OperandAt(i)->range()); 1756 } 1757 return range; 1758 } 1759 } else { 1760 return HValue::InferRange(zone); 1761 } 1762 } 1763 1764 1765 Range* HAdd::InferRange(Zone* zone) { 1766 Representation r = representation(); 1767 if (r.IsSmiOrInteger32()) { 1768 Range* a = left()->range(); 1769 Range* b = right()->range(); 1770 Range* res = a->Copy(zone); 1771 if (!res->AddAndCheckOverflow(r, b) || 1772 (r.IsInteger32() && CheckFlag(kAllUsesTruncatingToInt32)) || 1773 (r.IsSmi() && CheckFlag(kAllUsesTruncatingToSmi))) { 1774 ClearFlag(kCanOverflow); 1775 } 1776 res->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToSmi) && 1777 !CheckFlag(kAllUsesTruncatingToInt32) && 1778 a->CanBeMinusZero() && b->CanBeMinusZero()); 1779 return res; 1780 } else { 1781 return HValue::InferRange(zone); 1782 } 1783 } 1784 1785 1786 Range* HSub::InferRange(Zone* zone) { 1787 Representation r = representation(); 1788 if (r.IsSmiOrInteger32()) { 1789 Range* a = left()->range(); 1790 Range* b = right()->range(); 1791 Range* res = a->Copy(zone); 1792 if (!res->SubAndCheckOverflow(r, b) || 1793 (r.IsInteger32() && CheckFlag(kAllUsesTruncatingToInt32)) || 1794 (r.IsSmi() && CheckFlag(kAllUsesTruncatingToSmi))) { 1795 ClearFlag(kCanOverflow); 1796 } 1797 res->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToSmi) && 1798 !CheckFlag(kAllUsesTruncatingToInt32) && 1799 a->CanBeMinusZero() && b->CanBeZero()); 1800 return res; 1801 } else { 1802 return HValue::InferRange(zone); 1803 } 1804 } 1805 1806 1807 Range* HMul::InferRange(Zone* zone) { 1808 Representation r = representation(); 1809 if (r.IsSmiOrInteger32()) { 1810 Range* a = left()->range(); 1811 Range* b = right()->range(); 1812 Range* res = a->Copy(zone); 1813 if (!res->MulAndCheckOverflow(r, b) || 1814 (((r.IsInteger32() && CheckFlag(kAllUsesTruncatingToInt32)) || 1815 (r.IsSmi() && CheckFlag(kAllUsesTruncatingToSmi))) && 1816 MulMinusOne())) { 1817 // Truncated int multiplication is too precise and therefore not the 1818 // same as converting to Double and back. 1819 // Handle truncated integer multiplication by -1 special. 1820 ClearFlag(kCanOverflow); 1821 } 1822 res->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToSmi) && 1823 !CheckFlag(kAllUsesTruncatingToInt32) && 1824 ((a->CanBeZero() && b->CanBeNegative()) || 1825 (a->CanBeNegative() && b->CanBeZero()))); 1826 return res; 1827 } else { 1828 return HValue::InferRange(zone); 1829 } 1830 } 1831 1832 1833 Range* HDiv::InferRange(Zone* zone) { 1834 if (representation().IsInteger32()) { 1835 Range* a = left()->range(); 1836 Range* b = right()->range(); 1837 Range* result = new(zone) Range(); 1838 result->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToInt32) && 1839 (a->CanBeMinusZero() || 1840 (a->CanBeZero() && b->CanBeNegative()))); 1841 if (!a->Includes(kMinInt) || !b->Includes(-1)) { 1842 ClearFlag(kCanOverflow); 1843 } 1844 1845 if (!b->CanBeZero()) { 1846 ClearFlag(kCanBeDivByZero); 1847 } 1848 return result; 1849 } else { 1850 return HValue::InferRange(zone); 1851 } 1852 } 1853 1854 1855 Range* HMathFloorOfDiv::InferRange(Zone* zone) { 1856 if (representation().IsInteger32()) { 1857 Range* a = left()->range(); 1858 Range* b = right()->range(); 1859 Range* result = new(zone) Range(); 1860 result->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToInt32) && 1861 (a->CanBeMinusZero() || 1862 (a->CanBeZero() && b->CanBeNegative()))); 1863 if (!a->Includes(kMinInt)) { 1864 ClearFlag(kLeftCanBeMinInt); 1865 } 1866 1867 if (!a->CanBeNegative()) { 1868 ClearFlag(HValue::kLeftCanBeNegative); 1869 } 1870 1871 if (!a->CanBePositive()) { 1872 ClearFlag(HValue::kLeftCanBePositive); 1873 } 1874 1875 if (!a->Includes(kMinInt) || !b->Includes(-1)) { 1876 ClearFlag(kCanOverflow); 1877 } 1878 1879 if (!b->CanBeZero()) { 1880 ClearFlag(kCanBeDivByZero); 1881 } 1882 return result; 1883 } else { 1884 return HValue::InferRange(zone); 1885 } 1886 } 1887 1888 1889 // Returns the absolute value of its argument minus one, avoiding undefined 1890 // behavior at kMinInt. 1891 static int32_t AbsMinus1(int32_t a) { return a < 0 ? -(a + 1) : (a - 1); } 1892 1893 1894 Range* HMod::InferRange(Zone* zone) { 1895 if (representation().IsInteger32()) { 1896 Range* a = left()->range(); 1897 Range* b = right()->range(); 1898 1899 // The magnitude of the modulus is bounded by the right operand. 1900 int32_t positive_bound = Max(AbsMinus1(b->lower()), AbsMinus1(b->upper())); 1901 1902 // The result of the modulo operation has the sign of its left operand. 1903 bool left_can_be_negative = a->CanBeMinusZero() || a->CanBeNegative(); 1904 Range* result = new(zone) Range(left_can_be_negative ? -positive_bound : 0, 1905 a->CanBePositive() ? positive_bound : 0); 1906 1907 result->set_can_be_minus_zero(!CheckFlag(kAllUsesTruncatingToInt32) && 1908 left_can_be_negative); 1909 1910 if (!a->CanBeNegative()) { 1911 ClearFlag(HValue::kLeftCanBeNegative); 1912 } 1913 1914 if (!a->Includes(kMinInt) || !b->Includes(-1)) { 1915 ClearFlag(HValue::kCanOverflow); 1916 } 1917 1918 if (!b->CanBeZero()) { 1919 ClearFlag(HValue::kCanBeDivByZero); 1920 } 1921 return result; 1922 } else { 1923 return HValue::InferRange(zone); 1924 } 1925 } 1926 1927 1928 Range* HMathMinMax::InferRange(Zone* zone) { 1929 if (representation().IsSmiOrInteger32()) { 1930 Range* a = left()->range(); 1931 Range* b = right()->range(); 1932 Range* res = a->Copy(zone); 1933 if (operation_ == kMathMax) { 1934 res->CombinedMax(b); 1935 } else { 1936 DCHECK(operation_ == kMathMin); 1937 res->CombinedMin(b); 1938 } 1939 return res; 1940 } else { 1941 return HValue::InferRange(zone); 1942 } 1943 } 1944 1945 1946 void HPushArguments::AddInput(HValue* value) { 1947 inputs_.Add(NULL, value->block()->zone()); 1948 SetOperandAt(OperandCount() - 1, value); 1949 } 1950 1951 1952 std::ostream& HPhi::PrintTo(std::ostream& os) const { // NOLINT 1953 os << "["; 1954 for (int i = 0; i < OperandCount(); ++i) { 1955 os << " " << NameOf(OperandAt(i)) << " "; 1956 } 1957 return os << " uses" << UseCount() 1958 << representation_from_indirect_uses().Mnemonic() << " " 1959 << TypeOf(this) << "]"; 1960 } 1961 1962 1963 void HPhi::AddInput(HValue* value) { 1964 inputs_.Add(NULL, value->block()->zone()); 1965 SetOperandAt(OperandCount() - 1, value); 1966 // Mark phis that may have 'arguments' directly or indirectly as an operand. 1967 if (!CheckFlag(kIsArguments) && value->CheckFlag(kIsArguments)) { 1968 SetFlag(kIsArguments); 1969 } 1970 } 1971 1972 1973 bool HPhi::HasRealUses() { 1974 for (HUseIterator it(uses()); !it.Done(); it.Advance()) { 1975 if (!it.value()->IsPhi()) return true; 1976 } 1977 return false; 1978 } 1979 1980 1981 HValue* HPhi::GetRedundantReplacement() { 1982 HValue* candidate = NULL; 1983 int count = OperandCount(); 1984 int position = 0; 1985 while (position < count && candidate == NULL) { 1986 HValue* current = OperandAt(position++); 1987 if (current != this) candidate = current; 1988 } 1989 while (position < count) { 1990 HValue* current = OperandAt(position++); 1991 if (current != this && current != candidate) return NULL; 1992 } 1993 DCHECK(candidate != this); 1994 return candidate; 1995 } 1996 1997 1998 void HPhi::DeleteFromGraph() { 1999 DCHECK(block() != NULL); 2000 block()->RemovePhi(this); 2001 DCHECK(block() == NULL); 2002 } 2003 2004 2005 void HPhi::InitRealUses(int phi_id) { 2006 // Initialize real uses. 2007 phi_id_ = phi_id; 2008 // Compute a conservative approximation of truncating uses before inferring 2009 // representations. The proper, exact computation will be done later, when 2010 // inserting representation changes. 2011 SetFlag(kTruncatingToSmi); 2012 SetFlag(kTruncatingToInt32); 2013 for (HUseIterator it(uses()); !it.Done(); it.Advance()) { 2014 HValue* value = it.value(); 2015 if (!value->IsPhi()) { 2016 Representation rep = value->observed_input_representation(it.index()); 2017 representation_from_non_phi_uses_ = 2018 representation_from_non_phi_uses().generalize(rep); 2019 if (rep.IsSmi() || rep.IsInteger32() || rep.IsDouble()) { 2020 has_type_feedback_from_uses_ = true; 2021 } 2022 2023 if (FLAG_trace_representation) { 2024 PrintF("#%d Phi is used by real #%d %s as %s\n", 2025 id(), value->id(), value->Mnemonic(), rep.Mnemonic()); 2026 } 2027 if (!value->IsSimulate()) { 2028 if (!value->CheckFlag(kTruncatingToSmi)) { 2029 ClearFlag(kTruncatingToSmi); 2030 } 2031 if (!value->CheckFlag(kTruncatingToInt32)) { 2032 ClearFlag(kTruncatingToInt32); 2033 } 2034 } 2035 } 2036 } 2037 } 2038 2039 2040 void HPhi::AddNonPhiUsesFrom(HPhi* other) { 2041 if (FLAG_trace_representation) { 2042 PrintF( 2043 "generalizing use representation '%s' of #%d Phi " 2044 "with uses of #%d Phi '%s'\n", 2045 representation_from_indirect_uses().Mnemonic(), id(), other->id(), 2046 other->representation_from_non_phi_uses().Mnemonic()); 2047 } 2048 2049 representation_from_indirect_uses_ = 2050 representation_from_indirect_uses().generalize( 2051 other->representation_from_non_phi_uses()); 2052 } 2053 2054 2055 void HSimulate::MergeWith(ZoneList<HSimulate*>* list) { 2056 while (!list->is_empty()) { 2057 HSimulate* from = list->RemoveLast(); 2058 ZoneList<HValue*>* from_values = &from->values_; 2059 for (int i = 0; i < from_values->length(); ++i) { 2060 if (from->HasAssignedIndexAt(i)) { 2061 int index = from->GetAssignedIndexAt(i); 2062 if (HasValueForIndex(index)) continue; 2063 AddAssignedValue(index, from_values->at(i)); 2064 } else { 2065 if (pop_count_ > 0) { 2066 pop_count_--; 2067 } else { 2068 AddPushedValue(from_values->at(i)); 2069 } 2070 } 2071 } 2072 pop_count_ += from->pop_count_; 2073 from->DeleteAndReplaceWith(NULL); 2074 } 2075 } 2076 2077 2078 std::ostream& HSimulate::PrintDataTo(std::ostream& os) const { // NOLINT 2079 os << "id=" << ast_id().ToInt(); 2080 if (pop_count_ > 0) os << " pop " << pop_count_; 2081 if (values_.length() > 0) { 2082 if (pop_count_ > 0) os << " /"; 2083 for (int i = values_.length() - 1; i >= 0; --i) { 2084 if (HasAssignedIndexAt(i)) { 2085 os << " var[" << GetAssignedIndexAt(i) << "] = "; 2086 } else { 2087 os << " push "; 2088 } 2089 os << NameOf(values_[i]); 2090 if (i > 0) os << ","; 2091 } 2092 } 2093 return os; 2094 } 2095 2096 2097 void HSimulate::ReplayEnvironment(HEnvironment* env) { 2098 if (is_done_with_replay()) return; 2099 DCHECK(env != NULL); 2100 env->set_ast_id(ast_id()); 2101 env->Drop(pop_count()); 2102 for (int i = values()->length() - 1; i >= 0; --i) { 2103 HValue* value = values()->at(i); 2104 if (HasAssignedIndexAt(i)) { 2105 env->Bind(GetAssignedIndexAt(i), value); 2106 } else { 2107 env->Push(value); 2108 } 2109 } 2110 set_done_with_replay(); 2111 } 2112 2113 2114 static void ReplayEnvironmentNested(const ZoneList<HValue*>* values, 2115 HCapturedObject* other) { 2116 for (int i = 0; i < values->length(); ++i) { 2117 HValue* value = values->at(i); 2118 if (value->IsCapturedObject()) { 2119 if (HCapturedObject::cast(value)->capture_id() == other->capture_id()) { 2120 values->at(i) = other; 2121 } else { 2122 ReplayEnvironmentNested(HCapturedObject::cast(value)->values(), other); 2123 } 2124 } 2125 } 2126 } 2127 2128 2129 // Replay captured objects by replacing all captured objects with the 2130 // same capture id in the current and all outer environments. 2131 void HCapturedObject::ReplayEnvironment(HEnvironment* env) { 2132 DCHECK(env != NULL); 2133 while (env != NULL) { 2134 ReplayEnvironmentNested(env->values(), this); 2135 env = env->outer(); 2136 } 2137 } 2138 2139 2140 std::ostream& HCapturedObject::PrintDataTo(std::ostream& os) const { // NOLINT 2141 os << "#" << capture_id() << " "; 2142 return HDematerializedObject::PrintDataTo(os); 2143 } 2144 2145 2146 void HEnterInlined::RegisterReturnTarget(HBasicBlock* return_target, 2147 Zone* zone) { 2148 DCHECK(return_target->IsInlineReturnTarget()); 2149 return_targets_.Add(return_target, zone); 2150 } 2151 2152 2153 std::ostream& HEnterInlined::PrintDataTo(std::ostream& os) const { // NOLINT 2154 os << function()->debug_name()->ToCString().get(); 2155 if (syntactic_tail_call_mode() == TailCallMode::kAllow) { 2156 os << ", JSTailCall"; 2157 } 2158 return os; 2159 } 2160 2161 2162 static bool IsInteger32(double value) { 2163 if (value >= std::numeric_limits<int32_t>::min() && 2164 value <= std::numeric_limits<int32_t>::max()) { 2165 double roundtrip_value = static_cast<double>(static_cast<int32_t>(value)); 2166 return bit_cast<int64_t>(roundtrip_value) == bit_cast<int64_t>(value); 2167 } 2168 return false; 2169 } 2170 2171 2172 HConstant::HConstant(Special special) 2173 : HTemplateInstruction<0>(HType::TaggedNumber()), 2174 object_(Handle<Object>::null()), 2175 object_map_(Handle<Map>::null()), 2176 bit_field_(HasDoubleValueField::encode(true) | 2177 InstanceTypeField::encode(kUnknownInstanceType)), 2178 int32_value_(0) { 2179 DCHECK_EQ(kHoleNaN, special); 2180 std::memcpy(&double_value_, &kHoleNanInt64, sizeof(double_value_)); 2181 Initialize(Representation::Double()); 2182 } 2183 2184 2185 HConstant::HConstant(Handle<Object> object, Representation r) 2186 : HTemplateInstruction<0>(HType::FromValue(object)), 2187 object_(Unique<Object>::CreateUninitialized(object)), 2188 object_map_(Handle<Map>::null()), 2189 bit_field_( 2190 HasStableMapValueField::encode(false) | 2191 HasSmiValueField::encode(false) | HasInt32ValueField::encode(false) | 2192 HasDoubleValueField::encode(false) | 2193 HasExternalReferenceValueField::encode(false) | 2194 IsNotInNewSpaceField::encode(true) | 2195 BooleanValueField::encode(object->BooleanValue()) | 2196 IsUndetectableField::encode(false) | IsCallableField::encode(false) | 2197 InstanceTypeField::encode(kUnknownInstanceType)) { 2198 if (object->IsNumber()) { 2199 double n = object->Number(); 2200 bool has_int32_value = IsInteger32(n); 2201 bit_field_ = HasInt32ValueField::update(bit_field_, has_int32_value); 2202 int32_value_ = DoubleToInt32(n); 2203 bit_field_ = HasSmiValueField::update( 2204 bit_field_, has_int32_value && Smi::IsValid(int32_value_)); 2205 if (std::isnan(n)) { 2206 double_value_ = std::numeric_limits<double>::quiet_NaN(); 2207 // Canonicalize object with NaN value. 2208 DCHECK(object->IsHeapObject()); // NaN can't be a Smi. 2209 Isolate* isolate = HeapObject::cast(*object)->GetIsolate(); 2210 object = isolate->factory()->nan_value(); 2211 object_ = Unique<Object>::CreateUninitialized(object); 2212 } else { 2213 double_value_ = n; 2214 // Canonicalize object with -0.0 value. 2215 if (bit_cast<int64_t>(n) == bit_cast<int64_t>(-0.0)) { 2216 DCHECK(object->IsHeapObject()); // -0.0 can't be a Smi. 2217 Isolate* isolate = HeapObject::cast(*object)->GetIsolate(); 2218 object = isolate->factory()->minus_zero_value(); 2219 object_ = Unique<Object>::CreateUninitialized(object); 2220 } 2221 } 2222 bit_field_ = HasDoubleValueField::update(bit_field_, true); 2223 } 2224 if (object->IsHeapObject()) { 2225 Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object); 2226 Isolate* isolate = heap_object->GetIsolate(); 2227 Handle<Map> map(heap_object->map(), isolate); 2228 bit_field_ = IsNotInNewSpaceField::update( 2229 bit_field_, !isolate->heap()->InNewSpace(*object)); 2230 bit_field_ = InstanceTypeField::update(bit_field_, map->instance_type()); 2231 bit_field_ = 2232 IsUndetectableField::update(bit_field_, map->is_undetectable()); 2233 bit_field_ = IsCallableField::update(bit_field_, map->is_callable()); 2234 if (map->is_stable()) object_map_ = Unique<Map>::CreateImmovable(map); 2235 bit_field_ = HasStableMapValueField::update( 2236 bit_field_, 2237 HasMapValue() && Handle<Map>::cast(heap_object)->is_stable()); 2238 } 2239 2240 Initialize(r); 2241 } 2242 2243 2244 HConstant::HConstant(Unique<Object> object, Unique<Map> object_map, 2245 bool has_stable_map_value, Representation r, HType type, 2246 bool is_not_in_new_space, bool boolean_value, 2247 bool is_undetectable, InstanceType instance_type) 2248 : HTemplateInstruction<0>(type), 2249 object_(object), 2250 object_map_(object_map), 2251 bit_field_(HasStableMapValueField::encode(has_stable_map_value) | 2252 HasSmiValueField::encode(false) | 2253 HasInt32ValueField::encode(false) | 2254 HasDoubleValueField::encode(false) | 2255 HasExternalReferenceValueField::encode(false) | 2256 IsNotInNewSpaceField::encode(is_not_in_new_space) | 2257 BooleanValueField::encode(boolean_value) | 2258 IsUndetectableField::encode(is_undetectable) | 2259 InstanceTypeField::encode(instance_type)) { 2260 DCHECK(!object.handle().is_null()); 2261 DCHECK(!type.IsTaggedNumber() || type.IsNone()); 2262 Initialize(r); 2263 } 2264 2265 2266 HConstant::HConstant(int32_t integer_value, Representation r, 2267 bool is_not_in_new_space, Unique<Object> object) 2268 : object_(object), 2269 object_map_(Handle<Map>::null()), 2270 bit_field_(HasStableMapValueField::encode(false) | 2271 HasSmiValueField::encode(Smi::IsValid(integer_value)) | 2272 HasInt32ValueField::encode(true) | 2273 HasDoubleValueField::encode(true) | 2274 HasExternalReferenceValueField::encode(false) | 2275 IsNotInNewSpaceField::encode(is_not_in_new_space) | 2276 BooleanValueField::encode(integer_value != 0) | 2277 IsUndetectableField::encode(false) | 2278 InstanceTypeField::encode(kUnknownInstanceType)), 2279 int32_value_(integer_value), 2280 double_value_(FastI2D(integer_value)) { 2281 // It's possible to create a constant with a value in Smi-range but stored 2282 // in a (pre-existing) HeapNumber. See crbug.com/349878. 2283 bool could_be_heapobject = r.IsTagged() && !object.handle().is_null(); 2284 bool is_smi = HasSmiValue() && !could_be_heapobject; 2285 set_type(is_smi ? HType::Smi() : HType::TaggedNumber()); 2286 Initialize(r); 2287 } 2288 2289 HConstant::HConstant(double double_value, Representation r, 2290 bool is_not_in_new_space, Unique<Object> object) 2291 : object_(object), 2292 object_map_(Handle<Map>::null()), 2293 bit_field_(HasStableMapValueField::encode(false) | 2294 HasInt32ValueField::encode(IsInteger32(double_value)) | 2295 HasDoubleValueField::encode(true) | 2296 HasExternalReferenceValueField::encode(false) | 2297 IsNotInNewSpaceField::encode(is_not_in_new_space) | 2298 BooleanValueField::encode(double_value != 0 && 2299 !std::isnan(double_value)) | 2300 IsUndetectableField::encode(false) | 2301 InstanceTypeField::encode(kUnknownInstanceType)), 2302 int32_value_(DoubleToInt32(double_value)) { 2303 bit_field_ = HasSmiValueField::update( 2304 bit_field_, HasInteger32Value() && Smi::IsValid(int32_value_)); 2305 // It's possible to create a constant with a value in Smi-range but stored 2306 // in a (pre-existing) HeapNumber. See crbug.com/349878. 2307 bool could_be_heapobject = r.IsTagged() && !object.handle().is_null(); 2308 bool is_smi = HasSmiValue() && !could_be_heapobject; 2309 set_type(is_smi ? HType::Smi() : HType::TaggedNumber()); 2310 if (std::isnan(double_value)) { 2311 double_value_ = std::numeric_limits<double>::quiet_NaN(); 2312 } else { 2313 double_value_ = double_value; 2314 } 2315 Initialize(r); 2316 } 2317 2318 2319 HConstant::HConstant(ExternalReference reference) 2320 : HTemplateInstruction<0>(HType::Any()), 2321 object_(Unique<Object>(Handle<Object>::null())), 2322 object_map_(Handle<Map>::null()), 2323 bit_field_( 2324 HasStableMapValueField::encode(false) | 2325 HasSmiValueField::encode(false) | HasInt32ValueField::encode(false) | 2326 HasDoubleValueField::encode(false) | 2327 HasExternalReferenceValueField::encode(true) | 2328 IsNotInNewSpaceField::encode(true) | BooleanValueField::encode(true) | 2329 IsUndetectableField::encode(false) | 2330 InstanceTypeField::encode(kUnknownInstanceType)), 2331 external_reference_value_(reference) { 2332 Initialize(Representation::External()); 2333 } 2334 2335 2336 void HConstant::Initialize(Representation r) { 2337 if (r.IsNone()) { 2338 if (HasSmiValue() && SmiValuesAre31Bits()) { 2339 r = Representation::Smi(); 2340 } else if (HasInteger32Value()) { 2341 r = Representation::Integer32(); 2342 } else if (HasDoubleValue()) { 2343 r = Representation::Double(); 2344 } else if (HasExternalReferenceValue()) { 2345 r = Representation::External(); 2346 } else { 2347 Handle<Object> object = object_.handle(); 2348 if (object->IsJSObject()) { 2349 // Try to eagerly migrate JSObjects that have deprecated maps. 2350 Handle<JSObject> js_object = Handle<JSObject>::cast(object); 2351 if (js_object->map()->is_deprecated()) { 2352 JSObject::TryMigrateInstance(js_object); 2353 } 2354 } 2355 r = Representation::Tagged(); 2356 } 2357 } 2358 if (r.IsSmi()) { 2359 // If we have an existing handle, zap it, because it might be a heap 2360 // number which we must not re-use when copying this HConstant to 2361 // Tagged representation later, because having Smi representation now 2362 // could cause heap object checks not to get emitted. 2363 object_ = Unique<Object>(Handle<Object>::null()); 2364 } 2365 if (r.IsSmiOrInteger32() && object_.handle().is_null()) { 2366 // If it's not a heap object, it can't be in new space. 2367 bit_field_ = IsNotInNewSpaceField::update(bit_field_, true); 2368 } 2369 set_representation(r); 2370 SetFlag(kUseGVN); 2371 } 2372 2373 2374 bool HConstant::ImmortalImmovable() const { 2375 if (HasInteger32Value()) { 2376 return false; 2377 } 2378 if (HasDoubleValue()) { 2379 if (IsSpecialDouble()) { 2380 return true; 2381 } 2382 return false; 2383 } 2384 if (HasExternalReferenceValue()) { 2385 return false; 2386 } 2387 2388 DCHECK(!object_.handle().is_null()); 2389 Heap* heap = isolate()->heap(); 2390 DCHECK(!object_.IsKnownGlobal(heap->minus_zero_value())); 2391 DCHECK(!object_.IsKnownGlobal(heap->nan_value())); 2392 return 2393 #define IMMORTAL_IMMOVABLE_ROOT(name) \ 2394 object_.IsKnownGlobal(heap->root(Heap::k##name##RootIndex)) || 2395 IMMORTAL_IMMOVABLE_ROOT_LIST(IMMORTAL_IMMOVABLE_ROOT) 2396 #undef IMMORTAL_IMMOVABLE_ROOT 2397 #define INTERNALIZED_STRING(name, value) \ 2398 object_.IsKnownGlobal(heap->name()) || 2399 INTERNALIZED_STRING_LIST(INTERNALIZED_STRING) 2400 #undef INTERNALIZED_STRING 2401 #define STRING_TYPE(NAME, size, name, Name) \ 2402 object_.IsKnownGlobal(heap->name##_map()) || 2403 STRING_TYPE_LIST(STRING_TYPE) 2404 #undef STRING_TYPE 2405 false; 2406 } 2407 2408 2409 bool HConstant::EmitAtUses() { 2410 DCHECK(IsLinked()); 2411 if (block()->graph()->has_osr() && 2412 block()->graph()->IsStandardConstant(this)) { 2413 return true; 2414 } 2415 if (HasNoUses()) return true; 2416 if (IsCell()) return false; 2417 if (representation().IsDouble()) return false; 2418 if (representation().IsExternal()) return false; 2419 return true; 2420 } 2421 2422 2423 HConstant* HConstant::CopyToRepresentation(Representation r, Zone* zone) const { 2424 if (r.IsSmi() && !HasSmiValue()) return NULL; 2425 if (r.IsInteger32() && !HasInteger32Value()) return NULL; 2426 if (r.IsDouble() && !HasDoubleValue()) return NULL; 2427 if (r.IsExternal() && !HasExternalReferenceValue()) return NULL; 2428 if (HasInteger32Value()) { 2429 return new (zone) HConstant(int32_value_, r, NotInNewSpace(), object_); 2430 } 2431 if (HasDoubleValue()) { 2432 return new (zone) HConstant(double_value_, r, NotInNewSpace(), object_); 2433 } 2434 if (HasExternalReferenceValue()) { 2435 return new(zone) HConstant(external_reference_value_); 2436 } 2437 DCHECK(!object_.handle().is_null()); 2438 return new (zone) HConstant(object_, object_map_, HasStableMapValue(), r, 2439 type_, NotInNewSpace(), BooleanValue(), 2440 IsUndetectable(), GetInstanceType()); 2441 } 2442 2443 2444 Maybe<HConstant*> HConstant::CopyToTruncatedInt32(Zone* zone) { 2445 HConstant* res = NULL; 2446 if (HasInteger32Value()) { 2447 res = new (zone) HConstant(int32_value_, Representation::Integer32(), 2448 NotInNewSpace(), object_); 2449 } else if (HasDoubleValue()) { 2450 res = new (zone) 2451 HConstant(DoubleToInt32(double_value_), Representation::Integer32(), 2452 NotInNewSpace(), object_); 2453 } 2454 return res != NULL ? Just(res) : Nothing<HConstant*>(); 2455 } 2456 2457 2458 Maybe<HConstant*> HConstant::CopyToTruncatedNumber(Isolate* isolate, 2459 Zone* zone) { 2460 HConstant* res = NULL; 2461 Handle<Object> handle = this->handle(isolate); 2462 if (handle->IsBoolean()) { 2463 res = handle->BooleanValue() ? 2464 new(zone) HConstant(1) : new(zone) HConstant(0); 2465 } else if (handle->IsUndefined(isolate)) { 2466 res = new (zone) HConstant(std::numeric_limits<double>::quiet_NaN()); 2467 } else if (handle->IsNull(isolate)) { 2468 res = new(zone) HConstant(0); 2469 } else if (handle->IsString()) { 2470 res = new(zone) HConstant(String::ToNumber(Handle<String>::cast(handle))); 2471 } 2472 return res != NULL ? Just(res) : Nothing<HConstant*>(); 2473 } 2474 2475 2476 std::ostream& HConstant::PrintDataTo(std::ostream& os) const { // NOLINT 2477 if (HasInteger32Value()) { 2478 os << int32_value_ << " "; 2479 } else if (HasDoubleValue()) { 2480 os << double_value_ << " "; 2481 } else if (HasExternalReferenceValue()) { 2482 os << reinterpret_cast<void*>(external_reference_value_.address()) << " "; 2483 } else { 2484 // The handle() method is silently and lazily mutating the object. 2485 Handle<Object> h = const_cast<HConstant*>(this)->handle(isolate()); 2486 os << Brief(*h) << " "; 2487 if (HasStableMapValue()) os << "[stable-map] "; 2488 if (HasObjectMap()) os << "[map " << *ObjectMap().handle() << "] "; 2489 } 2490 if (!NotInNewSpace()) os << "[new space] "; 2491 return os; 2492 } 2493 2494 2495 std::ostream& HBinaryOperation::PrintDataTo(std::ostream& os) const { // NOLINT 2496 os << NameOf(left()) << " " << NameOf(right()); 2497 if (CheckFlag(kCanOverflow)) os << " !"; 2498 if (CheckFlag(kBailoutOnMinusZero)) os << " -0?"; 2499 return os; 2500 } 2501 2502 2503 void HBinaryOperation::InferRepresentation(HInferRepresentationPhase* h_infer) { 2504 DCHECK(CheckFlag(kFlexibleRepresentation)); 2505 Representation new_rep = RepresentationFromInputs(); 2506 UpdateRepresentation(new_rep, h_infer, "inputs"); 2507 2508 if (representation().IsSmi() && HasNonSmiUse()) { 2509 UpdateRepresentation( 2510 Representation::Integer32(), h_infer, "use requirements"); 2511 } 2512 2513 if (observed_output_representation_.IsNone()) { 2514 new_rep = RepresentationFromUses(); 2515 UpdateRepresentation(new_rep, h_infer, "uses"); 2516 } else { 2517 new_rep = RepresentationFromOutput(); 2518 UpdateRepresentation(new_rep, h_infer, "output"); 2519 } 2520 } 2521 2522 2523 Representation HBinaryOperation::RepresentationFromInputs() { 2524 // Determine the worst case of observed input representations and 2525 // the currently assumed output representation. 2526 Representation rep = representation(); 2527 for (int i = 1; i <= 2; ++i) { 2528 rep = rep.generalize(observed_input_representation(i)); 2529 } 2530 // If any of the actual input representation is more general than what we 2531 // have so far but not Tagged, use that representation instead. 2532 Representation left_rep = left()->representation(); 2533 Representation right_rep = right()->representation(); 2534 if (!left_rep.IsTagged()) rep = rep.generalize(left_rep); 2535 if (!right_rep.IsTagged()) rep = rep.generalize(right_rep); 2536 2537 return rep; 2538 } 2539 2540 2541 bool HBinaryOperation::IgnoreObservedOutputRepresentation( 2542 Representation current_rep) { 2543 return ((current_rep.IsInteger32() && CheckUsesForFlag(kTruncatingToInt32)) || 2544 (current_rep.IsSmi() && CheckUsesForFlag(kTruncatingToSmi))) && 2545 // Mul in Integer32 mode would be too precise. 2546 (!this->IsMul() || HMul::cast(this)->MulMinusOne()); 2547 } 2548 2549 2550 Representation HBinaryOperation::RepresentationFromOutput() { 2551 Representation rep = representation(); 2552 // Consider observed output representation, but ignore it if it's Double, 2553 // this instruction is not a division, and all its uses are truncating 2554 // to Integer32. 2555 if (observed_output_representation_.is_more_general_than(rep) && 2556 !IgnoreObservedOutputRepresentation(rep)) { 2557 return observed_output_representation_; 2558 } 2559 return Representation::None(); 2560 } 2561 2562 2563 void HBinaryOperation::AssumeRepresentation(Representation r) { 2564 set_observed_input_representation(1, r); 2565 set_observed_input_representation(2, r); 2566 HValue::AssumeRepresentation(r); 2567 } 2568 2569 2570 void HMathMinMax::InferRepresentation(HInferRepresentationPhase* h_infer) { 2571 DCHECK(CheckFlag(kFlexibleRepresentation)); 2572 Representation new_rep = RepresentationFromInputs(); 2573 UpdateRepresentation(new_rep, h_infer, "inputs"); 2574 // Do not care about uses. 2575 } 2576 2577 2578 Range* HBitwise::InferRange(Zone* zone) { 2579 if (op() == Token::BIT_XOR) { 2580 if (left()->HasRange() && right()->HasRange()) { 2581 // The maximum value has the high bit, and all bits below, set: 2582 // (1 << high) - 1. 2583 // If the range can be negative, the minimum int is a negative number with 2584 // the high bit, and all bits below, unset: 2585 // -(1 << high). 2586 // If it cannot be negative, conservatively choose 0 as minimum int. 2587 int64_t left_upper = left()->range()->upper(); 2588 int64_t left_lower = left()->range()->lower(); 2589 int64_t right_upper = right()->range()->upper(); 2590 int64_t right_lower = right()->range()->lower(); 2591 2592 if (left_upper < 0) left_upper = ~left_upper; 2593 if (left_lower < 0) left_lower = ~left_lower; 2594 if (right_upper < 0) right_upper = ~right_upper; 2595 if (right_lower < 0) right_lower = ~right_lower; 2596 2597 int high = MostSignificantBit( 2598 static_cast<uint32_t>( 2599 left_upper | left_lower | right_upper | right_lower)); 2600 2601 int64_t limit = 1; 2602 limit <<= high; 2603 int32_t min = (left()->range()->CanBeNegative() || 2604 right()->range()->CanBeNegative()) 2605 ? static_cast<int32_t>(-limit) : 0; 2606 return new(zone) Range(min, static_cast<int32_t>(limit - 1)); 2607 } 2608 Range* result = HValue::InferRange(zone); 2609 result->set_can_be_minus_zero(false); 2610 return result; 2611 } 2612 const int32_t kDefaultMask = static_cast<int32_t>(0xffffffff); 2613 int32_t left_mask = (left()->range() != NULL) 2614 ? left()->range()->Mask() 2615 : kDefaultMask; 2616 int32_t right_mask = (right()->range() != NULL) 2617 ? right()->range()->Mask() 2618 : kDefaultMask; 2619 int32_t result_mask = (op() == Token::BIT_AND) 2620 ? left_mask & right_mask 2621 : left_mask | right_mask; 2622 if (result_mask >= 0) return new(zone) Range(0, result_mask); 2623 2624 Range* result = HValue::InferRange(zone); 2625 result->set_can_be_minus_zero(false); 2626 return result; 2627 } 2628 2629 2630 Range* HSar::InferRange(Zone* zone) { 2631 if (right()->IsConstant()) { 2632 HConstant* c = HConstant::cast(right()); 2633 if (c->HasInteger32Value()) { 2634 Range* result = (left()->range() != NULL) 2635 ? left()->range()->Copy(zone) 2636 : new(zone) Range(); 2637 result->Sar(c->Integer32Value()); 2638 return result; 2639 } 2640 } 2641 return HValue::InferRange(zone); 2642 } 2643 2644 2645 Range* HShr::InferRange(Zone* zone) { 2646 if (right()->IsConstant()) { 2647 HConstant* c = HConstant::cast(right()); 2648 if (c->HasInteger32Value()) { 2649 int shift_count = c->Integer32Value() & 0x1f; 2650 if (left()->range()->CanBeNegative()) { 2651 // Only compute bounds if the result always fits into an int32. 2652 return (shift_count >= 1) 2653 ? new(zone) Range(0, 2654 static_cast<uint32_t>(0xffffffff) >> shift_count) 2655 : new(zone) Range(); 2656 } else { 2657 // For positive inputs we can use the >> operator. 2658 Range* result = (left()->range() != NULL) 2659 ? left()->range()->Copy(zone) 2660 : new(zone) Range(); 2661 result->Sar(c->Integer32Value()); 2662 return result; 2663 } 2664 } 2665 } 2666 return HValue::InferRange(zone); 2667 } 2668 2669 2670 Range* HShl::InferRange(Zone* zone) { 2671 if (right()->IsConstant()) { 2672 HConstant* c = HConstant::cast(right()); 2673 if (c->HasInteger32Value()) { 2674 Range* result = (left()->range() != NULL) 2675 ? left()->range()->Copy(zone) 2676 : new(zone) Range(); 2677 result->Shl(c->Integer32Value()); 2678 return result; 2679 } 2680 } 2681 return HValue::InferRange(zone); 2682 } 2683 2684 2685 Range* HLoadNamedField::InferRange(Zone* zone) { 2686 if (access().representation().IsInteger8()) { 2687 return new(zone) Range(kMinInt8, kMaxInt8); 2688 } 2689 if (access().representation().IsUInteger8()) { 2690 return new(zone) Range(kMinUInt8, kMaxUInt8); 2691 } 2692 if (access().representation().IsInteger16()) { 2693 return new(zone) Range(kMinInt16, kMaxInt16); 2694 } 2695 if (access().representation().IsUInteger16()) { 2696 return new(zone) Range(kMinUInt16, kMaxUInt16); 2697 } 2698 if (access().IsStringLength()) { 2699 return new(zone) Range(0, String::kMaxLength); 2700 } 2701 return HValue::InferRange(zone); 2702 } 2703 2704 2705 Range* HLoadKeyed::InferRange(Zone* zone) { 2706 switch (elements_kind()) { 2707 case INT8_ELEMENTS: 2708 return new(zone) Range(kMinInt8, kMaxInt8); 2709 case UINT8_ELEMENTS: 2710 case UINT8_CLAMPED_ELEMENTS: 2711 return new(zone) Range(kMinUInt8, kMaxUInt8); 2712 case INT16_ELEMENTS: 2713 return new(zone) Range(kMinInt16, kMaxInt16); 2714 case UINT16_ELEMENTS: 2715 return new(zone) Range(kMinUInt16, kMaxUInt16); 2716 default: 2717 return HValue::InferRange(zone); 2718 } 2719 } 2720 2721 2722 std::ostream& HCompareGeneric::PrintDataTo(std::ostream& os) const { // NOLINT 2723 os << Token::Name(token()) << " "; 2724 return HBinaryOperation::PrintDataTo(os); 2725 } 2726 2727 2728 std::ostream& HStringCompareAndBranch::PrintDataTo( 2729 std::ostream& os) const { // NOLINT 2730 os << Token::Name(token()) << " "; 2731 return HControlInstruction::PrintDataTo(os); 2732 } 2733 2734 2735 std::ostream& HCompareNumericAndBranch::PrintDataTo( 2736 std::ostream& os) const { // NOLINT 2737 os << Token::Name(token()) << " " << NameOf(left()) << " " << NameOf(right()); 2738 return HControlInstruction::PrintDataTo(os); 2739 } 2740 2741 2742 std::ostream& HCompareObjectEqAndBranch::PrintDataTo( 2743 std::ostream& os) const { // NOLINT 2744 os << NameOf(left()) << " " << NameOf(right()); 2745 return HControlInstruction::PrintDataTo(os); 2746 } 2747 2748 2749 bool HCompareObjectEqAndBranch::KnownSuccessorBlock(HBasicBlock** block) { 2750 if (known_successor_index() != kNoKnownSuccessorIndex) { 2751 *block = SuccessorAt(known_successor_index()); 2752 return true; 2753 } 2754 if (FLAG_fold_constants && left()->IsConstant() && right()->IsConstant()) { 2755 *block = HConstant::cast(left())->DataEquals(HConstant::cast(right())) 2756 ? FirstSuccessor() : SecondSuccessor(); 2757 return true; 2758 } 2759 *block = NULL; 2760 return false; 2761 } 2762 2763 2764 bool HIsStringAndBranch::KnownSuccessorBlock(HBasicBlock** block) { 2765 if (known_successor_index() != kNoKnownSuccessorIndex) { 2766 *block = SuccessorAt(known_successor_index()); 2767 return true; 2768 } 2769 if (FLAG_fold_constants && value()->IsConstant()) { 2770 *block = HConstant::cast(value())->HasStringValue() 2771 ? FirstSuccessor() : SecondSuccessor(); 2772 return true; 2773 } 2774 if (value()->type().IsString()) { 2775 *block = FirstSuccessor(); 2776 return true; 2777 } 2778 if (value()->type().IsSmi() || 2779 value()->type().IsNull() || 2780 value()->type().IsBoolean() || 2781 value()->type().IsUndefined() || 2782 value()->type().IsJSReceiver()) { 2783 *block = SecondSuccessor(); 2784 return true; 2785 } 2786 *block = NULL; 2787 return false; 2788 } 2789 2790 2791 bool HIsUndetectableAndBranch::KnownSuccessorBlock(HBasicBlock** block) { 2792 if (FLAG_fold_constants && value()->IsConstant()) { 2793 *block = HConstant::cast(value())->IsUndetectable() 2794 ? FirstSuccessor() : SecondSuccessor(); 2795 return true; 2796 } 2797 if (value()->type().IsNull() || value()->type().IsUndefined()) { 2798 *block = FirstSuccessor(); 2799 return true; 2800 } 2801 if (value()->type().IsBoolean() || 2802 value()->type().IsSmi() || 2803 value()->type().IsString() || 2804 value()->type().IsJSReceiver()) { 2805 *block = SecondSuccessor(); 2806 return true; 2807 } 2808 *block = NULL; 2809 return false; 2810 } 2811 2812 2813 bool HHasInstanceTypeAndBranch::KnownSuccessorBlock(HBasicBlock** block) { 2814 if (FLAG_fold_constants && value()->IsConstant()) { 2815 InstanceType type = HConstant::cast(value())->GetInstanceType(); 2816 *block = (from_ <= type) && (type <= to_) 2817 ? FirstSuccessor() : SecondSuccessor(); 2818 return true; 2819 } 2820 *block = NULL; 2821 return false; 2822 } 2823 2824 2825 void HCompareHoleAndBranch::InferRepresentation( 2826 HInferRepresentationPhase* h_infer) { 2827 ChangeRepresentation(value()->representation()); 2828 } 2829 2830 2831 bool HCompareNumericAndBranch::KnownSuccessorBlock(HBasicBlock** block) { 2832 if (left() == right() && 2833 left()->representation().IsSmiOrInteger32()) { 2834 *block = (token() == Token::EQ || 2835 token() == Token::EQ_STRICT || 2836 token() == Token::LTE || 2837 token() == Token::GTE) 2838 ? FirstSuccessor() : SecondSuccessor(); 2839 return true; 2840 } 2841 *block = NULL; 2842 return false; 2843 } 2844 2845 2846 std::ostream& HGoto::PrintDataTo(std::ostream& os) const { // NOLINT 2847 return os << *SuccessorAt(0); 2848 } 2849 2850 2851 void HCompareNumericAndBranch::InferRepresentation( 2852 HInferRepresentationPhase* h_infer) { 2853 Representation left_rep = left()->representation(); 2854 Representation right_rep = right()->representation(); 2855 Representation observed_left = observed_input_representation(0); 2856 Representation observed_right = observed_input_representation(1); 2857 2858 Representation rep = Representation::None(); 2859 rep = rep.generalize(observed_left); 2860 rep = rep.generalize(observed_right); 2861 if (rep.IsNone() || rep.IsSmiOrInteger32()) { 2862 if (!left_rep.IsTagged()) rep = rep.generalize(left_rep); 2863 if (!right_rep.IsTagged()) rep = rep.generalize(right_rep); 2864 } else { 2865 rep = Representation::Double(); 2866 } 2867 2868 if (rep.IsDouble()) { 2869 // According to the ES5 spec (11.9.3, 11.8.5), Equality comparisons (==, === 2870 // and !=) have special handling of undefined, e.g. undefined == undefined 2871 // is 'true'. Relational comparisons have a different semantic, first 2872 // calling ToPrimitive() on their arguments. The standard Crankshaft 2873 // tagged-to-double conversion to ensure the HCompareNumericAndBranch's 2874 // inputs are doubles caused 'undefined' to be converted to NaN. That's 2875 // compatible out-of-the box with ordered relational comparisons (<, >, <=, 2876 // >=). However, for equality comparisons (and for 'in' and 'instanceof'), 2877 // it is not consistent with the spec. For example, it would cause undefined 2878 // == undefined (should be true) to be evaluated as NaN == NaN 2879 // (false). Therefore, any comparisons other than ordered relational 2880 // comparisons must cause a deopt when one of their arguments is undefined. 2881 // See also v8:1434 2882 if (Token::IsOrderedRelationalCompareOp(token_)) { 2883 SetFlag(kTruncatingToNumber); 2884 } 2885 } 2886 ChangeRepresentation(rep); 2887 } 2888 2889 2890 std::ostream& HParameter::PrintDataTo(std::ostream& os) const { // NOLINT 2891 return os << index(); 2892 } 2893 2894 2895 std::ostream& HLoadNamedField::PrintDataTo(std::ostream& os) const { // NOLINT 2896 os << NameOf(object()) << access_; 2897 2898 if (maps() != NULL) { 2899 os << " [" << *maps()->at(0).handle(); 2900 for (int i = 1; i < maps()->size(); ++i) { 2901 os << "," << *maps()->at(i).handle(); 2902 } 2903 os << "]"; 2904 } 2905 2906 if (HasDependency()) os << " " << NameOf(dependency()); 2907 return os; 2908 } 2909 2910 2911 std::ostream& HLoadKeyed::PrintDataTo(std::ostream& os) const { // NOLINT 2912 if (!is_fixed_typed_array()) { 2913 os << NameOf(elements()); 2914 } else { 2915 DCHECK(elements_kind() >= FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND && 2916 elements_kind() <= LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND); 2917 os << NameOf(elements()) << "." << ElementsKindToString(elements_kind()); 2918 } 2919 2920 os << "[" << NameOf(key()); 2921 if (IsDehoisted()) os << " + " << base_offset(); 2922 os << "]"; 2923 2924 if (HasDependency()) os << " " << NameOf(dependency()); 2925 if (RequiresHoleCheck()) os << " check_hole"; 2926 return os; 2927 } 2928 2929 2930 bool HLoadKeyed::TryIncreaseBaseOffset(uint32_t increase_by_value) { 2931 // The base offset is usually simply the size of the array header, except 2932 // with dehoisting adds an addition offset due to a array index key 2933 // manipulation, in which case it becomes (array header size + 2934 // constant-offset-from-key * kPointerSize) 2935 uint32_t base_offset = BaseOffsetField::decode(bit_field_); 2936 v8::base::internal::CheckedNumeric<uint32_t> addition_result = base_offset; 2937 addition_result += increase_by_value; 2938 if (!addition_result.IsValid()) return false; 2939 base_offset = addition_result.ValueOrDie(); 2940 if (!BaseOffsetField::is_valid(base_offset)) return false; 2941 bit_field_ = BaseOffsetField::update(bit_field_, base_offset); 2942 return true; 2943 } 2944 2945 2946 bool HLoadKeyed::UsesMustHandleHole() const { 2947 if (IsFastPackedElementsKind(elements_kind())) { 2948 return false; 2949 } 2950 2951 if (IsFixedTypedArrayElementsKind(elements_kind())) { 2952 return false; 2953 } 2954 2955 if (hole_mode() == ALLOW_RETURN_HOLE) { 2956 if (IsFastDoubleElementsKind(elements_kind())) { 2957 return AllUsesCanTreatHoleAsNaN(); 2958 } 2959 return true; 2960 } 2961 2962 if (IsFastDoubleElementsKind(elements_kind())) { 2963 return false; 2964 } 2965 2966 // Holes are only returned as tagged values. 2967 if (!representation().IsTagged()) { 2968 return false; 2969 } 2970 2971 for (HUseIterator it(uses()); !it.Done(); it.Advance()) { 2972 HValue* use = it.value(); 2973 if (!use->IsChange()) return false; 2974 } 2975 2976 return true; 2977 } 2978 2979 2980 bool HLoadKeyed::AllUsesCanTreatHoleAsNaN() const { 2981 return IsFastDoubleElementsKind(elements_kind()) && 2982 CheckUsesForFlag(HValue::kTruncatingToNumber); 2983 } 2984 2985 2986 bool HLoadKeyed::RequiresHoleCheck() const { 2987 if (IsFastPackedElementsKind(elements_kind())) { 2988 return false; 2989 } 2990 2991 if (IsFixedTypedArrayElementsKind(elements_kind())) { 2992 return false; 2993 } 2994 2995 if (hole_mode() == CONVERT_HOLE_TO_UNDEFINED) { 2996 return false; 2997 } 2998 2999 return !UsesMustHandleHole(); 3000 } 3001 3002 HValue* HCallWithDescriptor::Canonicalize() { 3003 if (kind() != Code::KEYED_LOAD_IC) return this; 3004 3005 // Recognize generic keyed loads that use property name generated 3006 // by for-in statement as a key and rewrite them into fast property load 3007 // by index. 3008 typedef LoadWithVectorDescriptor Descriptor; 3009 HValue* key = parameter(Descriptor::kName); 3010 if (key->IsLoadKeyed()) { 3011 HLoadKeyed* key_load = HLoadKeyed::cast(key); 3012 if (key_load->elements()->IsForInCacheArray()) { 3013 HForInCacheArray* names_cache = 3014 HForInCacheArray::cast(key_load->elements()); 3015 3016 HValue* object = parameter(Descriptor::kReceiver); 3017 if (names_cache->enumerable() == object) { 3018 HForInCacheArray* index_cache = 3019 names_cache->index_cache(); 3020 HCheckMapValue* map_check = HCheckMapValue::New( 3021 block()->graph()->isolate(), block()->graph()->zone(), 3022 block()->graph()->GetInvalidContext(), object, names_cache->map()); 3023 HInstruction* index = HLoadKeyed::New( 3024 block()->graph()->isolate(), block()->graph()->zone(), 3025 block()->graph()->GetInvalidContext(), index_cache, key_load->key(), 3026 key_load->key(), nullptr, key_load->elements_kind()); 3027 map_check->InsertBefore(this); 3028 index->InsertBefore(this); 3029 return Prepend(new (block()->zone()) HLoadFieldByIndex(object, index)); 3030 } 3031 } 3032 } 3033 return this; 3034 } 3035 3036 std::ostream& HStoreNamedField::PrintDataTo(std::ostream& os) const { // NOLINT 3037 os << NameOf(object()) << access_ << " = " << NameOf(value()); 3038 if (NeedsWriteBarrier()) os << " (write-barrier)"; 3039 if (has_transition()) os << " (transition map " << *transition_map() << ")"; 3040 return os; 3041 } 3042 3043 3044 std::ostream& HStoreKeyed::PrintDataTo(std::ostream& os) const { // NOLINT 3045 if (!is_fixed_typed_array()) { 3046 os << NameOf(elements()); 3047 } else { 3048 DCHECK(elements_kind() >= FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND && 3049 elements_kind() <= LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND); 3050 os << NameOf(elements()) << "." << ElementsKindToString(elements_kind()); 3051 } 3052 3053 os << "[" << NameOf(key()); 3054 if (IsDehoisted()) os << " + " << base_offset(); 3055 return os << "] = " << NameOf(value()); 3056 } 3057 3058 3059 std::ostream& HTransitionElementsKind::PrintDataTo( 3060 std::ostream& os) const { // NOLINT 3061 os << NameOf(object()); 3062 ElementsKind from_kind = original_map().handle()->elements_kind(); 3063 ElementsKind to_kind = transitioned_map().handle()->elements_kind(); 3064 os << " " << *original_map().handle() << " [" 3065 << ElementsAccessor::ForKind(from_kind)->name() << "] -> " 3066 << *transitioned_map().handle() << " [" 3067 << ElementsAccessor::ForKind(to_kind)->name() << "]"; 3068 if (IsSimpleMapChangeTransition(from_kind, to_kind)) os << " (simple)"; 3069 return os; 3070 } 3071 3072 3073 std::ostream& HInnerAllocatedObject::PrintDataTo( 3074 std::ostream& os) const { // NOLINT 3075 os << NameOf(base_object()) << " offset "; 3076 return offset()->PrintTo(os); 3077 } 3078 3079 3080 std::ostream& HLoadContextSlot::PrintDataTo(std::ostream& os) const { // NOLINT 3081 return os << NameOf(value()) << "[" << slot_index() << "]"; 3082 } 3083 3084 3085 std::ostream& HStoreContextSlot::PrintDataTo( 3086 std::ostream& os) const { // NOLINT 3087 return os << NameOf(context()) << "[" << slot_index() 3088 << "] = " << NameOf(value()); 3089 } 3090 3091 3092 // Implementation of type inference and type conversions. Calculates 3093 // the inferred type of this instruction based on the input operands. 3094 3095 HType HValue::CalculateInferredType() { 3096 return type_; 3097 } 3098 3099 3100 HType HPhi::CalculateInferredType() { 3101 if (OperandCount() == 0) return HType::Tagged(); 3102 HType result = OperandAt(0)->type(); 3103 for (int i = 1; i < OperandCount(); ++i) { 3104 HType current = OperandAt(i)->type(); 3105 result = result.Combine(current); 3106 } 3107 return result; 3108 } 3109 3110 3111 HType HChange::CalculateInferredType() { 3112 if (from().IsDouble() && to().IsTagged()) return HType::HeapNumber(); 3113 return type(); 3114 } 3115 3116 3117 Representation HUnaryMathOperation::RepresentationFromInputs() { 3118 if (SupportsFlexibleFloorAndRound() && 3119 (op_ == kMathFloor || op_ == kMathRound)) { 3120 // Floor and Round always take a double input. The integral result can be 3121 // used as an integer or a double. Infer the representation from the uses. 3122 return Representation::None(); 3123 } 3124 Representation rep = representation(); 3125 // If any of the actual input representation is more general than what we 3126 // have so far but not Tagged, use that representation instead. 3127 Representation input_rep = value()->representation(); 3128 if (!input_rep.IsTagged()) { 3129 rep = rep.generalize(input_rep); 3130 } 3131 return rep; 3132 } 3133 3134 3135 bool HAllocate::HandleSideEffectDominator(GVNFlag side_effect, 3136 HValue* dominator) { 3137 DCHECK(side_effect == kNewSpacePromotion); 3138 DCHECK(!IsAllocationFolded()); 3139 Zone* zone = block()->zone(); 3140 Isolate* isolate = block()->isolate(); 3141 if (!FLAG_use_allocation_folding) return false; 3142 3143 // Try to fold allocations together with their dominating allocations. 3144 if (!dominator->IsAllocate()) { 3145 if (FLAG_trace_allocation_folding) { 3146 PrintF("#%d (%s) cannot fold into #%d (%s)\n", 3147 id(), Mnemonic(), dominator->id(), dominator->Mnemonic()); 3148 } 3149 return false; 3150 } 3151 3152 // Check whether we are folding within the same block for local folding. 3153 if (FLAG_use_local_allocation_folding && dominator->block() != block()) { 3154 if (FLAG_trace_allocation_folding) { 3155 PrintF("#%d (%s) cannot fold into #%d (%s), crosses basic blocks\n", 3156 id(), Mnemonic(), dominator->id(), dominator->Mnemonic()); 3157 } 3158 return false; 3159 } 3160 3161 HAllocate* dominator_allocate = HAllocate::cast(dominator); 3162 HValue* dominator_size = dominator_allocate->size(); 3163 HValue* current_size = size(); 3164 3165 // TODO(hpayer): Add support for non-constant allocation in dominator. 3166 if (!current_size->IsInteger32Constant() || 3167 !dominator_size->IsInteger32Constant()) { 3168 if (FLAG_trace_allocation_folding) { 3169 PrintF("#%d (%s) cannot fold into #%d (%s), " 3170 "dynamic allocation size in dominator\n", 3171 id(), Mnemonic(), dominator->id(), dominator->Mnemonic()); 3172 } 3173 return false; 3174 } 3175 3176 if (IsAllocationFoldingDominator()) { 3177 if (FLAG_trace_allocation_folding) { 3178 PrintF("#%d (%s) cannot fold into #%d (%s), already dominator\n", id(), 3179 Mnemonic(), dominator->id(), dominator->Mnemonic()); 3180 } 3181 return false; 3182 } 3183 3184 if (!IsFoldable(dominator_allocate)) { 3185 if (FLAG_trace_allocation_folding) { 3186 PrintF("#%d (%s) cannot fold into #%d (%s), different spaces\n", id(), 3187 Mnemonic(), dominator->id(), dominator->Mnemonic()); 3188 } 3189 return false; 3190 } 3191 3192 DCHECK( 3193 (IsNewSpaceAllocation() && dominator_allocate->IsNewSpaceAllocation()) || 3194 (IsOldSpaceAllocation() && dominator_allocate->IsOldSpaceAllocation())); 3195 3196 // First update the size of the dominator allocate instruction. 3197 dominator_size = dominator_allocate->size(); 3198 int32_t original_object_size = 3199 HConstant::cast(dominator_size)->GetInteger32Constant(); 3200 int32_t dominator_size_constant = original_object_size; 3201 3202 if (MustAllocateDoubleAligned()) { 3203 if ((dominator_size_constant & kDoubleAlignmentMask) != 0) { 3204 dominator_size_constant += kDoubleSize / 2; 3205 } 3206 } 3207 3208 int32_t current_size_max_value = size()->GetInteger32Constant(); 3209 int32_t new_dominator_size = dominator_size_constant + current_size_max_value; 3210 3211 // Since we clear the first word after folded memory, we cannot use the 3212 // whole kMaxRegularHeapObjectSize memory. 3213 if (new_dominator_size > kMaxRegularHeapObjectSize - kPointerSize) { 3214 if (FLAG_trace_allocation_folding) { 3215 PrintF("#%d (%s) cannot fold into #%d (%s) due to size: %d\n", 3216 id(), Mnemonic(), dominator_allocate->id(), 3217 dominator_allocate->Mnemonic(), new_dominator_size); 3218 } 3219 return false; 3220 } 3221 3222 HInstruction* new_dominator_size_value = HConstant::CreateAndInsertBefore( 3223 isolate, zone, context(), new_dominator_size, Representation::None(), 3224 dominator_allocate); 3225 3226 dominator_allocate->UpdateSize(new_dominator_size_value); 3227 3228 if (MustAllocateDoubleAligned()) { 3229 if (!dominator_allocate->MustAllocateDoubleAligned()) { 3230 dominator_allocate->MakeDoubleAligned(); 3231 } 3232 } 3233 3234 if (!dominator_allocate->IsAllocationFoldingDominator()) { 3235 HAllocate* first_alloc = 3236 HAllocate::New(isolate, zone, dominator_allocate->context(), 3237 dominator_size, dominator_allocate->type(), 3238 IsNewSpaceAllocation() ? NOT_TENURED : TENURED, 3239 JS_OBJECT_TYPE, block()->graph()->GetConstant0()); 3240 first_alloc->InsertAfter(dominator_allocate); 3241 dominator_allocate->ReplaceAllUsesWith(first_alloc); 3242 dominator_allocate->MakeAllocationFoldingDominator(); 3243 first_alloc->MakeFoldedAllocation(dominator_allocate); 3244 if (FLAG_trace_allocation_folding) { 3245 PrintF("#%d (%s) inserted for dominator #%d (%s)\n", first_alloc->id(), 3246 first_alloc->Mnemonic(), dominator_allocate->id(), 3247 dominator_allocate->Mnemonic()); 3248 } 3249 } 3250 3251 MakeFoldedAllocation(dominator_allocate); 3252 3253 if (FLAG_trace_allocation_folding) { 3254 PrintF("#%d (%s) folded into #%d (%s), new dominator size: %d\n", id(), 3255 Mnemonic(), dominator_allocate->id(), dominator_allocate->Mnemonic(), 3256 new_dominator_size); 3257 } 3258 return true; 3259 } 3260 3261 3262 std::ostream& HAllocate::PrintDataTo(std::ostream& os) const { // NOLINT 3263 os << NameOf(size()) << " ("; 3264 if (IsNewSpaceAllocation()) os << "N"; 3265 if (IsOldSpaceAllocation()) os << "P"; 3266 if (MustAllocateDoubleAligned()) os << "A"; 3267 if (MustPrefillWithFiller()) os << "F"; 3268 if (IsAllocationFoldingDominator()) os << "d"; 3269 if (IsAllocationFolded()) os << "f"; 3270 return os << ")"; 3271 } 3272 3273 3274 bool HStoreKeyed::TryIncreaseBaseOffset(uint32_t increase_by_value) { 3275 // The base offset is usually simply the size of the array header, except 3276 // with dehoisting adds an addition offset due to a array index key 3277 // manipulation, in which case it becomes (array header size + 3278 // constant-offset-from-key * kPointerSize) 3279 v8::base::internal::CheckedNumeric<uint32_t> addition_result = base_offset_; 3280 addition_result += increase_by_value; 3281 if (!addition_result.IsValid()) return false; 3282 base_offset_ = addition_result.ValueOrDie(); 3283 return true; 3284 } 3285 3286 3287 bool HStoreKeyed::NeedsCanonicalization() { 3288 switch (value()->opcode()) { 3289 case kLoadKeyed: { 3290 ElementsKind load_kind = HLoadKeyed::cast(value())->elements_kind(); 3291 return IsFixedFloatElementsKind(load_kind); 3292 } 3293 case kChange: { 3294 Representation from = HChange::cast(value())->from(); 3295 return from.IsTagged() || from.IsHeapObject(); 3296 } 3297 case kConstant: 3298 // Double constants are canonicalized upon construction. 3299 return false; 3300 default: 3301 return !value()->IsBinaryOperation(); 3302 } 3303 } 3304 3305 3306 #define H_CONSTANT_INT(val) \ 3307 HConstant::New(isolate, zone, context, static_cast<int32_t>(val)) 3308 #define H_CONSTANT_DOUBLE(val) \ 3309 HConstant::New(isolate, zone, context, static_cast<double>(val)) 3310 3311 #define DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR(HInstr, op) \ 3312 HInstruction* HInstr::New(Isolate* isolate, Zone* zone, HValue* context, \ 3313 HValue* left, HValue* right) { \ 3314 if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { \ 3315 HConstant* c_left = HConstant::cast(left); \ 3316 HConstant* c_right = HConstant::cast(right); \ 3317 if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { \ 3318 double double_res = c_left->DoubleValue() op c_right->DoubleValue(); \ 3319 if (IsInt32Double(double_res)) { \ 3320 return H_CONSTANT_INT(double_res); \ 3321 } \ 3322 return H_CONSTANT_DOUBLE(double_res); \ 3323 } \ 3324 } \ 3325 return new (zone) HInstr(context, left, right); \ 3326 } 3327 3328 DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR(HAdd, +) 3329 DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR(HMul, *) 3330 DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR(HSub, -) 3331 3332 #undef DEFINE_NEW_H_SIMPLE_ARITHMETIC_INSTR 3333 3334 3335 HInstruction* HStringAdd::New(Isolate* isolate, Zone* zone, HValue* context, 3336 HValue* left, HValue* right, 3337 PretenureFlag pretenure_flag, 3338 StringAddFlags flags, 3339 Handle<AllocationSite> allocation_site) { 3340 if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { 3341 HConstant* c_right = HConstant::cast(right); 3342 HConstant* c_left = HConstant::cast(left); 3343 if (c_left->HasStringValue() && c_right->HasStringValue()) { 3344 Handle<String> left_string = c_left->StringValue(); 3345 Handle<String> right_string = c_right->StringValue(); 3346 // Prevent possible exception by invalid string length. 3347 if (left_string->length() + right_string->length() < String::kMaxLength) { 3348 MaybeHandle<String> concat = isolate->factory()->NewConsString( 3349 c_left->StringValue(), c_right->StringValue()); 3350 return HConstant::New(isolate, zone, context, concat.ToHandleChecked()); 3351 } 3352 } 3353 } 3354 return new (zone) 3355 HStringAdd(context, left, right, pretenure_flag, flags, allocation_site); 3356 } 3357 3358 3359 std::ostream& HStringAdd::PrintDataTo(std::ostream& os) const { // NOLINT 3360 if ((flags() & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_BOTH) { 3361 os << "_CheckBoth"; 3362 } else if ((flags() & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_LEFT) { 3363 os << "_CheckLeft"; 3364 } else if ((flags() & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_RIGHT) { 3365 os << "_CheckRight"; 3366 } 3367 HBinaryOperation::PrintDataTo(os); 3368 os << " ("; 3369 if (pretenure_flag() == NOT_TENURED) 3370 os << "N"; 3371 else if (pretenure_flag() == TENURED) 3372 os << "D"; 3373 return os << ")"; 3374 } 3375 3376 3377 HInstruction* HStringCharFromCode::New(Isolate* isolate, Zone* zone, 3378 HValue* context, HValue* char_code) { 3379 if (FLAG_fold_constants && char_code->IsConstant()) { 3380 HConstant* c_code = HConstant::cast(char_code); 3381 if (c_code->HasNumberValue()) { 3382 if (std::isfinite(c_code->DoubleValue())) { 3383 uint32_t code = c_code->NumberValueAsInteger32() & 0xffff; 3384 return HConstant::New( 3385 isolate, zone, context, 3386 isolate->factory()->LookupSingleCharacterStringFromCode(code)); 3387 } 3388 return HConstant::New(isolate, zone, context, 3389 isolate->factory()->empty_string()); 3390 } 3391 } 3392 return new(zone) HStringCharFromCode(context, char_code); 3393 } 3394 3395 3396 HInstruction* HUnaryMathOperation::New(Isolate* isolate, Zone* zone, 3397 HValue* context, HValue* value, 3398 BuiltinFunctionId op) { 3399 do { 3400 if (!FLAG_fold_constants) break; 3401 if (!value->IsConstant()) break; 3402 HConstant* constant = HConstant::cast(value); 3403 if (!constant->HasNumberValue()) break; 3404 double d = constant->DoubleValue(); 3405 if (std::isnan(d)) { // NaN poisons everything. 3406 return H_CONSTANT_DOUBLE(std::numeric_limits<double>::quiet_NaN()); 3407 } 3408 if (std::isinf(d)) { // +Infinity and -Infinity. 3409 switch (op) { 3410 case kMathCos: 3411 case kMathSin: 3412 return H_CONSTANT_DOUBLE(std::numeric_limits<double>::quiet_NaN()); 3413 case kMathExp: 3414 return H_CONSTANT_DOUBLE((d > 0.0) ? d : 0.0); 3415 case kMathLog: 3416 case kMathSqrt: 3417 return H_CONSTANT_DOUBLE( 3418 (d > 0.0) ? d : std::numeric_limits<double>::quiet_NaN()); 3419 case kMathPowHalf: 3420 case kMathAbs: 3421 return H_CONSTANT_DOUBLE((d > 0.0) ? d : -d); 3422 case kMathRound: 3423 case kMathFround: 3424 case kMathFloor: 3425 return H_CONSTANT_DOUBLE(d); 3426 case kMathClz32: 3427 return H_CONSTANT_INT(32); 3428 default: 3429 UNREACHABLE(); 3430 break; 3431 } 3432 } 3433 switch (op) { 3434 case kMathCos: 3435 return H_CONSTANT_DOUBLE(base::ieee754::cos(d)); 3436 case kMathExp: 3437 return H_CONSTANT_DOUBLE(base::ieee754::exp(d)); 3438 case kMathLog: 3439 return H_CONSTANT_DOUBLE(base::ieee754::log(d)); 3440 case kMathSin: 3441 return H_CONSTANT_DOUBLE(base::ieee754::sin(d)); 3442 case kMathSqrt: 3443 lazily_initialize_fast_sqrt(isolate); 3444 return H_CONSTANT_DOUBLE(fast_sqrt(d, isolate)); 3445 case kMathPowHalf: 3446 return H_CONSTANT_DOUBLE(power_double_double(d, 0.5)); 3447 case kMathAbs: 3448 return H_CONSTANT_DOUBLE((d >= 0.0) ? d + 0.0 : -d); 3449 case kMathRound: 3450 // -0.5 .. -0.0 round to -0.0. 3451 if ((d >= -0.5 && Double(d).Sign() < 0)) return H_CONSTANT_DOUBLE(-0.0); 3452 // Doubles are represented as Significant * 2 ^ Exponent. If the 3453 // Exponent is not negative, the double value is already an integer. 3454 if (Double(d).Exponent() >= 0) return H_CONSTANT_DOUBLE(d); 3455 return H_CONSTANT_DOUBLE(Floor(d + 0.5)); 3456 case kMathFround: 3457 return H_CONSTANT_DOUBLE(static_cast<double>(static_cast<float>(d))); 3458 case kMathFloor: 3459 return H_CONSTANT_DOUBLE(Floor(d)); 3460 case kMathClz32: { 3461 uint32_t i = DoubleToUint32(d); 3462 return H_CONSTANT_INT(base::bits::CountLeadingZeros32(i)); 3463 } 3464 default: 3465 UNREACHABLE(); 3466 break; 3467 } 3468 } while (false); 3469 return new(zone) HUnaryMathOperation(context, value, op); 3470 } 3471 3472 3473 Representation HUnaryMathOperation::RepresentationFromUses() { 3474 if (op_ != kMathFloor && op_ != kMathRound) { 3475 return HValue::RepresentationFromUses(); 3476 } 3477 3478 // The instruction can have an int32 or double output. Prefer a double 3479 // representation if there are double uses. 3480 bool use_double = false; 3481 3482 for (HUseIterator it(uses()); !it.Done(); it.Advance()) { 3483 HValue* use = it.value(); 3484 int use_index = it.index(); 3485 Representation rep_observed = use->observed_input_representation(use_index); 3486 Representation rep_required = use->RequiredInputRepresentation(use_index); 3487 use_double |= (rep_observed.IsDouble() || rep_required.IsDouble()); 3488 if (use_double && !FLAG_trace_representation) { 3489 // Having seen one double is enough. 3490 break; 3491 } 3492 if (FLAG_trace_representation) { 3493 if (!rep_required.IsDouble() || rep_observed.IsDouble()) { 3494 PrintF("#%d %s is used by #%d %s as %s%s\n", 3495 id(), Mnemonic(), use->id(), 3496 use->Mnemonic(), rep_observed.Mnemonic(), 3497 (use->CheckFlag(kTruncatingToInt32) ? "-trunc" : "")); 3498 } else { 3499 PrintF("#%d %s is required by #%d %s as %s%s\n", 3500 id(), Mnemonic(), use->id(), 3501 use->Mnemonic(), rep_required.Mnemonic(), 3502 (use->CheckFlag(kTruncatingToInt32) ? "-trunc" : "")); 3503 } 3504 } 3505 } 3506 return use_double ? Representation::Double() : Representation::Integer32(); 3507 } 3508 3509 3510 HInstruction* HPower::New(Isolate* isolate, Zone* zone, HValue* context, 3511 HValue* left, HValue* right) { 3512 if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { 3513 HConstant* c_left = HConstant::cast(left); 3514 HConstant* c_right = HConstant::cast(right); 3515 if (c_left->HasNumberValue() && c_right->HasNumberValue()) { 3516 double result = 3517 power_helper(isolate, c_left->DoubleValue(), c_right->DoubleValue()); 3518 return H_CONSTANT_DOUBLE(std::isnan(result) 3519 ? std::numeric_limits<double>::quiet_NaN() 3520 : result); 3521 } 3522 } 3523 return new(zone) HPower(left, right); 3524 } 3525 3526 3527 HInstruction* HMathMinMax::New(Isolate* isolate, Zone* zone, HValue* context, 3528 HValue* left, HValue* right, Operation op) { 3529 if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { 3530 HConstant* c_left = HConstant::cast(left); 3531 HConstant* c_right = HConstant::cast(right); 3532 if (c_left->HasNumberValue() && c_right->HasNumberValue()) { 3533 double d_left = c_left->DoubleValue(); 3534 double d_right = c_right->DoubleValue(); 3535 if (op == kMathMin) { 3536 if (d_left > d_right) return H_CONSTANT_DOUBLE(d_right); 3537 if (d_left < d_right) return H_CONSTANT_DOUBLE(d_left); 3538 if (d_left == d_right) { 3539 // Handle +0 and -0. 3540 return H_CONSTANT_DOUBLE((Double(d_left).Sign() == -1) ? d_left 3541 : d_right); 3542 } 3543 } else { 3544 if (d_left < d_right) return H_CONSTANT_DOUBLE(d_right); 3545 if (d_left > d_right) return H_CONSTANT_DOUBLE(d_left); 3546 if (d_left == d_right) { 3547 // Handle +0 and -0. 3548 return H_CONSTANT_DOUBLE((Double(d_left).Sign() == -1) ? d_right 3549 : d_left); 3550 } 3551 } 3552 // All comparisons failed, must be NaN. 3553 return H_CONSTANT_DOUBLE(std::numeric_limits<double>::quiet_NaN()); 3554 } 3555 } 3556 return new(zone) HMathMinMax(context, left, right, op); 3557 } 3558 3559 HInstruction* HMod::New(Isolate* isolate, Zone* zone, HValue* context, 3560 HValue* left, HValue* right) { 3561 if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { 3562 HConstant* c_left = HConstant::cast(left); 3563 HConstant* c_right = HConstant::cast(right); 3564 if (c_left->HasInteger32Value() && c_right->HasInteger32Value()) { 3565 int32_t dividend = c_left->Integer32Value(); 3566 int32_t divisor = c_right->Integer32Value(); 3567 if (dividend == kMinInt && divisor == -1) { 3568 return H_CONSTANT_DOUBLE(-0.0); 3569 } 3570 if (divisor != 0) { 3571 int32_t res = dividend % divisor; 3572 if ((res == 0) && (dividend < 0)) { 3573 return H_CONSTANT_DOUBLE(-0.0); 3574 } 3575 return H_CONSTANT_INT(res); 3576 } 3577 } 3578 } 3579 return new (zone) HMod(context, left, right); 3580 } 3581 3582 HInstruction* HDiv::New(Isolate* isolate, Zone* zone, HValue* context, 3583 HValue* left, HValue* right) { 3584 // If left and right are constant values, try to return a constant value. 3585 if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { 3586 HConstant* c_left = HConstant::cast(left); 3587 HConstant* c_right = HConstant::cast(right); 3588 if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { 3589 if (std::isnan(c_left->DoubleValue()) || 3590 std::isnan(c_right->DoubleValue())) { 3591 return H_CONSTANT_DOUBLE(std::numeric_limits<double>::quiet_NaN()); 3592 } else if (c_right->DoubleValue() != 0) { 3593 double double_res = c_left->DoubleValue() / c_right->DoubleValue(); 3594 if (IsInt32Double(double_res)) { 3595 return H_CONSTANT_INT(double_res); 3596 } 3597 return H_CONSTANT_DOUBLE(double_res); 3598 } else if (c_left->DoubleValue() != 0) { 3599 int sign = Double(c_left->DoubleValue()).Sign() * 3600 Double(c_right->DoubleValue()).Sign(); // Right could be -0. 3601 return H_CONSTANT_DOUBLE(sign * V8_INFINITY); 3602 } else { 3603 return H_CONSTANT_DOUBLE(std::numeric_limits<double>::quiet_NaN()); 3604 } 3605 } 3606 } 3607 return new (zone) HDiv(context, left, right); 3608 } 3609 3610 HInstruction* HBitwise::New(Isolate* isolate, Zone* zone, HValue* context, 3611 Token::Value op, HValue* left, HValue* right) { 3612 if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { 3613 HConstant* c_left = HConstant::cast(left); 3614 HConstant* c_right = HConstant::cast(right); 3615 if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { 3616 int32_t result; 3617 int32_t v_left = c_left->NumberValueAsInteger32(); 3618 int32_t v_right = c_right->NumberValueAsInteger32(); 3619 switch (op) { 3620 case Token::BIT_XOR: 3621 result = v_left ^ v_right; 3622 break; 3623 case Token::BIT_AND: 3624 result = v_left & v_right; 3625 break; 3626 case Token::BIT_OR: 3627 result = v_left | v_right; 3628 break; 3629 default: 3630 result = 0; // Please the compiler. 3631 UNREACHABLE(); 3632 } 3633 return H_CONSTANT_INT(result); 3634 } 3635 } 3636 return new (zone) HBitwise(context, op, left, right); 3637 } 3638 3639 #define DEFINE_NEW_H_BITWISE_INSTR(HInstr, result) \ 3640 HInstruction* HInstr::New(Isolate* isolate, Zone* zone, HValue* context, \ 3641 HValue* left, HValue* right) { \ 3642 if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { \ 3643 HConstant* c_left = HConstant::cast(left); \ 3644 HConstant* c_right = HConstant::cast(right); \ 3645 if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { \ 3646 return H_CONSTANT_INT(result); \ 3647 } \ 3648 } \ 3649 return new (zone) HInstr(context, left, right); \ 3650 } 3651 3652 DEFINE_NEW_H_BITWISE_INSTR(HSar, 3653 c_left->NumberValueAsInteger32() >> (c_right->NumberValueAsInteger32() & 0x1f)) 3654 DEFINE_NEW_H_BITWISE_INSTR(HShl, 3655 c_left->NumberValueAsInteger32() << (c_right->NumberValueAsInteger32() & 0x1f)) 3656 3657 #undef DEFINE_NEW_H_BITWISE_INSTR 3658 3659 HInstruction* HShr::New(Isolate* isolate, Zone* zone, HValue* context, 3660 HValue* left, HValue* right) { 3661 if (FLAG_fold_constants && left->IsConstant() && right->IsConstant()) { 3662 HConstant* c_left = HConstant::cast(left); 3663 HConstant* c_right = HConstant::cast(right); 3664 if ((c_left->HasNumberValue() && c_right->HasNumberValue())) { 3665 int32_t left_val = c_left->NumberValueAsInteger32(); 3666 int32_t right_val = c_right->NumberValueAsInteger32() & 0x1f; 3667 if ((right_val == 0) && (left_val < 0)) { 3668 return H_CONSTANT_DOUBLE(static_cast<uint32_t>(left_val)); 3669 } 3670 return H_CONSTANT_INT(static_cast<uint32_t>(left_val) >> right_val); 3671 } 3672 } 3673 return new (zone) HShr(context, left, right); 3674 } 3675 3676 3677 HInstruction* HSeqStringGetChar::New(Isolate* isolate, Zone* zone, 3678 HValue* context, String::Encoding encoding, 3679 HValue* string, HValue* index) { 3680 if (FLAG_fold_constants && string->IsConstant() && index->IsConstant()) { 3681 HConstant* c_string = HConstant::cast(string); 3682 HConstant* c_index = HConstant::cast(index); 3683 if (c_string->HasStringValue() && c_index->HasInteger32Value()) { 3684 Handle<String> s = c_string->StringValue(); 3685 int32_t i = c_index->Integer32Value(); 3686 DCHECK_LE(0, i); 3687 DCHECK_LT(i, s->length()); 3688 return H_CONSTANT_INT(s->Get(i)); 3689 } 3690 } 3691 return new(zone) HSeqStringGetChar(encoding, string, index); 3692 } 3693 3694 3695 #undef H_CONSTANT_INT 3696 #undef H_CONSTANT_DOUBLE 3697 3698 3699 std::ostream& HBitwise::PrintDataTo(std::ostream& os) const { // NOLINT 3700 os << Token::Name(op_) << " "; 3701 return HBitwiseBinaryOperation::PrintDataTo(os); 3702 } 3703 3704 3705 void HPhi::SimplifyConstantInputs() { 3706 // Convert constant inputs to integers when all uses are truncating. 3707 // This must happen before representation inference takes place. 3708 if (!CheckUsesForFlag(kTruncatingToInt32)) return; 3709 for (int i = 0; i < OperandCount(); ++i) { 3710 if (!OperandAt(i)->IsConstant()) return; 3711 } 3712 HGraph* graph = block()->graph(); 3713 for (int i = 0; i < OperandCount(); ++i) { 3714 HConstant* operand = HConstant::cast(OperandAt(i)); 3715 if (operand->HasInteger32Value()) { 3716 continue; 3717 } else if (operand->HasDoubleValue()) { 3718 HConstant* integer_input = HConstant::New( 3719 graph->isolate(), graph->zone(), graph->GetInvalidContext(), 3720 DoubleToInt32(operand->DoubleValue())); 3721 integer_input->InsertAfter(operand); 3722 SetOperandAt(i, integer_input); 3723 } else if (operand->HasBooleanValue()) { 3724 SetOperandAt(i, operand->BooleanValue() ? graph->GetConstant1() 3725 : graph->GetConstant0()); 3726 } else if (operand->ImmortalImmovable()) { 3727 SetOperandAt(i, graph->GetConstant0()); 3728 } 3729 } 3730 // Overwrite observed input representations because they are likely Tagged. 3731 for (HUseIterator it(uses()); !it.Done(); it.Advance()) { 3732 HValue* use = it.value(); 3733 if (use->IsBinaryOperation()) { 3734 HBinaryOperation::cast(use)->set_observed_input_representation( 3735 it.index(), Representation::Smi()); 3736 } 3737 } 3738 } 3739 3740 3741 void HPhi::InferRepresentation(HInferRepresentationPhase* h_infer) { 3742 DCHECK(CheckFlag(kFlexibleRepresentation)); 3743 Representation new_rep = RepresentationFromUses(); 3744 UpdateRepresentation(new_rep, h_infer, "uses"); 3745 new_rep = RepresentationFromInputs(); 3746 UpdateRepresentation(new_rep, h_infer, "inputs"); 3747 new_rep = RepresentationFromUseRequirements(); 3748 UpdateRepresentation(new_rep, h_infer, "use requirements"); 3749 } 3750 3751 3752 Representation HPhi::RepresentationFromInputs() { 3753 Representation r = representation(); 3754 for (int i = 0; i < OperandCount(); ++i) { 3755 // Ignore conservative Tagged assumption of parameters if we have 3756 // reason to believe that it's too conservative. 3757 if (has_type_feedback_from_uses() && OperandAt(i)->IsParameter()) { 3758 continue; 3759 } 3760 3761 r = r.generalize(OperandAt(i)->KnownOptimalRepresentation()); 3762 } 3763 return r; 3764 } 3765 3766 3767 // Returns a representation if all uses agree on the same representation. 3768 // Integer32 is also returned when some uses are Smi but others are Integer32. 3769 Representation HValue::RepresentationFromUseRequirements() { 3770 Representation rep = Representation::None(); 3771 for (HUseIterator it(uses()); !it.Done(); it.Advance()) { 3772 // Ignore the use requirement from never run code 3773 if (it.value()->block()->IsUnreachable()) continue; 3774 3775 // We check for observed_input_representation elsewhere. 3776 Representation use_rep = 3777 it.value()->RequiredInputRepresentation(it.index()); 3778 if (rep.IsNone()) { 3779 rep = use_rep; 3780 continue; 3781 } 3782 if (use_rep.IsNone() || rep.Equals(use_rep)) continue; 3783 if (rep.generalize(use_rep).IsInteger32()) { 3784 rep = Representation::Integer32(); 3785 continue; 3786 } 3787 return Representation::None(); 3788 } 3789 return rep; 3790 } 3791 3792 3793 bool HValue::HasNonSmiUse() { 3794 for (HUseIterator it(uses()); !it.Done(); it.Advance()) { 3795 // We check for observed_input_representation elsewhere. 3796 Representation use_rep = 3797 it.value()->RequiredInputRepresentation(it.index()); 3798 if (!use_rep.IsNone() && 3799 !use_rep.IsSmi() && 3800 !use_rep.IsTagged()) { 3801 return true; 3802 } 3803 } 3804 return false; 3805 } 3806 3807 3808 // Node-specific verification code is only included in debug mode. 3809 #ifdef DEBUG 3810 3811 void HPhi::Verify() { 3812 DCHECK(OperandCount() == block()->predecessors()->length()); 3813 for (int i = 0; i < OperandCount(); ++i) { 3814 HValue* value = OperandAt(i); 3815 HBasicBlock* defining_block = value->block(); 3816 HBasicBlock* predecessor_block = block()->predecessors()->at(i); 3817 DCHECK(defining_block == predecessor_block || 3818 defining_block->Dominates(predecessor_block)); 3819 } 3820 } 3821 3822 3823 void HSimulate::Verify() { 3824 HInstruction::Verify(); 3825 DCHECK(HasAstId() || next()->IsEnterInlined()); 3826 } 3827 3828 3829 void HCheckHeapObject::Verify() { 3830 HInstruction::Verify(); 3831 DCHECK(HasNoUses()); 3832 } 3833 3834 3835 void HCheckValue::Verify() { 3836 HInstruction::Verify(); 3837 DCHECK(HasNoUses()); 3838 } 3839 3840 #endif 3841 3842 3843 HObjectAccess HObjectAccess::ForFixedArrayHeader(int offset) { 3844 DCHECK(offset >= 0); 3845 DCHECK(offset < FixedArray::kHeaderSize); 3846 if (offset == FixedArray::kLengthOffset) return ForFixedArrayLength(); 3847 return HObjectAccess(kInobject, offset); 3848 } 3849 3850 3851 HObjectAccess HObjectAccess::ForMapAndOffset(Handle<Map> map, int offset, 3852 Representation representation) { 3853 DCHECK(offset >= 0); 3854 Portion portion = kInobject; 3855 3856 if (offset == JSObject::kElementsOffset) { 3857 portion = kElementsPointer; 3858 } else if (offset == JSObject::kMapOffset) { 3859 portion = kMaps; 3860 } 3861 bool existing_inobject_property = true; 3862 if (!map.is_null()) { 3863 existing_inobject_property = (offset < 3864 map->instance_size() - map->unused_property_fields() * kPointerSize); 3865 } 3866 return HObjectAccess(portion, offset, representation, Handle<String>::null(), 3867 false, existing_inobject_property); 3868 } 3869 3870 3871 HObjectAccess HObjectAccess::ForAllocationSiteOffset(int offset) { 3872 switch (offset) { 3873 case AllocationSite::kTransitionInfoOffset: 3874 return HObjectAccess(kInobject, offset, Representation::Tagged()); 3875 case AllocationSite::kNestedSiteOffset: 3876 return HObjectAccess(kInobject, offset, Representation::Tagged()); 3877 case AllocationSite::kPretenureDataOffset: 3878 return HObjectAccess(kInobject, offset, Representation::Smi()); 3879 case AllocationSite::kPretenureCreateCountOffset: 3880 return HObjectAccess(kInobject, offset, Representation::Smi()); 3881 case AllocationSite::kDependentCodeOffset: 3882 return HObjectAccess(kInobject, offset, Representation::Tagged()); 3883 case AllocationSite::kWeakNextOffset: 3884 return HObjectAccess(kInobject, offset, Representation::Tagged()); 3885 default: 3886 UNREACHABLE(); 3887 } 3888 return HObjectAccess(kInobject, offset); 3889 } 3890 3891 3892 HObjectAccess HObjectAccess::ForContextSlot(int index) { 3893 DCHECK(index >= 0); 3894 Portion portion = kInobject; 3895 int offset = Context::kHeaderSize + index * kPointerSize; 3896 DCHECK_EQ(offset, Context::SlotOffset(index) + kHeapObjectTag); 3897 return HObjectAccess(portion, offset, Representation::Tagged()); 3898 } 3899 3900 3901 HObjectAccess HObjectAccess::ForScriptContext(int index) { 3902 DCHECK(index >= 0); 3903 Portion portion = kInobject; 3904 int offset = ScriptContextTable::GetContextOffset(index); 3905 return HObjectAccess(portion, offset, Representation::Tagged()); 3906 } 3907 3908 3909 HObjectAccess HObjectAccess::ForJSArrayOffset(int offset) { 3910 DCHECK(offset >= 0); 3911 Portion portion = kInobject; 3912 3913 if (offset == JSObject::kElementsOffset) { 3914 portion = kElementsPointer; 3915 } else if (offset == JSArray::kLengthOffset) { 3916 portion = kArrayLengths; 3917 } else if (offset == JSObject::kMapOffset) { 3918 portion = kMaps; 3919 } 3920 return HObjectAccess(portion, offset); 3921 } 3922 3923 3924 HObjectAccess HObjectAccess::ForBackingStoreOffset(int offset, 3925 Representation representation) { 3926 DCHECK(offset >= 0); 3927 return HObjectAccess(kBackingStore, offset, representation, 3928 Handle<String>::null(), false, false); 3929 } 3930 3931 3932 HObjectAccess HObjectAccess::ForField(Handle<Map> map, int index, 3933 Representation representation, 3934 Handle<Name> name) { 3935 if (index < 0) { 3936 // Negative property indices are in-object properties, indexed 3937 // from the end of the fixed part of the object. 3938 int offset = (index * kPointerSize) + map->instance_size(); 3939 return HObjectAccess(kInobject, offset, representation, name, false, true); 3940 } else { 3941 // Non-negative property indices are in the properties array. 3942 int offset = (index * kPointerSize) + FixedArray::kHeaderSize; 3943 return HObjectAccess(kBackingStore, offset, representation, name, 3944 false, false); 3945 } 3946 } 3947 3948 3949 void HObjectAccess::SetGVNFlags(HValue *instr, PropertyAccessType access_type) { 3950 // set the appropriate GVN flags for a given load or store instruction 3951 if (access_type == STORE) { 3952 // track dominating allocations in order to eliminate write barriers 3953 instr->SetDependsOnFlag(::v8::internal::kNewSpacePromotion); 3954 instr->SetFlag(HValue::kTrackSideEffectDominators); 3955 } else { 3956 // try to GVN loads, but don't hoist above map changes 3957 instr->SetFlag(HValue::kUseGVN); 3958 instr->SetDependsOnFlag(::v8::internal::kMaps); 3959 } 3960 3961 switch (portion()) { 3962 case kArrayLengths: 3963 if (access_type == STORE) { 3964 instr->SetChangesFlag(::v8::internal::kArrayLengths); 3965 } else { 3966 instr->SetDependsOnFlag(::v8::internal::kArrayLengths); 3967 } 3968 break; 3969 case kStringLengths: 3970 if (access_type == STORE) { 3971 instr->SetChangesFlag(::v8::internal::kStringLengths); 3972 } else { 3973 instr->SetDependsOnFlag(::v8::internal::kStringLengths); 3974 } 3975 break; 3976 case kInobject: 3977 if (access_type == STORE) { 3978 instr->SetChangesFlag(::v8::internal::kInobjectFields); 3979 } else { 3980 instr->SetDependsOnFlag(::v8::internal::kInobjectFields); 3981 } 3982 break; 3983 case kDouble: 3984 if (access_type == STORE) { 3985 instr->SetChangesFlag(::v8::internal::kDoubleFields); 3986 } else { 3987 instr->SetDependsOnFlag(::v8::internal::kDoubleFields); 3988 } 3989 break; 3990 case kBackingStore: 3991 if (access_type == STORE) { 3992 instr->SetChangesFlag(::v8::internal::kBackingStoreFields); 3993 } else { 3994 instr->SetDependsOnFlag(::v8::internal::kBackingStoreFields); 3995 } 3996 break; 3997 case kElementsPointer: 3998 if (access_type == STORE) { 3999 instr->SetChangesFlag(::v8::internal::kElementsPointer); 4000 } else { 4001 instr->SetDependsOnFlag(::v8::internal::kElementsPointer); 4002 } 4003 break; 4004 case kMaps: 4005 if (access_type == STORE) { 4006 instr->SetChangesFlag(::v8::internal::kMaps); 4007 } else { 4008 instr->SetDependsOnFlag(::v8::internal::kMaps); 4009 } 4010 break; 4011 case kExternalMemory: 4012 if (access_type == STORE) { 4013 instr->SetChangesFlag(::v8::internal::kExternalMemory); 4014 } else { 4015 instr->SetDependsOnFlag(::v8::internal::kExternalMemory); 4016 } 4017 break; 4018 } 4019 } 4020 4021 4022 std::ostream& operator<<(std::ostream& os, const HObjectAccess& access) { 4023 os << "."; 4024 4025 switch (access.portion()) { 4026 case HObjectAccess::kArrayLengths: 4027 case HObjectAccess::kStringLengths: 4028 os << "%length"; 4029 break; 4030 case HObjectAccess::kElementsPointer: 4031 os << "%elements"; 4032 break; 4033 case HObjectAccess::kMaps: 4034 os << "%map"; 4035 break; 4036 case HObjectAccess::kDouble: // fall through 4037 case HObjectAccess::kInobject: 4038 if (!access.name().is_null() && access.name()->IsString()) { 4039 os << Handle<String>::cast(access.name())->ToCString().get(); 4040 } 4041 os << "[in-object]"; 4042 break; 4043 case HObjectAccess::kBackingStore: 4044 if (!access.name().is_null() && access.name()->IsString()) { 4045 os << Handle<String>::cast(access.name())->ToCString().get(); 4046 } 4047 os << "[backing-store]"; 4048 break; 4049 case HObjectAccess::kExternalMemory: 4050 os << "[external-memory]"; 4051 break; 4052 } 4053 4054 return os << "@" << access.offset(); 4055 } 4056 4057 } // namespace internal 4058 } // namespace v8 4059