1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #ifndef V8_HYDROGEN_INSTRUCTIONS_H_ 29 #define V8_HYDROGEN_INSTRUCTIONS_H_ 30 31 #include "v8.h" 32 33 #include "allocation.h" 34 #include "code-stubs.h" 35 #include "data-flow.h" 36 #include "deoptimizer.h" 37 #include "small-pointer-list.h" 38 #include "string-stream.h" 39 #include "v8conversions.h" 40 #include "v8utils.h" 41 #include "zone.h" 42 43 namespace v8 { 44 namespace internal { 45 46 // Forward declarations. 47 class HBasicBlock; 48 class HEnvironment; 49 class HInferRepresentationPhase; 50 class HInstruction; 51 class HLoopInformation; 52 class HStoreNamedField; 53 class HValue; 54 class LInstruction; 55 class LChunkBuilder; 56 57 #define HYDROGEN_ABSTRACT_INSTRUCTION_LIST(V) \ 58 V(ArithmeticBinaryOperation) \ 59 V(BinaryOperation) \ 60 V(BitwiseBinaryOperation) \ 61 V(ControlInstruction) \ 62 V(Instruction) \ 63 64 65 #define HYDROGEN_CONCRETE_INSTRUCTION_LIST(V) \ 66 V(AccessArgumentsAt) \ 67 V(Add) \ 68 V(Allocate) \ 69 V(ApplyArguments) \ 70 V(ArgumentsElements) \ 71 V(ArgumentsLength) \ 72 V(ArgumentsObject) \ 73 V(Bitwise) \ 74 V(BlockEntry) \ 75 V(BoundsCheck) \ 76 V(BoundsCheckBaseIndexInformation) \ 77 V(Branch) \ 78 V(CallConstantFunction) \ 79 V(CallFunction) \ 80 V(CallGlobal) \ 81 V(CallKeyed) \ 82 V(CallKnownGlobal) \ 83 V(CallNamed) \ 84 V(CallNew) \ 85 V(CallNewArray) \ 86 V(CallRuntime) \ 87 V(CallStub) \ 88 V(CapturedObject) \ 89 V(Change) \ 90 V(CheckFunction) \ 91 V(CheckHeapObject) \ 92 V(CheckInstanceType) \ 93 V(CheckMaps) \ 94 V(CheckMapValue) \ 95 V(CheckSmi) \ 96 V(ClampToUint8) \ 97 V(ClassOfTestAndBranch) \ 98 V(CompareNumericAndBranch) \ 99 V(CompareHoleAndBranch) \ 100 V(CompareGeneric) \ 101 V(CompareObjectEqAndBranch) \ 102 V(CompareMap) \ 103 V(Constant) \ 104 V(Context) \ 105 V(DateField) \ 106 V(DebugBreak) \ 107 V(DeclareGlobals) \ 108 V(Deoptimize) \ 109 V(Div) \ 110 V(DummyUse) \ 111 V(ElementsKind) \ 112 V(EnterInlined) \ 113 V(EnvironmentMarker) \ 114 V(ForceRepresentation) \ 115 V(ForInCacheArray) \ 116 V(ForInPrepareMap) \ 117 V(FunctionLiteral) \ 118 V(GetCachedArrayIndex) \ 119 V(GlobalObject) \ 120 V(GlobalReceiver) \ 121 V(Goto) \ 122 V(HasCachedArrayIndexAndBranch) \ 123 V(HasInstanceTypeAndBranch) \ 124 V(InnerAllocatedObject) \ 125 V(InstanceOf) \ 126 V(InstanceOfKnownGlobal) \ 127 V(InstanceSize) \ 128 V(InvokeFunction) \ 129 V(IsConstructCallAndBranch) \ 130 V(IsObjectAndBranch) \ 131 V(IsNumberAndBranch) \ 132 V(IsStringAndBranch) \ 133 V(IsSmiAndBranch) \ 134 V(IsUndetectableAndBranch) \ 135 V(LeaveInlined) \ 136 V(LoadContextSlot) \ 137 V(LoadExternalArrayPointer) \ 138 V(LoadFieldByIndex) \ 139 V(LoadFunctionPrototype) \ 140 V(LoadGlobalCell) \ 141 V(LoadGlobalGeneric) \ 142 V(LoadKeyed) \ 143 V(LoadKeyedGeneric) \ 144 V(LoadNamedField) \ 145 V(LoadNamedGeneric) \ 146 V(MapEnumLength) \ 147 V(MathFloorOfDiv) \ 148 V(MathMinMax) \ 149 V(Mod) \ 150 V(Mul) \ 151 V(OsrEntry) \ 152 V(OuterContext) \ 153 V(Parameter) \ 154 V(Power) \ 155 V(PushArgument) \ 156 V(Random) \ 157 V(RegExpLiteral) \ 158 V(Return) \ 159 V(Ror) \ 160 V(Sar) \ 161 V(SeqStringSetChar) \ 162 V(Shl) \ 163 V(Shr) \ 164 V(Simulate) \ 165 V(StackCheck) \ 166 V(StoreContextSlot) \ 167 V(StoreGlobalCell) \ 168 V(StoreGlobalGeneric) \ 169 V(StoreKeyed) \ 170 V(StoreKeyedGeneric) \ 171 V(StoreNamedField) \ 172 V(StoreNamedGeneric) \ 173 V(StringAdd) \ 174 V(StringCharCodeAt) \ 175 V(StringCharFromCode) \ 176 V(StringCompareAndBranch) \ 177 V(Sub) \ 178 V(ThisFunction) \ 179 V(Throw) \ 180 V(ToFastProperties) \ 181 V(TransitionElementsKind) \ 182 V(TrapAllocationMemento) \ 183 V(Typeof) \ 184 V(TypeofIsAndBranch) \ 185 V(UnaryMathOperation) \ 186 V(UnknownOSRValue) \ 187 V(UseConst) \ 188 V(ValueOf) \ 189 V(WrapReceiver) 190 191 #define GVN_TRACKED_FLAG_LIST(V) \ 192 V(Maps) \ 193 V(NewSpacePromotion) 194 195 #define GVN_UNTRACKED_FLAG_LIST(V) \ 196 V(ArrayElements) \ 197 V(ArrayLengths) \ 198 V(StringLengths) \ 199 V(BackingStoreFields) \ 200 V(Calls) \ 201 V(ContextSlots) \ 202 V(DoubleArrayElements) \ 203 V(DoubleFields) \ 204 V(ElementsKind) \ 205 V(ElementsPointer) \ 206 V(GlobalVars) \ 207 V(InobjectFields) \ 208 V(OsrEntries) \ 209 V(ExternalMemory) 210 211 212 #define DECLARE_ABSTRACT_INSTRUCTION(type) \ 213 virtual bool Is##type() const { return true; } \ 214 static H##type* cast(HValue* value) { \ 215 ASSERT(value->Is##type()); \ 216 return reinterpret_cast<H##type*>(value); \ 217 } 218 219 220 #define DECLARE_CONCRETE_INSTRUCTION(type) \ 221 virtual LInstruction* CompileToLithium(LChunkBuilder* builder); \ 222 static H##type* cast(HValue* value) { \ 223 ASSERT(value->Is##type()); \ 224 return reinterpret_cast<H##type*>(value); \ 225 } \ 226 virtual Opcode opcode() const { return HValue::k##type; } 227 228 229 class Range: public ZoneObject { 230 public: 231 Range() 232 : lower_(kMinInt), 233 upper_(kMaxInt), 234 next_(NULL), 235 can_be_minus_zero_(false) { } 236 237 Range(int32_t lower, int32_t upper) 238 : lower_(lower), 239 upper_(upper), 240 next_(NULL), 241 can_be_minus_zero_(false) { } 242 243 int32_t upper() const { return upper_; } 244 int32_t lower() const { return lower_; } 245 Range* next() const { return next_; } 246 Range* CopyClearLower(Zone* zone) const { 247 return new(zone) Range(kMinInt, upper_); 248 } 249 Range* CopyClearUpper(Zone* zone) const { 250 return new(zone) Range(lower_, kMaxInt); 251 } 252 Range* Copy(Zone* zone) const { 253 Range* result = new(zone) Range(lower_, upper_); 254 result->set_can_be_minus_zero(CanBeMinusZero()); 255 return result; 256 } 257 int32_t Mask() const; 258 void set_can_be_minus_zero(bool b) { can_be_minus_zero_ = b; } 259 bool CanBeMinusZero() const { return CanBeZero() && can_be_minus_zero_; } 260 bool CanBeZero() const { return upper_ >= 0 && lower_ <= 0; } 261 bool CanBeNegative() const { return lower_ < 0; } 262 bool CanBePositive() const { return upper_ > 0; } 263 bool Includes(int value) const { return lower_ <= value && upper_ >= value; } 264 bool IsMostGeneric() const { 265 return lower_ == kMinInt && upper_ == kMaxInt && CanBeMinusZero(); 266 } 267 bool IsInSmiRange() const { 268 return lower_ >= Smi::kMinValue && upper_ <= Smi::kMaxValue; 269 } 270 void ClampToSmi() { 271 lower_ = Max(lower_, Smi::kMinValue); 272 upper_ = Min(upper_, Smi::kMaxValue); 273 } 274 void KeepOrder(); 275 #ifdef DEBUG 276 void Verify() const; 277 #endif 278 279 void StackUpon(Range* other) { 280 Intersect(other); 281 next_ = other; 282 } 283 284 void Intersect(Range* other); 285 void Union(Range* other); 286 void CombinedMax(Range* other); 287 void CombinedMin(Range* other); 288 289 void AddConstant(int32_t value); 290 void Sar(int32_t value); 291 void Shl(int32_t value); 292 bool AddAndCheckOverflow(const Representation& r, Range* other); 293 bool SubAndCheckOverflow(const Representation& r, Range* other); 294 bool MulAndCheckOverflow(const Representation& r, Range* other); 295 296 private: 297 int32_t lower_; 298 int32_t upper_; 299 Range* next_; 300 bool can_be_minus_zero_; 301 }; 302 303 304 class UniqueValueId { 305 public: 306 UniqueValueId() : raw_address_(NULL) { } 307 308 explicit UniqueValueId(Object* object) { 309 raw_address_ = reinterpret_cast<Address>(object); 310 ASSERT(IsInitialized()); 311 } 312 313 explicit UniqueValueId(Handle<Object> handle) { 314 static const Address kEmptyHandleSentinel = reinterpret_cast<Address>(1); 315 if (handle.is_null()) { 316 raw_address_ = kEmptyHandleSentinel; 317 } else { 318 raw_address_ = reinterpret_cast<Address>(*handle); 319 ASSERT_NE(kEmptyHandleSentinel, raw_address_); 320 } 321 ASSERT(IsInitialized()); 322 } 323 324 bool IsInitialized() const { return raw_address_ != NULL; } 325 326 bool operator==(const UniqueValueId& other) const { 327 ASSERT(IsInitialized() && other.IsInitialized()); 328 return raw_address_ == other.raw_address_; 329 } 330 331 bool operator!=(const UniqueValueId& other) const { 332 ASSERT(IsInitialized() && other.IsInitialized()); 333 return raw_address_ != other.raw_address_; 334 } 335 336 intptr_t Hashcode() const { 337 ASSERT(IsInitialized()); 338 return reinterpret_cast<intptr_t>(raw_address_); 339 } 340 341 private: 342 Address raw_address_; 343 }; 344 345 346 class HType { 347 public: 348 static HType None() { return HType(kNone); } 349 static HType Tagged() { return HType(kTagged); } 350 static HType TaggedPrimitive() { return HType(kTaggedPrimitive); } 351 static HType TaggedNumber() { return HType(kTaggedNumber); } 352 static HType Smi() { return HType(kSmi); } 353 static HType HeapNumber() { return HType(kHeapNumber); } 354 static HType String() { return HType(kString); } 355 static HType Boolean() { return HType(kBoolean); } 356 static HType NonPrimitive() { return HType(kNonPrimitive); } 357 static HType JSArray() { return HType(kJSArray); } 358 static HType JSObject() { return HType(kJSObject); } 359 360 // Return the weakest (least precise) common type. 361 HType Combine(HType other) { 362 return HType(static_cast<Type>(type_ & other.type_)); 363 } 364 365 bool Equals(const HType& other) const { 366 return type_ == other.type_; 367 } 368 369 bool IsSubtypeOf(const HType& other) { 370 return Combine(other).Equals(other); 371 } 372 373 bool IsTagged() const { 374 return ((type_ & kTagged) == kTagged); 375 } 376 377 bool IsTaggedPrimitive() const { 378 return ((type_ & kTaggedPrimitive) == kTaggedPrimitive); 379 } 380 381 bool IsTaggedNumber() const { 382 return ((type_ & kTaggedNumber) == kTaggedNumber); 383 } 384 385 bool IsSmi() const { 386 return ((type_ & kSmi) == kSmi); 387 } 388 389 bool IsHeapNumber() const { 390 return ((type_ & kHeapNumber) == kHeapNumber); 391 } 392 393 bool IsString() const { 394 return ((type_ & kString) == kString); 395 } 396 397 bool IsNonString() const { 398 return IsTaggedPrimitive() || IsSmi() || IsHeapNumber() || 399 IsBoolean() || IsJSArray(); 400 } 401 402 bool IsBoolean() const { 403 return ((type_ & kBoolean) == kBoolean); 404 } 405 406 bool IsNonPrimitive() const { 407 return ((type_ & kNonPrimitive) == kNonPrimitive); 408 } 409 410 bool IsJSArray() const { 411 return ((type_ & kJSArray) == kJSArray); 412 } 413 414 bool IsJSObject() const { 415 return ((type_ & kJSObject) == kJSObject); 416 } 417 418 bool IsHeapObject() const { 419 return IsHeapNumber() || IsString() || IsBoolean() || IsNonPrimitive(); 420 } 421 422 bool ToStringOrToNumberCanBeObserved(Representation representation) { 423 switch (type_) { 424 case kTaggedPrimitive: // fallthru 425 case kTaggedNumber: // fallthru 426 case kSmi: // fallthru 427 case kHeapNumber: // fallthru 428 case kString: // fallthru 429 case kBoolean: 430 return false; 431 case kJSArray: // fallthru 432 case kJSObject: 433 return true; 434 case kTagged: 435 break; 436 } 437 return !representation.IsSmiOrInteger32() && !representation.IsDouble(); 438 } 439 440 static HType TypeFromValue(Handle<Object> value); 441 442 const char* ToString(); 443 444 private: 445 enum Type { 446 kNone = 0x0, // 0000 0000 0000 0000 447 kTagged = 0x1, // 0000 0000 0000 0001 448 kTaggedPrimitive = 0x5, // 0000 0000 0000 0101 449 kTaggedNumber = 0xd, // 0000 0000 0000 1101 450 kSmi = 0x1d, // 0000 0000 0001 1101 451 kHeapNumber = 0x2d, // 0000 0000 0010 1101 452 kString = 0x45, // 0000 0000 0100 0101 453 kBoolean = 0x85, // 0000 0000 1000 0101 454 kNonPrimitive = 0x101, // 0000 0001 0000 0001 455 kJSObject = 0x301, // 0000 0011 0000 0001 456 kJSArray = 0x701 // 0000 0111 0000 0001 457 }; 458 459 // Make sure type fits in int16. 460 STATIC_ASSERT(kJSArray < (1 << (2 * kBitsPerByte))); 461 462 explicit HType(Type t) : type_(t) { } 463 464 int16_t type_; 465 }; 466 467 468 class HUseListNode: public ZoneObject { 469 public: 470 HUseListNode(HValue* value, int index, HUseListNode* tail) 471 : tail_(tail), value_(value), index_(index) { 472 } 473 474 HUseListNode* tail(); 475 HValue* value() const { return value_; } 476 int index() const { return index_; } 477 478 void set_tail(HUseListNode* list) { tail_ = list; } 479 480 #ifdef DEBUG 481 void Zap() { 482 tail_ = reinterpret_cast<HUseListNode*>(1); 483 value_ = NULL; 484 index_ = -1; 485 } 486 #endif 487 488 private: 489 HUseListNode* tail_; 490 HValue* value_; 491 int index_; 492 }; 493 494 495 // We reuse use list nodes behind the scenes as uses are added and deleted. 496 // This class is the safe way to iterate uses while deleting them. 497 class HUseIterator BASE_EMBEDDED { 498 public: 499 bool Done() { return current_ == NULL; } 500 void Advance(); 501 502 HValue* value() { 503 ASSERT(!Done()); 504 return value_; 505 } 506 507 int index() { 508 ASSERT(!Done()); 509 return index_; 510 } 511 512 private: 513 explicit HUseIterator(HUseListNode* head); 514 515 HUseListNode* current_; 516 HUseListNode* next_; 517 HValue* value_; 518 int index_; 519 520 friend class HValue; 521 }; 522 523 524 // There must be one corresponding kDepends flag for every kChanges flag and 525 // the order of the kChanges flags must be exactly the same as of the kDepends 526 // flags. All tracked flags should appear before untracked ones. 527 enum GVNFlag { 528 // Declare global value numbering flags. 529 #define DECLARE_FLAG(type) kChanges##type, kDependsOn##type, 530 GVN_TRACKED_FLAG_LIST(DECLARE_FLAG) 531 GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG) 532 #undef DECLARE_FLAG 533 kAfterLastFlag, 534 kLastFlag = kAfterLastFlag - 1, 535 #define COUNT_FLAG(type) + 1 536 kNumberOfTrackedSideEffects = 0 GVN_TRACKED_FLAG_LIST(COUNT_FLAG) 537 #undef COUNT_FLAG 538 }; 539 540 541 class DecompositionResult BASE_EMBEDDED { 542 public: 543 DecompositionResult() : base_(NULL), offset_(0), scale_(0) {} 544 545 HValue* base() { return base_; } 546 int offset() { return offset_; } 547 int scale() { return scale_; } 548 549 bool Apply(HValue* other_base, int other_offset, int other_scale = 0) { 550 if (base_ == NULL) { 551 base_ = other_base; 552 offset_ = other_offset; 553 scale_ = other_scale; 554 return true; 555 } else { 556 if (scale_ == 0) { 557 base_ = other_base; 558 offset_ += other_offset; 559 scale_ = other_scale; 560 return true; 561 } else { 562 return false; 563 } 564 } 565 } 566 567 void SwapValues(HValue** other_base, int* other_offset, int* other_scale) { 568 swap(&base_, other_base); 569 swap(&offset_, other_offset); 570 swap(&scale_, other_scale); 571 } 572 573 private: 574 template <class T> void swap(T* a, T* b) { 575 T c(*a); 576 *a = *b; 577 *b = c; 578 } 579 580 HValue* base_; 581 int offset_; 582 int scale_; 583 }; 584 585 586 typedef EnumSet<GVNFlag> GVNFlagSet; 587 588 589 class HValue: public ZoneObject { 590 public: 591 static const int kNoNumber = -1; 592 593 enum Flag { 594 kFlexibleRepresentation, 595 kCannotBeTagged, 596 // Participate in Global Value Numbering, i.e. elimination of 597 // unnecessary recomputations. If an instruction sets this flag, it must 598 // implement DataEquals(), which will be used to determine if other 599 // occurrences of the instruction are indeed the same. 600 kUseGVN, 601 // Track instructions that are dominating side effects. If an instruction 602 // sets this flag, it must implement HandleSideEffectDominator() and should 603 // indicate which side effects to track by setting GVN flags. 604 kTrackSideEffectDominators, 605 kCanOverflow, 606 kBailoutOnMinusZero, 607 kCanBeDivByZero, 608 kAllowUndefinedAsNaN, 609 kIsArguments, 610 kTruncatingToInt32, 611 kAllUsesTruncatingToInt32, 612 kTruncatingToSmi, 613 kAllUsesTruncatingToSmi, 614 // Set after an instruction is killed. 615 kIsDead, 616 // Instructions that are allowed to produce full range unsigned integer 617 // values are marked with kUint32 flag. If arithmetic shift or a load from 618 // EXTERNAL_UNSIGNED_INT_ELEMENTS array is not marked with this flag 619 // it will deoptimize if result does not fit into signed integer range. 620 // HGraph::ComputeSafeUint32Operations is responsible for setting this 621 // flag. 622 kUint32, 623 kHasNoObservableSideEffects, 624 // Indicates the instruction is live during dead code elimination. 625 kIsLive, 626 627 // HEnvironmentMarkers are deleted before dead code 628 // elimination takes place, so they can repurpose the kIsLive flag: 629 kEndsLiveRange = kIsLive, 630 631 // TODO(everyone): Don't forget to update this! 632 kLastFlag = kIsLive 633 }; 634 635 STATIC_ASSERT(kLastFlag < kBitsPerInt); 636 637 static const int kChangesToDependsFlagsLeftShift = 1; 638 639 static GVNFlag ChangesFlagFromInt(int x) { 640 return static_cast<GVNFlag>(x * 2); 641 } 642 static GVNFlag DependsOnFlagFromInt(int x) { 643 return static_cast<GVNFlag>(x * 2 + 1); 644 } 645 static GVNFlagSet ConvertChangesToDependsFlags(GVNFlagSet flags) { 646 return GVNFlagSet(flags.ToIntegral() << kChangesToDependsFlagsLeftShift); 647 } 648 649 static HValue* cast(HValue* value) { return value; } 650 651 enum Opcode { 652 // Declare a unique enum value for each hydrogen instruction. 653 #define DECLARE_OPCODE(type) k##type, 654 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_OPCODE) 655 kPhi 656 #undef DECLARE_OPCODE 657 }; 658 virtual Opcode opcode() const = 0; 659 660 // Declare a non-virtual predicates for each concrete HInstruction or HValue. 661 #define DECLARE_PREDICATE(type) \ 662 bool Is##type() const { return opcode() == k##type; } 663 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_PREDICATE) 664 #undef DECLARE_PREDICATE 665 bool IsPhi() const { return opcode() == kPhi; } 666 667 // Declare virtual predicates for abstract HInstruction or HValue 668 #define DECLARE_PREDICATE(type) \ 669 virtual bool Is##type() const { return false; } 670 HYDROGEN_ABSTRACT_INSTRUCTION_LIST(DECLARE_PREDICATE) 671 #undef DECLARE_PREDICATE 672 673 HValue(HType type = HType::Tagged()) 674 : block_(NULL), 675 id_(kNoNumber), 676 type_(type), 677 use_list_(NULL), 678 range_(NULL), 679 flags_(0) {} 680 virtual ~HValue() {} 681 682 HBasicBlock* block() const { return block_; } 683 void SetBlock(HBasicBlock* block); 684 int LoopWeight() const; 685 686 // Note: Never call this method for an unlinked value. 687 Isolate* isolate() const; 688 689 int id() const { return id_; } 690 void set_id(int id) { id_ = id; } 691 692 HUseIterator uses() const { return HUseIterator(use_list_); } 693 694 virtual bool EmitAtUses() { return false; } 695 696 Representation representation() const { return representation_; } 697 void ChangeRepresentation(Representation r) { 698 ASSERT(CheckFlag(kFlexibleRepresentation)); 699 ASSERT(!CheckFlag(kCannotBeTagged) || !r.IsTagged()); 700 RepresentationChanged(r); 701 representation_ = r; 702 if (r.IsTagged()) { 703 // Tagged is the bottom of the lattice, don't go any further. 704 ClearFlag(kFlexibleRepresentation); 705 } 706 } 707 virtual void AssumeRepresentation(Representation r); 708 709 virtual Representation KnownOptimalRepresentation() { 710 Representation r = representation(); 711 if (r.IsTagged()) { 712 HType t = type(); 713 if (t.IsSmi()) return Representation::Smi(); 714 if (t.IsHeapNumber()) return Representation::Double(); 715 if (t.IsHeapObject()) return r; 716 return Representation::None(); 717 } 718 return r; 719 } 720 721 HType type() const { return type_; } 722 void set_type(HType new_type) { 723 ASSERT(new_type.IsSubtypeOf(type_)); 724 type_ = new_type; 725 } 726 727 bool IsHeapObject() { 728 return representation_.IsHeapObject() || type_.IsHeapObject(); 729 } 730 731 // An operation needs to override this function iff: 732 // 1) it can produce an int32 output. 733 // 2) the true value of its output can potentially be minus zero. 734 // The implementation must set a flag so that it bails out in the case where 735 // it would otherwise output what should be a minus zero as an int32 zero. 736 // If the operation also exists in a form that takes int32 and outputs int32 737 // then the operation should return its input value so that we can propagate 738 // back. There are three operations that need to propagate back to more than 739 // one input. They are phi and binary div and mul. They always return NULL 740 // and expect the caller to take care of things. 741 virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited) { 742 visited->Add(id()); 743 return NULL; 744 } 745 746 // There are HInstructions that do not really change a value, they 747 // only add pieces of information to it (like bounds checks, map checks, 748 // smi checks...). 749 // We call these instructions "informative definitions", or "iDef". 750 // One of the iDef operands is special because it is the value that is 751 // "transferred" to the output, we call it the "redefined operand". 752 // If an HValue is an iDef it must override RedefinedOperandIndex() so that 753 // it does not return kNoRedefinedOperand; 754 static const int kNoRedefinedOperand = -1; 755 virtual int RedefinedOperandIndex() { return kNoRedefinedOperand; } 756 bool IsInformativeDefinition() { 757 return RedefinedOperandIndex() != kNoRedefinedOperand; 758 } 759 HValue* RedefinedOperand() { 760 int index = RedefinedOperandIndex(); 761 return index == kNoRedefinedOperand ? NULL : OperandAt(index); 762 } 763 764 // A purely informative definition is an idef that will not emit code and 765 // should therefore be removed from the graph in the RestoreActualValues 766 // phase (so that live ranges will be shorter). 767 virtual bool IsPurelyInformativeDefinition() { return false; } 768 769 // This method must always return the original HValue SSA definition 770 // (regardless of any iDef of this value). 771 HValue* ActualValue() { 772 int index = RedefinedOperandIndex(); 773 return index == kNoRedefinedOperand ? this : OperandAt(index); 774 } 775 776 bool IsInteger32Constant(); 777 int32_t GetInteger32Constant(); 778 bool EqualsInteger32Constant(int32_t value); 779 780 bool IsDefinedAfter(HBasicBlock* other) const; 781 782 // Operands. 783 virtual int OperandCount() = 0; 784 virtual HValue* OperandAt(int index) const = 0; 785 void SetOperandAt(int index, HValue* value); 786 787 void DeleteAndReplaceWith(HValue* other); 788 void ReplaceAllUsesWith(HValue* other); 789 bool HasNoUses() const { return use_list_ == NULL; } 790 bool HasMultipleUses() const { 791 return use_list_ != NULL && use_list_->tail() != NULL; 792 } 793 int UseCount() const; 794 795 // Mark this HValue as dead and to be removed from other HValues' use lists. 796 void Kill(); 797 798 int flags() const { return flags_; } 799 void SetFlag(Flag f) { flags_ |= (1 << f); } 800 void ClearFlag(Flag f) { flags_ &= ~(1 << f); } 801 bool CheckFlag(Flag f) const { return (flags_ & (1 << f)) != 0; } 802 803 // Returns true if the flag specified is set for all uses, false otherwise. 804 bool CheckUsesForFlag(Flag f) const; 805 // Returns true if the flag specified is set for all uses, and this set 806 // of uses is non-empty. 807 bool HasAtLeastOneUseWithFlagAndNoneWithout(Flag f) const; 808 809 GVNFlagSet gvn_flags() const { return gvn_flags_; } 810 void SetGVNFlag(GVNFlag f) { gvn_flags_.Add(f); } 811 void ClearGVNFlag(GVNFlag f) { gvn_flags_.Remove(f); } 812 bool CheckGVNFlag(GVNFlag f) const { return gvn_flags_.Contains(f); } 813 void SetAllSideEffects() { gvn_flags_.Add(AllSideEffectsFlagSet()); } 814 void ClearAllSideEffects() { 815 gvn_flags_.Remove(AllSideEffectsFlagSet()); 816 } 817 bool HasSideEffects() const { 818 return gvn_flags_.ContainsAnyOf(AllSideEffectsFlagSet()); 819 } 820 bool HasObservableSideEffects() const { 821 return !CheckFlag(kHasNoObservableSideEffects) && 822 gvn_flags_.ContainsAnyOf(AllObservableSideEffectsFlagSet()); 823 } 824 825 GVNFlagSet DependsOnFlags() const { 826 GVNFlagSet result = gvn_flags_; 827 result.Intersect(AllDependsOnFlagSet()); 828 return result; 829 } 830 831 GVNFlagSet SideEffectFlags() const { 832 GVNFlagSet result = gvn_flags_; 833 result.Intersect(AllSideEffectsFlagSet()); 834 return result; 835 } 836 837 GVNFlagSet ChangesFlags() const { 838 GVNFlagSet result = gvn_flags_; 839 result.Intersect(AllChangesFlagSet()); 840 return result; 841 } 842 843 GVNFlagSet ObservableChangesFlags() const { 844 GVNFlagSet result = gvn_flags_; 845 result.Intersect(AllChangesFlagSet()); 846 result.Intersect(AllObservableSideEffectsFlagSet()); 847 return result; 848 } 849 850 Range* range() const { return range_; } 851 // TODO(svenpanne) We should really use the null object pattern here. 852 bool HasRange() const { return range_ != NULL; } 853 bool CanBeNegative() const { return !HasRange() || range()->CanBeNegative(); } 854 bool CanBeZero() const { return !HasRange() || range()->CanBeZero(); } 855 bool RangeCanInclude(int value) const { 856 return !HasRange() || range()->Includes(value); 857 } 858 void AddNewRange(Range* r, Zone* zone); 859 void RemoveLastAddedRange(); 860 void ComputeInitialRange(Zone* zone); 861 862 // Escape analysis helpers. 863 virtual bool HasEscapingOperandAt(int index) { return true; } 864 865 // Representation helpers. 866 virtual Representation observed_input_representation(int index) { 867 return Representation::None(); 868 } 869 virtual Representation RequiredInputRepresentation(int index) = 0; 870 virtual void InferRepresentation(HInferRepresentationPhase* h_infer); 871 872 // This gives the instruction an opportunity to replace itself with an 873 // instruction that does the same in some better way. To replace an 874 // instruction with a new one, first add the new instruction to the graph, 875 // then return it. Return NULL to have the instruction deleted. 876 virtual HValue* Canonicalize() { return this; } 877 878 bool Equals(HValue* other); 879 virtual intptr_t Hashcode(); 880 881 // Compute unique ids upfront that is safe wrt GC and parallel recompilation. 882 virtual void FinalizeUniqueValueId() { } 883 884 // Printing support. 885 virtual void PrintTo(StringStream* stream) = 0; 886 void PrintNameTo(StringStream* stream); 887 void PrintTypeTo(StringStream* stream); 888 void PrintRangeTo(StringStream* stream); 889 void PrintChangesTo(StringStream* stream); 890 891 const char* Mnemonic() const; 892 893 // Type information helpers. 894 bool HasMonomorphicJSObjectType(); 895 896 // TODO(mstarzinger): For now instructions can override this function to 897 // specify statically known types, once HType can convey more information 898 // it should be based on the HType. 899 virtual Handle<Map> GetMonomorphicJSObjectMap() { return Handle<Map>(); } 900 901 // Updated the inferred type of this instruction and returns true if 902 // it has changed. 903 bool UpdateInferredType(); 904 905 virtual HType CalculateInferredType(); 906 907 // This function must be overridden for instructions which have the 908 // kTrackSideEffectDominators flag set, to track instructions that are 909 // dominating side effects. 910 virtual void HandleSideEffectDominator(GVNFlag side_effect, 911 HValue* dominator) { 912 UNREACHABLE(); 913 } 914 915 // Check if this instruction has some reason that prevents elimination. 916 bool CannotBeEliminated() const { 917 return HasObservableSideEffects() || !IsDeletable(); 918 } 919 920 #ifdef DEBUG 921 virtual void Verify() = 0; 922 #endif 923 924 virtual bool TryDecompose(DecompositionResult* decomposition) { 925 if (RedefinedOperand() != NULL) { 926 return RedefinedOperand()->TryDecompose(decomposition); 927 } else { 928 return false; 929 } 930 } 931 932 // Returns true conservatively if the program might be able to observe a 933 // ToString() operation on this value. 934 bool ToStringCanBeObserved() const { 935 return type().ToStringOrToNumberCanBeObserved(representation()); 936 } 937 938 // Returns true conservatively if the program might be able to observe a 939 // ToNumber() operation on this value. 940 bool ToNumberCanBeObserved() const { 941 return type().ToStringOrToNumberCanBeObserved(representation()); 942 } 943 944 protected: 945 // This function must be overridden for instructions with flag kUseGVN, to 946 // compare the non-Operand parts of the instruction. 947 virtual bool DataEquals(HValue* other) { 948 UNREACHABLE(); 949 return false; 950 } 951 952 virtual Representation RepresentationFromInputs() { 953 return representation(); 954 } 955 Representation RepresentationFromUses(); 956 Representation RepresentationFromUseRequirements(); 957 bool HasNonSmiUse(); 958 virtual void UpdateRepresentation(Representation new_rep, 959 HInferRepresentationPhase* h_infer, 960 const char* reason); 961 void AddDependantsToWorklist(HInferRepresentationPhase* h_infer); 962 963 virtual void RepresentationChanged(Representation to) { } 964 965 virtual Range* InferRange(Zone* zone); 966 virtual void DeleteFromGraph() = 0; 967 virtual void InternalSetOperandAt(int index, HValue* value) = 0; 968 void clear_block() { 969 ASSERT(block_ != NULL); 970 block_ = NULL; 971 } 972 973 void set_representation(Representation r) { 974 ASSERT(representation_.IsNone() && !r.IsNone()); 975 representation_ = r; 976 } 977 978 static GVNFlagSet AllDependsOnFlagSet() { 979 GVNFlagSet result; 980 // Create changes mask. 981 #define ADD_FLAG(type) result.Add(kDependsOn##type); 982 GVN_TRACKED_FLAG_LIST(ADD_FLAG) 983 GVN_UNTRACKED_FLAG_LIST(ADD_FLAG) 984 #undef ADD_FLAG 985 return result; 986 } 987 988 static GVNFlagSet AllChangesFlagSet() { 989 GVNFlagSet result; 990 // Create changes mask. 991 #define ADD_FLAG(type) result.Add(kChanges##type); 992 GVN_TRACKED_FLAG_LIST(ADD_FLAG) 993 GVN_UNTRACKED_FLAG_LIST(ADD_FLAG) 994 #undef ADD_FLAG 995 return result; 996 } 997 998 // A flag mask to mark an instruction as having arbitrary side effects. 999 static GVNFlagSet AllSideEffectsFlagSet() { 1000 GVNFlagSet result = AllChangesFlagSet(); 1001 result.Remove(kChangesOsrEntries); 1002 return result; 1003 } 1004 1005 // A flag mask of all side effects that can make observable changes in 1006 // an executing program (i.e. are not safe to repeat, move or remove); 1007 static GVNFlagSet AllObservableSideEffectsFlagSet() { 1008 GVNFlagSet result = AllChangesFlagSet(); 1009 result.Remove(kChangesNewSpacePromotion); 1010 result.Remove(kChangesElementsKind); 1011 result.Remove(kChangesElementsPointer); 1012 result.Remove(kChangesMaps); 1013 return result; 1014 } 1015 1016 // Remove the matching use from the use list if present. Returns the 1017 // removed list node or NULL. 1018 HUseListNode* RemoveUse(HValue* value, int index); 1019 1020 void RegisterUse(int index, HValue* new_value); 1021 1022 HBasicBlock* block_; 1023 1024 // The id of this instruction in the hydrogen graph, assigned when first 1025 // added to the graph. Reflects creation order. 1026 int id_; 1027 1028 Representation representation_; 1029 HType type_; 1030 HUseListNode* use_list_; 1031 Range* range_; 1032 int flags_; 1033 GVNFlagSet gvn_flags_; 1034 1035 private: 1036 virtual bool IsDeletable() const { return false; } 1037 1038 DISALLOW_COPY_AND_ASSIGN(HValue); 1039 }; 1040 1041 1042 #define DECLARE_INSTRUCTION_FACTORY_P0(I) \ 1043 static I* New(Zone* zone, HValue* context) { \ 1044 return new(zone) I(); \ 1045 } 1046 1047 #define DECLARE_INSTRUCTION_FACTORY_P1(I, P1) \ 1048 static I* New(Zone* zone, HValue* context, P1 p1) { \ 1049 return new(zone) I(p1); \ 1050 } 1051 1052 #define DECLARE_INSTRUCTION_FACTORY_P2(I, P1, P2) \ 1053 static I* New(Zone* zone, HValue* context, P1 p1, P2 p2) { \ 1054 return new(zone) I(p1, p2); \ 1055 } 1056 1057 #define DECLARE_INSTRUCTION_FACTORY_P3(I, P1, P2, P3) \ 1058 static I* New(Zone* zone, HValue* context, P1 p1, P2 p2, P3 p3) { \ 1059 return new(zone) I(p1, p2, p3); \ 1060 } 1061 1062 #define DECLARE_INSTRUCTION_FACTORY_P4(I, P1, P2, P3, P4) \ 1063 static I* New(Zone* zone, \ 1064 HValue* context, \ 1065 P1 p1, \ 1066 P2 p2, \ 1067 P3 p3, \ 1068 P4 p4) { \ 1069 return new(zone) I(p1, p2, p3, p4); \ 1070 } 1071 1072 #define DECLARE_INSTRUCTION_FACTORY_P5(I, P1, P2, P3, P4, P5) \ 1073 static I* New(Zone* zone, \ 1074 HValue* context, \ 1075 P1 p1, \ 1076 P2 p2, \ 1077 P3 p3, \ 1078 P4 p4, \ 1079 P5 p5) { \ 1080 return new(zone) I(p1, p2, p3, p4, p5); \ 1081 } 1082 1083 1084 class HInstruction: public HValue { 1085 public: 1086 HInstruction* next() const { return next_; } 1087 HInstruction* previous() const { return previous_; } 1088 1089 virtual void PrintTo(StringStream* stream); 1090 virtual void PrintDataTo(StringStream* stream); 1091 1092 bool IsLinked() const { return block() != NULL; } 1093 void Unlink(); 1094 void InsertBefore(HInstruction* next); 1095 void InsertAfter(HInstruction* previous); 1096 1097 // The position is a write-once variable. 1098 int position() const { return position_; } 1099 bool has_position() const { return position_ != RelocInfo::kNoPosition; } 1100 void set_position(int position) { 1101 ASSERT(!has_position()); 1102 ASSERT(position != RelocInfo::kNoPosition); 1103 position_ = position; 1104 } 1105 1106 bool CanTruncateToInt32() const { return CheckFlag(kTruncatingToInt32); } 1107 1108 virtual LInstruction* CompileToLithium(LChunkBuilder* builder) = 0; 1109 1110 #ifdef DEBUG 1111 virtual void Verify(); 1112 #endif 1113 1114 virtual bool IsCall() { return false; } 1115 1116 DECLARE_ABSTRACT_INSTRUCTION(Instruction) 1117 1118 protected: 1119 HInstruction(HType type = HType::Tagged()) 1120 : HValue(type), 1121 next_(NULL), 1122 previous_(NULL), 1123 position_(RelocInfo::kNoPosition) { 1124 SetGVNFlag(kDependsOnOsrEntries); 1125 } 1126 1127 virtual void DeleteFromGraph() { Unlink(); } 1128 1129 private: 1130 void InitializeAsFirst(HBasicBlock* block) { 1131 ASSERT(!IsLinked()); 1132 SetBlock(block); 1133 } 1134 1135 void PrintMnemonicTo(StringStream* stream); 1136 1137 HInstruction* next_; 1138 HInstruction* previous_; 1139 int position_; 1140 1141 friend class HBasicBlock; 1142 }; 1143 1144 1145 template<int V> 1146 class HTemplateInstruction : public HInstruction { 1147 public: 1148 int OperandCount() { return V; } 1149 HValue* OperandAt(int i) const { return inputs_[i]; } 1150 1151 protected: 1152 HTemplateInstruction(HType type = HType::Tagged()) : HInstruction(type) {} 1153 1154 void InternalSetOperandAt(int i, HValue* value) { inputs_[i] = value; } 1155 1156 private: 1157 EmbeddedContainer<HValue*, V> inputs_; 1158 }; 1159 1160 1161 class HControlInstruction: public HInstruction { 1162 public: 1163 virtual HBasicBlock* SuccessorAt(int i) = 0; 1164 virtual int SuccessorCount() = 0; 1165 virtual void SetSuccessorAt(int i, HBasicBlock* block) = 0; 1166 1167 virtual void PrintDataTo(StringStream* stream); 1168 1169 HBasicBlock* FirstSuccessor() { 1170 return SuccessorCount() > 0 ? SuccessorAt(0) : NULL; 1171 } 1172 HBasicBlock* SecondSuccessor() { 1173 return SuccessorCount() > 1 ? SuccessorAt(1) : NULL; 1174 } 1175 1176 DECLARE_ABSTRACT_INSTRUCTION(ControlInstruction) 1177 }; 1178 1179 1180 class HSuccessorIterator BASE_EMBEDDED { 1181 public: 1182 explicit HSuccessorIterator(HControlInstruction* instr) 1183 : instr_(instr), current_(0) { } 1184 1185 bool Done() { return current_ >= instr_->SuccessorCount(); } 1186 HBasicBlock* Current() { return instr_->SuccessorAt(current_); } 1187 void Advance() { current_++; } 1188 1189 private: 1190 HControlInstruction* instr_; 1191 int current_; 1192 }; 1193 1194 1195 template<int S, int V> 1196 class HTemplateControlInstruction: public HControlInstruction { 1197 public: 1198 int SuccessorCount() { return S; } 1199 HBasicBlock* SuccessorAt(int i) { return successors_[i]; } 1200 void SetSuccessorAt(int i, HBasicBlock* block) { successors_[i] = block; } 1201 1202 int OperandCount() { return V; } 1203 HValue* OperandAt(int i) const { return inputs_[i]; } 1204 1205 1206 protected: 1207 void InternalSetOperandAt(int i, HValue* value) { inputs_[i] = value; } 1208 1209 private: 1210 EmbeddedContainer<HBasicBlock*, S> successors_; 1211 EmbeddedContainer<HValue*, V> inputs_; 1212 }; 1213 1214 1215 class HBlockEntry: public HTemplateInstruction<0> { 1216 public: 1217 virtual Representation RequiredInputRepresentation(int index) { 1218 return Representation::None(); 1219 } 1220 1221 DECLARE_CONCRETE_INSTRUCTION(BlockEntry) 1222 }; 1223 1224 1225 class HDummyUse: public HTemplateInstruction<1> { 1226 public: 1227 explicit HDummyUse(HValue* value) 1228 : HTemplateInstruction<1>(HType::Smi()) { 1229 SetOperandAt(0, value); 1230 // Pretend to be a Smi so that the HChange instructions inserted 1231 // before any use generate as little code as possible. 1232 set_representation(Representation::Tagged()); 1233 } 1234 1235 HValue* value() { return OperandAt(0); } 1236 1237 virtual bool HasEscapingOperandAt(int index) { return false; } 1238 virtual Representation RequiredInputRepresentation(int index) { 1239 return Representation::None(); 1240 } 1241 1242 virtual void PrintDataTo(StringStream* stream); 1243 1244 DECLARE_CONCRETE_INSTRUCTION(DummyUse); 1245 }; 1246 1247 1248 class HDeoptimize: public HTemplateInstruction<0> { 1249 public: 1250 DECLARE_INSTRUCTION_FACTORY_P2(HDeoptimize, const char*, 1251 Deoptimizer::BailoutType); 1252 1253 virtual Representation RequiredInputRepresentation(int index) { 1254 return Representation::None(); 1255 } 1256 1257 const char* reason() const { return reason_; } 1258 Deoptimizer::BailoutType type() { return type_; } 1259 1260 DECLARE_CONCRETE_INSTRUCTION(Deoptimize) 1261 1262 private: 1263 explicit HDeoptimize(const char* reason, Deoptimizer::BailoutType type) 1264 : reason_(reason), type_(type) {} 1265 1266 const char* reason_; 1267 Deoptimizer::BailoutType type_; 1268 }; 1269 1270 1271 // Inserts an int3/stop break instruction for debugging purposes. 1272 class HDebugBreak: public HTemplateInstruction<0> { 1273 public: 1274 virtual Representation RequiredInputRepresentation(int index) { 1275 return Representation::None(); 1276 } 1277 1278 DECLARE_CONCRETE_INSTRUCTION(DebugBreak) 1279 }; 1280 1281 1282 class HGoto: public HTemplateControlInstruction<1, 0> { 1283 public: 1284 explicit HGoto(HBasicBlock* target) { 1285 SetSuccessorAt(0, target); 1286 } 1287 1288 virtual Representation RequiredInputRepresentation(int index) { 1289 return Representation::None(); 1290 } 1291 1292 virtual void PrintDataTo(StringStream* stream); 1293 1294 DECLARE_CONCRETE_INSTRUCTION(Goto) 1295 }; 1296 1297 1298 class HUnaryControlInstruction: public HTemplateControlInstruction<2, 1> { 1299 public: 1300 HUnaryControlInstruction(HValue* value, 1301 HBasicBlock* true_target, 1302 HBasicBlock* false_target) { 1303 SetOperandAt(0, value); 1304 SetSuccessorAt(0, true_target); 1305 SetSuccessorAt(1, false_target); 1306 } 1307 1308 virtual void PrintDataTo(StringStream* stream); 1309 1310 HValue* value() { return OperandAt(0); } 1311 }; 1312 1313 1314 class HBranch: public HUnaryControlInstruction { 1315 public: 1316 HBranch(HValue* value, 1317 ToBooleanStub::Types expected_input_types = ToBooleanStub::Types(), 1318 HBasicBlock* true_target = NULL, 1319 HBasicBlock* false_target = NULL) 1320 : HUnaryControlInstruction(value, true_target, false_target), 1321 expected_input_types_(expected_input_types) { 1322 SetFlag(kAllowUndefinedAsNaN); 1323 } 1324 1325 virtual Representation RequiredInputRepresentation(int index) { 1326 return Representation::None(); 1327 } 1328 virtual Representation observed_input_representation(int index); 1329 1330 ToBooleanStub::Types expected_input_types() const { 1331 return expected_input_types_; 1332 } 1333 1334 DECLARE_CONCRETE_INSTRUCTION(Branch) 1335 1336 private: 1337 ToBooleanStub::Types expected_input_types_; 1338 }; 1339 1340 1341 class HCompareMap: public HUnaryControlInstruction { 1342 public: 1343 HCompareMap(HValue* value, 1344 Handle<Map> map, 1345 HBasicBlock* true_target = NULL, 1346 HBasicBlock* false_target = NULL) 1347 : HUnaryControlInstruction(value, true_target, false_target), 1348 map_(map) { 1349 ASSERT(!map.is_null()); 1350 } 1351 1352 virtual void PrintDataTo(StringStream* stream); 1353 1354 Handle<Map> map() const { return map_; } 1355 1356 virtual Representation RequiredInputRepresentation(int index) { 1357 return Representation::Tagged(); 1358 } 1359 1360 DECLARE_CONCRETE_INSTRUCTION(CompareMap) 1361 1362 private: 1363 Handle<Map> map_; 1364 }; 1365 1366 1367 class HContext: public HTemplateInstruction<0> { 1368 public: 1369 static HContext* New(Zone* zone) { 1370 return new(zone) HContext(); 1371 } 1372 1373 virtual Representation RequiredInputRepresentation(int index) { 1374 return Representation::None(); 1375 } 1376 1377 DECLARE_CONCRETE_INSTRUCTION(Context) 1378 1379 protected: 1380 virtual bool DataEquals(HValue* other) { return true; } 1381 1382 private: 1383 HContext() { 1384 set_representation(Representation::Tagged()); 1385 SetFlag(kUseGVN); 1386 } 1387 1388 virtual bool IsDeletable() const { return true; } 1389 }; 1390 1391 1392 class HReturn: public HTemplateControlInstruction<0, 3> { 1393 public: 1394 static HInstruction* New(Zone* zone, 1395 HValue* context, 1396 HValue* value, 1397 HValue* parameter_count) { 1398 return new(zone) HReturn(value, context, parameter_count); 1399 } 1400 1401 static HInstruction* New(Zone* zone, 1402 HValue* context, 1403 HValue* value) { 1404 return new(zone) HReturn(value, context, 0); 1405 } 1406 1407 virtual Representation RequiredInputRepresentation(int index) { 1408 return Representation::Tagged(); 1409 } 1410 1411 virtual void PrintDataTo(StringStream* stream); 1412 1413 HValue* value() { return OperandAt(0); } 1414 HValue* context() { return OperandAt(1); } 1415 HValue* parameter_count() { return OperandAt(2); } 1416 1417 DECLARE_CONCRETE_INSTRUCTION(Return) 1418 1419 private: 1420 HReturn(HValue* value, HValue* context, HValue* parameter_count) { 1421 SetOperandAt(0, value); 1422 SetOperandAt(1, context); 1423 SetOperandAt(2, parameter_count); 1424 } 1425 }; 1426 1427 1428 class HUnaryOperation: public HTemplateInstruction<1> { 1429 public: 1430 HUnaryOperation(HValue* value, HType type = HType::Tagged()) 1431 : HTemplateInstruction<1>(type) { 1432 SetOperandAt(0, value); 1433 } 1434 1435 static HUnaryOperation* cast(HValue* value) { 1436 return reinterpret_cast<HUnaryOperation*>(value); 1437 } 1438 1439 HValue* value() const { return OperandAt(0); } 1440 virtual void PrintDataTo(StringStream* stream); 1441 }; 1442 1443 1444 class HThrow: public HTemplateInstruction<2> { 1445 public: 1446 static HThrow* New(Zone* zone, 1447 HValue* context, 1448 HValue* value) { 1449 return new(zone) HThrow(context, value); 1450 } 1451 1452 virtual Representation RequiredInputRepresentation(int index) { 1453 return Representation::Tagged(); 1454 } 1455 1456 HValue* context() { return OperandAt(0); } 1457 HValue* value() { return OperandAt(1); } 1458 1459 DECLARE_CONCRETE_INSTRUCTION(Throw) 1460 1461 private: 1462 HThrow(HValue* context, HValue* value) { 1463 SetOperandAt(0, context); 1464 SetOperandAt(1, value); 1465 SetAllSideEffects(); 1466 } 1467 }; 1468 1469 1470 class HUseConst: public HUnaryOperation { 1471 public: 1472 DECLARE_INSTRUCTION_FACTORY_P1(HUseConst, HValue*); 1473 1474 virtual Representation RequiredInputRepresentation(int index) { 1475 return Representation::None(); 1476 } 1477 1478 DECLARE_CONCRETE_INSTRUCTION(UseConst) 1479 1480 private: 1481 explicit HUseConst(HValue* old_value) : HUnaryOperation(old_value) { } 1482 }; 1483 1484 1485 class HForceRepresentation: public HTemplateInstruction<1> { 1486 public: 1487 DECLARE_INSTRUCTION_FACTORY_P2(HForceRepresentation, HValue*, Representation); 1488 1489 HValue* value() { return OperandAt(0); } 1490 1491 virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited); 1492 1493 virtual Representation RequiredInputRepresentation(int index) { 1494 return representation(); // Same as the output representation. 1495 } 1496 1497 virtual void PrintDataTo(StringStream* stream); 1498 1499 DECLARE_CONCRETE_INSTRUCTION(ForceRepresentation) 1500 1501 private: 1502 HForceRepresentation(HValue* value, Representation required_representation) { 1503 SetOperandAt(0, value); 1504 set_representation(required_representation); 1505 } 1506 }; 1507 1508 1509 class HChange: public HUnaryOperation { 1510 public: 1511 HChange(HValue* value, 1512 Representation to, 1513 bool is_truncating_to_smi, 1514 bool is_truncating_to_int32) 1515 : HUnaryOperation(value) { 1516 ASSERT(!value->representation().IsNone()); 1517 ASSERT(!to.IsNone()); 1518 ASSERT(!value->representation().Equals(to)); 1519 set_representation(to); 1520 SetFlag(kUseGVN); 1521 if (is_truncating_to_smi) SetFlag(kTruncatingToSmi); 1522 if (is_truncating_to_int32) SetFlag(kTruncatingToInt32); 1523 if (value->representation().IsSmi() || value->type().IsSmi()) { 1524 set_type(HType::Smi()); 1525 } else { 1526 set_type(HType::TaggedNumber()); 1527 if (to.IsTagged()) SetGVNFlag(kChangesNewSpacePromotion); 1528 } 1529 } 1530 1531 bool can_convert_undefined_to_nan() { 1532 return CheckUsesForFlag(kAllowUndefinedAsNaN); 1533 } 1534 1535 virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited); 1536 virtual HType CalculateInferredType(); 1537 virtual HValue* Canonicalize(); 1538 1539 Representation from() const { return value()->representation(); } 1540 Representation to() const { return representation(); } 1541 bool deoptimize_on_minus_zero() const { 1542 return CheckFlag(kBailoutOnMinusZero); 1543 } 1544 virtual Representation RequiredInputRepresentation(int index) { 1545 return from(); 1546 } 1547 1548 virtual Range* InferRange(Zone* zone); 1549 1550 virtual void PrintDataTo(StringStream* stream); 1551 1552 DECLARE_CONCRETE_INSTRUCTION(Change) 1553 1554 protected: 1555 virtual bool DataEquals(HValue* other) { return true; } 1556 1557 private: 1558 virtual bool IsDeletable() const { 1559 return !from().IsTagged() || value()->type().IsSmi(); 1560 } 1561 }; 1562 1563 1564 class HClampToUint8: public HUnaryOperation { 1565 public: 1566 DECLARE_INSTRUCTION_FACTORY_P1(HClampToUint8, HValue*); 1567 1568 virtual Representation RequiredInputRepresentation(int index) { 1569 return Representation::None(); 1570 } 1571 1572 DECLARE_CONCRETE_INSTRUCTION(ClampToUint8) 1573 1574 protected: 1575 virtual bool DataEquals(HValue* other) { return true; } 1576 1577 private: 1578 explicit HClampToUint8(HValue* value) 1579 : HUnaryOperation(value) { 1580 set_representation(Representation::Integer32()); 1581 SetFlag(kAllowUndefinedAsNaN); 1582 SetFlag(kUseGVN); 1583 } 1584 1585 virtual bool IsDeletable() const { return true; } 1586 }; 1587 1588 1589 enum RemovableSimulate { 1590 REMOVABLE_SIMULATE, 1591 FIXED_SIMULATE 1592 }; 1593 1594 1595 class HSimulate: public HInstruction { 1596 public: 1597 HSimulate(BailoutId ast_id, 1598 int pop_count, 1599 Zone* zone, 1600 RemovableSimulate removable) 1601 : ast_id_(ast_id), 1602 pop_count_(pop_count), 1603 values_(2, zone), 1604 assigned_indexes_(2, zone), 1605 zone_(zone), 1606 removable_(removable) {} 1607 virtual ~HSimulate() {} 1608 1609 virtual void PrintDataTo(StringStream* stream); 1610 1611 bool HasAstId() const { return !ast_id_.IsNone(); } 1612 BailoutId ast_id() const { return ast_id_; } 1613 void set_ast_id(BailoutId id) { 1614 ASSERT(!HasAstId()); 1615 ast_id_ = id; 1616 } 1617 1618 int pop_count() const { return pop_count_; } 1619 const ZoneList<HValue*>* values() const { return &values_; } 1620 int GetAssignedIndexAt(int index) const { 1621 ASSERT(HasAssignedIndexAt(index)); 1622 return assigned_indexes_[index]; 1623 } 1624 bool HasAssignedIndexAt(int index) const { 1625 return assigned_indexes_[index] != kNoIndex; 1626 } 1627 void AddAssignedValue(int index, HValue* value) { 1628 AddValue(index, value); 1629 } 1630 void AddPushedValue(HValue* value) { 1631 AddValue(kNoIndex, value); 1632 } 1633 int ToOperandIndex(int environment_index) { 1634 for (int i = 0; i < assigned_indexes_.length(); ++i) { 1635 if (assigned_indexes_[i] == environment_index) return i; 1636 } 1637 return -1; 1638 } 1639 virtual int OperandCount() { return values_.length(); } 1640 virtual HValue* OperandAt(int index) const { return values_[index]; } 1641 1642 virtual bool HasEscapingOperandAt(int index) { return false; } 1643 virtual Representation RequiredInputRepresentation(int index) { 1644 return Representation::None(); 1645 } 1646 1647 void MergeWith(ZoneList<HSimulate*>* list); 1648 bool is_candidate_for_removal() { return removable_ == REMOVABLE_SIMULATE; } 1649 1650 DECLARE_CONCRETE_INSTRUCTION(Simulate) 1651 1652 #ifdef DEBUG 1653 virtual void Verify(); 1654 void set_closure(Handle<JSFunction> closure) { closure_ = closure; } 1655 Handle<JSFunction> closure() const { return closure_; } 1656 #endif 1657 1658 protected: 1659 virtual void InternalSetOperandAt(int index, HValue* value) { 1660 values_[index] = value; 1661 } 1662 1663 private: 1664 static const int kNoIndex = -1; 1665 void AddValue(int index, HValue* value) { 1666 assigned_indexes_.Add(index, zone_); 1667 // Resize the list of pushed values. 1668 values_.Add(NULL, zone_); 1669 // Set the operand through the base method in HValue to make sure that the 1670 // use lists are correctly updated. 1671 SetOperandAt(values_.length() - 1, value); 1672 } 1673 bool HasValueForIndex(int index) { 1674 for (int i = 0; i < assigned_indexes_.length(); ++i) { 1675 if (assigned_indexes_[i] == index) return true; 1676 } 1677 return false; 1678 } 1679 BailoutId ast_id_; 1680 int pop_count_; 1681 ZoneList<HValue*> values_; 1682 ZoneList<int> assigned_indexes_; 1683 Zone* zone_; 1684 RemovableSimulate removable_; 1685 1686 #ifdef DEBUG 1687 Handle<JSFunction> closure_; 1688 #endif 1689 }; 1690 1691 1692 class HEnvironmentMarker: public HTemplateInstruction<1> { 1693 public: 1694 enum Kind { BIND, LOOKUP }; 1695 1696 HEnvironmentMarker(Kind kind, int index) 1697 : kind_(kind), index_(index), next_simulate_(NULL) { } 1698 1699 Kind kind() { return kind_; } 1700 int index() { return index_; } 1701 HSimulate* next_simulate() { return next_simulate_; } 1702 void set_next_simulate(HSimulate* simulate) { 1703 next_simulate_ = simulate; 1704 } 1705 1706 virtual Representation RequiredInputRepresentation(int index) { 1707 return Representation::None(); 1708 } 1709 1710 virtual void PrintDataTo(StringStream* stream); 1711 1712 #ifdef DEBUG 1713 void set_closure(Handle<JSFunction> closure) { 1714 ASSERT(closure_.is_null()); 1715 ASSERT(!closure.is_null()); 1716 closure_ = closure; 1717 } 1718 Handle<JSFunction> closure() const { return closure_; } 1719 #endif 1720 1721 DECLARE_CONCRETE_INSTRUCTION(EnvironmentMarker); 1722 1723 private: 1724 Kind kind_; 1725 int index_; 1726 HSimulate* next_simulate_; 1727 1728 #ifdef DEBUG 1729 Handle<JSFunction> closure_; 1730 #endif 1731 }; 1732 1733 1734 class HStackCheck: public HTemplateInstruction<1> { 1735 public: 1736 enum Type { 1737 kFunctionEntry, 1738 kBackwardsBranch 1739 }; 1740 1741 DECLARE_INSTRUCTION_FACTORY_P2(HStackCheck, HValue*, Type); 1742 1743 HValue* context() { return OperandAt(0); } 1744 1745 virtual Representation RequiredInputRepresentation(int index) { 1746 return Representation::Tagged(); 1747 } 1748 1749 void Eliminate() { 1750 // The stack check eliminator might try to eliminate the same stack 1751 // check instruction multiple times. 1752 if (IsLinked()) { 1753 DeleteAndReplaceWith(NULL); 1754 } 1755 } 1756 1757 bool is_function_entry() { return type_ == kFunctionEntry; } 1758 bool is_backwards_branch() { return type_ == kBackwardsBranch; } 1759 1760 DECLARE_CONCRETE_INSTRUCTION(StackCheck) 1761 1762 private: 1763 HStackCheck(HValue* context, Type type) : type_(type) { 1764 SetOperandAt(0, context); 1765 SetGVNFlag(kChangesNewSpacePromotion); 1766 } 1767 1768 Type type_; 1769 }; 1770 1771 1772 enum InliningKind { 1773 NORMAL_RETURN, // Normal function/method call and return. 1774 DROP_EXTRA_ON_RETURN, // Drop an extra value from the environment on return. 1775 CONSTRUCT_CALL_RETURN, // Either use allocated receiver or return value. 1776 GETTER_CALL_RETURN, // Returning from a getter, need to restore context. 1777 SETTER_CALL_RETURN // Use the RHS of the assignment as the return value. 1778 }; 1779 1780 1781 class HArgumentsObject; 1782 1783 1784 class HEnterInlined: public HTemplateInstruction<0> { 1785 public: 1786 static HEnterInlined* New(Zone* zone, 1787 HValue* context, 1788 Handle<JSFunction> closure, 1789 int arguments_count, 1790 FunctionLiteral* function, 1791 InliningKind inlining_kind, 1792 Variable* arguments_var, 1793 HArgumentsObject* arguments_object, 1794 bool undefined_receiver) { 1795 return new(zone) HEnterInlined(closure, arguments_count, function, 1796 inlining_kind, arguments_var, 1797 arguments_object, undefined_receiver, zone); 1798 } 1799 1800 void RegisterReturnTarget(HBasicBlock* return_target, Zone* zone); 1801 ZoneList<HBasicBlock*>* return_targets() { return &return_targets_; } 1802 1803 virtual void PrintDataTo(StringStream* stream); 1804 1805 Handle<JSFunction> closure() const { return closure_; } 1806 int arguments_count() const { return arguments_count_; } 1807 bool arguments_pushed() const { return arguments_pushed_; } 1808 void set_arguments_pushed() { arguments_pushed_ = true; } 1809 FunctionLiteral* function() const { return function_; } 1810 InliningKind inlining_kind() const { return inlining_kind_; } 1811 bool undefined_receiver() const { return undefined_receiver_; } 1812 1813 virtual Representation RequiredInputRepresentation(int index) { 1814 return Representation::None(); 1815 } 1816 1817 Variable* arguments_var() { return arguments_var_; } 1818 HArgumentsObject* arguments_object() { return arguments_object_; } 1819 1820 DECLARE_CONCRETE_INSTRUCTION(EnterInlined) 1821 1822 private: 1823 HEnterInlined(Handle<JSFunction> closure, 1824 int arguments_count, 1825 FunctionLiteral* function, 1826 InliningKind inlining_kind, 1827 Variable* arguments_var, 1828 HArgumentsObject* arguments_object, 1829 bool undefined_receiver, 1830 Zone* zone) 1831 : closure_(closure), 1832 arguments_count_(arguments_count), 1833 arguments_pushed_(false), 1834 function_(function), 1835 inlining_kind_(inlining_kind), 1836 arguments_var_(arguments_var), 1837 arguments_object_(arguments_object), 1838 undefined_receiver_(undefined_receiver), 1839 return_targets_(2, zone) { 1840 } 1841 1842 Handle<JSFunction> closure_; 1843 int arguments_count_; 1844 bool arguments_pushed_; 1845 FunctionLiteral* function_; 1846 InliningKind inlining_kind_; 1847 Variable* arguments_var_; 1848 HArgumentsObject* arguments_object_; 1849 bool undefined_receiver_; 1850 ZoneList<HBasicBlock*> return_targets_; 1851 }; 1852 1853 1854 class HLeaveInlined: public HTemplateInstruction<0> { 1855 public: 1856 HLeaveInlined() { } 1857 1858 virtual Representation RequiredInputRepresentation(int index) { 1859 return Representation::None(); 1860 } 1861 1862 DECLARE_CONCRETE_INSTRUCTION(LeaveInlined) 1863 }; 1864 1865 1866 class HPushArgument: public HUnaryOperation { 1867 public: 1868 DECLARE_INSTRUCTION_FACTORY_P1(HPushArgument, HValue*); 1869 1870 virtual Representation RequiredInputRepresentation(int index) { 1871 return Representation::Tagged(); 1872 } 1873 1874 HValue* argument() { return OperandAt(0); } 1875 1876 DECLARE_CONCRETE_INSTRUCTION(PushArgument) 1877 1878 private: 1879 explicit HPushArgument(HValue* value) : HUnaryOperation(value) { 1880 set_representation(Representation::Tagged()); 1881 } 1882 }; 1883 1884 1885 class HThisFunction: public HTemplateInstruction<0> { 1886 public: 1887 HThisFunction() { 1888 set_representation(Representation::Tagged()); 1889 SetFlag(kUseGVN); 1890 } 1891 1892 virtual Representation RequiredInputRepresentation(int index) { 1893 return Representation::None(); 1894 } 1895 1896 DECLARE_CONCRETE_INSTRUCTION(ThisFunction) 1897 1898 protected: 1899 virtual bool DataEquals(HValue* other) { return true; } 1900 1901 private: 1902 virtual bool IsDeletable() const { return true; } 1903 }; 1904 1905 1906 class HOuterContext: public HUnaryOperation { 1907 public: 1908 DECLARE_INSTRUCTION_FACTORY_P1(HOuterContext, HValue*); 1909 1910 DECLARE_CONCRETE_INSTRUCTION(OuterContext); 1911 1912 virtual Representation RequiredInputRepresentation(int index) { 1913 return Representation::Tagged(); 1914 } 1915 1916 protected: 1917 virtual bool DataEquals(HValue* other) { return true; } 1918 1919 private: 1920 explicit HOuterContext(HValue* inner) : HUnaryOperation(inner) { 1921 set_representation(Representation::Tagged()); 1922 SetFlag(kUseGVN); 1923 } 1924 1925 virtual bool IsDeletable() const { return true; } 1926 }; 1927 1928 1929 class HDeclareGlobals: public HUnaryOperation { 1930 public: 1931 HDeclareGlobals(HValue* context, 1932 Handle<FixedArray> pairs, 1933 int flags) 1934 : HUnaryOperation(context), 1935 pairs_(pairs), 1936 flags_(flags) { 1937 set_representation(Representation::Tagged()); 1938 SetAllSideEffects(); 1939 } 1940 1941 static HDeclareGlobals* New(Zone* zone, 1942 HValue* context, 1943 Handle<FixedArray> pairs, 1944 int flags) { 1945 return new(zone) HDeclareGlobals(context, pairs, flags); 1946 } 1947 1948 HValue* context() { return OperandAt(0); } 1949 Handle<FixedArray> pairs() const { return pairs_; } 1950 int flags() const { return flags_; } 1951 1952 DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals) 1953 1954 virtual Representation RequiredInputRepresentation(int index) { 1955 return Representation::Tagged(); 1956 } 1957 1958 private: 1959 Handle<FixedArray> pairs_; 1960 int flags_; 1961 }; 1962 1963 1964 class HGlobalObject: public HUnaryOperation { 1965 public: 1966 explicit HGlobalObject(HValue* context) : HUnaryOperation(context) { 1967 set_representation(Representation::Tagged()); 1968 SetFlag(kUseGVN); 1969 } 1970 1971 static HGlobalObject* New(Zone* zone, HValue* context) { 1972 return new(zone) HGlobalObject(context); 1973 } 1974 1975 DECLARE_CONCRETE_INSTRUCTION(GlobalObject) 1976 1977 virtual Representation RequiredInputRepresentation(int index) { 1978 return Representation::Tagged(); 1979 } 1980 1981 protected: 1982 virtual bool DataEquals(HValue* other) { return true; } 1983 1984 private: 1985 virtual bool IsDeletable() const { return true; } 1986 }; 1987 1988 1989 class HGlobalReceiver: public HUnaryOperation { 1990 public: 1991 DECLARE_INSTRUCTION_FACTORY_P1(HGlobalReceiver, HValue*); 1992 1993 DECLARE_CONCRETE_INSTRUCTION(GlobalReceiver) 1994 1995 virtual Representation RequiredInputRepresentation(int index) { 1996 return Representation::Tagged(); 1997 } 1998 1999 protected: 2000 virtual bool DataEquals(HValue* other) { return true; } 2001 2002 private: 2003 explicit HGlobalReceiver(HValue* global_object) 2004 : HUnaryOperation(global_object) { 2005 set_representation(Representation::Tagged()); 2006 SetFlag(kUseGVN); 2007 } 2008 2009 virtual bool IsDeletable() const { return true; } 2010 }; 2011 2012 2013 template <int V> 2014 class HCall: public HTemplateInstruction<V> { 2015 public: 2016 // The argument count includes the receiver. 2017 explicit HCall<V>(int argument_count) : argument_count_(argument_count) { 2018 this->set_representation(Representation::Tagged()); 2019 this->SetAllSideEffects(); 2020 } 2021 2022 virtual HType CalculateInferredType() { return HType::Tagged(); } 2023 2024 virtual int argument_count() const { return argument_count_; } 2025 2026 virtual bool IsCall() { return true; } 2027 2028 private: 2029 int argument_count_; 2030 }; 2031 2032 2033 class HUnaryCall: public HCall<1> { 2034 public: 2035 HUnaryCall(HValue* value, int argument_count) 2036 : HCall<1>(argument_count) { 2037 SetOperandAt(0, value); 2038 } 2039 2040 virtual Representation RequiredInputRepresentation(int index) { 2041 return Representation::Tagged(); 2042 } 2043 2044 virtual void PrintDataTo(StringStream* stream); 2045 2046 HValue* value() { return OperandAt(0); } 2047 }; 2048 2049 2050 class HBinaryCall: public HCall<2> { 2051 public: 2052 HBinaryCall(HValue* first, HValue* second, int argument_count) 2053 : HCall<2>(argument_count) { 2054 SetOperandAt(0, first); 2055 SetOperandAt(1, second); 2056 } 2057 2058 virtual void PrintDataTo(StringStream* stream); 2059 2060 virtual Representation RequiredInputRepresentation(int index) { 2061 return Representation::Tagged(); 2062 } 2063 2064 HValue* first() { return OperandAt(0); } 2065 HValue* second() { return OperandAt(1); } 2066 }; 2067 2068 2069 class HInvokeFunction: public HBinaryCall { 2070 public: 2071 HInvokeFunction(HValue* context, HValue* function, int argument_count) 2072 : HBinaryCall(context, function, argument_count) { 2073 } 2074 2075 static HInvokeFunction* New(Zone* zone, 2076 HValue* context, 2077 HValue* function, 2078 int argument_count) { 2079 return new(zone) HInvokeFunction(context, function, argument_count); 2080 } 2081 2082 HInvokeFunction(HValue* context, 2083 HValue* function, 2084 Handle<JSFunction> known_function, 2085 int argument_count) 2086 : HBinaryCall(context, function, argument_count), 2087 known_function_(known_function) { 2088 formal_parameter_count_ = known_function.is_null() 2089 ? 0 : known_function->shared()->formal_parameter_count(); 2090 } 2091 2092 static HInvokeFunction* New(Zone* zone, 2093 HValue* context, 2094 HValue* function, 2095 Handle<JSFunction> known_function, 2096 int argument_count) { 2097 return new(zone) HInvokeFunction(context, function, 2098 known_function, argument_count); 2099 } 2100 2101 virtual Representation RequiredInputRepresentation(int index) { 2102 return Representation::Tagged(); 2103 } 2104 2105 HValue* context() { return first(); } 2106 HValue* function() { return second(); } 2107 Handle<JSFunction> known_function() { return known_function_; } 2108 int formal_parameter_count() const { return formal_parameter_count_; } 2109 2110 DECLARE_CONCRETE_INSTRUCTION(InvokeFunction) 2111 2112 private: 2113 Handle<JSFunction> known_function_; 2114 int formal_parameter_count_; 2115 }; 2116 2117 2118 class HCallConstantFunction: public HCall<0> { 2119 public: 2120 HCallConstantFunction(Handle<JSFunction> function, int argument_count) 2121 : HCall<0>(argument_count), 2122 function_(function), 2123 formal_parameter_count_(function->shared()->formal_parameter_count()) {} 2124 2125 Handle<JSFunction> function() const { return function_; } 2126 int formal_parameter_count() const { return formal_parameter_count_; } 2127 2128 bool IsApplyFunction() const { 2129 return function_->code() == 2130 Isolate::Current()->builtins()->builtin(Builtins::kFunctionApply); 2131 } 2132 2133 virtual void PrintDataTo(StringStream* stream); 2134 2135 virtual Representation RequiredInputRepresentation(int index) { 2136 return Representation::None(); 2137 } 2138 2139 DECLARE_CONCRETE_INSTRUCTION(CallConstantFunction) 2140 2141 private: 2142 Handle<JSFunction> function_; 2143 int formal_parameter_count_; 2144 }; 2145 2146 2147 class HCallKeyed: public HBinaryCall { 2148 public: 2149 HCallKeyed(HValue* context, HValue* key, int argument_count) 2150 : HBinaryCall(context, key, argument_count) { 2151 } 2152 2153 virtual Representation RequiredInputRepresentation(int index) { 2154 return Representation::Tagged(); 2155 } 2156 2157 HValue* context() { return first(); } 2158 HValue* key() { return second(); } 2159 2160 DECLARE_CONCRETE_INSTRUCTION(CallKeyed) 2161 }; 2162 2163 2164 class HCallNamed: public HUnaryCall { 2165 public: 2166 HCallNamed(HValue* context, Handle<String> name, int argument_count) 2167 : HUnaryCall(context, argument_count), name_(name) { 2168 } 2169 2170 virtual void PrintDataTo(StringStream* stream); 2171 2172 HValue* context() { return value(); } 2173 Handle<String> name() const { return name_; } 2174 2175 DECLARE_CONCRETE_INSTRUCTION(CallNamed) 2176 2177 virtual Representation RequiredInputRepresentation(int index) { 2178 return Representation::Tagged(); 2179 } 2180 2181 private: 2182 Handle<String> name_; 2183 }; 2184 2185 2186 class HCallFunction: public HBinaryCall { 2187 public: 2188 HCallFunction(HValue* context, HValue* function, int argument_count) 2189 : HBinaryCall(context, function, argument_count) { 2190 } 2191 2192 static HCallFunction* New(Zone* zone, 2193 HValue* context, 2194 HValue* function, 2195 int argument_count) { 2196 return new(zone) HCallFunction(context, function, argument_count); 2197 } 2198 2199 HValue* context() { return first(); } 2200 HValue* function() { return second(); } 2201 2202 virtual Representation RequiredInputRepresentation(int index) { 2203 return Representation::Tagged(); 2204 } 2205 2206 DECLARE_CONCRETE_INSTRUCTION(CallFunction) 2207 }; 2208 2209 2210 class HCallGlobal: public HUnaryCall { 2211 public: 2212 HCallGlobal(HValue* context, Handle<String> name, int argument_count) 2213 : HUnaryCall(context, argument_count), name_(name) { 2214 } 2215 2216 static HCallGlobal* New(Zone* zone, 2217 HValue* context, 2218 Handle<String> name, 2219 int argument_count) { 2220 return new(zone) HCallGlobal(context, name, argument_count); 2221 } 2222 2223 virtual void PrintDataTo(StringStream* stream); 2224 2225 HValue* context() { return value(); } 2226 Handle<String> name() const { return name_; } 2227 2228 virtual Representation RequiredInputRepresentation(int index) { 2229 return Representation::Tagged(); 2230 } 2231 2232 DECLARE_CONCRETE_INSTRUCTION(CallGlobal) 2233 2234 private: 2235 Handle<String> name_; 2236 }; 2237 2238 2239 class HCallKnownGlobal: public HCall<0> { 2240 public: 2241 HCallKnownGlobal(Handle<JSFunction> target, int argument_count) 2242 : HCall<0>(argument_count), 2243 target_(target), 2244 formal_parameter_count_(target->shared()->formal_parameter_count()) { } 2245 2246 virtual void PrintDataTo(StringStream* stream); 2247 2248 Handle<JSFunction> target() const { return target_; } 2249 int formal_parameter_count() const { return formal_parameter_count_; } 2250 2251 virtual Representation RequiredInputRepresentation(int index) { 2252 return Representation::None(); 2253 } 2254 2255 DECLARE_CONCRETE_INSTRUCTION(CallKnownGlobal) 2256 2257 private: 2258 Handle<JSFunction> target_; 2259 int formal_parameter_count_; 2260 }; 2261 2262 2263 class HCallNew: public HBinaryCall { 2264 public: 2265 HCallNew(HValue* context, HValue* constructor, int argument_count) 2266 : HBinaryCall(context, constructor, argument_count) { 2267 } 2268 2269 virtual Representation RequiredInputRepresentation(int index) { 2270 return Representation::Tagged(); 2271 } 2272 2273 HValue* context() { return first(); } 2274 HValue* constructor() { return second(); } 2275 2276 DECLARE_CONCRETE_INSTRUCTION(CallNew) 2277 }; 2278 2279 2280 class HCallNewArray: public HCallNew { 2281 public: 2282 HCallNewArray(HValue* context, HValue* constructor, int argument_count, 2283 Handle<Cell> type_cell, ElementsKind elements_kind) 2284 : HCallNew(context, constructor, argument_count), 2285 elements_kind_(elements_kind), 2286 type_cell_(type_cell) {} 2287 2288 virtual void PrintDataTo(StringStream* stream); 2289 2290 Handle<Cell> property_cell() const { 2291 return type_cell_; 2292 } 2293 2294 ElementsKind elements_kind() const { return elements_kind_; } 2295 2296 DECLARE_CONCRETE_INSTRUCTION(CallNewArray) 2297 2298 private: 2299 ElementsKind elements_kind_; 2300 Handle<Cell> type_cell_; 2301 }; 2302 2303 2304 class HCallRuntime: public HCall<1> { 2305 public: 2306 static HCallRuntime* New(Zone* zone, 2307 HValue* context, 2308 Handle<String> name, 2309 const Runtime::Function* c_function, 2310 int argument_count) { 2311 return new(zone) HCallRuntime(context, name, c_function, argument_count); 2312 } 2313 2314 virtual void PrintDataTo(StringStream* stream); 2315 2316 HValue* context() { return OperandAt(0); } 2317 const Runtime::Function* function() const { return c_function_; } 2318 Handle<String> name() const { return name_; } 2319 2320 virtual Representation RequiredInputRepresentation(int index) { 2321 return Representation::Tagged(); 2322 } 2323 2324 DECLARE_CONCRETE_INSTRUCTION(CallRuntime) 2325 2326 private: 2327 HCallRuntime(HValue* context, 2328 Handle<String> name, 2329 const Runtime::Function* c_function, 2330 int argument_count) 2331 : HCall<1>(argument_count), c_function_(c_function), name_(name) { 2332 SetOperandAt(0, context); 2333 } 2334 2335 const Runtime::Function* c_function_; 2336 Handle<String> name_; 2337 }; 2338 2339 2340 class HMapEnumLength: public HUnaryOperation { 2341 public: 2342 DECLARE_INSTRUCTION_FACTORY_P1(HMapEnumLength, HValue*); 2343 2344 virtual Representation RequiredInputRepresentation(int index) { 2345 return Representation::Tagged(); 2346 } 2347 2348 DECLARE_CONCRETE_INSTRUCTION(MapEnumLength) 2349 2350 protected: 2351 virtual bool DataEquals(HValue* other) { return true; } 2352 2353 private: 2354 explicit HMapEnumLength(HValue* value) 2355 : HUnaryOperation(value, HType::Smi()) { 2356 set_representation(Representation::Smi()); 2357 SetFlag(kUseGVN); 2358 SetGVNFlag(kDependsOnMaps); 2359 } 2360 2361 virtual bool IsDeletable() const { return true; } 2362 }; 2363 2364 2365 class HElementsKind: public HUnaryOperation { 2366 public: 2367 explicit HElementsKind(HValue* value) : HUnaryOperation(value) { 2368 set_representation(Representation::Integer32()); 2369 SetFlag(kUseGVN); 2370 SetGVNFlag(kDependsOnElementsKind); 2371 } 2372 2373 virtual Representation RequiredInputRepresentation(int index) { 2374 return Representation::Tagged(); 2375 } 2376 2377 DECLARE_CONCRETE_INSTRUCTION(ElementsKind) 2378 2379 protected: 2380 virtual bool DataEquals(HValue* other) { return true; } 2381 2382 private: 2383 virtual bool IsDeletable() const { return true; } 2384 }; 2385 2386 2387 class HUnaryMathOperation: public HTemplateInstruction<2> { 2388 public: 2389 static HInstruction* New(Zone* zone, 2390 HValue* context, 2391 HValue* value, 2392 BuiltinFunctionId op); 2393 2394 HValue* context() { return OperandAt(0); } 2395 HValue* value() { return OperandAt(1); } 2396 2397 virtual void PrintDataTo(StringStream* stream); 2398 2399 virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited); 2400 2401 virtual Representation RequiredInputRepresentation(int index) { 2402 if (index == 0) { 2403 return Representation::Tagged(); 2404 } else { 2405 switch (op_) { 2406 case kMathFloor: 2407 case kMathRound: 2408 case kMathSqrt: 2409 case kMathPowHalf: 2410 case kMathLog: 2411 case kMathExp: 2412 case kMathSin: 2413 case kMathCos: 2414 case kMathTan: 2415 return Representation::Double(); 2416 case kMathAbs: 2417 return representation(); 2418 default: 2419 UNREACHABLE(); 2420 return Representation::None(); 2421 } 2422 } 2423 } 2424 2425 virtual Range* InferRange(Zone* zone); 2426 2427 virtual HValue* Canonicalize(); 2428 virtual Representation RepresentationFromInputs(); 2429 2430 BuiltinFunctionId op() const { return op_; } 2431 const char* OpName() const; 2432 2433 DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation) 2434 2435 protected: 2436 virtual bool DataEquals(HValue* other) { 2437 HUnaryMathOperation* b = HUnaryMathOperation::cast(other); 2438 return op_ == b->op(); 2439 } 2440 2441 private: 2442 HUnaryMathOperation(HValue* context, HValue* value, BuiltinFunctionId op) 2443 : HTemplateInstruction<2>(HType::TaggedNumber()), op_(op) { 2444 SetOperandAt(0, context); 2445 SetOperandAt(1, value); 2446 switch (op) { 2447 case kMathFloor: 2448 case kMathRound: 2449 set_representation(Representation::Integer32()); 2450 break; 2451 case kMathAbs: 2452 // Not setting representation here: it is None intentionally. 2453 SetFlag(kFlexibleRepresentation); 2454 // TODO(svenpanne) This flag is actually only needed if representation() 2455 // is tagged, and not when it is an unboxed double or unboxed integer. 2456 SetGVNFlag(kChangesNewSpacePromotion); 2457 break; 2458 case kMathLog: 2459 case kMathSin: 2460 case kMathCos: 2461 case kMathTan: 2462 set_representation(Representation::Double()); 2463 // These operations use the TranscendentalCache, so they may allocate. 2464 SetGVNFlag(kChangesNewSpacePromotion); 2465 break; 2466 case kMathExp: 2467 case kMathSqrt: 2468 case kMathPowHalf: 2469 set_representation(Representation::Double()); 2470 break; 2471 default: 2472 UNREACHABLE(); 2473 } 2474 SetFlag(kUseGVN); 2475 SetFlag(kAllowUndefinedAsNaN); 2476 } 2477 2478 virtual bool IsDeletable() const { return true; } 2479 2480 BuiltinFunctionId op_; 2481 }; 2482 2483 2484 class HLoadExternalArrayPointer: public HUnaryOperation { 2485 public: 2486 DECLARE_INSTRUCTION_FACTORY_P1(HLoadExternalArrayPointer, HValue*); 2487 2488 virtual Representation RequiredInputRepresentation(int index) { 2489 return Representation::Tagged(); 2490 } 2491 2492 virtual HType CalculateInferredType() { 2493 return HType::None(); 2494 } 2495 2496 DECLARE_CONCRETE_INSTRUCTION(LoadExternalArrayPointer) 2497 2498 protected: 2499 virtual bool DataEquals(HValue* other) { return true; } 2500 2501 private: 2502 explicit HLoadExternalArrayPointer(HValue* value) 2503 : HUnaryOperation(value) { 2504 set_representation(Representation::External()); 2505 // The result of this instruction is idempotent as long as its inputs don't 2506 // change. The external array of a specialized array elements object cannot 2507 // change once set, so it's no necessary to introduce any additional 2508 // dependencies on top of the inputs. 2509 SetFlag(kUseGVN); 2510 } 2511 2512 virtual bool IsDeletable() const { return true; } 2513 }; 2514 2515 2516 class HCheckMaps: public HTemplateInstruction<2> { 2517 public: 2518 static HCheckMaps* New(Zone* zone, HValue* context, HValue* value, 2519 Handle<Map> map, CompilationInfo* info, 2520 HValue *typecheck = NULL); 2521 static HCheckMaps* New(Zone* zone, HValue* context, 2522 HValue* value, SmallMapList* maps, 2523 HValue *typecheck = NULL) { 2524 HCheckMaps* check_map = new(zone) HCheckMaps(value, zone, typecheck); 2525 for (int i = 0; i < maps->length(); i++) { 2526 check_map->Add(maps->at(i), zone); 2527 } 2528 check_map->map_set_.Sort(); 2529 return check_map; 2530 } 2531 2532 bool CanOmitMapChecks() { return omit_; } 2533 2534 virtual bool HasEscapingOperandAt(int index) { return false; } 2535 virtual Representation RequiredInputRepresentation(int index) { 2536 return Representation::Tagged(); 2537 } 2538 virtual void HandleSideEffectDominator(GVNFlag side_effect, 2539 HValue* dominator); 2540 virtual void PrintDataTo(StringStream* stream); 2541 2542 HValue* value() { return OperandAt(0); } 2543 SmallMapList* map_set() { return &map_set_; } 2544 2545 bool has_migration_target() { 2546 return has_migration_target_; 2547 } 2548 2549 virtual void FinalizeUniqueValueId(); 2550 2551 DECLARE_CONCRETE_INSTRUCTION(CheckMaps) 2552 2553 protected: 2554 virtual bool DataEquals(HValue* other) { 2555 ASSERT_EQ(map_set_.length(), map_unique_ids_.length()); 2556 HCheckMaps* b = HCheckMaps::cast(other); 2557 // Relies on the fact that map_set has been sorted before. 2558 if (map_unique_ids_.length() != b->map_unique_ids_.length()) { 2559 return false; 2560 } 2561 for (int i = 0; i < map_unique_ids_.length(); i++) { 2562 if (map_unique_ids_.at(i) != b->map_unique_ids_.at(i)) { 2563 return false; 2564 } 2565 } 2566 return true; 2567 } 2568 2569 private: 2570 void Add(Handle<Map> map, Zone* zone) { 2571 map_set_.Add(map, zone); 2572 if (!has_migration_target_ && map->is_migration_target()) { 2573 has_migration_target_ = true; 2574 SetGVNFlag(kChangesNewSpacePromotion); 2575 } 2576 } 2577 2578 // Clients should use one of the static New* methods above. 2579 HCheckMaps(HValue* value, Zone *zone, HValue* typecheck) 2580 : HTemplateInstruction<2>(value->type()), 2581 omit_(false), has_migration_target_(false), map_unique_ids_(0, zone) { 2582 SetOperandAt(0, value); 2583 // Use the object value for the dependency if NULL is passed. 2584 // TODO(titzer): do GVN flags already express this dependency? 2585 SetOperandAt(1, typecheck != NULL ? typecheck : value); 2586 set_representation(Representation::Tagged()); 2587 SetFlag(kUseGVN); 2588 SetFlag(kTrackSideEffectDominators); 2589 SetGVNFlag(kDependsOnMaps); 2590 SetGVNFlag(kDependsOnElementsKind); 2591 } 2592 2593 void omit(CompilationInfo* info) { 2594 omit_ = true; 2595 for (int i = 0; i < map_set_.length(); i++) { 2596 Handle<Map> map = map_set_.at(i); 2597 map->AddDependentCompilationInfo(DependentCode::kPrototypeCheckGroup, 2598 info); 2599 } 2600 } 2601 2602 bool omit_; 2603 bool has_migration_target_; 2604 SmallMapList map_set_; 2605 ZoneList<UniqueValueId> map_unique_ids_; 2606 }; 2607 2608 2609 class HCheckFunction: public HUnaryOperation { 2610 public: 2611 DECLARE_INSTRUCTION_FACTORY_P2(HCheckFunction, HValue*, Handle<JSFunction>); 2612 2613 virtual Representation RequiredInputRepresentation(int index) { 2614 return Representation::Tagged(); 2615 } 2616 virtual void PrintDataTo(StringStream* stream); 2617 2618 virtual HValue* Canonicalize(); 2619 2620 #ifdef DEBUG 2621 virtual void Verify(); 2622 #endif 2623 2624 virtual void FinalizeUniqueValueId() { 2625 target_unique_id_ = UniqueValueId(target_); 2626 } 2627 2628 Handle<JSFunction> target() const { return target_; } 2629 bool target_in_new_space() const { return target_in_new_space_; } 2630 2631 DECLARE_CONCRETE_INSTRUCTION(CheckFunction) 2632 2633 protected: 2634 virtual bool DataEquals(HValue* other) { 2635 HCheckFunction* b = HCheckFunction::cast(other); 2636 return target_unique_id_ == b->target_unique_id_; 2637 } 2638 2639 private: 2640 HCheckFunction(HValue* value, Handle<JSFunction> function) 2641 : HUnaryOperation(value, value->type()), 2642 target_(function), target_unique_id_() { 2643 set_representation(Representation::Tagged()); 2644 SetFlag(kUseGVN); 2645 target_in_new_space_ = Isolate::Current()->heap()->InNewSpace(*function); 2646 } 2647 2648 Handle<JSFunction> target_; 2649 UniqueValueId target_unique_id_; 2650 bool target_in_new_space_; 2651 }; 2652 2653 2654 class HCheckInstanceType: public HUnaryOperation { 2655 public: 2656 static HCheckInstanceType* NewIsSpecObject(HValue* value, Zone* zone) { 2657 return new(zone) HCheckInstanceType(value, IS_SPEC_OBJECT); 2658 } 2659 static HCheckInstanceType* NewIsJSArray(HValue* value, Zone* zone) { 2660 return new(zone) HCheckInstanceType(value, IS_JS_ARRAY); 2661 } 2662 static HCheckInstanceType* NewIsString(HValue* value, Zone* zone) { 2663 return new(zone) HCheckInstanceType(value, IS_STRING); 2664 } 2665 static HCheckInstanceType* NewIsInternalizedString( 2666 HValue* value, Zone* zone) { 2667 return new(zone) HCheckInstanceType(value, IS_INTERNALIZED_STRING); 2668 } 2669 2670 virtual void PrintDataTo(StringStream* stream); 2671 2672 virtual Representation RequiredInputRepresentation(int index) { 2673 return Representation::Tagged(); 2674 } 2675 2676 virtual HValue* Canonicalize(); 2677 2678 bool is_interval_check() const { return check_ <= LAST_INTERVAL_CHECK; } 2679 void GetCheckInterval(InstanceType* first, InstanceType* last); 2680 void GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag); 2681 2682 DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType) 2683 2684 protected: 2685 // TODO(ager): It could be nice to allow the ommision of instance 2686 // type checks if we have already performed an instance type check 2687 // with a larger range. 2688 virtual bool DataEquals(HValue* other) { 2689 HCheckInstanceType* b = HCheckInstanceType::cast(other); 2690 return check_ == b->check_; 2691 } 2692 2693 private: 2694 enum Check { 2695 IS_SPEC_OBJECT, 2696 IS_JS_ARRAY, 2697 IS_STRING, 2698 IS_INTERNALIZED_STRING, 2699 LAST_INTERVAL_CHECK = IS_JS_ARRAY 2700 }; 2701 2702 const char* GetCheckName(); 2703 2704 HCheckInstanceType(HValue* value, Check check) 2705 : HUnaryOperation(value), check_(check) { 2706 set_representation(Representation::Tagged()); 2707 SetFlag(kUseGVN); 2708 } 2709 2710 const Check check_; 2711 }; 2712 2713 2714 class HCheckSmi: public HUnaryOperation { 2715 public: 2716 DECLARE_INSTRUCTION_FACTORY_P1(HCheckSmi, HValue*); 2717 2718 virtual Representation RequiredInputRepresentation(int index) { 2719 return Representation::Tagged(); 2720 } 2721 2722 virtual HValue* Canonicalize() { 2723 HType value_type = value()->type(); 2724 if (value_type.IsSmi()) { 2725 return NULL; 2726 } 2727 return this; 2728 } 2729 2730 DECLARE_CONCRETE_INSTRUCTION(CheckSmi) 2731 2732 protected: 2733 virtual bool DataEquals(HValue* other) { return true; } 2734 2735 private: 2736 explicit HCheckSmi(HValue* value) : HUnaryOperation(value, HType::Smi()) { 2737 set_representation(Representation::Smi()); 2738 SetFlag(kUseGVN); 2739 } 2740 }; 2741 2742 2743 class HIsNumberAndBranch: public HUnaryControlInstruction { 2744 public: 2745 explicit HIsNumberAndBranch(HValue* value) 2746 : HUnaryControlInstruction(value, NULL, NULL) { 2747 SetFlag(kFlexibleRepresentation); 2748 } 2749 2750 virtual Representation RequiredInputRepresentation(int index) { 2751 return Representation::None(); 2752 } 2753 2754 DECLARE_CONCRETE_INSTRUCTION(IsNumberAndBranch) 2755 }; 2756 2757 2758 class HCheckHeapObject: public HUnaryOperation { 2759 public: 2760 DECLARE_INSTRUCTION_FACTORY_P1(HCheckHeapObject, HValue*); 2761 2762 virtual bool HasEscapingOperandAt(int index) { return false; } 2763 virtual Representation RequiredInputRepresentation(int index) { 2764 return Representation::Tagged(); 2765 } 2766 2767 #ifdef DEBUG 2768 virtual void Verify(); 2769 #endif 2770 2771 virtual HValue* Canonicalize() { 2772 return value()->type().IsHeapObject() ? NULL : this; 2773 } 2774 2775 DECLARE_CONCRETE_INSTRUCTION(CheckHeapObject) 2776 2777 protected: 2778 virtual bool DataEquals(HValue* other) { return true; } 2779 2780 private: 2781 explicit HCheckHeapObject(HValue* value) 2782 : HUnaryOperation(value, HType::NonPrimitive()) { 2783 set_representation(Representation::Tagged()); 2784 SetFlag(kUseGVN); 2785 } 2786 }; 2787 2788 2789 class InductionVariableData; 2790 2791 2792 struct InductionVariableLimitUpdate { 2793 InductionVariableData* updated_variable; 2794 HValue* limit; 2795 bool limit_is_upper; 2796 bool limit_is_included; 2797 2798 InductionVariableLimitUpdate() 2799 : updated_variable(NULL), limit(NULL), 2800 limit_is_upper(false), limit_is_included(false) {} 2801 }; 2802 2803 2804 class HBoundsCheck; 2805 class HPhi; 2806 class HConstant; 2807 class HBitwise; 2808 2809 2810 class InductionVariableData : public ZoneObject { 2811 public: 2812 class InductionVariableCheck : public ZoneObject { 2813 public: 2814 HBoundsCheck* check() { return check_; } 2815 InductionVariableCheck* next() { return next_; } 2816 bool HasUpperLimit() { return upper_limit_ >= 0; } 2817 int32_t upper_limit() { 2818 ASSERT(HasUpperLimit()); 2819 return upper_limit_; 2820 } 2821 void set_upper_limit(int32_t upper_limit) { 2822 upper_limit_ = upper_limit; 2823 } 2824 2825 bool processed() { return processed_; } 2826 void set_processed() { processed_ = true; } 2827 2828 InductionVariableCheck(HBoundsCheck* check, 2829 InductionVariableCheck* next, 2830 int32_t upper_limit = kNoLimit) 2831 : check_(check), next_(next), upper_limit_(upper_limit), 2832 processed_(false) {} 2833 2834 private: 2835 HBoundsCheck* check_; 2836 InductionVariableCheck* next_; 2837 int32_t upper_limit_; 2838 bool processed_; 2839 }; 2840 2841 class ChecksRelatedToLength : public ZoneObject { 2842 public: 2843 HValue* length() { return length_; } 2844 ChecksRelatedToLength* next() { return next_; } 2845 InductionVariableCheck* checks() { return checks_; } 2846 2847 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit); 2848 void CloseCurrentBlock(); 2849 2850 ChecksRelatedToLength(HValue* length, ChecksRelatedToLength* next) 2851 : length_(length), next_(next), checks_(NULL), 2852 first_check_in_block_(NULL), 2853 added_index_(NULL), 2854 added_constant_(NULL), 2855 current_and_mask_in_block_(0), 2856 current_or_mask_in_block_(0) {} 2857 2858 private: 2859 void UseNewIndexInCurrentBlock(Token::Value token, 2860 int32_t mask, 2861 HValue* index_base, 2862 HValue* context); 2863 2864 HBoundsCheck* first_check_in_block() { return first_check_in_block_; } 2865 HBitwise* added_index() { return added_index_; } 2866 void set_added_index(HBitwise* index) { added_index_ = index; } 2867 HConstant* added_constant() { return added_constant_; } 2868 void set_added_constant(HConstant* constant) { added_constant_ = constant; } 2869 int32_t current_and_mask_in_block() { return current_and_mask_in_block_; } 2870 int32_t current_or_mask_in_block() { return current_or_mask_in_block_; } 2871 int32_t current_upper_limit() { return current_upper_limit_; } 2872 2873 HValue* length_; 2874 ChecksRelatedToLength* next_; 2875 InductionVariableCheck* checks_; 2876 2877 HBoundsCheck* first_check_in_block_; 2878 HBitwise* added_index_; 2879 HConstant* added_constant_; 2880 int32_t current_and_mask_in_block_; 2881 int32_t current_or_mask_in_block_; 2882 int32_t current_upper_limit_; 2883 }; 2884 2885 struct LimitFromPredecessorBlock { 2886 InductionVariableData* variable; 2887 Token::Value token; 2888 HValue* limit; 2889 HBasicBlock* other_target; 2890 2891 bool LimitIsValid() { return token != Token::ILLEGAL; } 2892 2893 bool LimitIsIncluded() { 2894 return Token::IsEqualityOp(token) || 2895 token == Token::GTE || token == Token::LTE; 2896 } 2897 bool LimitIsUpper() { 2898 return token == Token::LTE || token == Token::LT || token == Token::NE; 2899 } 2900 2901 LimitFromPredecessorBlock() 2902 : variable(NULL), 2903 token(Token::ILLEGAL), 2904 limit(NULL), 2905 other_target(NULL) {} 2906 }; 2907 2908 static const int32_t kNoLimit = -1; 2909 2910 static InductionVariableData* ExaminePhi(HPhi* phi); 2911 static void ComputeLimitFromPredecessorBlock( 2912 HBasicBlock* block, 2913 LimitFromPredecessorBlock* result); 2914 static bool ComputeInductionVariableLimit( 2915 HBasicBlock* block, 2916 InductionVariableLimitUpdate* additional_limit); 2917 2918 struct BitwiseDecompositionResult { 2919 HValue* base; 2920 int32_t and_mask; 2921 int32_t or_mask; 2922 HValue* context; 2923 2924 BitwiseDecompositionResult() 2925 : base(NULL), and_mask(0), or_mask(0), context(NULL) {} 2926 }; 2927 static void DecomposeBitwise(HValue* value, 2928 BitwiseDecompositionResult* result); 2929 2930 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit); 2931 2932 bool CheckIfBranchIsLoopGuard(Token::Value token, 2933 HBasicBlock* current_branch, 2934 HBasicBlock* other_branch); 2935 2936 void UpdateAdditionalLimit(InductionVariableLimitUpdate* update); 2937 2938 HPhi* phi() { return phi_; } 2939 HValue* base() { return base_; } 2940 int32_t increment() { return increment_; } 2941 HValue* limit() { return limit_; } 2942 bool limit_included() { return limit_included_; } 2943 HBasicBlock* limit_validity() { return limit_validity_; } 2944 HBasicBlock* induction_exit_block() { return induction_exit_block_; } 2945 HBasicBlock* induction_exit_target() { return induction_exit_target_; } 2946 ChecksRelatedToLength* checks() { return checks_; } 2947 HValue* additional_upper_limit() { return additional_upper_limit_; } 2948 bool additional_upper_limit_is_included() { 2949 return additional_upper_limit_is_included_; 2950 } 2951 HValue* additional_lower_limit() { return additional_lower_limit_; } 2952 bool additional_lower_limit_is_included() { 2953 return additional_lower_limit_is_included_; 2954 } 2955 2956 bool LowerLimitIsNonNegativeConstant() { 2957 if (base()->IsInteger32Constant() && base()->GetInteger32Constant() >= 0) { 2958 return true; 2959 } 2960 if (additional_lower_limit() != NULL && 2961 additional_lower_limit()->IsInteger32Constant() && 2962 additional_lower_limit()->GetInteger32Constant() >= 0) { 2963 // Ignoring the corner case of !additional_lower_limit_is_included() 2964 // is safe, handling it adds unneeded complexity. 2965 return true; 2966 } 2967 return false; 2968 } 2969 2970 int32_t ComputeUpperLimit(int32_t and_mask, int32_t or_mask); 2971 2972 private: 2973 template <class T> void swap(T* a, T* b) { 2974 T c(*a); 2975 *a = *b; 2976 *b = c; 2977 } 2978 2979 InductionVariableData(HPhi* phi, HValue* base, int32_t increment) 2980 : phi_(phi), base_(IgnoreOsrValue(base)), increment_(increment), 2981 limit_(NULL), limit_included_(false), limit_validity_(NULL), 2982 induction_exit_block_(NULL), induction_exit_target_(NULL), 2983 checks_(NULL), 2984 additional_upper_limit_(NULL), 2985 additional_upper_limit_is_included_(false), 2986 additional_lower_limit_(NULL), 2987 additional_lower_limit_is_included_(false) {} 2988 2989 static int32_t ComputeIncrement(HPhi* phi, HValue* phi_operand); 2990 2991 static HValue* IgnoreOsrValue(HValue* v); 2992 static InductionVariableData* GetInductionVariableData(HValue* v); 2993 2994 HPhi* phi_; 2995 HValue* base_; 2996 int32_t increment_; 2997 HValue* limit_; 2998 bool limit_included_; 2999 HBasicBlock* limit_validity_; 3000 HBasicBlock* induction_exit_block_; 3001 HBasicBlock* induction_exit_target_; 3002 ChecksRelatedToLength* checks_; 3003 HValue* additional_upper_limit_; 3004 bool additional_upper_limit_is_included_; 3005 HValue* additional_lower_limit_; 3006 bool additional_lower_limit_is_included_; 3007 }; 3008 3009 3010 class HPhi: public HValue { 3011 public: 3012 HPhi(int merged_index, Zone* zone) 3013 : inputs_(2, zone), 3014 merged_index_(merged_index), 3015 phi_id_(-1), 3016 induction_variable_data_(NULL) { 3017 for (int i = 0; i < Representation::kNumRepresentations; i++) { 3018 non_phi_uses_[i] = 0; 3019 indirect_uses_[i] = 0; 3020 } 3021 ASSERT(merged_index >= 0 || merged_index == kInvalidMergedIndex); 3022 SetFlag(kFlexibleRepresentation); 3023 SetFlag(kAllowUndefinedAsNaN); 3024 } 3025 3026 virtual Representation RepresentationFromInputs(); 3027 3028 virtual Range* InferRange(Zone* zone); 3029 virtual void InferRepresentation(HInferRepresentationPhase* h_infer); 3030 virtual Representation RequiredInputRepresentation(int index) { 3031 return representation(); 3032 } 3033 virtual Representation KnownOptimalRepresentation() { 3034 return representation(); 3035 } 3036 virtual HType CalculateInferredType(); 3037 virtual int OperandCount() { return inputs_.length(); } 3038 virtual HValue* OperandAt(int index) const { return inputs_[index]; } 3039 HValue* GetRedundantReplacement(); 3040 void AddInput(HValue* value); 3041 bool HasRealUses(); 3042 3043 bool IsReceiver() const { return merged_index_ == 0; } 3044 bool HasMergedIndex() const { return merged_index_ != kInvalidMergedIndex; } 3045 3046 int merged_index() const { return merged_index_; } 3047 3048 InductionVariableData* induction_variable_data() { 3049 return induction_variable_data_; 3050 } 3051 bool IsInductionVariable() { 3052 return induction_variable_data_ != NULL; 3053 } 3054 bool IsLimitedInductionVariable() { 3055 return IsInductionVariable() && 3056 induction_variable_data_->limit() != NULL; 3057 } 3058 void DetectInductionVariable() { 3059 ASSERT(induction_variable_data_ == NULL); 3060 induction_variable_data_ = InductionVariableData::ExaminePhi(this); 3061 } 3062 3063 virtual void PrintTo(StringStream* stream); 3064 3065 #ifdef DEBUG 3066 virtual void Verify(); 3067 #endif 3068 3069 void InitRealUses(int id); 3070 void AddNonPhiUsesFrom(HPhi* other); 3071 void AddIndirectUsesTo(int* use_count); 3072 3073 int tagged_non_phi_uses() const { 3074 return non_phi_uses_[Representation::kTagged]; 3075 } 3076 int smi_non_phi_uses() const { 3077 return non_phi_uses_[Representation::kSmi]; 3078 } 3079 int int32_non_phi_uses() const { 3080 return non_phi_uses_[Representation::kInteger32]; 3081 } 3082 int double_non_phi_uses() const { 3083 return non_phi_uses_[Representation::kDouble]; 3084 } 3085 int tagged_indirect_uses() const { 3086 return indirect_uses_[Representation::kTagged]; 3087 } 3088 int smi_indirect_uses() const { 3089 return indirect_uses_[Representation::kSmi]; 3090 } 3091 int int32_indirect_uses() const { 3092 return indirect_uses_[Representation::kInteger32]; 3093 } 3094 int double_indirect_uses() const { 3095 return indirect_uses_[Representation::kDouble]; 3096 } 3097 int phi_id() { return phi_id_; } 3098 3099 static HPhi* cast(HValue* value) { 3100 ASSERT(value->IsPhi()); 3101 return reinterpret_cast<HPhi*>(value); 3102 } 3103 virtual Opcode opcode() const { return HValue::kPhi; } 3104 3105 void SimplifyConstantInputs(); 3106 3107 // Marker value representing an invalid merge index. 3108 static const int kInvalidMergedIndex = -1; 3109 3110 protected: 3111 virtual void DeleteFromGraph(); 3112 virtual void InternalSetOperandAt(int index, HValue* value) { 3113 inputs_[index] = value; 3114 } 3115 3116 private: 3117 ZoneList<HValue*> inputs_; 3118 int merged_index_; 3119 3120 int non_phi_uses_[Representation::kNumRepresentations]; 3121 int indirect_uses_[Representation::kNumRepresentations]; 3122 int phi_id_; 3123 InductionVariableData* induction_variable_data_; 3124 3125 // TODO(titzer): we can't eliminate the receiver for generating backtraces 3126 virtual bool IsDeletable() const { return !IsReceiver(); } 3127 }; 3128 3129 3130 // Common base class for HArgumentsObject and HCapturedObject. 3131 class HDematerializedObject: public HTemplateInstruction<0> { 3132 public: 3133 HDematerializedObject(int count, Zone* zone) : values_(count, zone) {} 3134 3135 virtual int OperandCount() { return values_.length(); } 3136 virtual HValue* OperandAt(int index) const { return values_[index]; } 3137 3138 virtual bool HasEscapingOperandAt(int index) { return false; } 3139 virtual Representation RequiredInputRepresentation(int index) { 3140 return Representation::None(); 3141 } 3142 3143 protected: 3144 virtual void InternalSetOperandAt(int index, HValue* value) { 3145 values_[index] = value; 3146 } 3147 3148 // List of values tracked by this marker. 3149 ZoneList<HValue*> values_; 3150 3151 private: 3152 virtual bool IsDeletable() const { return true; } 3153 }; 3154 3155 3156 class HArgumentsObject: public HDematerializedObject { 3157 public: 3158 static HArgumentsObject* New(Zone* zone, HValue* context, int count) { 3159 return new(zone) HArgumentsObject(count, zone); 3160 } 3161 3162 // The values contain a list of all elements in the arguments object 3163 // including the receiver object, which is skipped when materializing. 3164 const ZoneList<HValue*>* arguments_values() const { return &values_; } 3165 int arguments_count() const { return values_.length(); } 3166 3167 void AddArgument(HValue* argument, Zone* zone) { 3168 values_.Add(NULL, zone); // Resize list. 3169 SetOperandAt(values_.length() - 1, argument); 3170 } 3171 3172 DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject) 3173 3174 private: 3175 HArgumentsObject(int count, Zone* zone) 3176 : HDematerializedObject(count, zone) { 3177 set_representation(Representation::Tagged()); 3178 SetFlag(kIsArguments); 3179 } 3180 }; 3181 3182 3183 class HCapturedObject: public HDematerializedObject { 3184 public: 3185 HCapturedObject(int length, Zone* zone) 3186 : HDematerializedObject(length, zone) { 3187 set_representation(Representation::Tagged()); 3188 values_.AddBlock(NULL, length, zone); // Resize list. 3189 } 3190 3191 // The values contain a list of all in-object properties inside the 3192 // captured object and is index by field index. Properties in the 3193 // properties or elements backing store are not tracked here. 3194 const ZoneList<HValue*>* values() const { return &values_; } 3195 int length() const { return values_.length(); } 3196 3197 DECLARE_CONCRETE_INSTRUCTION(CapturedObject) 3198 }; 3199 3200 3201 class HConstant: public HTemplateInstruction<0> { 3202 public: 3203 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, int32_t); 3204 DECLARE_INSTRUCTION_FACTORY_P2(HConstant, int32_t, Representation); 3205 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, double); 3206 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Handle<Object>); 3207 DECLARE_INSTRUCTION_FACTORY_P2(HConstant, Handle<Map>, UniqueValueId); 3208 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, ExternalReference); 3209 3210 static HConstant* CreateAndInsertAfter(Zone* zone, 3211 HValue* context, 3212 int32_t value, 3213 Representation representation, 3214 HInstruction* instruction) { 3215 HConstant* new_constant = 3216 HConstant::New(zone, context, value, representation); 3217 new_constant->InsertAfter(instruction); 3218 return new_constant; 3219 } 3220 3221 static HConstant* CreateAndInsertBefore(Zone* zone, 3222 HValue* context, 3223 int32_t value, 3224 Representation representation, 3225 HInstruction* instruction) { 3226 HConstant* new_constant = 3227 HConstant::New(zone, context, value, representation); 3228 new_constant->InsertBefore(instruction); 3229 return new_constant; 3230 } 3231 3232 Handle<Object> handle() { 3233 if (handle_.is_null()) { 3234 Factory* factory = Isolate::Current()->factory(); 3235 // Default arguments to is_not_in_new_space depend on this heap number 3236 // to be tenured so that it's guaranteed not be be located in new space. 3237 handle_ = factory->NewNumber(double_value_, TENURED); 3238 } 3239 AllowDeferredHandleDereference smi_check; 3240 ASSERT(has_int32_value_ || !handle_->IsSmi()); 3241 return handle_; 3242 } 3243 3244 bool InstanceOf(Handle<Map> map) { 3245 Handle<Object> constant_object = handle(); 3246 return constant_object->IsJSObject() && 3247 Handle<JSObject>::cast(constant_object)->map() == *map; 3248 } 3249 3250 bool IsSpecialDouble() const { 3251 return has_double_value_ && 3252 (BitCast<int64_t>(double_value_) == BitCast<int64_t>(-0.0) || 3253 FixedDoubleArray::is_the_hole_nan(double_value_) || 3254 std::isnan(double_value_)); 3255 } 3256 3257 bool NotInNewSpace() const { 3258 return is_not_in_new_space_; 3259 } 3260 3261 bool ImmortalImmovable() const { 3262 if (has_int32_value_) { 3263 return false; 3264 } 3265 if (has_double_value_) { 3266 if (IsSpecialDouble()) { 3267 return true; 3268 } 3269 return false; 3270 } 3271 if (has_external_reference_value_) { 3272 return false; 3273 } 3274 3275 ASSERT(!handle_.is_null()); 3276 Heap* heap = isolate()->heap(); 3277 ASSERT(unique_id_ != UniqueValueId(heap->minus_zero_value())); 3278 ASSERT(unique_id_ != UniqueValueId(heap->nan_value())); 3279 return unique_id_ == UniqueValueId(heap->undefined_value()) || 3280 unique_id_ == UniqueValueId(heap->null_value()) || 3281 unique_id_ == UniqueValueId(heap->true_value()) || 3282 unique_id_ == UniqueValueId(heap->false_value()) || 3283 unique_id_ == UniqueValueId(heap->the_hole_value()) || 3284 unique_id_ == UniqueValueId(heap->empty_string()); 3285 } 3286 3287 bool IsCell() const { 3288 return is_cell_; 3289 } 3290 3291 virtual Representation RequiredInputRepresentation(int index) { 3292 return Representation::None(); 3293 } 3294 3295 virtual Representation KnownOptimalRepresentation() { 3296 if (HasSmiValue() && kSmiValueSize == 31) return Representation::Smi(); 3297 if (HasInteger32Value()) return Representation::Integer32(); 3298 if (HasNumberValue()) return Representation::Double(); 3299 if (HasExternalReferenceValue()) return Representation::External(); 3300 return Representation::Tagged(); 3301 } 3302 3303 virtual bool EmitAtUses(); 3304 virtual void PrintDataTo(StringStream* stream); 3305 bool IsInteger() { return handle()->IsSmi(); } 3306 HConstant* CopyToRepresentation(Representation r, Zone* zone) const; 3307 Maybe<HConstant*> CopyToTruncatedInt32(Zone* zone); 3308 Maybe<HConstant*> CopyToTruncatedNumber(Zone* zone); 3309 bool HasInteger32Value() const { return has_int32_value_; } 3310 int32_t Integer32Value() const { 3311 ASSERT(HasInteger32Value()); 3312 return int32_value_; 3313 } 3314 bool HasSmiValue() const { return has_smi_value_; } 3315 bool HasDoubleValue() const { return has_double_value_; } 3316 double DoubleValue() const { 3317 ASSERT(HasDoubleValue()); 3318 return double_value_; 3319 } 3320 bool IsTheHole() const { 3321 if (HasDoubleValue() && FixedDoubleArray::is_the_hole_nan(double_value_)) { 3322 return true; 3323 } 3324 Heap* heap = isolate()->heap(); 3325 if (!handle_.is_null() && *handle_ == heap->the_hole_value()) { 3326 return true; 3327 } 3328 return false; 3329 } 3330 bool HasNumberValue() const { return has_double_value_; } 3331 int32_t NumberValueAsInteger32() const { 3332 ASSERT(HasNumberValue()); 3333 // Irrespective of whether a numeric HConstant can be safely 3334 // represented as an int32, we store the (in some cases lossy) 3335 // representation of the number in int32_value_. 3336 return int32_value_; 3337 } 3338 bool HasStringValue() const { 3339 if (has_double_value_ || has_int32_value_) return false; 3340 ASSERT(!handle_.is_null()); 3341 return type_.IsString(); 3342 } 3343 Handle<String> StringValue() const { 3344 ASSERT(HasStringValue()); 3345 return Handle<String>::cast(handle_); 3346 } 3347 bool HasInternalizedStringValue() const { 3348 return HasStringValue() && is_internalized_string_; 3349 } 3350 3351 bool HasExternalReferenceValue() const { 3352 return has_external_reference_value_; 3353 } 3354 ExternalReference ExternalReferenceValue() const { 3355 return external_reference_value_; 3356 } 3357 3358 bool HasBooleanValue() const { return type_.IsBoolean(); } 3359 bool BooleanValue() const { return boolean_value_; } 3360 3361 virtual intptr_t Hashcode() { 3362 if (has_int32_value_) { 3363 return static_cast<intptr_t>(int32_value_); 3364 } else if (has_double_value_) { 3365 return static_cast<intptr_t>(BitCast<int64_t>(double_value_)); 3366 } else if (has_external_reference_value_) { 3367 return reinterpret_cast<intptr_t>(external_reference_value_.address()); 3368 } else { 3369 ASSERT(!handle_.is_null()); 3370 return unique_id_.Hashcode(); 3371 } 3372 } 3373 3374 virtual void FinalizeUniqueValueId() { 3375 if (!has_double_value_ && !has_external_reference_value_) { 3376 ASSERT(!handle_.is_null()); 3377 unique_id_ = UniqueValueId(handle_); 3378 } 3379 } 3380 3381 bool UniqueValueIdsMatch(UniqueValueId other) { 3382 return !has_double_value_ && !has_external_reference_value_ && 3383 unique_id_ == other; 3384 } 3385 3386 #ifdef DEBUG 3387 virtual void Verify() { } 3388 #endif 3389 3390 DECLARE_CONCRETE_INSTRUCTION(Constant) 3391 3392 protected: 3393 virtual Range* InferRange(Zone* zone); 3394 3395 virtual bool DataEquals(HValue* other) { 3396 HConstant* other_constant = HConstant::cast(other); 3397 if (has_int32_value_) { 3398 return other_constant->has_int32_value_ && 3399 int32_value_ == other_constant->int32_value_; 3400 } else if (has_double_value_) { 3401 return other_constant->has_double_value_ && 3402 BitCast<int64_t>(double_value_) == 3403 BitCast<int64_t>(other_constant->double_value_); 3404 } else if (has_external_reference_value_) { 3405 return other_constant->has_external_reference_value_ && 3406 external_reference_value_ == 3407 other_constant->external_reference_value_; 3408 } else { 3409 ASSERT(!handle_.is_null()); 3410 return !other_constant->handle_.is_null() && 3411 unique_id_ == other_constant->unique_id_; 3412 } 3413 } 3414 3415 private: 3416 friend class HGraph; 3417 HConstant(Handle<Object> handle, Representation r = Representation::None()); 3418 HConstant(int32_t value, 3419 Representation r = Representation::None(), 3420 bool is_not_in_new_space = true, 3421 Handle<Object> optional_handle = Handle<Object>::null()); 3422 HConstant(double value, 3423 Representation r = Representation::None(), 3424 bool is_not_in_new_space = true, 3425 Handle<Object> optional_handle = Handle<Object>::null()); 3426 HConstant(Handle<Object> handle, 3427 UniqueValueId unique_id, 3428 Representation r, 3429 HType type, 3430 bool is_internalized_string, 3431 bool is_not_in_new_space, 3432 bool is_cell, 3433 bool boolean_value); 3434 HConstant(Handle<Map> handle, 3435 UniqueValueId unique_id); 3436 explicit HConstant(ExternalReference reference); 3437 3438 void Initialize(Representation r); 3439 3440 virtual bool IsDeletable() const { return true; } 3441 3442 // If this is a numerical constant, handle_ either points to to the 3443 // HeapObject the constant originated from or is null. If the 3444 // constant is non-numeric, handle_ always points to a valid 3445 // constant HeapObject. 3446 Handle<Object> handle_; 3447 UniqueValueId unique_id_; 3448 3449 // We store the HConstant in the most specific form safely possible. 3450 // The two flags, has_int32_value_ and has_double_value_ tell us if 3451 // int32_value_ and double_value_ hold valid, safe representations 3452 // of the constant. has_int32_value_ implies has_double_value_ but 3453 // not the converse. 3454 bool has_smi_value_ : 1; 3455 bool has_int32_value_ : 1; 3456 bool has_double_value_ : 1; 3457 bool has_external_reference_value_ : 1; 3458 bool is_internalized_string_ : 1; // TODO(yangguo): make this part of HType. 3459 bool is_not_in_new_space_ : 1; 3460 bool is_cell_ : 1; 3461 bool boolean_value_ : 1; 3462 int32_t int32_value_; 3463 double double_value_; 3464 ExternalReference external_reference_value_; 3465 }; 3466 3467 3468 class HBinaryOperation: public HTemplateInstruction<3> { 3469 public: 3470 HBinaryOperation(HValue* context, HValue* left, HValue* right, 3471 HType type = HType::Tagged()) 3472 : HTemplateInstruction<3>(type), 3473 observed_output_representation_(Representation::None()) { 3474 ASSERT(left != NULL && right != NULL); 3475 SetOperandAt(0, context); 3476 SetOperandAt(1, left); 3477 SetOperandAt(2, right); 3478 observed_input_representation_[0] = Representation::None(); 3479 observed_input_representation_[1] = Representation::None(); 3480 } 3481 3482 HValue* context() const { return OperandAt(0); } 3483 HValue* left() const { return OperandAt(1); } 3484 HValue* right() const { return OperandAt(2); } 3485 3486 // True if switching left and right operands likely generates better code. 3487 bool AreOperandsBetterSwitched() { 3488 if (!IsCommutative()) return false; 3489 3490 // Constant operands are better off on the right, they can be inlined in 3491 // many situations on most platforms. 3492 if (left()->IsConstant()) return true; 3493 if (right()->IsConstant()) return false; 3494 3495 // Otherwise, if there is only one use of the right operand, it would be 3496 // better off on the left for platforms that only have 2-arg arithmetic 3497 // ops (e.g ia32, x64) that clobber the left operand. 3498 return right()->UseCount() == 1; 3499 } 3500 3501 HValue* BetterLeftOperand() { 3502 return AreOperandsBetterSwitched() ? right() : left(); 3503 } 3504 3505 HValue* BetterRightOperand() { 3506 return AreOperandsBetterSwitched() ? left() : right(); 3507 } 3508 3509 void set_observed_input_representation(int index, Representation rep) { 3510 ASSERT(index >= 1 && index <= 2); 3511 observed_input_representation_[index - 1] = rep; 3512 } 3513 3514 virtual void initialize_output_representation(Representation observed) { 3515 observed_output_representation_ = observed; 3516 } 3517 3518 virtual Representation observed_input_representation(int index) { 3519 if (index == 0) return Representation::Tagged(); 3520 return observed_input_representation_[index - 1]; 3521 } 3522 3523 virtual void UpdateRepresentation(Representation new_rep, 3524 HInferRepresentationPhase* h_infer, 3525 const char* reason) { 3526 Representation rep = !FLAG_smi_binop && new_rep.IsSmi() 3527 ? Representation::Integer32() : new_rep; 3528 HValue::UpdateRepresentation(rep, h_infer, reason); 3529 } 3530 3531 virtual void InferRepresentation(HInferRepresentationPhase* h_infer); 3532 virtual Representation RepresentationFromInputs(); 3533 Representation RepresentationFromOutput(); 3534 virtual void AssumeRepresentation(Representation r); 3535 3536 virtual bool IsCommutative() const { return false; } 3537 3538 virtual void PrintDataTo(StringStream* stream); 3539 3540 virtual Representation RequiredInputRepresentation(int index) { 3541 if (index == 0) return Representation::Tagged(); 3542 return representation(); 3543 } 3544 3545 DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation) 3546 3547 private: 3548 bool IgnoreObservedOutputRepresentation(Representation current_rep); 3549 3550 Representation observed_input_representation_[2]; 3551 Representation observed_output_representation_; 3552 }; 3553 3554 3555 class HWrapReceiver: public HTemplateInstruction<2> { 3556 public: 3557 DECLARE_INSTRUCTION_FACTORY_P2(HWrapReceiver, HValue*, HValue*); 3558 3559 virtual Representation RequiredInputRepresentation(int index) { 3560 return Representation::Tagged(); 3561 } 3562 3563 HValue* receiver() { return OperandAt(0); } 3564 HValue* function() { return OperandAt(1); } 3565 3566 virtual HValue* Canonicalize(); 3567 3568 virtual void PrintDataTo(StringStream* stream); 3569 3570 DECLARE_CONCRETE_INSTRUCTION(WrapReceiver) 3571 3572 private: 3573 HWrapReceiver(HValue* receiver, HValue* function) { 3574 set_representation(Representation::Tagged()); 3575 SetOperandAt(0, receiver); 3576 SetOperandAt(1, function); 3577 } 3578 }; 3579 3580 3581 class HApplyArguments: public HTemplateInstruction<4> { 3582 public: 3583 HApplyArguments(HValue* function, 3584 HValue* receiver, 3585 HValue* length, 3586 HValue* elements) { 3587 set_representation(Representation::Tagged()); 3588 SetOperandAt(0, function); 3589 SetOperandAt(1, receiver); 3590 SetOperandAt(2, length); 3591 SetOperandAt(3, elements); 3592 SetAllSideEffects(); 3593 } 3594 3595 virtual Representation RequiredInputRepresentation(int index) { 3596 // The length is untagged, all other inputs are tagged. 3597 return (index == 2) 3598 ? Representation::Integer32() 3599 : Representation::Tagged(); 3600 } 3601 3602 HValue* function() { return OperandAt(0); } 3603 HValue* receiver() { return OperandAt(1); } 3604 HValue* length() { return OperandAt(2); } 3605 HValue* elements() { return OperandAt(3); } 3606 3607 DECLARE_CONCRETE_INSTRUCTION(ApplyArguments) 3608 }; 3609 3610 3611 class HArgumentsElements: public HTemplateInstruction<0> { 3612 public: 3613 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsElements, bool); 3614 3615 DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements) 3616 3617 virtual Representation RequiredInputRepresentation(int index) { 3618 return Representation::None(); 3619 } 3620 3621 bool from_inlined() const { return from_inlined_; } 3622 3623 protected: 3624 virtual bool DataEquals(HValue* other) { return true; } 3625 3626 private: 3627 explicit HArgumentsElements(bool from_inlined) : from_inlined_(from_inlined) { 3628 // The value produced by this instruction is a pointer into the stack 3629 // that looks as if it was a smi because of alignment. 3630 set_representation(Representation::Tagged()); 3631 SetFlag(kUseGVN); 3632 } 3633 3634 virtual bool IsDeletable() const { return true; } 3635 3636 bool from_inlined_; 3637 }; 3638 3639 3640 class HArgumentsLength: public HUnaryOperation { 3641 public: 3642 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsLength, HValue*); 3643 3644 virtual Representation RequiredInputRepresentation(int index) { 3645 return Representation::Tagged(); 3646 } 3647 3648 DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength) 3649 3650 protected: 3651 virtual bool DataEquals(HValue* other) { return true; } 3652 3653 private: 3654 explicit HArgumentsLength(HValue* value) : HUnaryOperation(value) { 3655 set_representation(Representation::Integer32()); 3656 SetFlag(kUseGVN); 3657 } 3658 3659 virtual bool IsDeletable() const { return true; } 3660 }; 3661 3662 3663 class HAccessArgumentsAt: public HTemplateInstruction<3> { 3664 public: 3665 HAccessArgumentsAt(HValue* arguments, HValue* length, HValue* index) { 3666 set_representation(Representation::Tagged()); 3667 SetFlag(kUseGVN); 3668 SetOperandAt(0, arguments); 3669 SetOperandAt(1, length); 3670 SetOperandAt(2, index); 3671 } 3672 3673 virtual void PrintDataTo(StringStream* stream); 3674 3675 virtual Representation RequiredInputRepresentation(int index) { 3676 // The arguments elements is considered tagged. 3677 return index == 0 3678 ? Representation::Tagged() 3679 : Representation::Integer32(); 3680 } 3681 3682 HValue* arguments() { return OperandAt(0); } 3683 HValue* length() { return OperandAt(1); } 3684 HValue* index() { return OperandAt(2); } 3685 3686 DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt) 3687 3688 virtual bool DataEquals(HValue* other) { return true; } 3689 }; 3690 3691 3692 class HBoundsCheckBaseIndexInformation; 3693 3694 3695 class HBoundsCheck: public HTemplateInstruction<2> { 3696 public: 3697 DECLARE_INSTRUCTION_FACTORY_P2(HBoundsCheck, HValue*, HValue*); 3698 3699 bool skip_check() const { return skip_check_; } 3700 void set_skip_check() { skip_check_ = true; } 3701 3702 HValue* base() { return base_; } 3703 int offset() { return offset_; } 3704 int scale() { return scale_; } 3705 3706 void ApplyIndexChange(); 3707 bool DetectCompoundIndex() { 3708 ASSERT(base() == NULL); 3709 3710 DecompositionResult decomposition; 3711 if (index()->TryDecompose(&decomposition)) { 3712 base_ = decomposition.base(); 3713 offset_ = decomposition.offset(); 3714 scale_ = decomposition.scale(); 3715 return true; 3716 } else { 3717 base_ = index(); 3718 offset_ = 0; 3719 scale_ = 0; 3720 return false; 3721 } 3722 } 3723 3724 virtual Representation RequiredInputRepresentation(int arg_index) { 3725 return representation(); 3726 } 3727 3728 virtual void PrintDataTo(StringStream* stream); 3729 virtual void InferRepresentation(HInferRepresentationPhase* h_infer); 3730 3731 HValue* index() { return OperandAt(0); } 3732 HValue* length() { return OperandAt(1); } 3733 bool allow_equality() { return allow_equality_; } 3734 void set_allow_equality(bool v) { allow_equality_ = v; } 3735 3736 virtual int RedefinedOperandIndex() { return 0; } 3737 virtual bool IsPurelyInformativeDefinition() { return skip_check(); } 3738 3739 DECLARE_CONCRETE_INSTRUCTION(BoundsCheck) 3740 3741 protected: 3742 friend class HBoundsCheckBaseIndexInformation; 3743 3744 virtual bool DataEquals(HValue* other) { return true; } 3745 bool skip_check_; 3746 HValue* base_; 3747 int offset_; 3748 int scale_; 3749 bool allow_equality_; 3750 3751 private: 3752 // Normally HBoundsCheck should be created using the 3753 // HGraphBuilder::AddBoundsCheck() helper. 3754 // However when building stubs, where we know that the arguments are Int32, 3755 // it makes sense to invoke this constructor directly. 3756 HBoundsCheck(HValue* index, HValue* length) 3757 : skip_check_(false), 3758 base_(NULL), offset_(0), scale_(0), 3759 allow_equality_(false) { 3760 SetOperandAt(0, index); 3761 SetOperandAt(1, length); 3762 SetFlag(kFlexibleRepresentation); 3763 SetFlag(kUseGVN); 3764 } 3765 3766 virtual bool IsDeletable() const { 3767 return skip_check() && !FLAG_debug_code; 3768 } 3769 }; 3770 3771 3772 class HBoundsCheckBaseIndexInformation: public HTemplateInstruction<2> { 3773 public: 3774 explicit HBoundsCheckBaseIndexInformation(HBoundsCheck* check) { 3775 DecompositionResult decomposition; 3776 if (check->index()->TryDecompose(&decomposition)) { 3777 SetOperandAt(0, decomposition.base()); 3778 SetOperandAt(1, check); 3779 } else { 3780 UNREACHABLE(); 3781 } 3782 } 3783 3784 HValue* base_index() { return OperandAt(0); } 3785 HBoundsCheck* bounds_check() { return HBoundsCheck::cast(OperandAt(1)); } 3786 3787 DECLARE_CONCRETE_INSTRUCTION(BoundsCheckBaseIndexInformation) 3788 3789 virtual Representation RequiredInputRepresentation(int arg_index) { 3790 return representation(); 3791 } 3792 3793 virtual void PrintDataTo(StringStream* stream); 3794 3795 virtual int RedefinedOperandIndex() { return 0; } 3796 virtual bool IsPurelyInformativeDefinition() { return true; } 3797 }; 3798 3799 3800 class HBitwiseBinaryOperation: public HBinaryOperation { 3801 public: 3802 HBitwiseBinaryOperation(HValue* context, HValue* left, HValue* right, 3803 HType type = HType::Tagged()) 3804 : HBinaryOperation(context, left, right, type) { 3805 SetFlag(kFlexibleRepresentation); 3806 SetFlag(kTruncatingToInt32); 3807 SetFlag(kAllowUndefinedAsNaN); 3808 SetAllSideEffects(); 3809 } 3810 3811 virtual void RepresentationChanged(Representation to) { 3812 if (!to.IsTagged()) { 3813 ASSERT(to.IsSmiOrInteger32()); 3814 ClearAllSideEffects(); 3815 SetFlag(kUseGVN); 3816 } else { 3817 SetAllSideEffects(); 3818 ClearFlag(kUseGVN); 3819 } 3820 } 3821 3822 virtual void UpdateRepresentation(Representation new_rep, 3823 HInferRepresentationPhase* h_infer, 3824 const char* reason) { 3825 // We only generate either int32 or generic tagged bitwise operations. 3826 if (new_rep.IsDouble()) new_rep = Representation::Integer32(); 3827 HBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); 3828 } 3829 3830 virtual Representation observed_input_representation(int index) { 3831 Representation r = HBinaryOperation::observed_input_representation(index); 3832 if (r.IsDouble()) return Representation::Integer32(); 3833 return r; 3834 } 3835 3836 virtual void initialize_output_representation(Representation observed) { 3837 if (observed.IsDouble()) observed = Representation::Integer32(); 3838 HBinaryOperation::initialize_output_representation(observed); 3839 } 3840 3841 DECLARE_ABSTRACT_INSTRUCTION(BitwiseBinaryOperation) 3842 3843 private: 3844 virtual bool IsDeletable() const { return true; } 3845 }; 3846 3847 3848 class HMathFloorOfDiv: public HBinaryOperation { 3849 public: 3850 static HMathFloorOfDiv* New(Zone* zone, 3851 HValue* context, 3852 HValue* left, 3853 HValue* right) { 3854 return new(zone) HMathFloorOfDiv(context, left, right); 3855 } 3856 3857 virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited); 3858 3859 virtual Representation RequiredInputRepresentation(int index) { 3860 return Representation::Integer32(); 3861 } 3862 3863 DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv) 3864 3865 protected: 3866 virtual bool DataEquals(HValue* other) { return true; } 3867 3868 private: 3869 HMathFloorOfDiv(HValue* context, HValue* left, HValue* right) 3870 : HBinaryOperation(context, left, right) { 3871 set_representation(Representation::Integer32()); 3872 SetFlag(kUseGVN); 3873 SetFlag(kCanOverflow); 3874 if (!right->IsConstant()) { 3875 SetFlag(kCanBeDivByZero); 3876 } 3877 SetFlag(kAllowUndefinedAsNaN); 3878 } 3879 3880 virtual bool IsDeletable() const { return true; } 3881 }; 3882 3883 3884 class HArithmeticBinaryOperation: public HBinaryOperation { 3885 public: 3886 HArithmeticBinaryOperation(HValue* context, HValue* left, HValue* right) 3887 : HBinaryOperation(context, left, right, HType::TaggedNumber()) { 3888 SetAllSideEffects(); 3889 SetFlag(kFlexibleRepresentation); 3890 SetFlag(kAllowUndefinedAsNaN); 3891 } 3892 3893 virtual void RepresentationChanged(Representation to) { 3894 if (to.IsTagged()) { 3895 SetAllSideEffects(); 3896 ClearFlag(kUseGVN); 3897 } else { 3898 ClearAllSideEffects(); 3899 SetFlag(kUseGVN); 3900 } 3901 } 3902 3903 DECLARE_ABSTRACT_INSTRUCTION(ArithmeticBinaryOperation) 3904 3905 private: 3906 virtual bool IsDeletable() const { return true; } 3907 }; 3908 3909 3910 class HCompareGeneric: public HBinaryOperation { 3911 public: 3912 HCompareGeneric(HValue* context, 3913 HValue* left, 3914 HValue* right, 3915 Token::Value token) 3916 : HBinaryOperation(context, left, right, HType::Boolean()), 3917 token_(token) { 3918 ASSERT(Token::IsCompareOp(token)); 3919 set_representation(Representation::Tagged()); 3920 SetAllSideEffects(); 3921 } 3922 3923 virtual Representation RequiredInputRepresentation(int index) { 3924 return index == 0 3925 ? Representation::Tagged() 3926 : representation(); 3927 } 3928 3929 Token::Value token() const { return token_; } 3930 virtual void PrintDataTo(StringStream* stream); 3931 3932 DECLARE_CONCRETE_INSTRUCTION(CompareGeneric) 3933 3934 private: 3935 Token::Value token_; 3936 }; 3937 3938 3939 class HCompareNumericAndBranch: public HTemplateControlInstruction<2, 2> { 3940 public: 3941 HCompareNumericAndBranch(HValue* left, HValue* right, Token::Value token) 3942 : token_(token) { 3943 SetFlag(kFlexibleRepresentation); 3944 ASSERT(Token::IsCompareOp(token)); 3945 SetOperandAt(0, left); 3946 SetOperandAt(1, right); 3947 } 3948 3949 HValue* left() { return OperandAt(0); } 3950 HValue* right() { return OperandAt(1); } 3951 Token::Value token() const { return token_; } 3952 3953 void set_observed_input_representation(Representation left, 3954 Representation right) { 3955 observed_input_representation_[0] = left; 3956 observed_input_representation_[1] = right; 3957 } 3958 3959 virtual void InferRepresentation(HInferRepresentationPhase* h_infer); 3960 3961 virtual Representation RequiredInputRepresentation(int index) { 3962 return representation(); 3963 } 3964 virtual Representation observed_input_representation(int index) { 3965 return observed_input_representation_[index]; 3966 } 3967 virtual void PrintDataTo(StringStream* stream); 3968 3969 DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch) 3970 3971 private: 3972 Representation observed_input_representation_[2]; 3973 Token::Value token_; 3974 }; 3975 3976 3977 class HCompareHoleAndBranch: public HTemplateControlInstruction<2, 1> { 3978 public: 3979 // TODO(danno): make this private when the IfBuilder properly constructs 3980 // control flow instructions. 3981 explicit HCompareHoleAndBranch(HValue* object) { 3982 SetFlag(kFlexibleRepresentation); 3983 SetFlag(kAllowUndefinedAsNaN); 3984 SetOperandAt(0, object); 3985 } 3986 3987 DECLARE_INSTRUCTION_FACTORY_P1(HCompareHoleAndBranch, HValue*); 3988 3989 HValue* object() { return OperandAt(0); } 3990 3991 virtual void InferRepresentation(HInferRepresentationPhase* h_infer); 3992 3993 virtual Representation RequiredInputRepresentation(int index) { 3994 return representation(); 3995 } 3996 3997 virtual void PrintDataTo(StringStream* stream); 3998 3999 DECLARE_CONCRETE_INSTRUCTION(CompareHoleAndBranch) 4000 }; 4001 4002 4003 class HCompareObjectEqAndBranch: public HTemplateControlInstruction<2, 2> { 4004 public: 4005 // TODO(danno): make this private when the IfBuilder properly constructs 4006 // control flow instructions. 4007 HCompareObjectEqAndBranch(HValue* left, 4008 HValue* right) { 4009 SetOperandAt(0, left); 4010 SetOperandAt(1, right); 4011 } 4012 4013 DECLARE_INSTRUCTION_FACTORY_P2(HCompareObjectEqAndBranch, HValue*, HValue*); 4014 4015 HValue* left() { return OperandAt(0); } 4016 HValue* right() { return OperandAt(1); } 4017 4018 virtual void PrintDataTo(StringStream* stream); 4019 4020 virtual Representation RequiredInputRepresentation(int index) { 4021 return Representation::Tagged(); 4022 } 4023 4024 virtual Representation observed_input_representation(int index) { 4025 return Representation::Tagged(); 4026 } 4027 4028 DECLARE_CONCRETE_INSTRUCTION(CompareObjectEqAndBranch) 4029 }; 4030 4031 4032 class HIsObjectAndBranch: public HUnaryControlInstruction { 4033 public: 4034 explicit HIsObjectAndBranch(HValue* value) 4035 : HUnaryControlInstruction(value, NULL, NULL) { } 4036 4037 virtual Representation RequiredInputRepresentation(int index) { 4038 return Representation::Tagged(); 4039 } 4040 4041 DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch) 4042 }; 4043 4044 class HIsStringAndBranch: public HUnaryControlInstruction { 4045 public: 4046 explicit HIsStringAndBranch(HValue* value) 4047 : HUnaryControlInstruction(value, NULL, NULL) { } 4048 4049 virtual Representation RequiredInputRepresentation(int index) { 4050 return Representation::Tagged(); 4051 } 4052 4053 DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch) 4054 }; 4055 4056 4057 class HIsSmiAndBranch: public HUnaryControlInstruction { 4058 public: 4059 explicit HIsSmiAndBranch(HValue* value) 4060 : HUnaryControlInstruction(value, NULL, NULL) { } 4061 4062 DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch) 4063 4064 virtual Representation RequiredInputRepresentation(int index) { 4065 return Representation::Tagged(); 4066 } 4067 4068 protected: 4069 virtual bool DataEquals(HValue* other) { return true; } 4070 }; 4071 4072 4073 class HIsUndetectableAndBranch: public HUnaryControlInstruction { 4074 public: 4075 explicit HIsUndetectableAndBranch(HValue* value) 4076 : HUnaryControlInstruction(value, NULL, NULL) { } 4077 4078 virtual Representation RequiredInputRepresentation(int index) { 4079 return Representation::Tagged(); 4080 } 4081 4082 DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch) 4083 }; 4084 4085 4086 class HStringCompareAndBranch: public HTemplateControlInstruction<2, 3> { 4087 public: 4088 HStringCompareAndBranch(HValue* context, 4089 HValue* left, 4090 HValue* right, 4091 Token::Value token) 4092 : token_(token) { 4093 ASSERT(Token::IsCompareOp(token)); 4094 SetOperandAt(0, context); 4095 SetOperandAt(1, left); 4096 SetOperandAt(2, right); 4097 set_representation(Representation::Tagged()); 4098 SetGVNFlag(kChangesNewSpacePromotion); 4099 } 4100 4101 HValue* context() { return OperandAt(0); } 4102 HValue* left() { return OperandAt(1); } 4103 HValue* right() { return OperandAt(2); } 4104 Token::Value token() const { return token_; } 4105 4106 virtual void PrintDataTo(StringStream* stream); 4107 4108 virtual Representation RequiredInputRepresentation(int index) { 4109 return Representation::Tagged(); 4110 } 4111 4112 Representation GetInputRepresentation() const { 4113 return Representation::Tagged(); 4114 } 4115 4116 DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch) 4117 4118 private: 4119 Token::Value token_; 4120 }; 4121 4122 4123 class HIsConstructCallAndBranch: public HTemplateControlInstruction<2, 0> { 4124 public: 4125 virtual Representation RequiredInputRepresentation(int index) { 4126 return Representation::None(); 4127 } 4128 4129 DECLARE_CONCRETE_INSTRUCTION(IsConstructCallAndBranch) 4130 }; 4131 4132 4133 class HHasInstanceTypeAndBranch: public HUnaryControlInstruction { 4134 public: 4135 HHasInstanceTypeAndBranch(HValue* value, InstanceType type) 4136 : HUnaryControlInstruction(value, NULL, NULL), from_(type), to_(type) { } 4137 HHasInstanceTypeAndBranch(HValue* value, InstanceType from, InstanceType to) 4138 : HUnaryControlInstruction(value, NULL, NULL), from_(from), to_(to) { 4139 ASSERT(to == LAST_TYPE); // Others not implemented yet in backend. 4140 } 4141 4142 InstanceType from() { return from_; } 4143 InstanceType to() { return to_; } 4144 4145 virtual void PrintDataTo(StringStream* stream); 4146 4147 virtual Representation RequiredInputRepresentation(int index) { 4148 return Representation::Tagged(); 4149 } 4150 4151 DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch) 4152 4153 private: 4154 InstanceType from_; 4155 InstanceType to_; // Inclusive range, not all combinations work. 4156 }; 4157 4158 4159 class HHasCachedArrayIndexAndBranch: public HUnaryControlInstruction { 4160 public: 4161 explicit HHasCachedArrayIndexAndBranch(HValue* value) 4162 : HUnaryControlInstruction(value, NULL, NULL) { } 4163 4164 virtual Representation RequiredInputRepresentation(int index) { 4165 return Representation::Tagged(); 4166 } 4167 4168 DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch) 4169 }; 4170 4171 4172 class HGetCachedArrayIndex: public HUnaryOperation { 4173 public: 4174 explicit HGetCachedArrayIndex(HValue* value) : HUnaryOperation(value) { 4175 set_representation(Representation::Tagged()); 4176 SetFlag(kUseGVN); 4177 } 4178 4179 virtual Representation RequiredInputRepresentation(int index) { 4180 return Representation::Tagged(); 4181 } 4182 4183 DECLARE_CONCRETE_INSTRUCTION(GetCachedArrayIndex) 4184 4185 protected: 4186 virtual bool DataEquals(HValue* other) { return true; } 4187 4188 private: 4189 virtual bool IsDeletable() const { return true; } 4190 }; 4191 4192 4193 class HClassOfTestAndBranch: public HUnaryControlInstruction { 4194 public: 4195 HClassOfTestAndBranch(HValue* value, Handle<String> class_name) 4196 : HUnaryControlInstruction(value, NULL, NULL), 4197 class_name_(class_name) { } 4198 4199 DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch) 4200 4201 virtual Representation RequiredInputRepresentation(int index) { 4202 return Representation::Tagged(); 4203 } 4204 4205 virtual void PrintDataTo(StringStream* stream); 4206 4207 Handle<String> class_name() const { return class_name_; } 4208 4209 private: 4210 Handle<String> class_name_; 4211 }; 4212 4213 4214 class HTypeofIsAndBranch: public HUnaryControlInstruction { 4215 public: 4216 HTypeofIsAndBranch(HValue* value, Handle<String> type_literal) 4217 : HUnaryControlInstruction(value, NULL, NULL), 4218 type_literal_(type_literal) { } 4219 4220 Handle<String> type_literal() { return type_literal_; } 4221 virtual void PrintDataTo(StringStream* stream); 4222 4223 DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch) 4224 4225 virtual Representation RequiredInputRepresentation(int index) { 4226 return Representation::Tagged(); 4227 } 4228 4229 private: 4230 Handle<String> type_literal_; 4231 }; 4232 4233 4234 class HInstanceOf: public HBinaryOperation { 4235 public: 4236 HInstanceOf(HValue* context, HValue* left, HValue* right) 4237 : HBinaryOperation(context, left, right, HType::Boolean()) { 4238 set_representation(Representation::Tagged()); 4239 SetAllSideEffects(); 4240 } 4241 4242 virtual Representation RequiredInputRepresentation(int index) { 4243 return Representation::Tagged(); 4244 } 4245 4246 virtual void PrintDataTo(StringStream* stream); 4247 4248 DECLARE_CONCRETE_INSTRUCTION(InstanceOf) 4249 }; 4250 4251 4252 class HInstanceOfKnownGlobal: public HTemplateInstruction<2> { 4253 public: 4254 HInstanceOfKnownGlobal(HValue* context, 4255 HValue* left, 4256 Handle<JSFunction> right) 4257 : HTemplateInstruction<2>(HType::Boolean()), function_(right) { 4258 SetOperandAt(0, context); 4259 SetOperandAt(1, left); 4260 set_representation(Representation::Tagged()); 4261 SetAllSideEffects(); 4262 } 4263 4264 HValue* context() { return OperandAt(0); } 4265 HValue* left() { return OperandAt(1); } 4266 Handle<JSFunction> function() { return function_; } 4267 4268 virtual Representation RequiredInputRepresentation(int index) { 4269 return Representation::Tagged(); 4270 } 4271 4272 DECLARE_CONCRETE_INSTRUCTION(InstanceOfKnownGlobal) 4273 4274 private: 4275 Handle<JSFunction> function_; 4276 }; 4277 4278 4279 // TODO(mstarzinger): This instruction should be modeled as a load of the map 4280 // field followed by a load of the instance size field once HLoadNamedField is 4281 // flexible enough to accommodate byte-field loads. 4282 class HInstanceSize: public HTemplateInstruction<1> { 4283 public: 4284 explicit HInstanceSize(HValue* object) { 4285 SetOperandAt(0, object); 4286 set_representation(Representation::Integer32()); 4287 } 4288 4289 HValue* object() { return OperandAt(0); } 4290 4291 virtual Representation RequiredInputRepresentation(int index) { 4292 return Representation::Tagged(); 4293 } 4294 4295 DECLARE_CONCRETE_INSTRUCTION(InstanceSize) 4296 }; 4297 4298 4299 class HPower: public HTemplateInstruction<2> { 4300 public: 4301 static HInstruction* New(Zone* zone, 4302 HValue* context, 4303 HValue* left, 4304 HValue* right); 4305 4306 HValue* left() { return OperandAt(0); } 4307 HValue* right() const { return OperandAt(1); } 4308 4309 virtual Representation RequiredInputRepresentation(int index) { 4310 return index == 0 4311 ? Representation::Double() 4312 : Representation::None(); 4313 } 4314 virtual Representation observed_input_representation(int index) { 4315 return RequiredInputRepresentation(index); 4316 } 4317 4318 DECLARE_CONCRETE_INSTRUCTION(Power) 4319 4320 protected: 4321 virtual bool DataEquals(HValue* other) { return true; } 4322 4323 private: 4324 HPower(HValue* left, HValue* right) { 4325 SetOperandAt(0, left); 4326 SetOperandAt(1, right); 4327 set_representation(Representation::Double()); 4328 SetFlag(kUseGVN); 4329 SetGVNFlag(kChangesNewSpacePromotion); 4330 } 4331 4332 virtual bool IsDeletable() const { 4333 return !right()->representation().IsTagged(); 4334 } 4335 }; 4336 4337 4338 class HRandom: public HTemplateInstruction<1> { 4339 public: 4340 explicit HRandom(HValue* global_object) { 4341 SetOperandAt(0, global_object); 4342 set_representation(Representation::Double()); 4343 } 4344 4345 HValue* global_object() { return OperandAt(0); } 4346 4347 virtual Representation RequiredInputRepresentation(int index) { 4348 return Representation::Tagged(); 4349 } 4350 4351 DECLARE_CONCRETE_INSTRUCTION(Random) 4352 4353 private: 4354 virtual bool IsDeletable() const { return true; } 4355 }; 4356 4357 4358 class HAdd: public HArithmeticBinaryOperation { 4359 public: 4360 static HInstruction* New(Zone* zone, 4361 HValue* context, 4362 HValue* left, 4363 HValue* right); 4364 4365 // Add is only commutative if two integer values are added and not if two 4366 // tagged values are added (because it might be a String concatenation). 4367 virtual bool IsCommutative() const { 4368 return !representation().IsTagged(); 4369 } 4370 4371 virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited); 4372 4373 virtual HValue* Canonicalize(); 4374 4375 virtual bool TryDecompose(DecompositionResult* decomposition) { 4376 if (left()->IsInteger32Constant()) { 4377 decomposition->Apply(right(), left()->GetInteger32Constant()); 4378 return true; 4379 } else if (right()->IsInteger32Constant()) { 4380 decomposition->Apply(left(), right()->GetInteger32Constant()); 4381 return true; 4382 } else { 4383 return false; 4384 } 4385 } 4386 4387 virtual void RepresentationChanged(Representation to) { 4388 if (to.IsTagged()) ClearFlag(kAllowUndefinedAsNaN); 4389 HArithmeticBinaryOperation::RepresentationChanged(to); 4390 } 4391 4392 DECLARE_CONCRETE_INSTRUCTION(Add) 4393 4394 protected: 4395 virtual bool DataEquals(HValue* other) { return true; } 4396 4397 virtual Range* InferRange(Zone* zone); 4398 4399 private: 4400 HAdd(HValue* context, HValue* left, HValue* right) 4401 : HArithmeticBinaryOperation(context, left, right) { 4402 SetFlag(kCanOverflow); 4403 } 4404 }; 4405 4406 4407 class HSub: public HArithmeticBinaryOperation { 4408 public: 4409 static HInstruction* New(Zone* zone, 4410 HValue* context, 4411 HValue* left, 4412 HValue* right); 4413 4414 virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited); 4415 4416 virtual HValue* Canonicalize(); 4417 4418 virtual bool TryDecompose(DecompositionResult* decomposition) { 4419 if (right()->IsInteger32Constant()) { 4420 decomposition->Apply(left(), -right()->GetInteger32Constant()); 4421 return true; 4422 } else { 4423 return false; 4424 } 4425 } 4426 4427 DECLARE_CONCRETE_INSTRUCTION(Sub) 4428 4429 protected: 4430 virtual bool DataEquals(HValue* other) { return true; } 4431 4432 virtual Range* InferRange(Zone* zone); 4433 4434 private: 4435 HSub(HValue* context, HValue* left, HValue* right) 4436 : HArithmeticBinaryOperation(context, left, right) { 4437 SetFlag(kCanOverflow); 4438 } 4439 }; 4440 4441 4442 class HMul: public HArithmeticBinaryOperation { 4443 public: 4444 static HInstruction* New(Zone* zone, 4445 HValue* context, 4446 HValue* left, 4447 HValue* right); 4448 4449 static HInstruction* NewImul(Zone* zone, 4450 HValue* context, 4451 HValue* left, 4452 HValue* right) { 4453 HMul* mul = new(zone) HMul(context, left, right); 4454 // TODO(mstarzinger): Prevent bailout on minus zero for imul. 4455 mul->AssumeRepresentation(Representation::Integer32()); 4456 mul->ClearFlag(HValue::kCanOverflow); 4457 return mul; 4458 } 4459 4460 virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited); 4461 4462 virtual HValue* Canonicalize(); 4463 4464 // Only commutative if it is certain that not two objects are multiplicated. 4465 virtual bool IsCommutative() const { 4466 return !representation().IsTagged(); 4467 } 4468 4469 virtual void UpdateRepresentation(Representation new_rep, 4470 HInferRepresentationPhase* h_infer, 4471 const char* reason) { 4472 if (new_rep.IsSmi()) new_rep = Representation::Integer32(); 4473 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); 4474 } 4475 4476 DECLARE_CONCRETE_INSTRUCTION(Mul) 4477 4478 protected: 4479 virtual bool DataEquals(HValue* other) { return true; } 4480 4481 virtual Range* InferRange(Zone* zone); 4482 4483 private: 4484 HMul(HValue* context, HValue* left, HValue* right) 4485 : HArithmeticBinaryOperation(context, left, right) { 4486 SetFlag(kCanOverflow); 4487 } 4488 }; 4489 4490 4491 class HMod: public HArithmeticBinaryOperation { 4492 public: 4493 static HInstruction* New(Zone* zone, 4494 HValue* context, 4495 HValue* left, 4496 HValue* right, 4497 Maybe<int> fixed_right_arg); 4498 4499 Maybe<int> fixed_right_arg() const { return fixed_right_arg_; } 4500 4501 bool HasPowerOf2Divisor() { 4502 if (right()->IsConstant() && 4503 HConstant::cast(right())->HasInteger32Value()) { 4504 int32_t value = HConstant::cast(right())->Integer32Value(); 4505 return value != 0 && (IsPowerOf2(value) || IsPowerOf2(-value)); 4506 } 4507 4508 return false; 4509 } 4510 4511 virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited); 4512 4513 virtual HValue* Canonicalize(); 4514 4515 virtual void UpdateRepresentation(Representation new_rep, 4516 HInferRepresentationPhase* h_infer, 4517 const char* reason) { 4518 if (new_rep.IsSmi()) new_rep = Representation::Integer32(); 4519 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); 4520 } 4521 4522 DECLARE_CONCRETE_INSTRUCTION(Mod) 4523 4524 protected: 4525 virtual bool DataEquals(HValue* other) { return true; } 4526 4527 virtual Range* InferRange(Zone* zone); 4528 4529 private: 4530 HMod(HValue* context, 4531 HValue* left, 4532 HValue* right, 4533 Maybe<int> fixed_right_arg) 4534 : HArithmeticBinaryOperation(context, left, right), 4535 fixed_right_arg_(fixed_right_arg) { 4536 SetFlag(kCanBeDivByZero); 4537 SetFlag(kCanOverflow); 4538 } 4539 4540 const Maybe<int> fixed_right_arg_; 4541 }; 4542 4543 4544 class HDiv: public HArithmeticBinaryOperation { 4545 public: 4546 static HInstruction* New(Zone* zone, 4547 HValue* context, 4548 HValue* left, 4549 HValue* right); 4550 4551 bool HasPowerOf2Divisor() { 4552 if (right()->IsInteger32Constant()) { 4553 int32_t value = right()->GetInteger32Constant(); 4554 return value != 0 && (IsPowerOf2(value) || IsPowerOf2(-value)); 4555 } 4556 4557 return false; 4558 } 4559 4560 virtual HValue* EnsureAndPropagateNotMinusZero(BitVector* visited); 4561 4562 virtual HValue* Canonicalize(); 4563 4564 virtual void UpdateRepresentation(Representation new_rep, 4565 HInferRepresentationPhase* h_infer, 4566 const char* reason) { 4567 if (new_rep.IsSmi()) new_rep = Representation::Integer32(); 4568 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); 4569 } 4570 4571 DECLARE_CONCRETE_INSTRUCTION(Div) 4572 4573 protected: 4574 virtual bool DataEquals(HValue* other) { return true; } 4575 4576 virtual Range* InferRange(Zone* zone); 4577 4578 private: 4579 HDiv(HValue* context, HValue* left, HValue* right) 4580 : HArithmeticBinaryOperation(context, left, right) { 4581 SetFlag(kCanBeDivByZero); 4582 SetFlag(kCanOverflow); 4583 } 4584 }; 4585 4586 4587 class HMathMinMax: public HArithmeticBinaryOperation { 4588 public: 4589 enum Operation { kMathMin, kMathMax }; 4590 4591 static HInstruction* New(Zone* zone, 4592 HValue* context, 4593 HValue* left, 4594 HValue* right, 4595 Operation op); 4596 4597 virtual Representation RequiredInputRepresentation(int index) { 4598 return index == 0 ? Representation::Tagged() 4599 : representation(); 4600 } 4601 4602 virtual Representation observed_input_representation(int index) { 4603 return RequiredInputRepresentation(index); 4604 } 4605 4606 virtual void InferRepresentation(HInferRepresentationPhase* h_infer); 4607 4608 virtual Representation RepresentationFromInputs() { 4609 Representation left_rep = left()->representation(); 4610 Representation right_rep = right()->representation(); 4611 Representation result = Representation::Smi(); 4612 result = result.generalize(left_rep); 4613 result = result.generalize(right_rep); 4614 if (result.IsTagged()) return Representation::Double(); 4615 return result; 4616 } 4617 4618 virtual bool IsCommutative() const { return true; } 4619 4620 Operation operation() { return operation_; } 4621 4622 DECLARE_CONCRETE_INSTRUCTION(MathMinMax) 4623 4624 protected: 4625 virtual bool DataEquals(HValue* other) { 4626 return other->IsMathMinMax() && 4627 HMathMinMax::cast(other)->operation_ == operation_; 4628 } 4629 4630 virtual Range* InferRange(Zone* zone); 4631 4632 private: 4633 HMathMinMax(HValue* context, HValue* left, HValue* right, Operation op) 4634 : HArithmeticBinaryOperation(context, left, right), 4635 operation_(op) { } 4636 4637 Operation operation_; 4638 }; 4639 4640 4641 class HBitwise: public HBitwiseBinaryOperation { 4642 public: 4643 static HInstruction* New(Zone* zone, 4644 HValue* context, 4645 Token::Value op, 4646 HValue* left, 4647 HValue* right); 4648 4649 Token::Value op() const { return op_; } 4650 4651 virtual bool IsCommutative() const { return true; } 4652 4653 virtual HValue* Canonicalize(); 4654 4655 virtual void PrintDataTo(StringStream* stream); 4656 4657 DECLARE_CONCRETE_INSTRUCTION(Bitwise) 4658 4659 protected: 4660 virtual bool DataEquals(HValue* other) { 4661 return op() == HBitwise::cast(other)->op(); 4662 } 4663 4664 virtual Range* InferRange(Zone* zone); 4665 4666 private: 4667 HBitwise(HValue* context, 4668 Token::Value op, 4669 HValue* left, 4670 HValue* right) 4671 : HBitwiseBinaryOperation(context, left, right, HType::TaggedNumber()), 4672 op_(op) { 4673 ASSERT(op == Token::BIT_AND || op == Token::BIT_OR || op == Token::BIT_XOR); 4674 // BIT_AND with a smi-range positive value will always unset the 4675 // entire sign-extension of the smi-sign. 4676 if (op == Token::BIT_AND && 4677 ((left->IsConstant() && 4678 left->representation().IsSmi() && 4679 HConstant::cast(left)->Integer32Value() >= 0) || 4680 (right->IsConstant() && 4681 right->representation().IsSmi() && 4682 HConstant::cast(right)->Integer32Value() >= 0))) { 4683 SetFlag(kTruncatingToSmi); 4684 // BIT_OR with a smi-range negative value will always set the entire 4685 // sign-extension of the smi-sign. 4686 } else if (op == Token::BIT_OR && 4687 ((left->IsConstant() && 4688 left->representation().IsSmi() && 4689 HConstant::cast(left)->Integer32Value() < 0) || 4690 (right->IsConstant() && 4691 right->representation().IsSmi() && 4692 HConstant::cast(right)->Integer32Value() < 0))) { 4693 SetFlag(kTruncatingToSmi); 4694 } 4695 } 4696 4697 Token::Value op_; 4698 }; 4699 4700 4701 class HShl: public HBitwiseBinaryOperation { 4702 public: 4703 static HInstruction* New(Zone* zone, 4704 HValue* context, 4705 HValue* left, 4706 HValue* right); 4707 4708 virtual Range* InferRange(Zone* zone); 4709 4710 virtual void UpdateRepresentation(Representation new_rep, 4711 HInferRepresentationPhase* h_infer, 4712 const char* reason) { 4713 if (new_rep.IsSmi() && 4714 !(right()->IsInteger32Constant() && 4715 right()->GetInteger32Constant() >= 0)) { 4716 new_rep = Representation::Integer32(); 4717 } 4718 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); 4719 } 4720 4721 DECLARE_CONCRETE_INSTRUCTION(Shl) 4722 4723 protected: 4724 virtual bool DataEquals(HValue* other) { return true; } 4725 4726 private: 4727 HShl(HValue* context, HValue* left, HValue* right) 4728 : HBitwiseBinaryOperation(context, left, right) { } 4729 }; 4730 4731 4732 class HShr: public HBitwiseBinaryOperation { 4733 public: 4734 static HInstruction* New(Zone* zone, 4735 HValue* context, 4736 HValue* left, 4737 HValue* right); 4738 4739 virtual bool TryDecompose(DecompositionResult* decomposition) { 4740 if (right()->IsInteger32Constant()) { 4741 if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) { 4742 // This is intended to look for HAdd and HSub, to handle compounds 4743 // like ((base + offset) >> scale) with one single decomposition. 4744 left()->TryDecompose(decomposition); 4745 return true; 4746 } 4747 } 4748 return false; 4749 } 4750 4751 virtual Range* InferRange(Zone* zone); 4752 4753 virtual void UpdateRepresentation(Representation new_rep, 4754 HInferRepresentationPhase* h_infer, 4755 const char* reason) { 4756 if (new_rep.IsSmi()) new_rep = Representation::Integer32(); 4757 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); 4758 } 4759 4760 DECLARE_CONCRETE_INSTRUCTION(Shr) 4761 4762 protected: 4763 virtual bool DataEquals(HValue* other) { return true; } 4764 4765 private: 4766 HShr(HValue* context, HValue* left, HValue* right) 4767 : HBitwiseBinaryOperation(context, left, right) { } 4768 }; 4769 4770 4771 class HSar: public HBitwiseBinaryOperation { 4772 public: 4773 static HInstruction* New(Zone* zone, 4774 HValue* context, 4775 HValue* left, 4776 HValue* right); 4777 4778 virtual bool TryDecompose(DecompositionResult* decomposition) { 4779 if (right()->IsInteger32Constant()) { 4780 if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) { 4781 // This is intended to look for HAdd and HSub, to handle compounds 4782 // like ((base + offset) >> scale) with one single decomposition. 4783 left()->TryDecompose(decomposition); 4784 return true; 4785 } 4786 } 4787 return false; 4788 } 4789 4790 virtual Range* InferRange(Zone* zone); 4791 4792 virtual void UpdateRepresentation(Representation new_rep, 4793 HInferRepresentationPhase* h_infer, 4794 const char* reason) { 4795 if (new_rep.IsSmi()) new_rep = Representation::Integer32(); 4796 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); 4797 } 4798 4799 DECLARE_CONCRETE_INSTRUCTION(Sar) 4800 4801 protected: 4802 virtual bool DataEquals(HValue* other) { return true; } 4803 4804 private: 4805 HSar(HValue* context, HValue* left, HValue* right) 4806 : HBitwiseBinaryOperation(context, left, right) { } 4807 }; 4808 4809 4810 class HRor: public HBitwiseBinaryOperation { 4811 public: 4812 HRor(HValue* context, HValue* left, HValue* right) 4813 : HBitwiseBinaryOperation(context, left, right) { 4814 ChangeRepresentation(Representation::Integer32()); 4815 } 4816 4817 virtual void UpdateRepresentation(Representation new_rep, 4818 HInferRepresentationPhase* h_infer, 4819 const char* reason) { 4820 if (new_rep.IsSmi()) new_rep = Representation::Integer32(); 4821 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); 4822 } 4823 4824 DECLARE_CONCRETE_INSTRUCTION(Ror) 4825 4826 protected: 4827 virtual bool DataEquals(HValue* other) { return true; } 4828 }; 4829 4830 4831 class HOsrEntry: public HTemplateInstruction<0> { 4832 public: 4833 DECLARE_INSTRUCTION_FACTORY_P1(HOsrEntry, BailoutId); 4834 4835 BailoutId ast_id() const { return ast_id_; } 4836 4837 virtual Representation RequiredInputRepresentation(int index) { 4838 return Representation::None(); 4839 } 4840 4841 DECLARE_CONCRETE_INSTRUCTION(OsrEntry) 4842 4843 private: 4844 explicit HOsrEntry(BailoutId ast_id) : ast_id_(ast_id) { 4845 SetGVNFlag(kChangesOsrEntries); 4846 SetGVNFlag(kChangesNewSpacePromotion); 4847 } 4848 4849 BailoutId ast_id_; 4850 }; 4851 4852 4853 class HParameter: public HTemplateInstruction<0> { 4854 public: 4855 enum ParameterKind { 4856 STACK_PARAMETER, 4857 REGISTER_PARAMETER 4858 }; 4859 4860 DECLARE_INSTRUCTION_FACTORY_P1(HParameter, unsigned); 4861 DECLARE_INSTRUCTION_FACTORY_P2(HParameter, unsigned, ParameterKind); 4862 DECLARE_INSTRUCTION_FACTORY_P3(HParameter, unsigned, ParameterKind, 4863 Representation); 4864 4865 unsigned index() const { return index_; } 4866 ParameterKind kind() const { return kind_; } 4867 4868 virtual void PrintDataTo(StringStream* stream); 4869 4870 virtual Representation RequiredInputRepresentation(int index) { 4871 return Representation::None(); 4872 } 4873 4874 DECLARE_CONCRETE_INSTRUCTION(Parameter) 4875 4876 private: 4877 explicit HParameter(unsigned index, 4878 ParameterKind kind = STACK_PARAMETER) 4879 : index_(index), 4880 kind_(kind) { 4881 set_representation(Representation::Tagged()); 4882 } 4883 4884 explicit HParameter(unsigned index, 4885 ParameterKind kind, 4886 Representation r) 4887 : index_(index), 4888 kind_(kind) { 4889 set_representation(r); 4890 } 4891 4892 unsigned index_; 4893 ParameterKind kind_; 4894 }; 4895 4896 4897 class HCallStub: public HUnaryCall { 4898 public: 4899 HCallStub(HValue* context, CodeStub::Major major_key, int argument_count) 4900 : HUnaryCall(context, argument_count), 4901 major_key_(major_key), 4902 transcendental_type_(TranscendentalCache::kNumberOfCaches) { 4903 } 4904 4905 CodeStub::Major major_key() { return major_key_; } 4906 4907 HValue* context() { return value(); } 4908 4909 void set_transcendental_type(TranscendentalCache::Type transcendental_type) { 4910 transcendental_type_ = transcendental_type; 4911 } 4912 TranscendentalCache::Type transcendental_type() { 4913 return transcendental_type_; 4914 } 4915 4916 virtual void PrintDataTo(StringStream* stream); 4917 4918 virtual Representation RequiredInputRepresentation(int index) { 4919 return Representation::Tagged(); 4920 } 4921 4922 DECLARE_CONCRETE_INSTRUCTION(CallStub) 4923 4924 private: 4925 CodeStub::Major major_key_; 4926 TranscendentalCache::Type transcendental_type_; 4927 }; 4928 4929 4930 class HUnknownOSRValue: public HTemplateInstruction<0> { 4931 public: 4932 DECLARE_INSTRUCTION_FACTORY_P0(HUnknownOSRValue) 4933 4934 virtual Representation RequiredInputRepresentation(int index) { 4935 return Representation::None(); 4936 } 4937 4938 void set_incoming_value(HPhi* value) { 4939 incoming_value_ = value; 4940 } 4941 4942 HPhi* incoming_value() { 4943 return incoming_value_; 4944 } 4945 4946 virtual Representation KnownOptimalRepresentation() { 4947 if (incoming_value_ == NULL) return Representation::None(); 4948 return incoming_value_->KnownOptimalRepresentation(); 4949 } 4950 4951 DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue) 4952 4953 private: 4954 HUnknownOSRValue() 4955 : incoming_value_(NULL) { 4956 set_representation(Representation::Tagged()); 4957 } 4958 4959 HPhi* incoming_value_; 4960 }; 4961 4962 4963 class HLoadGlobalCell: public HTemplateInstruction<0> { 4964 public: 4965 HLoadGlobalCell(Handle<Cell> cell, PropertyDetails details) 4966 : cell_(cell), details_(details), unique_id_() { 4967 set_representation(Representation::Tagged()); 4968 SetFlag(kUseGVN); 4969 SetGVNFlag(kDependsOnGlobalVars); 4970 } 4971 4972 Handle<Cell> cell() const { return cell_; } 4973 bool RequiresHoleCheck() const; 4974 4975 virtual void PrintDataTo(StringStream* stream); 4976 4977 virtual intptr_t Hashcode() { 4978 return unique_id_.Hashcode(); 4979 } 4980 4981 virtual void FinalizeUniqueValueId() { 4982 unique_id_ = UniqueValueId(cell_); 4983 } 4984 4985 virtual Representation RequiredInputRepresentation(int index) { 4986 return Representation::None(); 4987 } 4988 4989 DECLARE_CONCRETE_INSTRUCTION(LoadGlobalCell) 4990 4991 protected: 4992 virtual bool DataEquals(HValue* other) { 4993 HLoadGlobalCell* b = HLoadGlobalCell::cast(other); 4994 return unique_id_ == b->unique_id_; 4995 } 4996 4997 private: 4998 virtual bool IsDeletable() const { return !RequiresHoleCheck(); } 4999 5000 Handle<Cell> cell_; 5001 PropertyDetails details_; 5002 UniqueValueId unique_id_; 5003 }; 5004 5005 5006 class HLoadGlobalGeneric: public HTemplateInstruction<2> { 5007 public: 5008 HLoadGlobalGeneric(HValue* context, 5009 HValue* global_object, 5010 Handle<Object> name, 5011 bool for_typeof) 5012 : name_(name), 5013 for_typeof_(for_typeof) { 5014 SetOperandAt(0, context); 5015 SetOperandAt(1, global_object); 5016 set_representation(Representation::Tagged()); 5017 SetAllSideEffects(); 5018 } 5019 5020 HValue* context() { return OperandAt(0); } 5021 HValue* global_object() { return OperandAt(1); } 5022 Handle<Object> name() const { return name_; } 5023 bool for_typeof() const { return for_typeof_; } 5024 5025 virtual void PrintDataTo(StringStream* stream); 5026 5027 virtual Representation RequiredInputRepresentation(int index) { 5028 return Representation::Tagged(); 5029 } 5030 5031 DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric) 5032 5033 private: 5034 Handle<Object> name_; 5035 bool for_typeof_; 5036 }; 5037 5038 5039 class HAllocate: public HTemplateInstruction<2> { 5040 public: 5041 static HAllocate* New(Zone* zone, 5042 HValue* context, 5043 HValue* size, 5044 HType type, 5045 PretenureFlag pretenure_flag, 5046 InstanceType instance_type) { 5047 return new(zone) HAllocate(context, size, type, pretenure_flag, 5048 instance_type); 5049 } 5050 5051 // Maximum instance size for which allocations will be inlined. 5052 static const int kMaxInlineSize = 64 * kPointerSize; 5053 5054 HValue* context() { return OperandAt(0); } 5055 HValue* size() { return OperandAt(1); } 5056 5057 virtual Representation RequiredInputRepresentation(int index) { 5058 if (index == 0) { 5059 return Representation::Tagged(); 5060 } else { 5061 return Representation::Integer32(); 5062 } 5063 } 5064 5065 virtual Handle<Map> GetMonomorphicJSObjectMap() { 5066 return known_initial_map_; 5067 } 5068 5069 void set_known_initial_map(Handle<Map> known_initial_map) { 5070 known_initial_map_ = known_initial_map; 5071 } 5072 5073 bool IsNewSpaceAllocation() const { 5074 return (flags_ & ALLOCATE_IN_NEW_SPACE) != 0; 5075 } 5076 5077 bool IsOldDataSpaceAllocation() const { 5078 return (flags_ & ALLOCATE_IN_OLD_DATA_SPACE) != 0; 5079 } 5080 5081 bool IsOldPointerSpaceAllocation() const { 5082 return (flags_ & ALLOCATE_IN_OLD_POINTER_SPACE) != 0; 5083 } 5084 5085 bool MustAllocateDoubleAligned() const { 5086 return (flags_ & ALLOCATE_DOUBLE_ALIGNED) != 0; 5087 } 5088 5089 bool MustPrefillWithFiller() const { 5090 return (flags_ & PREFILL_WITH_FILLER) != 0; 5091 } 5092 5093 void MakePrefillWithFiller() { 5094 flags_ = static_cast<HAllocate::Flags>(flags_ | PREFILL_WITH_FILLER); 5095 } 5096 5097 void MakeDoubleAligned() { 5098 flags_ = static_cast<HAllocate::Flags>(flags_ | ALLOCATE_DOUBLE_ALIGNED); 5099 } 5100 5101 void UpdateSize(HValue* size) { 5102 SetOperandAt(1, size); 5103 } 5104 5105 virtual void HandleSideEffectDominator(GVNFlag side_effect, 5106 HValue* dominator); 5107 5108 virtual void PrintDataTo(StringStream* stream); 5109 5110 DECLARE_CONCRETE_INSTRUCTION(Allocate) 5111 5112 private: 5113 enum Flags { 5114 ALLOCATE_IN_NEW_SPACE = 1 << 0, 5115 ALLOCATE_IN_OLD_DATA_SPACE = 1 << 1, 5116 ALLOCATE_IN_OLD_POINTER_SPACE = 1 << 2, 5117 ALLOCATE_DOUBLE_ALIGNED = 1 << 3, 5118 PREFILL_WITH_FILLER = 1 << 4 5119 }; 5120 5121 HAllocate(HValue* context, 5122 HValue* size, 5123 HType type, 5124 PretenureFlag pretenure_flag, 5125 InstanceType instance_type) 5126 : HTemplateInstruction<2>(type), 5127 dominating_allocate_(NULL), 5128 filler_free_space_size_(NULL), 5129 clear_next_map_word_(false) { 5130 SetOperandAt(0, context); 5131 SetOperandAt(1, size); 5132 set_representation(Representation::Tagged()); 5133 SetFlag(kTrackSideEffectDominators); 5134 SetGVNFlag(kChangesNewSpacePromotion); 5135 SetGVNFlag(kDependsOnNewSpacePromotion); 5136 flags_ = pretenure_flag == TENURED 5137 ? (Heap::TargetSpaceId(instance_type) == OLD_POINTER_SPACE 5138 ? ALLOCATE_IN_OLD_POINTER_SPACE : ALLOCATE_IN_OLD_DATA_SPACE) 5139 : ALLOCATE_IN_NEW_SPACE; 5140 if (instance_type == FIXED_DOUBLE_ARRAY_TYPE) { 5141 flags_ = static_cast<HAllocate::Flags>(flags_ | ALLOCATE_DOUBLE_ALIGNED); 5142 } 5143 // We have to fill the allocated object with one word fillers if we do 5144 // not use allocation folding since some allocations may depend on each 5145 // other, i.e., have a pointer to each other. A GC in between these 5146 // allocations may leave such objects behind in a not completely initialized 5147 // state. 5148 if (!FLAG_use_gvn || !FLAG_use_allocation_folding) { 5149 flags_ = static_cast<HAllocate::Flags>(flags_ | PREFILL_WITH_FILLER); 5150 } 5151 clear_next_map_word_ = pretenure_flag == NOT_TENURED && 5152 AllocationSite::CanTrack(instance_type); 5153 } 5154 5155 HAllocate* GetFoldableDominator(HAllocate* dominator); 5156 5157 void UpdateFreeSpaceFiller(int32_t filler_size); 5158 5159 void CreateFreeSpaceFiller(int32_t filler_size); 5160 5161 bool IsFoldable(HAllocate* allocate) { 5162 return (IsNewSpaceAllocation() && allocate->IsNewSpaceAllocation()) || 5163 (IsOldDataSpaceAllocation() && allocate->IsOldDataSpaceAllocation()) || 5164 (IsOldPointerSpaceAllocation() && 5165 allocate->IsOldPointerSpaceAllocation()); 5166 } 5167 5168 void ClearNextMapWord(int offset); 5169 5170 Flags flags_; 5171 Handle<Map> known_initial_map_; 5172 HAllocate* dominating_allocate_; 5173 HStoreNamedField* filler_free_space_size_; 5174 bool clear_next_map_word_; 5175 }; 5176 5177 5178 class HInnerAllocatedObject: public HTemplateInstruction<1> { 5179 public: 5180 static HInnerAllocatedObject* New(Zone* zone, 5181 HValue* context, 5182 HValue* value, 5183 int offset, 5184 HType type = HType::Tagged()) { 5185 return new(zone) HInnerAllocatedObject(value, offset, type); 5186 } 5187 5188 HValue* base_object() { return OperandAt(0); } 5189 int offset() { return offset_; } 5190 5191 virtual Representation RequiredInputRepresentation(int index) { 5192 return Representation::Tagged(); 5193 } 5194 5195 virtual void PrintDataTo(StringStream* stream); 5196 5197 DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject) 5198 5199 private: 5200 HInnerAllocatedObject(HValue* value, int offset, HType type = HType::Tagged()) 5201 : HTemplateInstruction<1>(type), offset_(offset) { 5202 ASSERT(value->IsAllocate()); 5203 SetOperandAt(0, value); 5204 set_type(type); 5205 set_representation(Representation::Tagged()); 5206 } 5207 5208 int offset_; 5209 }; 5210 5211 5212 inline bool StoringValueNeedsWriteBarrier(HValue* value) { 5213 return !value->type().IsBoolean() 5214 && !value->type().IsSmi() 5215 && !(value->IsConstant() && HConstant::cast(value)->ImmortalImmovable()); 5216 } 5217 5218 5219 inline bool ReceiverObjectNeedsWriteBarrier(HValue* object, 5220 HValue* new_space_dominator) { 5221 if (object->IsInnerAllocatedObject()) { 5222 return ReceiverObjectNeedsWriteBarrier( 5223 HInnerAllocatedObject::cast(object)->base_object(), 5224 new_space_dominator); 5225 } 5226 if (object->IsConstant() && HConstant::cast(object)->IsCell()) { 5227 return false; 5228 } 5229 if (object->IsConstant() && 5230 HConstant::cast(object)->HasExternalReferenceValue()) { 5231 // Stores to external references require no write barriers 5232 return false; 5233 } 5234 if (object != new_space_dominator) return true; 5235 if (object->IsAllocate()) { 5236 return !HAllocate::cast(object)->IsNewSpaceAllocation(); 5237 } 5238 return true; 5239 } 5240 5241 5242 class HStoreGlobalCell: public HUnaryOperation { 5243 public: 5244 DECLARE_INSTRUCTION_FACTORY_P3(HStoreGlobalCell, HValue*, 5245 Handle<PropertyCell>, PropertyDetails); 5246 5247 Handle<PropertyCell> cell() const { return cell_; } 5248 bool RequiresHoleCheck() { 5249 return !details_.IsDontDelete() || details_.IsReadOnly(); 5250 } 5251 bool NeedsWriteBarrier() { 5252 return StoringValueNeedsWriteBarrier(value()); 5253 } 5254 5255 virtual Representation RequiredInputRepresentation(int index) { 5256 return Representation::Tagged(); 5257 } 5258 virtual void PrintDataTo(StringStream* stream); 5259 5260 DECLARE_CONCRETE_INSTRUCTION(StoreGlobalCell) 5261 5262 private: 5263 HStoreGlobalCell(HValue* value, 5264 Handle<PropertyCell> cell, 5265 PropertyDetails details) 5266 : HUnaryOperation(value), 5267 cell_(cell), 5268 details_(details) { 5269 SetGVNFlag(kChangesGlobalVars); 5270 } 5271 5272 Handle<PropertyCell> cell_; 5273 PropertyDetails details_; 5274 }; 5275 5276 5277 class HStoreGlobalGeneric: public HTemplateInstruction<3> { 5278 public: 5279 inline static HStoreGlobalGeneric* New(Zone* zone, 5280 HValue* context, 5281 HValue* global_object, 5282 Handle<Object> name, 5283 HValue* value, 5284 StrictModeFlag strict_mode_flag) { 5285 return new(zone) HStoreGlobalGeneric(context, global_object, 5286 name, value, strict_mode_flag); 5287 } 5288 5289 HValue* context() { return OperandAt(0); } 5290 HValue* global_object() { return OperandAt(1); } 5291 Handle<Object> name() const { return name_; } 5292 HValue* value() { return OperandAt(2); } 5293 StrictModeFlag strict_mode_flag() { return strict_mode_flag_; } 5294 5295 virtual void PrintDataTo(StringStream* stream); 5296 5297 virtual Representation RequiredInputRepresentation(int index) { 5298 return Representation::Tagged(); 5299 } 5300 5301 DECLARE_CONCRETE_INSTRUCTION(StoreGlobalGeneric) 5302 5303 private: 5304 HStoreGlobalGeneric(HValue* context, 5305 HValue* global_object, 5306 Handle<Object> name, 5307 HValue* value, 5308 StrictModeFlag strict_mode_flag) 5309 : name_(name), 5310 strict_mode_flag_(strict_mode_flag) { 5311 SetOperandAt(0, context); 5312 SetOperandAt(1, global_object); 5313 SetOperandAt(2, value); 5314 set_representation(Representation::Tagged()); 5315 SetAllSideEffects(); 5316 } 5317 5318 Handle<Object> name_; 5319 StrictModeFlag strict_mode_flag_; 5320 }; 5321 5322 5323 class HLoadContextSlot: public HUnaryOperation { 5324 public: 5325 enum Mode { 5326 // Perform a normal load of the context slot without checking its value. 5327 kNoCheck, 5328 // Load and check the value of the context slot. Deoptimize if it's the 5329 // hole value. This is used for checking for loading of uninitialized 5330 // harmony bindings where we deoptimize into full-codegen generated code 5331 // which will subsequently throw a reference error. 5332 kCheckDeoptimize, 5333 // Load and check the value of the context slot. Return undefined if it's 5334 // the hole value. This is used for non-harmony const assignments 5335 kCheckReturnUndefined 5336 }; 5337 5338 HLoadContextSlot(HValue* context, Variable* var) 5339 : HUnaryOperation(context), slot_index_(var->index()) { 5340 ASSERT(var->IsContextSlot()); 5341 switch (var->mode()) { 5342 case LET: 5343 case CONST_HARMONY: 5344 mode_ = kCheckDeoptimize; 5345 break; 5346 case CONST: 5347 mode_ = kCheckReturnUndefined; 5348 break; 5349 default: 5350 mode_ = kNoCheck; 5351 } 5352 set_representation(Representation::Tagged()); 5353 SetFlag(kUseGVN); 5354 SetGVNFlag(kDependsOnContextSlots); 5355 } 5356 5357 int slot_index() const { return slot_index_; } 5358 Mode mode() const { return mode_; } 5359 5360 bool DeoptimizesOnHole() { 5361 return mode_ == kCheckDeoptimize; 5362 } 5363 5364 bool RequiresHoleCheck() const { 5365 return mode_ != kNoCheck; 5366 } 5367 5368 virtual Representation RequiredInputRepresentation(int index) { 5369 return Representation::Tagged(); 5370 } 5371 5372 virtual void PrintDataTo(StringStream* stream); 5373 5374 DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot) 5375 5376 protected: 5377 virtual bool DataEquals(HValue* other) { 5378 HLoadContextSlot* b = HLoadContextSlot::cast(other); 5379 return (slot_index() == b->slot_index()); 5380 } 5381 5382 private: 5383 virtual bool IsDeletable() const { return !RequiresHoleCheck(); } 5384 5385 int slot_index_; 5386 Mode mode_; 5387 }; 5388 5389 5390 class HStoreContextSlot: public HTemplateInstruction<2> { 5391 public: 5392 enum Mode { 5393 // Perform a normal store to the context slot without checking its previous 5394 // value. 5395 kNoCheck, 5396 // Check the previous value of the context slot and deoptimize if it's the 5397 // hole value. This is used for checking for assignments to uninitialized 5398 // harmony bindings where we deoptimize into full-codegen generated code 5399 // which will subsequently throw a reference error. 5400 kCheckDeoptimize, 5401 // Check the previous value and ignore assignment if it isn't a hole value 5402 kCheckIgnoreAssignment 5403 }; 5404 5405 DECLARE_INSTRUCTION_FACTORY_P4(HStoreContextSlot, HValue*, int, 5406 Mode, HValue*); 5407 5408 HValue* context() { return OperandAt(0); } 5409 HValue* value() { return OperandAt(1); } 5410 int slot_index() const { return slot_index_; } 5411 Mode mode() const { return mode_; } 5412 5413 bool NeedsWriteBarrier() { 5414 return StoringValueNeedsWriteBarrier(value()); 5415 } 5416 5417 bool DeoptimizesOnHole() { 5418 return mode_ == kCheckDeoptimize; 5419 } 5420 5421 bool RequiresHoleCheck() { 5422 return mode_ != kNoCheck; 5423 } 5424 5425 virtual Representation RequiredInputRepresentation(int index) { 5426 return Representation::Tagged(); 5427 } 5428 5429 virtual void PrintDataTo(StringStream* stream); 5430 5431 DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot) 5432 5433 private: 5434 HStoreContextSlot(HValue* context, int slot_index, Mode mode, HValue* value) 5435 : slot_index_(slot_index), mode_(mode) { 5436 SetOperandAt(0, context); 5437 SetOperandAt(1, value); 5438 SetGVNFlag(kChangesContextSlots); 5439 } 5440 5441 int slot_index_; 5442 Mode mode_; 5443 }; 5444 5445 5446 // Represents an access to a portion of an object, such as the map pointer, 5447 // array elements pointer, etc, but not accesses to array elements themselves. 5448 class HObjectAccess { 5449 public: 5450 inline bool IsInobject() const { 5451 return portion() != kBackingStore && portion() != kExternalMemory; 5452 } 5453 5454 inline bool IsExternalMemory() const { 5455 return portion() == kExternalMemory; 5456 } 5457 5458 inline bool IsStringLength() const { 5459 return portion() == kStringLengths; 5460 } 5461 5462 inline int offset() const { 5463 return OffsetField::decode(value_); 5464 } 5465 5466 inline Representation representation() const { 5467 return Representation::FromKind(RepresentationField::decode(value_)); 5468 } 5469 5470 inline Handle<String> name() const { 5471 return name_; 5472 } 5473 5474 inline HObjectAccess WithRepresentation(Representation representation) { 5475 return HObjectAccess(portion(), offset(), representation, name()); 5476 } 5477 5478 static HObjectAccess ForHeapNumberValue() { 5479 return HObjectAccess( 5480 kDouble, HeapNumber::kValueOffset, Representation::Double()); 5481 } 5482 5483 static HObjectAccess ForElementsPointer() { 5484 return HObjectAccess(kElementsPointer, JSObject::kElementsOffset); 5485 } 5486 5487 static HObjectAccess ForArrayLength(ElementsKind elements_kind) { 5488 return HObjectAccess( 5489 kArrayLengths, 5490 JSArray::kLengthOffset, 5491 IsFastElementsKind(elements_kind) && 5492 FLAG_track_fields 5493 ? Representation::Smi() : Representation::Tagged()); 5494 } 5495 5496 static HObjectAccess ForAllocationSiteTransitionInfo() { 5497 return HObjectAccess(kInobject, AllocationSite::kTransitionInfoOffset); 5498 } 5499 5500 static HObjectAccess ForAllocationSiteWeakNext() { 5501 return HObjectAccess(kInobject, AllocationSite::kWeakNextOffset); 5502 } 5503 5504 static HObjectAccess ForAllocationSiteList() { 5505 return HObjectAccess(kExternalMemory, 0, Representation::Tagged()); 5506 } 5507 5508 static HObjectAccess ForFixedArrayLength() { 5509 return HObjectAccess( 5510 kArrayLengths, 5511 FixedArray::kLengthOffset, 5512 FLAG_track_fields ? Representation::Smi() : Representation::Tagged()); 5513 } 5514 5515 static HObjectAccess ForStringLength() { 5516 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue); 5517 return HObjectAccess( 5518 kStringLengths, 5519 String::kLengthOffset, 5520 FLAG_track_fields ? Representation::Smi() : Representation::Tagged()); 5521 } 5522 5523 static HObjectAccess ForPropertiesPointer() { 5524 return HObjectAccess(kInobject, JSObject::kPropertiesOffset); 5525 } 5526 5527 static HObjectAccess ForPrototypeOrInitialMap() { 5528 return HObjectAccess(kInobject, JSFunction::kPrototypeOrInitialMapOffset); 5529 } 5530 5531 static HObjectAccess ForMap() { 5532 return HObjectAccess(kMaps, JSObject::kMapOffset); 5533 } 5534 5535 static HObjectAccess ForPropertyCellValue() { 5536 return HObjectAccess(kInobject, PropertyCell::kValueOffset); 5537 } 5538 5539 static HObjectAccess ForCellValue() { 5540 return HObjectAccess(kInobject, Cell::kValueOffset); 5541 } 5542 5543 static HObjectAccess ForAllocationMementoSite() { 5544 return HObjectAccess(kInobject, AllocationMemento::kAllocationSiteOffset); 5545 } 5546 5547 static HObjectAccess ForCounter() { 5548 return HObjectAccess(kExternalMemory, 0, Representation::Integer32()); 5549 } 5550 5551 // Create an access to an offset in a fixed array header. 5552 static HObjectAccess ForFixedArrayHeader(int offset); 5553 5554 // Create an access to an in-object property in a JSObject. 5555 static HObjectAccess ForJSObjectOffset(int offset, 5556 Representation representation = Representation::Tagged()); 5557 5558 // Create an access to an in-object property in a JSArray. 5559 static HObjectAccess ForJSArrayOffset(int offset); 5560 5561 // Create an access to the backing store of an object. 5562 static HObjectAccess ForBackingStoreOffset(int offset, 5563 Representation representation = Representation::Tagged()); 5564 5565 // Create an access to a resolved field (in-object or backing store). 5566 static HObjectAccess ForField(Handle<Map> map, 5567 LookupResult *lookup, Handle<String> name = Handle<String>::null()); 5568 5569 // Create an access for the payload of a Cell or JSGlobalPropertyCell. 5570 static HObjectAccess ForCellPayload(Isolate* isolate); 5571 5572 void PrintTo(StringStream* stream); 5573 5574 inline bool Equals(HObjectAccess that) const { 5575 return value_ == that.value_; // portion and offset must match 5576 } 5577 5578 protected: 5579 void SetGVNFlags(HValue *instr, bool is_store); 5580 5581 private: 5582 // internal use only; different parts of an object or array 5583 enum Portion { 5584 kMaps, // map of an object 5585 kArrayLengths, // the length of an array 5586 kStringLengths, // the length of a string 5587 kElementsPointer, // elements pointer 5588 kBackingStore, // some field in the backing store 5589 kDouble, // some double field 5590 kInobject, // some other in-object field 5591 kExternalMemory // some field in external memory 5592 }; 5593 5594 HObjectAccess(Portion portion, int offset, 5595 Representation representation = Representation::Tagged(), 5596 Handle<String> name = Handle<String>::null()) 5597 : value_(PortionField::encode(portion) | 5598 RepresentationField::encode(representation.kind()) | 5599 OffsetField::encode(offset)), 5600 name_(name) { 5601 // assert that the fields decode correctly 5602 ASSERT(this->offset() == offset); 5603 ASSERT(this->portion() == portion); 5604 ASSERT(RepresentationField::decode(value_) == representation.kind()); 5605 } 5606 5607 class PortionField : public BitField<Portion, 0, 3> {}; 5608 class RepresentationField : public BitField<Representation::Kind, 3, 3> {}; 5609 class OffsetField : public BitField<int, 6, 26> {}; 5610 5611 uint32_t value_; // encodes portion, representation, and offset 5612 Handle<String> name_; 5613 5614 friend class HLoadNamedField; 5615 friend class HStoreNamedField; 5616 5617 inline Portion portion() const { 5618 return PortionField::decode(value_); 5619 } 5620 }; 5621 5622 5623 class HLoadNamedField: public HTemplateInstruction<2> { 5624 public: 5625 DECLARE_INSTRUCTION_FACTORY_P2(HLoadNamedField, HValue*, HObjectAccess); 5626 DECLARE_INSTRUCTION_FACTORY_P3(HLoadNamedField, HValue*, HObjectAccess, 5627 HValue*); 5628 5629 HValue* object() { return OperandAt(0); } 5630 HValue* typecheck() { 5631 ASSERT(HasTypeCheck()); 5632 return OperandAt(1); 5633 } 5634 5635 bool HasTypeCheck() const { return OperandAt(0) != OperandAt(1); } 5636 void ClearTypeCheck() { SetOperandAt(1, object()); } 5637 HObjectAccess access() const { return access_; } 5638 Representation field_representation() const { 5639 return access_.representation(); 5640 } 5641 5642 virtual bool HasEscapingOperandAt(int index) { return false; } 5643 virtual Representation RequiredInputRepresentation(int index) { 5644 if (index == 0 && access().IsExternalMemory()) { 5645 // object must be external in case of external memory access 5646 return Representation::External(); 5647 } 5648 return Representation::Tagged(); 5649 } 5650 virtual Range* InferRange(Zone* zone); 5651 virtual void PrintDataTo(StringStream* stream); 5652 5653 DECLARE_CONCRETE_INSTRUCTION(LoadNamedField) 5654 5655 protected: 5656 virtual bool DataEquals(HValue* other) { 5657 HLoadNamedField* b = HLoadNamedField::cast(other); 5658 return access_.Equals(b->access_); 5659 } 5660 5661 private: 5662 HLoadNamedField(HValue* object, 5663 HObjectAccess access, 5664 HValue* typecheck = NULL) 5665 : access_(access) { 5666 ASSERT(object != NULL); 5667 SetOperandAt(0, object); 5668 SetOperandAt(1, typecheck != NULL ? typecheck : object); 5669 5670 Representation representation = access.representation(); 5671 if (representation.IsSmi()) { 5672 set_type(HType::Smi()); 5673 set_representation(representation); 5674 } else if (representation.IsDouble() || 5675 representation.IsExternal() || 5676 representation.IsInteger32()) { 5677 set_representation(representation); 5678 } else if (FLAG_track_heap_object_fields && 5679 representation.IsHeapObject()) { 5680 set_type(HType::NonPrimitive()); 5681 set_representation(Representation::Tagged()); 5682 } else { 5683 set_representation(Representation::Tagged()); 5684 } 5685 access.SetGVNFlags(this, false); 5686 } 5687 5688 virtual bool IsDeletable() const { return true; } 5689 5690 HObjectAccess access_; 5691 }; 5692 5693 5694 class HLoadNamedGeneric: public HTemplateInstruction<2> { 5695 public: 5696 HLoadNamedGeneric(HValue* context, HValue* object, Handle<Object> name) 5697 : name_(name) { 5698 SetOperandAt(0, context); 5699 SetOperandAt(1, object); 5700 set_representation(Representation::Tagged()); 5701 SetAllSideEffects(); 5702 } 5703 5704 HValue* context() { return OperandAt(0); } 5705 HValue* object() { return OperandAt(1); } 5706 Handle<Object> name() const { return name_; } 5707 5708 virtual Representation RequiredInputRepresentation(int index) { 5709 return Representation::Tagged(); 5710 } 5711 5712 virtual void PrintDataTo(StringStream* stream); 5713 5714 DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric) 5715 5716 private: 5717 Handle<Object> name_; 5718 }; 5719 5720 5721 class HLoadFunctionPrototype: public HUnaryOperation { 5722 public: 5723 explicit HLoadFunctionPrototype(HValue* function) 5724 : HUnaryOperation(function) { 5725 set_representation(Representation::Tagged()); 5726 SetFlag(kUseGVN); 5727 SetGVNFlag(kDependsOnCalls); 5728 } 5729 5730 HValue* function() { return OperandAt(0); } 5731 5732 virtual Representation RequiredInputRepresentation(int index) { 5733 return Representation::Tagged(); 5734 } 5735 5736 DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype) 5737 5738 protected: 5739 virtual bool DataEquals(HValue* other) { return true; } 5740 }; 5741 5742 class ArrayInstructionInterface { 5743 public: 5744 virtual HValue* GetKey() = 0; 5745 virtual void SetKey(HValue* key) = 0; 5746 virtual void SetIndexOffset(uint32_t index_offset) = 0; 5747 virtual bool IsDehoisted() = 0; 5748 virtual void SetDehoisted(bool is_dehoisted) = 0; 5749 virtual ~ArrayInstructionInterface() { }; 5750 5751 static Representation KeyedAccessIndexRequirement(Representation r) { 5752 return r.IsInteger32() || kSmiValueSize != 31 5753 ? Representation::Integer32() : Representation::Smi(); 5754 } 5755 }; 5756 5757 5758 enum LoadKeyedHoleMode { 5759 NEVER_RETURN_HOLE, 5760 ALLOW_RETURN_HOLE 5761 }; 5762 5763 5764 class HLoadKeyed 5765 : public HTemplateInstruction<3>, public ArrayInstructionInterface { 5766 public: 5767 DECLARE_INSTRUCTION_FACTORY_P4(HLoadKeyed, HValue*, HValue*, HValue*, 5768 ElementsKind); 5769 DECLARE_INSTRUCTION_FACTORY_P5(HLoadKeyed, HValue*, HValue*, HValue*, 5770 ElementsKind, LoadKeyedHoleMode); 5771 5772 bool is_external() const { 5773 return IsExternalArrayElementsKind(elements_kind()); 5774 } 5775 HValue* elements() { return OperandAt(0); } 5776 HValue* key() { return OperandAt(1); } 5777 HValue* dependency() { 5778 ASSERT(HasDependency()); 5779 return OperandAt(2); 5780 } 5781 bool HasDependency() const { return OperandAt(0) != OperandAt(2); } 5782 uint32_t index_offset() { return IndexOffsetField::decode(bit_field_); } 5783 void SetIndexOffset(uint32_t index_offset) { 5784 bit_field_ = IndexOffsetField::update(bit_field_, index_offset); 5785 } 5786 HValue* GetKey() { return key(); } 5787 void SetKey(HValue* key) { SetOperandAt(1, key); } 5788 bool IsDehoisted() { return IsDehoistedField::decode(bit_field_); } 5789 void SetDehoisted(bool is_dehoisted) { 5790 bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted); 5791 } 5792 ElementsKind elements_kind() const { 5793 return ElementsKindField::decode(bit_field_); 5794 } 5795 LoadKeyedHoleMode hole_mode() const { 5796 return HoleModeField::decode(bit_field_); 5797 } 5798 5799 virtual Representation RequiredInputRepresentation(int index) { 5800 // kind_fast: tagged[int32] (none) 5801 // kind_double: tagged[int32] (none) 5802 // kind_external: external[int32] (none) 5803 if (index == 0) { 5804 return is_external() ? Representation::External() 5805 : Representation::Tagged(); 5806 } 5807 if (index == 1) { 5808 return ArrayInstructionInterface::KeyedAccessIndexRequirement( 5809 OperandAt(1)->representation()); 5810 } 5811 return Representation::None(); 5812 } 5813 5814 virtual Representation observed_input_representation(int index) { 5815 return RequiredInputRepresentation(index); 5816 } 5817 5818 virtual void PrintDataTo(StringStream* stream); 5819 5820 bool UsesMustHandleHole() const; 5821 bool AllUsesCanTreatHoleAsNaN() const; 5822 bool RequiresHoleCheck() const; 5823 5824 virtual Range* InferRange(Zone* zone); 5825 5826 DECLARE_CONCRETE_INSTRUCTION(LoadKeyed) 5827 5828 protected: 5829 virtual bool DataEquals(HValue* other) { 5830 if (!other->IsLoadKeyed()) return false; 5831 HLoadKeyed* other_load = HLoadKeyed::cast(other); 5832 5833 if (IsDehoisted() && index_offset() != other_load->index_offset()) 5834 return false; 5835 return elements_kind() == other_load->elements_kind(); 5836 } 5837 5838 private: 5839 HLoadKeyed(HValue* obj, 5840 HValue* key, 5841 HValue* dependency, 5842 ElementsKind elements_kind, 5843 LoadKeyedHoleMode mode = NEVER_RETURN_HOLE) 5844 : bit_field_(0) { 5845 bit_field_ = ElementsKindField::encode(elements_kind) | 5846 HoleModeField::encode(mode); 5847 5848 SetOperandAt(0, obj); 5849 SetOperandAt(1, key); 5850 SetOperandAt(2, dependency != NULL ? dependency : obj); 5851 5852 if (!is_external()) { 5853 // I can detect the case between storing double (holey and fast) and 5854 // smi/object by looking at elements_kind_. 5855 ASSERT(IsFastSmiOrObjectElementsKind(elements_kind) || 5856 IsFastDoubleElementsKind(elements_kind)); 5857 5858 if (IsFastSmiOrObjectElementsKind(elements_kind)) { 5859 if (IsFastSmiElementsKind(elements_kind) && 5860 (!IsHoleyElementsKind(elements_kind) || 5861 mode == NEVER_RETURN_HOLE)) { 5862 set_type(HType::Smi()); 5863 set_representation(Representation::Smi()); 5864 } else { 5865 set_representation(Representation::Tagged()); 5866 } 5867 5868 SetGVNFlag(kDependsOnArrayElements); 5869 } else { 5870 set_representation(Representation::Double()); 5871 SetGVNFlag(kDependsOnDoubleArrayElements); 5872 } 5873 } else { 5874 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS || 5875 elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { 5876 set_representation(Representation::Double()); 5877 } else { 5878 set_representation(Representation::Integer32()); 5879 } 5880 5881 SetGVNFlag(kDependsOnExternalMemory); 5882 // Native code could change the specialized array. 5883 SetGVNFlag(kDependsOnCalls); 5884 } 5885 5886 SetFlag(kUseGVN); 5887 } 5888 5889 virtual bool IsDeletable() const { 5890 return !RequiresHoleCheck(); 5891 } 5892 5893 // Establish some checks around our packed fields 5894 enum LoadKeyedBits { 5895 kBitsForElementsKind = 5, 5896 kBitsForHoleMode = 1, 5897 kBitsForIndexOffset = 25, 5898 kBitsForIsDehoisted = 1, 5899 5900 kStartElementsKind = 0, 5901 kStartHoleMode = kStartElementsKind + kBitsForElementsKind, 5902 kStartIndexOffset = kStartHoleMode + kBitsForHoleMode, 5903 kStartIsDehoisted = kStartIndexOffset + kBitsForIndexOffset 5904 }; 5905 5906 STATIC_ASSERT((kBitsForElementsKind + kBitsForIndexOffset + 5907 kBitsForIsDehoisted) <= sizeof(uint32_t)*8); 5908 STATIC_ASSERT(kElementsKindCount <= (1 << kBitsForElementsKind)); 5909 class ElementsKindField: 5910 public BitField<ElementsKind, kStartElementsKind, kBitsForElementsKind> 5911 {}; // NOLINT 5912 class HoleModeField: 5913 public BitField<LoadKeyedHoleMode, kStartHoleMode, kBitsForHoleMode> 5914 {}; // NOLINT 5915 class IndexOffsetField: 5916 public BitField<uint32_t, kStartIndexOffset, kBitsForIndexOffset> 5917 {}; // NOLINT 5918 class IsDehoistedField: 5919 public BitField<bool, kStartIsDehoisted, kBitsForIsDehoisted> 5920 {}; // NOLINT 5921 uint32_t bit_field_; 5922 }; 5923 5924 5925 class HLoadKeyedGeneric: public HTemplateInstruction<3> { 5926 public: 5927 HLoadKeyedGeneric(HValue* context, HValue* obj, HValue* key) { 5928 set_representation(Representation::Tagged()); 5929 SetOperandAt(0, obj); 5930 SetOperandAt(1, key); 5931 SetOperandAt(2, context); 5932 SetAllSideEffects(); 5933 } 5934 5935 HValue* object() { return OperandAt(0); } 5936 HValue* key() { return OperandAt(1); } 5937 HValue* context() { return OperandAt(2); } 5938 5939 virtual void PrintDataTo(StringStream* stream); 5940 5941 virtual Representation RequiredInputRepresentation(int index) { 5942 // tagged[tagged] 5943 return Representation::Tagged(); 5944 } 5945 5946 virtual HValue* Canonicalize(); 5947 5948 DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric) 5949 }; 5950 5951 5952 class HStoreNamedField: public HTemplateInstruction<3> { 5953 public: 5954 DECLARE_INSTRUCTION_FACTORY_P3(HStoreNamedField, HValue*, 5955 HObjectAccess, HValue*); 5956 5957 DECLARE_CONCRETE_INSTRUCTION(StoreNamedField) 5958 5959 virtual bool HasEscapingOperandAt(int index) { return index == 1; } 5960 virtual Representation RequiredInputRepresentation(int index) { 5961 if (index == 0 && access().IsExternalMemory()) { 5962 // object must be external in case of external memory access 5963 return Representation::External(); 5964 } else if (index == 1 && 5965 (field_representation().IsDouble() || 5966 field_representation().IsSmi() || 5967 field_representation().IsInteger32())) { 5968 return field_representation(); 5969 } 5970 return Representation::Tagged(); 5971 } 5972 virtual void HandleSideEffectDominator(GVNFlag side_effect, 5973 HValue* dominator) { 5974 ASSERT(side_effect == kChangesNewSpacePromotion); 5975 new_space_dominator_ = dominator; 5976 } 5977 virtual void PrintDataTo(StringStream* stream); 5978 5979 void SkipWriteBarrier() { write_barrier_mode_ = SKIP_WRITE_BARRIER; } 5980 bool IsSkipWriteBarrier() const { 5981 return write_barrier_mode_ == SKIP_WRITE_BARRIER; 5982 } 5983 5984 HValue* object() const { return OperandAt(0); } 5985 HValue* value() const { return OperandAt(1); } 5986 HValue* transition() const { return OperandAt(2); } 5987 5988 HObjectAccess access() const { return access_; } 5989 HValue* new_space_dominator() const { return new_space_dominator_; } 5990 bool has_transition() const { return has_transition_; } 5991 5992 Handle<Map> transition_map() const { 5993 if (has_transition()) { 5994 return Handle<Map>::cast(HConstant::cast(transition())->handle()); 5995 } else { 5996 return Handle<Map>(); 5997 } 5998 } 5999 6000 void SetTransition(HConstant* map_constant, CompilationInfo* info) { 6001 ASSERT(!has_transition()); // Only set once. 6002 Handle<Map> map = Handle<Map>::cast(map_constant->handle()); 6003 if (map->CanBeDeprecated()) { 6004 map->AddDependentCompilationInfo(DependentCode::kTransitionGroup, info); 6005 } 6006 SetOperandAt(2, map_constant); 6007 has_transition_ = true; 6008 } 6009 6010 bool NeedsWriteBarrier() { 6011 ASSERT(!(FLAG_track_double_fields && field_representation().IsDouble()) || 6012 !has_transition()); 6013 if (IsSkipWriteBarrier()) return false; 6014 if (field_representation().IsDouble()) return false; 6015 if (field_representation().IsSmi()) return false; 6016 if (field_representation().IsInteger32()) return false; 6017 if (field_representation().IsExternal()) return false; 6018 return StoringValueNeedsWriteBarrier(value()) && 6019 ReceiverObjectNeedsWriteBarrier(object(), new_space_dominator()); 6020 } 6021 6022 bool NeedsWriteBarrierForMap() { 6023 if (IsSkipWriteBarrier()) return false; 6024 return ReceiverObjectNeedsWriteBarrier(object(), new_space_dominator()); 6025 } 6026 6027 Representation field_representation() const { 6028 return access_.representation(); 6029 } 6030 6031 void UpdateValue(HValue* value) { 6032 SetOperandAt(1, value); 6033 } 6034 6035 private: 6036 HStoreNamedField(HValue* obj, 6037 HObjectAccess access, 6038 HValue* val) 6039 : access_(access), 6040 new_space_dominator_(NULL), 6041 write_barrier_mode_(UPDATE_WRITE_BARRIER), 6042 has_transition_(false) { 6043 SetOperandAt(0, obj); 6044 SetOperandAt(1, val); 6045 SetOperandAt(2, obj); 6046 access.SetGVNFlags(this, true); 6047 } 6048 6049 HObjectAccess access_; 6050 HValue* new_space_dominator_; 6051 WriteBarrierMode write_barrier_mode_ : 1; 6052 bool has_transition_ : 1; 6053 }; 6054 6055 6056 class HStoreNamedGeneric: public HTemplateInstruction<3> { 6057 public: 6058 HStoreNamedGeneric(HValue* context, 6059 HValue* object, 6060 Handle<String> name, 6061 HValue* value, 6062 StrictModeFlag strict_mode_flag) 6063 : name_(name), 6064 strict_mode_flag_(strict_mode_flag) { 6065 SetOperandAt(0, object); 6066 SetOperandAt(1, value); 6067 SetOperandAt(2, context); 6068 SetAllSideEffects(); 6069 } 6070 6071 HValue* object() { return OperandAt(0); } 6072 HValue* value() { return OperandAt(1); } 6073 HValue* context() { return OperandAt(2); } 6074 Handle<String> name() { return name_; } 6075 StrictModeFlag strict_mode_flag() { return strict_mode_flag_; } 6076 6077 virtual void PrintDataTo(StringStream* stream); 6078 6079 virtual Representation RequiredInputRepresentation(int index) { 6080 return Representation::Tagged(); 6081 } 6082 6083 DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric) 6084 6085 private: 6086 Handle<String> name_; 6087 StrictModeFlag strict_mode_flag_; 6088 }; 6089 6090 6091 class HStoreKeyed 6092 : public HTemplateInstruction<3>, public ArrayInstructionInterface { 6093 public: 6094 DECLARE_INSTRUCTION_FACTORY_P4(HStoreKeyed, HValue*, HValue*, HValue*, 6095 ElementsKind); 6096 6097 virtual Representation RequiredInputRepresentation(int index) { 6098 // kind_fast: tagged[int32] = tagged 6099 // kind_double: tagged[int32] = double 6100 // kind_smi : tagged[int32] = smi 6101 // kind_external: external[int32] = (double | int32) 6102 if (index == 0) { 6103 return is_external() ? Representation::External() 6104 : Representation::Tagged(); 6105 } else if (index == 1) { 6106 return ArrayInstructionInterface::KeyedAccessIndexRequirement( 6107 OperandAt(1)->representation()); 6108 } 6109 6110 ASSERT_EQ(index, 2); 6111 if (IsDoubleOrFloatElementsKind(elements_kind())) { 6112 return Representation::Double(); 6113 } 6114 6115 if (IsFastSmiElementsKind(elements_kind())) { 6116 return Representation::Smi(); 6117 } 6118 6119 return is_external() ? Representation::Integer32() 6120 : Representation::Tagged(); 6121 } 6122 6123 bool is_external() const { 6124 return IsExternalArrayElementsKind(elements_kind()); 6125 } 6126 6127 virtual Representation observed_input_representation(int index) { 6128 if (index < 2) return RequiredInputRepresentation(index); 6129 if (IsUninitialized()) { 6130 return Representation::None(); 6131 } 6132 if (IsFastSmiElementsKind(elements_kind())) { 6133 return Representation::Smi(); 6134 } 6135 if (IsDoubleOrFloatElementsKind(elements_kind())) { 6136 return Representation::Double(); 6137 } 6138 if (is_external()) { 6139 return Representation::Integer32(); 6140 } 6141 // For fast object elements kinds, don't assume anything. 6142 return Representation::None(); 6143 } 6144 6145 HValue* elements() { return OperandAt(0); } 6146 HValue* key() { return OperandAt(1); } 6147 HValue* value() { return OperandAt(2); } 6148 bool value_is_smi() const { 6149 return IsFastSmiElementsKind(elements_kind_); 6150 } 6151 ElementsKind elements_kind() const { return elements_kind_; } 6152 uint32_t index_offset() { return index_offset_; } 6153 void SetIndexOffset(uint32_t index_offset) { index_offset_ = index_offset; } 6154 HValue* GetKey() { return key(); } 6155 void SetKey(HValue* key) { SetOperandAt(1, key); } 6156 bool IsDehoisted() { return is_dehoisted_; } 6157 void SetDehoisted(bool is_dehoisted) { is_dehoisted_ = is_dehoisted; } 6158 bool IsUninitialized() { return is_uninitialized_; } 6159 void SetUninitialized(bool is_uninitialized) { 6160 is_uninitialized_ = is_uninitialized; 6161 } 6162 6163 bool IsConstantHoleStore() { 6164 return value()->IsConstant() && HConstant::cast(value())->IsTheHole(); 6165 } 6166 6167 virtual void HandleSideEffectDominator(GVNFlag side_effect, 6168 HValue* dominator) { 6169 ASSERT(side_effect == kChangesNewSpacePromotion); 6170 new_space_dominator_ = dominator; 6171 } 6172 6173 HValue* new_space_dominator() const { return new_space_dominator_; } 6174 6175 bool NeedsWriteBarrier() { 6176 if (value_is_smi()) { 6177 return false; 6178 } else { 6179 return StoringValueNeedsWriteBarrier(value()) && 6180 ReceiverObjectNeedsWriteBarrier(elements(), new_space_dominator()); 6181 } 6182 } 6183 6184 bool NeedsCanonicalization(); 6185 6186 virtual void PrintDataTo(StringStream* stream); 6187 6188 DECLARE_CONCRETE_INSTRUCTION(StoreKeyed) 6189 6190 private: 6191 HStoreKeyed(HValue* obj, HValue* key, HValue* val, 6192 ElementsKind elements_kind) 6193 : elements_kind_(elements_kind), 6194 index_offset_(0), 6195 is_dehoisted_(false), 6196 is_uninitialized_(false), 6197 new_space_dominator_(NULL) { 6198 SetOperandAt(0, obj); 6199 SetOperandAt(1, key); 6200 SetOperandAt(2, val); 6201 6202 if (IsFastObjectElementsKind(elements_kind)) { 6203 SetFlag(kTrackSideEffectDominators); 6204 SetGVNFlag(kDependsOnNewSpacePromotion); 6205 } 6206 if (is_external()) { 6207 SetGVNFlag(kChangesExternalMemory); 6208 SetFlag(kAllowUndefinedAsNaN); 6209 } else if (IsFastDoubleElementsKind(elements_kind)) { 6210 SetGVNFlag(kChangesDoubleArrayElements); 6211 } else if (IsFastSmiElementsKind(elements_kind)) { 6212 SetGVNFlag(kChangesArrayElements); 6213 } else { 6214 SetGVNFlag(kChangesArrayElements); 6215 } 6216 6217 // EXTERNAL_{UNSIGNED_,}{BYTE,SHORT,INT}_ELEMENTS are truncating. 6218 if (elements_kind >= EXTERNAL_BYTE_ELEMENTS && 6219 elements_kind <= EXTERNAL_UNSIGNED_INT_ELEMENTS) { 6220 SetFlag(kTruncatingToInt32); 6221 } 6222 } 6223 6224 ElementsKind elements_kind_; 6225 uint32_t index_offset_; 6226 bool is_dehoisted_ : 1; 6227 bool is_uninitialized_ : 1; 6228 HValue* new_space_dominator_; 6229 }; 6230 6231 6232 class HStoreKeyedGeneric: public HTemplateInstruction<4> { 6233 public: 6234 HStoreKeyedGeneric(HValue* context, 6235 HValue* object, 6236 HValue* key, 6237 HValue* value, 6238 StrictModeFlag strict_mode_flag) 6239 : strict_mode_flag_(strict_mode_flag) { 6240 SetOperandAt(0, object); 6241 SetOperandAt(1, key); 6242 SetOperandAt(2, value); 6243 SetOperandAt(3, context); 6244 SetAllSideEffects(); 6245 } 6246 6247 HValue* object() { return OperandAt(0); } 6248 HValue* key() { return OperandAt(1); } 6249 HValue* value() { return OperandAt(2); } 6250 HValue* context() { return OperandAt(3); } 6251 StrictModeFlag strict_mode_flag() { return strict_mode_flag_; } 6252 6253 virtual Representation RequiredInputRepresentation(int index) { 6254 // tagged[tagged] = tagged 6255 return Representation::Tagged(); 6256 } 6257 6258 virtual void PrintDataTo(StringStream* stream); 6259 6260 DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric) 6261 6262 private: 6263 StrictModeFlag strict_mode_flag_; 6264 }; 6265 6266 6267 class HTransitionElementsKind: public HTemplateInstruction<2> { 6268 public: 6269 inline static HTransitionElementsKind* New(Zone* zone, 6270 HValue* context, 6271 HValue* object, 6272 Handle<Map> original_map, 6273 Handle<Map> transitioned_map) { 6274 return new(zone) HTransitionElementsKind(context, object, 6275 original_map, transitioned_map); 6276 } 6277 6278 virtual Representation RequiredInputRepresentation(int index) { 6279 return Representation::Tagged(); 6280 } 6281 6282 HValue* object() { return OperandAt(0); } 6283 HValue* context() { return OperandAt(1); } 6284 Handle<Map> original_map() { return original_map_; } 6285 Handle<Map> transitioned_map() { return transitioned_map_; } 6286 ElementsKind from_kind() { return from_kind_; } 6287 ElementsKind to_kind() { return to_kind_; } 6288 6289 virtual void PrintDataTo(StringStream* stream); 6290 6291 virtual void FinalizeUniqueValueId() { 6292 original_map_unique_id_ = UniqueValueId(original_map_); 6293 transitioned_map_unique_id_ = UniqueValueId(transitioned_map_); 6294 } 6295 6296 DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind) 6297 6298 protected: 6299 virtual bool DataEquals(HValue* other) { 6300 HTransitionElementsKind* instr = HTransitionElementsKind::cast(other); 6301 return original_map_unique_id_ == instr->original_map_unique_id_ && 6302 transitioned_map_unique_id_ == instr->transitioned_map_unique_id_; 6303 } 6304 6305 private: 6306 HTransitionElementsKind(HValue* context, 6307 HValue* object, 6308 Handle<Map> original_map, 6309 Handle<Map> transitioned_map) 6310 : original_map_(original_map), 6311 transitioned_map_(transitioned_map), 6312 original_map_unique_id_(), 6313 transitioned_map_unique_id_(), 6314 from_kind_(original_map->elements_kind()), 6315 to_kind_(transitioned_map->elements_kind()) { 6316 SetOperandAt(0, object); 6317 SetOperandAt(1, context); 6318 SetFlag(kUseGVN); 6319 SetGVNFlag(kChangesElementsKind); 6320 if (original_map->has_fast_double_elements()) { 6321 SetGVNFlag(kChangesElementsPointer); 6322 SetGVNFlag(kChangesNewSpacePromotion); 6323 } 6324 if (transitioned_map->has_fast_double_elements()) { 6325 SetGVNFlag(kChangesElementsPointer); 6326 SetGVNFlag(kChangesNewSpacePromotion); 6327 } 6328 set_representation(Representation::Tagged()); 6329 } 6330 6331 Handle<Map> original_map_; 6332 Handle<Map> transitioned_map_; 6333 UniqueValueId original_map_unique_id_; 6334 UniqueValueId transitioned_map_unique_id_; 6335 ElementsKind from_kind_; 6336 ElementsKind to_kind_; 6337 }; 6338 6339 6340 class HStringAdd: public HBinaryOperation { 6341 public: 6342 static HInstruction* New(Zone* zone, 6343 HValue* context, 6344 HValue* left, 6345 HValue* right, 6346 StringAddFlags flags = STRING_ADD_CHECK_NONE); 6347 6348 StringAddFlags flags() const { return flags_; } 6349 6350 virtual Representation RequiredInputRepresentation(int index) { 6351 return Representation::Tagged(); 6352 } 6353 6354 DECLARE_CONCRETE_INSTRUCTION(StringAdd) 6355 6356 protected: 6357 virtual bool DataEquals(HValue* other) { return true; } 6358 6359 private: 6360 HStringAdd(HValue* context, HValue* left, HValue* right, StringAddFlags flags) 6361 : HBinaryOperation(context, left, right, HType::String()), flags_(flags) { 6362 set_representation(Representation::Tagged()); 6363 SetFlag(kUseGVN); 6364 SetGVNFlag(kDependsOnMaps); 6365 SetGVNFlag(kChangesNewSpacePromotion); 6366 } 6367 6368 // No side-effects except possible allocation. 6369 // NOTE: this instruction _does not_ call ToString() on its inputs. 6370 virtual bool IsDeletable() const { return true; } 6371 6372 const StringAddFlags flags_; 6373 }; 6374 6375 6376 class HStringCharCodeAt: public HTemplateInstruction<3> { 6377 public: 6378 static HStringCharCodeAt* New(Zone* zone, 6379 HValue* context, 6380 HValue* string, 6381 HValue* index) { 6382 return new(zone) HStringCharCodeAt(context, string, index); 6383 } 6384 6385 virtual Representation RequiredInputRepresentation(int index) { 6386 // The index is supposed to be Integer32. 6387 return index == 2 6388 ? Representation::Integer32() 6389 : Representation::Tagged(); 6390 } 6391 6392 HValue* context() const { return OperandAt(0); } 6393 HValue* string() const { return OperandAt(1); } 6394 HValue* index() const { return OperandAt(2); } 6395 6396 DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt) 6397 6398 protected: 6399 virtual bool DataEquals(HValue* other) { return true; } 6400 6401 virtual Range* InferRange(Zone* zone) { 6402 return new(zone) Range(0, String::kMaxUtf16CodeUnit); 6403 } 6404 6405 private: 6406 HStringCharCodeAt(HValue* context, HValue* string, HValue* index) { 6407 SetOperandAt(0, context); 6408 SetOperandAt(1, string); 6409 SetOperandAt(2, index); 6410 set_representation(Representation::Integer32()); 6411 SetFlag(kUseGVN); 6412 SetGVNFlag(kDependsOnMaps); 6413 SetGVNFlag(kChangesNewSpacePromotion); 6414 } 6415 6416 // No side effects: runtime function assumes string + number inputs. 6417 virtual bool IsDeletable() const { return true; } 6418 }; 6419 6420 6421 class HStringCharFromCode: public HTemplateInstruction<2> { 6422 public: 6423 static HInstruction* New(Zone* zone, 6424 HValue* context, 6425 HValue* char_code); 6426 6427 virtual Representation RequiredInputRepresentation(int index) { 6428 return index == 0 6429 ? Representation::Tagged() 6430 : Representation::Integer32(); 6431 } 6432 6433 HValue* context() const { return OperandAt(0); } 6434 HValue* value() const { return OperandAt(1); } 6435 6436 virtual bool DataEquals(HValue* other) { return true; } 6437 6438 DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode) 6439 6440 private: 6441 HStringCharFromCode(HValue* context, HValue* char_code) 6442 : HTemplateInstruction<2>(HType::String()) { 6443 SetOperandAt(0, context); 6444 SetOperandAt(1, char_code); 6445 set_representation(Representation::Tagged()); 6446 SetFlag(kUseGVN); 6447 SetGVNFlag(kChangesNewSpacePromotion); 6448 } 6449 6450 virtual bool IsDeletable() const { 6451 return !value()->ToNumberCanBeObserved(); 6452 } 6453 }; 6454 6455 6456 template <int V> 6457 class HMaterializedLiteral: public HTemplateInstruction<V> { 6458 public: 6459 HMaterializedLiteral<V>(int index, int depth, AllocationSiteMode mode) 6460 : literal_index_(index), depth_(depth), allocation_site_mode_(mode) { 6461 this->set_representation(Representation::Tagged()); 6462 } 6463 6464 HMaterializedLiteral<V>(int index, int depth) 6465 : literal_index_(index), depth_(depth), 6466 allocation_site_mode_(DONT_TRACK_ALLOCATION_SITE) { 6467 this->set_representation(Representation::Tagged()); 6468 } 6469 6470 int literal_index() const { return literal_index_; } 6471 int depth() const { return depth_; } 6472 AllocationSiteMode allocation_site_mode() const { 6473 return allocation_site_mode_; 6474 } 6475 6476 private: 6477 virtual bool IsDeletable() const { return true; } 6478 6479 int literal_index_; 6480 int depth_; 6481 AllocationSiteMode allocation_site_mode_; 6482 }; 6483 6484 6485 class HRegExpLiteral: public HMaterializedLiteral<1> { 6486 public: 6487 HRegExpLiteral(HValue* context, 6488 Handle<FixedArray> literals, 6489 Handle<String> pattern, 6490 Handle<String> flags, 6491 int literal_index) 6492 : HMaterializedLiteral<1>(literal_index, 0), 6493 literals_(literals), 6494 pattern_(pattern), 6495 flags_(flags) { 6496 SetOperandAt(0, context); 6497 SetAllSideEffects(); 6498 set_type(HType::JSObject()); 6499 } 6500 6501 HValue* context() { return OperandAt(0); } 6502 Handle<FixedArray> literals() { return literals_; } 6503 Handle<String> pattern() { return pattern_; } 6504 Handle<String> flags() { return flags_; } 6505 6506 virtual Representation RequiredInputRepresentation(int index) { 6507 return Representation::Tagged(); 6508 } 6509 6510 DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral) 6511 6512 private: 6513 Handle<FixedArray> literals_; 6514 Handle<String> pattern_; 6515 Handle<String> flags_; 6516 }; 6517 6518 6519 class HFunctionLiteral: public HTemplateInstruction<1> { 6520 public: 6521 HFunctionLiteral(HValue* context, 6522 Handle<SharedFunctionInfo> shared, 6523 bool pretenure) 6524 : HTemplateInstruction<1>(HType::JSObject()), 6525 shared_info_(shared), 6526 pretenure_(pretenure), 6527 has_no_literals_(shared->num_literals() == 0), 6528 is_generator_(shared->is_generator()), 6529 language_mode_(shared->language_mode()) { 6530 SetOperandAt(0, context); 6531 set_representation(Representation::Tagged()); 6532 SetGVNFlag(kChangesNewSpacePromotion); 6533 } 6534 6535 HValue* context() { return OperandAt(0); } 6536 6537 virtual Representation RequiredInputRepresentation(int index) { 6538 return Representation::Tagged(); 6539 } 6540 6541 DECLARE_CONCRETE_INSTRUCTION(FunctionLiteral) 6542 6543 Handle<SharedFunctionInfo> shared_info() const { return shared_info_; } 6544 bool pretenure() const { return pretenure_; } 6545 bool has_no_literals() const { return has_no_literals_; } 6546 bool is_generator() const { return is_generator_; } 6547 LanguageMode language_mode() const { return language_mode_; } 6548 6549 private: 6550 virtual bool IsDeletable() const { return true; } 6551 6552 Handle<SharedFunctionInfo> shared_info_; 6553 bool pretenure_ : 1; 6554 bool has_no_literals_ : 1; 6555 bool is_generator_ : 1; 6556 LanguageMode language_mode_; 6557 }; 6558 6559 6560 class HTypeof: public HTemplateInstruction<2> { 6561 public: 6562 explicit HTypeof(HValue* context, HValue* value) { 6563 SetOperandAt(0, context); 6564 SetOperandAt(1, value); 6565 set_representation(Representation::Tagged()); 6566 } 6567 6568 HValue* context() { return OperandAt(0); } 6569 HValue* value() { return OperandAt(1); } 6570 6571 virtual void PrintDataTo(StringStream* stream); 6572 6573 virtual Representation RequiredInputRepresentation(int index) { 6574 return Representation::Tagged(); 6575 } 6576 6577 DECLARE_CONCRETE_INSTRUCTION(Typeof) 6578 6579 private: 6580 virtual bool IsDeletable() const { return true; } 6581 }; 6582 6583 6584 class HTrapAllocationMemento : public HTemplateInstruction<1> { 6585 public: 6586 DECLARE_INSTRUCTION_FACTORY_P1(HTrapAllocationMemento, HValue*); 6587 6588 virtual Representation RequiredInputRepresentation(int index) { 6589 return Representation::Tagged(); 6590 } 6591 6592 HValue* object() { return OperandAt(0); } 6593 6594 DECLARE_CONCRETE_INSTRUCTION(TrapAllocationMemento) 6595 6596 private: 6597 explicit HTrapAllocationMemento(HValue* obj) { 6598 SetOperandAt(0, obj); 6599 } 6600 }; 6601 6602 6603 class HToFastProperties: public HUnaryOperation { 6604 public: 6605 DECLARE_INSTRUCTION_FACTORY_P1(HToFastProperties, HValue*); 6606 6607 virtual Representation RequiredInputRepresentation(int index) { 6608 return Representation::Tagged(); 6609 } 6610 6611 DECLARE_CONCRETE_INSTRUCTION(ToFastProperties) 6612 6613 private: 6614 explicit HToFastProperties(HValue* value) : HUnaryOperation(value) { 6615 set_representation(Representation::Tagged()); 6616 SetGVNFlag(kChangesNewSpacePromotion); 6617 6618 // This instruction is not marked as kChangesMaps, but does 6619 // change the map of the input operand. Use it only when creating 6620 // object literals via a runtime call. 6621 ASSERT(value->IsCallRuntime()); 6622 #ifdef DEBUG 6623 const Runtime::Function* function = HCallRuntime::cast(value)->function(); 6624 ASSERT(function->function_id == Runtime::kCreateObjectLiteral || 6625 function->function_id == Runtime::kCreateObjectLiteralShallow); 6626 #endif 6627 } 6628 6629 virtual bool IsDeletable() const { return true; } 6630 }; 6631 6632 6633 class HValueOf: public HUnaryOperation { 6634 public: 6635 explicit HValueOf(HValue* value) : HUnaryOperation(value) { 6636 set_representation(Representation::Tagged()); 6637 } 6638 6639 virtual Representation RequiredInputRepresentation(int index) { 6640 return Representation::Tagged(); 6641 } 6642 6643 DECLARE_CONCRETE_INSTRUCTION(ValueOf) 6644 6645 private: 6646 virtual bool IsDeletable() const { return true; } 6647 }; 6648 6649 6650 class HDateField: public HUnaryOperation { 6651 public: 6652 HDateField(HValue* date, Smi* index) 6653 : HUnaryOperation(date), index_(index) { 6654 set_representation(Representation::Tagged()); 6655 } 6656 6657 Smi* index() const { return index_; } 6658 6659 virtual Representation RequiredInputRepresentation(int index) { 6660 return Representation::Tagged(); 6661 } 6662 6663 DECLARE_CONCRETE_INSTRUCTION(DateField) 6664 6665 private: 6666 Smi* index_; 6667 }; 6668 6669 6670 class HSeqStringSetChar: public HTemplateInstruction<3> { 6671 public: 6672 HSeqStringSetChar(String::Encoding encoding, 6673 HValue* string, 6674 HValue* index, 6675 HValue* value) : encoding_(encoding) { 6676 SetOperandAt(0, string); 6677 SetOperandAt(1, index); 6678 SetOperandAt(2, value); 6679 set_representation(Representation::Tagged()); 6680 } 6681 6682 String::Encoding encoding() { return encoding_; } 6683 HValue* string() { return OperandAt(0); } 6684 HValue* index() { return OperandAt(1); } 6685 HValue* value() { return OperandAt(2); } 6686 6687 virtual Representation RequiredInputRepresentation(int index) { 6688 return (index == 0) ? Representation::Tagged() 6689 : Representation::Integer32(); 6690 } 6691 6692 DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar) 6693 6694 private: 6695 String::Encoding encoding_; 6696 }; 6697 6698 6699 class HCheckMapValue: public HTemplateInstruction<2> { 6700 public: 6701 DECLARE_INSTRUCTION_FACTORY_P2(HCheckMapValue, HValue*, HValue*); 6702 6703 virtual Representation RequiredInputRepresentation(int index) { 6704 return Representation::Tagged(); 6705 } 6706 6707 virtual void PrintDataTo(StringStream* stream); 6708 6709 virtual HType CalculateInferredType() { 6710 return HType::Tagged(); 6711 } 6712 6713 HValue* value() { return OperandAt(0); } 6714 HValue* map() { return OperandAt(1); } 6715 6716 DECLARE_CONCRETE_INSTRUCTION(CheckMapValue) 6717 6718 protected: 6719 virtual bool DataEquals(HValue* other) { 6720 return true; 6721 } 6722 6723 private: 6724 HCheckMapValue(HValue* value, 6725 HValue* map) { 6726 SetOperandAt(0, value); 6727 SetOperandAt(1, map); 6728 set_representation(Representation::Tagged()); 6729 SetFlag(kUseGVN); 6730 SetGVNFlag(kDependsOnMaps); 6731 SetGVNFlag(kDependsOnElementsKind); 6732 } 6733 }; 6734 6735 6736 class HForInPrepareMap : public HTemplateInstruction<2> { 6737 public: 6738 static HForInPrepareMap* New(Zone* zone, 6739 HValue* context, 6740 HValue* object) { 6741 return new(zone) HForInPrepareMap(context, object); 6742 } 6743 6744 virtual Representation RequiredInputRepresentation(int index) { 6745 return Representation::Tagged(); 6746 } 6747 6748 HValue* context() { return OperandAt(0); } 6749 HValue* enumerable() { return OperandAt(1); } 6750 6751 virtual void PrintDataTo(StringStream* stream); 6752 6753 virtual HType CalculateInferredType() { 6754 return HType::Tagged(); 6755 } 6756 6757 DECLARE_CONCRETE_INSTRUCTION(ForInPrepareMap); 6758 6759 private: 6760 HForInPrepareMap(HValue* context, 6761 HValue* object) { 6762 SetOperandAt(0, context); 6763 SetOperandAt(1, object); 6764 set_representation(Representation::Tagged()); 6765 SetAllSideEffects(); 6766 } 6767 }; 6768 6769 6770 class HForInCacheArray : public HTemplateInstruction<2> { 6771 public: 6772 DECLARE_INSTRUCTION_FACTORY_P3(HForInCacheArray, HValue*, HValue*, int); 6773 6774 virtual Representation RequiredInputRepresentation(int index) { 6775 return Representation::Tagged(); 6776 } 6777 6778 HValue* enumerable() { return OperandAt(0); } 6779 HValue* map() { return OperandAt(1); } 6780 int idx() { return idx_; } 6781 6782 HForInCacheArray* index_cache() { 6783 return index_cache_; 6784 } 6785 6786 void set_index_cache(HForInCacheArray* index_cache) { 6787 index_cache_ = index_cache; 6788 } 6789 6790 virtual void PrintDataTo(StringStream* stream); 6791 6792 virtual HType CalculateInferredType() { 6793 return HType::Tagged(); 6794 } 6795 6796 DECLARE_CONCRETE_INSTRUCTION(ForInCacheArray); 6797 6798 private: 6799 HForInCacheArray(HValue* enumerable, 6800 HValue* keys, 6801 int idx) : idx_(idx) { 6802 SetOperandAt(0, enumerable); 6803 SetOperandAt(1, keys); 6804 set_representation(Representation::Tagged()); 6805 } 6806 6807 int idx_; 6808 HForInCacheArray* index_cache_; 6809 }; 6810 6811 6812 class HLoadFieldByIndex : public HTemplateInstruction<2> { 6813 public: 6814 HLoadFieldByIndex(HValue* object, 6815 HValue* index) { 6816 SetOperandAt(0, object); 6817 SetOperandAt(1, index); 6818 set_representation(Representation::Tagged()); 6819 } 6820 6821 virtual Representation RequiredInputRepresentation(int index) { 6822 return Representation::Tagged(); 6823 } 6824 6825 HValue* object() { return OperandAt(0); } 6826 HValue* index() { return OperandAt(1); } 6827 6828 virtual void PrintDataTo(StringStream* stream); 6829 6830 virtual HType CalculateInferredType() { 6831 return HType::Tagged(); 6832 } 6833 6834 DECLARE_CONCRETE_INSTRUCTION(LoadFieldByIndex); 6835 6836 private: 6837 virtual bool IsDeletable() const { return true; } 6838 }; 6839 6840 6841 #undef DECLARE_INSTRUCTION 6842 #undef DECLARE_CONCRETE_INSTRUCTION 6843 6844 } } // namespace v8::internal 6845 6846 #endif // V8_HYDROGEN_INSTRUCTIONS_H_ 6847