| OLD | NEW |
| (Empty) |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #ifndef V8_HYDROGEN_INSTRUCTIONS_H_ | |
| 6 #define V8_HYDROGEN_INSTRUCTIONS_H_ | |
| 7 | |
| 8 #include <cstring> | |
| 9 #include <iosfwd> | |
| 10 | |
| 11 #include "src/allocation.h" | |
| 12 #include "src/base/bits.h" | |
| 13 #include "src/bit-vector.h" | |
| 14 #include "src/code-stubs.h" | |
| 15 #include "src/conversions.h" | |
| 16 #include "src/deoptimizer.h" | |
| 17 #include "src/hydrogen-types.h" | |
| 18 #include "src/small-pointer-list.h" | |
| 19 #include "src/unique.h" | |
| 20 #include "src/utils.h" | |
| 21 #include "src/zone.h" | |
| 22 | |
| 23 namespace v8 { | |
| 24 namespace internal { | |
| 25 | |
| 26 // Forward declarations. | |
| 27 struct ChangesOf; | |
| 28 class HBasicBlock; | |
| 29 class HDiv; | |
| 30 class HEnvironment; | |
| 31 class HInferRepresentationPhase; | |
| 32 class HInstruction; | |
| 33 class HLoopInformation; | |
| 34 class HStoreNamedField; | |
| 35 class HValue; | |
| 36 class LInstruction; | |
| 37 class LChunkBuilder; | |
| 38 | |
| 39 #define HYDROGEN_ABSTRACT_INSTRUCTION_LIST(V) \ | |
| 40 V(ArithmeticBinaryOperation) \ | |
| 41 V(BinaryOperation) \ | |
| 42 V(BitwiseBinaryOperation) \ | |
| 43 V(ControlInstruction) \ | |
| 44 V(Instruction) | |
| 45 | |
| 46 | |
| 47 #define HYDROGEN_CONCRETE_INSTRUCTION_LIST(V) \ | |
| 48 V(AbnormalExit) \ | |
| 49 V(AccessArgumentsAt) \ | |
| 50 V(Add) \ | |
| 51 V(AllocateBlockContext) \ | |
| 52 V(Allocate) \ | |
| 53 V(ApplyArguments) \ | |
| 54 V(ArgumentsElements) \ | |
| 55 V(ArgumentsLength) \ | |
| 56 V(ArgumentsObject) \ | |
| 57 V(Bitwise) \ | |
| 58 V(BlockEntry) \ | |
| 59 V(BoundsCheck) \ | |
| 60 V(BoundsCheckBaseIndexInformation) \ | |
| 61 V(Branch) \ | |
| 62 V(CallWithDescriptor) \ | |
| 63 V(CallJSFunction) \ | |
| 64 V(CallFunction) \ | |
| 65 V(CallNew) \ | |
| 66 V(CallNewArray) \ | |
| 67 V(CallRuntime) \ | |
| 68 V(CallStub) \ | |
| 69 V(CapturedObject) \ | |
| 70 V(Change) \ | |
| 71 V(CheckArrayBufferNotNeutered) \ | |
| 72 V(CheckHeapObject) \ | |
| 73 V(CheckInstanceType) \ | |
| 74 V(CheckMaps) \ | |
| 75 V(CheckMapValue) \ | |
| 76 V(CheckSmi) \ | |
| 77 V(CheckValue) \ | |
| 78 V(ClampToUint8) \ | |
| 79 V(ClassOfTestAndBranch) \ | |
| 80 V(CompareNumericAndBranch) \ | |
| 81 V(CompareHoleAndBranch) \ | |
| 82 V(CompareGeneric) \ | |
| 83 V(CompareMinusZeroAndBranch) \ | |
| 84 V(CompareObjectEqAndBranch) \ | |
| 85 V(CompareMap) \ | |
| 86 V(Constant) \ | |
| 87 V(ConstructDouble) \ | |
| 88 V(Context) \ | |
| 89 V(DateField) \ | |
| 90 V(DebugBreak) \ | |
| 91 V(DeclareGlobals) \ | |
| 92 V(Deoptimize) \ | |
| 93 V(Div) \ | |
| 94 V(DoubleBits) \ | |
| 95 V(DummyUse) \ | |
| 96 V(EnterInlined) \ | |
| 97 V(EnvironmentMarker) \ | |
| 98 V(ForceRepresentation) \ | |
| 99 V(ForInCacheArray) \ | |
| 100 V(ForInPrepareMap) \ | |
| 101 V(GetCachedArrayIndex) \ | |
| 102 V(Goto) \ | |
| 103 V(HasCachedArrayIndexAndBranch) \ | |
| 104 V(HasInstanceTypeAndBranch) \ | |
| 105 V(InnerAllocatedObject) \ | |
| 106 V(InstanceOf) \ | |
| 107 V(InvokeFunction) \ | |
| 108 V(IsConstructCallAndBranch) \ | |
| 109 V(HasInPrototypeChainAndBranch) \ | |
| 110 V(IsStringAndBranch) \ | |
| 111 V(IsSmiAndBranch) \ | |
| 112 V(IsUndetectableAndBranch) \ | |
| 113 V(LeaveInlined) \ | |
| 114 V(LoadContextSlot) \ | |
| 115 V(LoadFieldByIndex) \ | |
| 116 V(LoadFunctionPrototype) \ | |
| 117 V(LoadGlobalGeneric) \ | |
| 118 V(LoadGlobalViaContext) \ | |
| 119 V(LoadKeyed) \ | |
| 120 V(LoadKeyedGeneric) \ | |
| 121 V(LoadNamedField) \ | |
| 122 V(LoadNamedGeneric) \ | |
| 123 V(LoadRoot) \ | |
| 124 V(MapEnumLength) \ | |
| 125 V(MathFloorOfDiv) \ | |
| 126 V(MathMinMax) \ | |
| 127 V(MaybeGrowElements) \ | |
| 128 V(Mod) \ | |
| 129 V(Mul) \ | |
| 130 V(OsrEntry) \ | |
| 131 V(Parameter) \ | |
| 132 V(Power) \ | |
| 133 V(Prologue) \ | |
| 134 V(PushArguments) \ | |
| 135 V(RegExpLiteral) \ | |
| 136 V(Return) \ | |
| 137 V(Ror) \ | |
| 138 V(Sar) \ | |
| 139 V(SeqStringGetChar) \ | |
| 140 V(SeqStringSetChar) \ | |
| 141 V(Shl) \ | |
| 142 V(Shr) \ | |
| 143 V(Simulate) \ | |
| 144 V(StackCheck) \ | |
| 145 V(StoreCodeEntry) \ | |
| 146 V(StoreContextSlot) \ | |
| 147 V(StoreFrameContext) \ | |
| 148 V(StoreGlobalViaContext) \ | |
| 149 V(StoreKeyed) \ | |
| 150 V(StoreKeyedGeneric) \ | |
| 151 V(StoreNamedField) \ | |
| 152 V(StoreNamedGeneric) \ | |
| 153 V(StringAdd) \ | |
| 154 V(StringCharCodeAt) \ | |
| 155 V(StringCharFromCode) \ | |
| 156 V(StringCompareAndBranch) \ | |
| 157 V(Sub) \ | |
| 158 V(ThisFunction) \ | |
| 159 V(ToFastProperties) \ | |
| 160 V(TransitionElementsKind) \ | |
| 161 V(TrapAllocationMemento) \ | |
| 162 V(Typeof) \ | |
| 163 V(TypeofIsAndBranch) \ | |
| 164 V(UnaryMathOperation) \ | |
| 165 V(UnknownOSRValue) \ | |
| 166 V(UseConst) \ | |
| 167 V(WrapReceiver) | |
| 168 | |
| 169 #define GVN_TRACKED_FLAG_LIST(V) \ | |
| 170 V(NewSpacePromotion) | |
| 171 | |
| 172 #define GVN_UNTRACKED_FLAG_LIST(V) \ | |
| 173 V(ArrayElements) \ | |
| 174 V(ArrayLengths) \ | |
| 175 V(StringLengths) \ | |
| 176 V(BackingStoreFields) \ | |
| 177 V(Calls) \ | |
| 178 V(ContextSlots) \ | |
| 179 V(DoubleArrayElements) \ | |
| 180 V(DoubleFields) \ | |
| 181 V(ElementsKind) \ | |
| 182 V(ElementsPointer) \ | |
| 183 V(GlobalVars) \ | |
| 184 V(InobjectFields) \ | |
| 185 V(Maps) \ | |
| 186 V(OsrEntries) \ | |
| 187 V(ExternalMemory) \ | |
| 188 V(StringChars) \ | |
| 189 V(TypedArrayElements) | |
| 190 | |
| 191 | |
| 192 #define DECLARE_ABSTRACT_INSTRUCTION(type) \ | |
| 193 bool Is##type() const final { return true; } \ | |
| 194 static H##type* cast(HValue* value) { \ | |
| 195 DCHECK(value->Is##type()); \ | |
| 196 return reinterpret_cast<H##type*>(value); \ | |
| 197 } | |
| 198 | |
| 199 | |
| 200 #define DECLARE_CONCRETE_INSTRUCTION(type) \ | |
| 201 LInstruction* CompileToLithium(LChunkBuilder* builder) final; \ | |
| 202 static H##type* cast(HValue* value) { \ | |
| 203 DCHECK(value->Is##type()); \ | |
| 204 return reinterpret_cast<H##type*>(value); \ | |
| 205 } \ | |
| 206 Opcode opcode() const final { return HValue::k##type; } | |
| 207 | |
| 208 | |
| 209 enum PropertyAccessType { LOAD, STORE }; | |
| 210 | |
| 211 | |
| 212 class Range final : public ZoneObject { | |
| 213 public: | |
| 214 Range() | |
| 215 : lower_(kMinInt), | |
| 216 upper_(kMaxInt), | |
| 217 next_(NULL), | |
| 218 can_be_minus_zero_(false) { } | |
| 219 | |
| 220 Range(int32_t lower, int32_t upper) | |
| 221 : lower_(lower), | |
| 222 upper_(upper), | |
| 223 next_(NULL), | |
| 224 can_be_minus_zero_(false) { } | |
| 225 | |
| 226 int32_t upper() const { return upper_; } | |
| 227 int32_t lower() const { return lower_; } | |
| 228 Range* next() const { return next_; } | |
| 229 Range* CopyClearLower(Zone* zone) const { | |
| 230 return new(zone) Range(kMinInt, upper_); | |
| 231 } | |
| 232 Range* CopyClearUpper(Zone* zone) const { | |
| 233 return new(zone) Range(lower_, kMaxInt); | |
| 234 } | |
| 235 Range* Copy(Zone* zone) const { | |
| 236 Range* result = new(zone) Range(lower_, upper_); | |
| 237 result->set_can_be_minus_zero(CanBeMinusZero()); | |
| 238 return result; | |
| 239 } | |
| 240 int32_t Mask() const; | |
| 241 void set_can_be_minus_zero(bool b) { can_be_minus_zero_ = b; } | |
| 242 bool CanBeMinusZero() const { return CanBeZero() && can_be_minus_zero_; } | |
| 243 bool CanBeZero() const { return upper_ >= 0 && lower_ <= 0; } | |
| 244 bool CanBeNegative() const { return lower_ < 0; } | |
| 245 bool CanBePositive() const { return upper_ > 0; } | |
| 246 bool Includes(int value) const { return lower_ <= value && upper_ >= value; } | |
| 247 bool IsMostGeneric() const { | |
| 248 return lower_ == kMinInt && upper_ == kMaxInt && CanBeMinusZero(); | |
| 249 } | |
| 250 bool IsInSmiRange() const { | |
| 251 return lower_ >= Smi::kMinValue && upper_ <= Smi::kMaxValue; | |
| 252 } | |
| 253 void ClampToSmi() { | |
| 254 lower_ = Max(lower_, Smi::kMinValue); | |
| 255 upper_ = Min(upper_, Smi::kMaxValue); | |
| 256 } | |
| 257 void KeepOrder(); | |
| 258 #ifdef DEBUG | |
| 259 void Verify() const; | |
| 260 #endif | |
| 261 | |
| 262 void StackUpon(Range* other) { | |
| 263 Intersect(other); | |
| 264 next_ = other; | |
| 265 } | |
| 266 | |
| 267 void Intersect(Range* other); | |
| 268 void Union(Range* other); | |
| 269 void CombinedMax(Range* other); | |
| 270 void CombinedMin(Range* other); | |
| 271 | |
| 272 void AddConstant(int32_t value); | |
| 273 void Sar(int32_t value); | |
| 274 void Shl(int32_t value); | |
| 275 bool AddAndCheckOverflow(const Representation& r, Range* other); | |
| 276 bool SubAndCheckOverflow(const Representation& r, Range* other); | |
| 277 bool MulAndCheckOverflow(const Representation& r, Range* other); | |
| 278 | |
| 279 private: | |
| 280 int32_t lower_; | |
| 281 int32_t upper_; | |
| 282 Range* next_; | |
| 283 bool can_be_minus_zero_; | |
| 284 }; | |
| 285 | |
| 286 | |
| 287 class HUseListNode: public ZoneObject { | |
| 288 public: | |
| 289 HUseListNode(HValue* value, int index, HUseListNode* tail) | |
| 290 : tail_(tail), value_(value), index_(index) { | |
| 291 } | |
| 292 | |
| 293 HUseListNode* tail(); | |
| 294 HValue* value() const { return value_; } | |
| 295 int index() const { return index_; } | |
| 296 | |
| 297 void set_tail(HUseListNode* list) { tail_ = list; } | |
| 298 | |
| 299 #ifdef DEBUG | |
| 300 void Zap() { | |
| 301 tail_ = reinterpret_cast<HUseListNode*>(1); | |
| 302 value_ = NULL; | |
| 303 index_ = -1; | |
| 304 } | |
| 305 #endif | |
| 306 | |
| 307 private: | |
| 308 HUseListNode* tail_; | |
| 309 HValue* value_; | |
| 310 int index_; | |
| 311 }; | |
| 312 | |
| 313 | |
| 314 // We reuse use list nodes behind the scenes as uses are added and deleted. | |
| 315 // This class is the safe way to iterate uses while deleting them. | |
| 316 class HUseIterator final BASE_EMBEDDED { | |
| 317 public: | |
| 318 bool Done() { return current_ == NULL; } | |
| 319 void Advance(); | |
| 320 | |
| 321 HValue* value() { | |
| 322 DCHECK(!Done()); | |
| 323 return value_; | |
| 324 } | |
| 325 | |
| 326 int index() { | |
| 327 DCHECK(!Done()); | |
| 328 return index_; | |
| 329 } | |
| 330 | |
| 331 private: | |
| 332 explicit HUseIterator(HUseListNode* head); | |
| 333 | |
| 334 HUseListNode* current_; | |
| 335 HUseListNode* next_; | |
| 336 HValue* value_; | |
| 337 int index_; | |
| 338 | |
| 339 friend class HValue; | |
| 340 }; | |
| 341 | |
| 342 | |
| 343 // All tracked flags should appear before untracked ones. | |
| 344 enum GVNFlag { | |
| 345 // Declare global value numbering flags. | |
| 346 #define DECLARE_FLAG(Type) k##Type, | |
| 347 GVN_TRACKED_FLAG_LIST(DECLARE_FLAG) | |
| 348 GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG) | |
| 349 #undef DECLARE_FLAG | |
| 350 #define COUNT_FLAG(Type) + 1 | |
| 351 kNumberOfTrackedSideEffects = 0 GVN_TRACKED_FLAG_LIST(COUNT_FLAG), | |
| 352 kNumberOfUntrackedSideEffects = 0 GVN_UNTRACKED_FLAG_LIST(COUNT_FLAG), | |
| 353 #undef COUNT_FLAG | |
| 354 kNumberOfFlags = kNumberOfTrackedSideEffects + kNumberOfUntrackedSideEffects | |
| 355 }; | |
| 356 | |
| 357 | |
| 358 static inline GVNFlag GVNFlagFromInt(int i) { | |
| 359 DCHECK(i >= 0); | |
| 360 DCHECK(i < kNumberOfFlags); | |
| 361 return static_cast<GVNFlag>(i); | |
| 362 } | |
| 363 | |
| 364 | |
| 365 class DecompositionResult final BASE_EMBEDDED { | |
| 366 public: | |
| 367 DecompositionResult() : base_(NULL), offset_(0), scale_(0) {} | |
| 368 | |
| 369 HValue* base() { return base_; } | |
| 370 int offset() { return offset_; } | |
| 371 int scale() { return scale_; } | |
| 372 | |
| 373 bool Apply(HValue* other_base, int other_offset, int other_scale = 0) { | |
| 374 if (base_ == NULL) { | |
| 375 base_ = other_base; | |
| 376 offset_ = other_offset; | |
| 377 scale_ = other_scale; | |
| 378 return true; | |
| 379 } else { | |
| 380 if (scale_ == 0) { | |
| 381 base_ = other_base; | |
| 382 offset_ += other_offset; | |
| 383 scale_ = other_scale; | |
| 384 return true; | |
| 385 } else { | |
| 386 return false; | |
| 387 } | |
| 388 } | |
| 389 } | |
| 390 | |
| 391 void SwapValues(HValue** other_base, int* other_offset, int* other_scale) { | |
| 392 swap(&base_, other_base); | |
| 393 swap(&offset_, other_offset); | |
| 394 swap(&scale_, other_scale); | |
| 395 } | |
| 396 | |
| 397 private: | |
| 398 template <class T> void swap(T* a, T* b) { | |
| 399 T c(*a); | |
| 400 *a = *b; | |
| 401 *b = c; | |
| 402 } | |
| 403 | |
| 404 HValue* base_; | |
| 405 int offset_; | |
| 406 int scale_; | |
| 407 }; | |
| 408 | |
| 409 | |
| 410 typedef EnumSet<GVNFlag, int32_t> GVNFlagSet; | |
| 411 | |
| 412 | |
| 413 class HValue : public ZoneObject { | |
| 414 public: | |
| 415 static const int kNoNumber = -1; | |
| 416 | |
| 417 enum Flag { | |
| 418 kFlexibleRepresentation, | |
| 419 kCannotBeTagged, | |
| 420 // Participate in Global Value Numbering, i.e. elimination of | |
| 421 // unnecessary recomputations. If an instruction sets this flag, it must | |
| 422 // implement DataEquals(), which will be used to determine if other | |
| 423 // occurrences of the instruction are indeed the same. | |
| 424 kUseGVN, | |
| 425 // Track instructions that are dominating side effects. If an instruction | |
| 426 // sets this flag, it must implement HandleSideEffectDominator() and should | |
| 427 // indicate which side effects to track by setting GVN flags. | |
| 428 kTrackSideEffectDominators, | |
| 429 kCanOverflow, | |
| 430 kBailoutOnMinusZero, | |
| 431 kCanBeDivByZero, | |
| 432 kLeftCanBeMinInt, | |
| 433 kLeftCanBeNegative, | |
| 434 kLeftCanBePositive, | |
| 435 kAllowUndefinedAsNaN, | |
| 436 kIsArguments, | |
| 437 kTruncatingToInt32, | |
| 438 kAllUsesTruncatingToInt32, | |
| 439 kTruncatingToSmi, | |
| 440 kAllUsesTruncatingToSmi, | |
| 441 // Set after an instruction is killed. | |
| 442 kIsDead, | |
| 443 // Instructions that are allowed to produce full range unsigned integer | |
| 444 // values are marked with kUint32 flag. If arithmetic shift or a load from | |
| 445 // EXTERNAL_UINT32_ELEMENTS array is not marked with this flag | |
| 446 // it will deoptimize if result does not fit into signed integer range. | |
| 447 // HGraph::ComputeSafeUint32Operations is responsible for setting this | |
| 448 // flag. | |
| 449 kUint32, | |
| 450 kHasNoObservableSideEffects, | |
| 451 // Indicates an instruction shouldn't be replaced by optimization, this flag | |
| 452 // is useful to set in cases where recomputing a value is cheaper than | |
| 453 // extending the value's live range and spilling it. | |
| 454 kCantBeReplaced, | |
| 455 // Indicates the instruction is live during dead code elimination. | |
| 456 kIsLive, | |
| 457 | |
| 458 // HEnvironmentMarkers are deleted before dead code | |
| 459 // elimination takes place, so they can repurpose the kIsLive flag: | |
| 460 kEndsLiveRange = kIsLive, | |
| 461 | |
| 462 // TODO(everyone): Don't forget to update this! | |
| 463 kLastFlag = kIsLive | |
| 464 }; | |
| 465 | |
| 466 STATIC_ASSERT(kLastFlag < kBitsPerInt); | |
| 467 | |
| 468 static HValue* cast(HValue* value) { return value; } | |
| 469 | |
| 470 enum Opcode { | |
| 471 // Declare a unique enum value for each hydrogen instruction. | |
| 472 #define DECLARE_OPCODE(type) k##type, | |
| 473 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_OPCODE) | |
| 474 kPhi | |
| 475 #undef DECLARE_OPCODE | |
| 476 }; | |
| 477 virtual Opcode opcode() const = 0; | |
| 478 | |
| 479 // Declare a non-virtual predicates for each concrete HInstruction or HValue. | |
| 480 #define DECLARE_PREDICATE(type) \ | |
| 481 bool Is##type() const { return opcode() == k##type; } | |
| 482 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_PREDICATE) | |
| 483 #undef DECLARE_PREDICATE | |
| 484 bool IsPhi() const { return opcode() == kPhi; } | |
| 485 | |
| 486 // Declare virtual predicates for abstract HInstruction or HValue | |
| 487 #define DECLARE_PREDICATE(type) \ | |
| 488 virtual bool Is##type() const { return false; } | |
| 489 HYDROGEN_ABSTRACT_INSTRUCTION_LIST(DECLARE_PREDICATE) | |
| 490 #undef DECLARE_PREDICATE | |
| 491 | |
| 492 bool IsBitwiseBinaryShift() { | |
| 493 return IsShl() || IsShr() || IsSar(); | |
| 494 } | |
| 495 | |
| 496 explicit HValue(HType type = HType::Tagged()) | |
| 497 : block_(NULL), | |
| 498 id_(kNoNumber), | |
| 499 type_(type), | |
| 500 use_list_(NULL), | |
| 501 range_(NULL), | |
| 502 #ifdef DEBUG | |
| 503 range_poisoned_(false), | |
| 504 #endif | |
| 505 flags_(0) {} | |
| 506 virtual ~HValue() {} | |
| 507 | |
| 508 virtual SourcePosition position() const { return SourcePosition::Unknown(); } | |
| 509 virtual SourcePosition operand_position(int index) const { | |
| 510 return position(); | |
| 511 } | |
| 512 | |
| 513 HBasicBlock* block() const { return block_; } | |
| 514 void SetBlock(HBasicBlock* block); | |
| 515 | |
| 516 // Note: Never call this method for an unlinked value. | |
| 517 Isolate* isolate() const; | |
| 518 | |
| 519 int id() const { return id_; } | |
| 520 void set_id(int id) { id_ = id; } | |
| 521 | |
| 522 HUseIterator uses() const { return HUseIterator(use_list_); } | |
| 523 | |
| 524 virtual bool EmitAtUses() { return false; } | |
| 525 | |
| 526 Representation representation() const { return representation_; } | |
| 527 void ChangeRepresentation(Representation r) { | |
| 528 DCHECK(CheckFlag(kFlexibleRepresentation)); | |
| 529 DCHECK(!CheckFlag(kCannotBeTagged) || !r.IsTagged()); | |
| 530 RepresentationChanged(r); | |
| 531 representation_ = r; | |
| 532 if (r.IsTagged()) { | |
| 533 // Tagged is the bottom of the lattice, don't go any further. | |
| 534 ClearFlag(kFlexibleRepresentation); | |
| 535 } | |
| 536 } | |
| 537 virtual void AssumeRepresentation(Representation r); | |
| 538 | |
| 539 virtual Representation KnownOptimalRepresentation() { | |
| 540 Representation r = representation(); | |
| 541 if (r.IsTagged()) { | |
| 542 HType t = type(); | |
| 543 if (t.IsSmi()) return Representation::Smi(); | |
| 544 if (t.IsHeapNumber()) return Representation::Double(); | |
| 545 if (t.IsHeapObject()) return r; | |
| 546 return Representation::None(); | |
| 547 } | |
| 548 return r; | |
| 549 } | |
| 550 | |
| 551 HType type() const { return type_; } | |
| 552 void set_type(HType new_type) { | |
| 553 DCHECK(new_type.IsSubtypeOf(type_)); | |
| 554 type_ = new_type; | |
| 555 } | |
| 556 | |
| 557 // There are HInstructions that do not really change a value, they | |
| 558 // only add pieces of information to it (like bounds checks, map checks, | |
| 559 // smi checks...). | |
| 560 // We call these instructions "informative definitions", or "iDef". | |
| 561 // One of the iDef operands is special because it is the value that is | |
| 562 // "transferred" to the output, we call it the "redefined operand". | |
| 563 // If an HValue is an iDef it must override RedefinedOperandIndex() so that | |
| 564 // it does not return kNoRedefinedOperand; | |
| 565 static const int kNoRedefinedOperand = -1; | |
| 566 virtual int RedefinedOperandIndex() { return kNoRedefinedOperand; } | |
| 567 bool IsInformativeDefinition() { | |
| 568 return RedefinedOperandIndex() != kNoRedefinedOperand; | |
| 569 } | |
| 570 HValue* RedefinedOperand() { | |
| 571 int index = RedefinedOperandIndex(); | |
| 572 return index == kNoRedefinedOperand ? NULL : OperandAt(index); | |
| 573 } | |
| 574 | |
| 575 bool CanReplaceWithDummyUses(); | |
| 576 | |
| 577 virtual int argument_delta() const { return 0; } | |
| 578 | |
| 579 // A purely informative definition is an idef that will not emit code and | |
| 580 // should therefore be removed from the graph in the RestoreActualValues | |
| 581 // phase (so that live ranges will be shorter). | |
| 582 virtual bool IsPurelyInformativeDefinition() { return false; } | |
| 583 | |
| 584 // This method must always return the original HValue SSA definition, | |
| 585 // regardless of any chain of iDefs of this value. | |
| 586 HValue* ActualValue() { | |
| 587 HValue* value = this; | |
| 588 int index; | |
| 589 while ((index = value->RedefinedOperandIndex()) != kNoRedefinedOperand) { | |
| 590 value = value->OperandAt(index); | |
| 591 } | |
| 592 return value; | |
| 593 } | |
| 594 | |
| 595 bool IsInteger32Constant(); | |
| 596 int32_t GetInteger32Constant(); | |
| 597 bool EqualsInteger32Constant(int32_t value); | |
| 598 | |
| 599 bool IsDefinedAfter(HBasicBlock* other) const; | |
| 600 | |
| 601 // Operands. | |
| 602 virtual int OperandCount() const = 0; | |
| 603 virtual HValue* OperandAt(int index) const = 0; | |
| 604 void SetOperandAt(int index, HValue* value); | |
| 605 | |
| 606 void DeleteAndReplaceWith(HValue* other); | |
| 607 void ReplaceAllUsesWith(HValue* other); | |
| 608 bool HasNoUses() const { return use_list_ == NULL; } | |
| 609 bool HasOneUse() const { | |
| 610 return use_list_ != NULL && use_list_->tail() == NULL; | |
| 611 } | |
| 612 bool HasMultipleUses() const { | |
| 613 return use_list_ != NULL && use_list_->tail() != NULL; | |
| 614 } | |
| 615 int UseCount() const; | |
| 616 | |
| 617 // Mark this HValue as dead and to be removed from other HValues' use lists. | |
| 618 void Kill(); | |
| 619 | |
| 620 int flags() const { return flags_; } | |
| 621 void SetFlag(Flag f) { flags_ |= (1 << f); } | |
| 622 void ClearFlag(Flag f) { flags_ &= ~(1 << f); } | |
| 623 bool CheckFlag(Flag f) const { return (flags_ & (1 << f)) != 0; } | |
| 624 void CopyFlag(Flag f, HValue* other) { | |
| 625 if (other->CheckFlag(f)) SetFlag(f); | |
| 626 } | |
| 627 | |
| 628 // Returns true if the flag specified is set for all uses, false otherwise. | |
| 629 bool CheckUsesForFlag(Flag f) const; | |
| 630 // Same as before and the first one without the flag is returned in value. | |
| 631 bool CheckUsesForFlag(Flag f, HValue** value) const; | |
| 632 // Returns true if the flag specified is set for all uses, and this set | |
| 633 // of uses is non-empty. | |
| 634 bool HasAtLeastOneUseWithFlagAndNoneWithout(Flag f) const; | |
| 635 | |
| 636 GVNFlagSet ChangesFlags() const { return changes_flags_; } | |
| 637 GVNFlagSet DependsOnFlags() const { return depends_on_flags_; } | |
| 638 void SetChangesFlag(GVNFlag f) { changes_flags_.Add(f); } | |
| 639 void SetDependsOnFlag(GVNFlag f) { depends_on_flags_.Add(f); } | |
| 640 void ClearChangesFlag(GVNFlag f) { changes_flags_.Remove(f); } | |
| 641 void ClearDependsOnFlag(GVNFlag f) { depends_on_flags_.Remove(f); } | |
| 642 bool CheckChangesFlag(GVNFlag f) const { | |
| 643 return changes_flags_.Contains(f); | |
| 644 } | |
| 645 bool CheckDependsOnFlag(GVNFlag f) const { | |
| 646 return depends_on_flags_.Contains(f); | |
| 647 } | |
| 648 void SetAllSideEffects() { changes_flags_.Add(AllSideEffectsFlagSet()); } | |
| 649 void ClearAllSideEffects() { | |
| 650 changes_flags_.Remove(AllSideEffectsFlagSet()); | |
| 651 } | |
| 652 bool HasSideEffects() const { | |
| 653 return changes_flags_.ContainsAnyOf(AllSideEffectsFlagSet()); | |
| 654 } | |
| 655 bool HasObservableSideEffects() const { | |
| 656 return !CheckFlag(kHasNoObservableSideEffects) && | |
| 657 changes_flags_.ContainsAnyOf(AllObservableSideEffectsFlagSet()); | |
| 658 } | |
| 659 | |
| 660 GVNFlagSet SideEffectFlags() const { | |
| 661 GVNFlagSet result = ChangesFlags(); | |
| 662 result.Intersect(AllSideEffectsFlagSet()); | |
| 663 return result; | |
| 664 } | |
| 665 | |
| 666 GVNFlagSet ObservableChangesFlags() const { | |
| 667 GVNFlagSet result = ChangesFlags(); | |
| 668 result.Intersect(AllObservableSideEffectsFlagSet()); | |
| 669 return result; | |
| 670 } | |
| 671 | |
| 672 Range* range() const { | |
| 673 DCHECK(!range_poisoned_); | |
| 674 return range_; | |
| 675 } | |
| 676 bool HasRange() const { | |
| 677 DCHECK(!range_poisoned_); | |
| 678 return range_ != NULL; | |
| 679 } | |
| 680 #ifdef DEBUG | |
| 681 void PoisonRange() { range_poisoned_ = true; } | |
| 682 #endif | |
| 683 void AddNewRange(Range* r, Zone* zone); | |
| 684 void RemoveLastAddedRange(); | |
| 685 void ComputeInitialRange(Zone* zone); | |
| 686 | |
| 687 // Escape analysis helpers. | |
| 688 virtual bool HasEscapingOperandAt(int index) { return true; } | |
| 689 virtual bool HasOutOfBoundsAccess(int size) { return false; } | |
| 690 | |
| 691 // Representation helpers. | |
| 692 virtual Representation observed_input_representation(int index) { | |
| 693 return Representation::None(); | |
| 694 } | |
| 695 virtual Representation RequiredInputRepresentation(int index) = 0; | |
| 696 virtual void InferRepresentation(HInferRepresentationPhase* h_infer); | |
| 697 | |
| 698 // This gives the instruction an opportunity to replace itself with an | |
| 699 // instruction that does the same in some better way. To replace an | |
| 700 // instruction with a new one, first add the new instruction to the graph, | |
| 701 // then return it. Return NULL to have the instruction deleted. | |
| 702 virtual HValue* Canonicalize() { return this; } | |
| 703 | |
| 704 bool Equals(HValue* other); | |
| 705 virtual intptr_t Hashcode(); | |
| 706 | |
| 707 // Compute unique ids upfront that is safe wrt GC and concurrent compilation. | |
| 708 virtual void FinalizeUniqueness() { } | |
| 709 | |
| 710 // Printing support. | |
| 711 virtual std::ostream& PrintTo(std::ostream& os) const = 0; // NOLINT | |
| 712 | |
| 713 const char* Mnemonic() const; | |
| 714 | |
| 715 // Type information helpers. | |
| 716 bool HasMonomorphicJSObjectType(); | |
| 717 | |
| 718 // TODO(mstarzinger): For now instructions can override this function to | |
| 719 // specify statically known types, once HType can convey more information | |
| 720 // it should be based on the HType. | |
| 721 virtual Handle<Map> GetMonomorphicJSObjectMap() { return Handle<Map>(); } | |
| 722 | |
| 723 // Updated the inferred type of this instruction and returns true if | |
| 724 // it has changed. | |
| 725 bool UpdateInferredType(); | |
| 726 | |
| 727 virtual HType CalculateInferredType(); | |
| 728 | |
| 729 // This function must be overridden for instructions which have the | |
| 730 // kTrackSideEffectDominators flag set, to track instructions that are | |
| 731 // dominating side effects. | |
| 732 // It returns true if it removed an instruction which had side effects. | |
| 733 virtual bool HandleSideEffectDominator(GVNFlag side_effect, | |
| 734 HValue* dominator) { | |
| 735 UNREACHABLE(); | |
| 736 return false; | |
| 737 } | |
| 738 | |
| 739 // Check if this instruction has some reason that prevents elimination. | |
| 740 bool CannotBeEliminated() const { | |
| 741 return HasObservableSideEffects() || !IsDeletable(); | |
| 742 } | |
| 743 | |
| 744 #ifdef DEBUG | |
| 745 virtual void Verify() = 0; | |
| 746 #endif | |
| 747 | |
| 748 virtual bool TryDecompose(DecompositionResult* decomposition) { | |
| 749 if (RedefinedOperand() != NULL) { | |
| 750 return RedefinedOperand()->TryDecompose(decomposition); | |
| 751 } else { | |
| 752 return false; | |
| 753 } | |
| 754 } | |
| 755 | |
| 756 // Returns true conservatively if the program might be able to observe a | |
| 757 // ToString() operation on this value. | |
| 758 bool ToStringCanBeObserved() const { | |
| 759 return ToStringOrToNumberCanBeObserved(); | |
| 760 } | |
| 761 | |
| 762 // Returns true conservatively if the program might be able to observe a | |
| 763 // ToNumber() operation on this value. | |
| 764 bool ToNumberCanBeObserved() const { | |
| 765 return ToStringOrToNumberCanBeObserved(); | |
| 766 } | |
| 767 | |
| 768 MinusZeroMode GetMinusZeroMode() { | |
| 769 return CheckFlag(kBailoutOnMinusZero) | |
| 770 ? FAIL_ON_MINUS_ZERO : TREAT_MINUS_ZERO_AS_ZERO; | |
| 771 } | |
| 772 | |
| 773 protected: | |
| 774 // This function must be overridden for instructions with flag kUseGVN, to | |
| 775 // compare the non-Operand parts of the instruction. | |
| 776 virtual bool DataEquals(HValue* other) { | |
| 777 UNREACHABLE(); | |
| 778 return false; | |
| 779 } | |
| 780 | |
| 781 bool ToStringOrToNumberCanBeObserved() const { | |
| 782 if (type().IsTaggedPrimitive()) return false; | |
| 783 if (type().IsJSObject()) return true; | |
| 784 return !representation().IsSmiOrInteger32() && !representation().IsDouble(); | |
| 785 } | |
| 786 | |
| 787 virtual Representation RepresentationFromInputs() { | |
| 788 return representation(); | |
| 789 } | |
| 790 virtual Representation RepresentationFromUses(); | |
| 791 Representation RepresentationFromUseRequirements(); | |
| 792 bool HasNonSmiUse(); | |
| 793 virtual void UpdateRepresentation(Representation new_rep, | |
| 794 HInferRepresentationPhase* h_infer, | |
| 795 const char* reason); | |
| 796 void AddDependantsToWorklist(HInferRepresentationPhase* h_infer); | |
| 797 | |
| 798 virtual void RepresentationChanged(Representation to) { } | |
| 799 | |
| 800 virtual Range* InferRange(Zone* zone); | |
| 801 virtual void DeleteFromGraph() = 0; | |
| 802 virtual void InternalSetOperandAt(int index, HValue* value) = 0; | |
| 803 void clear_block() { | |
| 804 DCHECK(block_ != NULL); | |
| 805 block_ = NULL; | |
| 806 } | |
| 807 | |
| 808 void set_representation(Representation r) { | |
| 809 DCHECK(representation_.IsNone() && !r.IsNone()); | |
| 810 representation_ = r; | |
| 811 } | |
| 812 | |
| 813 static GVNFlagSet AllFlagSet() { | |
| 814 GVNFlagSet result; | |
| 815 #define ADD_FLAG(Type) result.Add(k##Type); | |
| 816 GVN_TRACKED_FLAG_LIST(ADD_FLAG) | |
| 817 GVN_UNTRACKED_FLAG_LIST(ADD_FLAG) | |
| 818 #undef ADD_FLAG | |
| 819 return result; | |
| 820 } | |
| 821 | |
| 822 // A flag mask to mark an instruction as having arbitrary side effects. | |
| 823 static GVNFlagSet AllSideEffectsFlagSet() { | |
| 824 GVNFlagSet result = AllFlagSet(); | |
| 825 result.Remove(kOsrEntries); | |
| 826 return result; | |
| 827 } | |
| 828 friend std::ostream& operator<<(std::ostream& os, const ChangesOf& v); | |
| 829 | |
| 830 // A flag mask of all side effects that can make observable changes in | |
| 831 // an executing program (i.e. are not safe to repeat, move or remove); | |
| 832 static GVNFlagSet AllObservableSideEffectsFlagSet() { | |
| 833 GVNFlagSet result = AllFlagSet(); | |
| 834 result.Remove(kNewSpacePromotion); | |
| 835 result.Remove(kElementsKind); | |
| 836 result.Remove(kElementsPointer); | |
| 837 result.Remove(kMaps); | |
| 838 return result; | |
| 839 } | |
| 840 | |
| 841 // Remove the matching use from the use list if present. Returns the | |
| 842 // removed list node or NULL. | |
| 843 HUseListNode* RemoveUse(HValue* value, int index); | |
| 844 | |
| 845 void RegisterUse(int index, HValue* new_value); | |
| 846 | |
| 847 HBasicBlock* block_; | |
| 848 | |
| 849 // The id of this instruction in the hydrogen graph, assigned when first | |
| 850 // added to the graph. Reflects creation order. | |
| 851 int id_; | |
| 852 | |
| 853 Representation representation_; | |
| 854 HType type_; | |
| 855 HUseListNode* use_list_; | |
| 856 Range* range_; | |
| 857 #ifdef DEBUG | |
| 858 bool range_poisoned_; | |
| 859 #endif | |
| 860 int flags_; | |
| 861 GVNFlagSet changes_flags_; | |
| 862 GVNFlagSet depends_on_flags_; | |
| 863 | |
| 864 private: | |
| 865 virtual bool IsDeletable() const { return false; } | |
| 866 | |
| 867 DISALLOW_COPY_AND_ASSIGN(HValue); | |
| 868 }; | |
| 869 | |
| 870 // Support for printing various aspects of an HValue. | |
| 871 struct NameOf { | |
| 872 explicit NameOf(const HValue* const v) : value(v) {} | |
| 873 const HValue* value; | |
| 874 }; | |
| 875 | |
| 876 | |
| 877 struct TypeOf { | |
| 878 explicit TypeOf(const HValue* const v) : value(v) {} | |
| 879 const HValue* value; | |
| 880 }; | |
| 881 | |
| 882 | |
| 883 struct ChangesOf { | |
| 884 explicit ChangesOf(const HValue* const v) : value(v) {} | |
| 885 const HValue* value; | |
| 886 }; | |
| 887 | |
| 888 | |
| 889 std::ostream& operator<<(std::ostream& os, const HValue& v); | |
| 890 std::ostream& operator<<(std::ostream& os, const NameOf& v); | |
| 891 std::ostream& operator<<(std::ostream& os, const TypeOf& v); | |
| 892 std::ostream& operator<<(std::ostream& os, const ChangesOf& v); | |
| 893 | |
| 894 | |
| 895 #define DECLARE_INSTRUCTION_FACTORY_P0(I) \ | |
| 896 static I* New(Isolate* isolate, Zone* zone, HValue* context) { \ | |
| 897 return new (zone) I(); \ | |
| 898 } | |
| 899 | |
| 900 #define DECLARE_INSTRUCTION_FACTORY_P1(I, P1) \ | |
| 901 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1) { \ | |
| 902 return new (zone) I(p1); \ | |
| 903 } | |
| 904 | |
| 905 #define DECLARE_INSTRUCTION_FACTORY_P2(I, P1, P2) \ | |
| 906 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2) { \ | |
| 907 return new (zone) I(p1, p2); \ | |
| 908 } | |
| 909 | |
| 910 #define DECLARE_INSTRUCTION_FACTORY_P3(I, P1, P2, P3) \ | |
| 911 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \ | |
| 912 P3 p3) { \ | |
| 913 return new (zone) I(p1, p2, p3); \ | |
| 914 } | |
| 915 | |
| 916 #define DECLARE_INSTRUCTION_FACTORY_P4(I, P1, P2, P3, P4) \ | |
| 917 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \ | |
| 918 P3 p3, P4 p4) { \ | |
| 919 return new (zone) I(p1, p2, p3, p4); \ | |
| 920 } | |
| 921 | |
| 922 #define DECLARE_INSTRUCTION_FACTORY_P5(I, P1, P2, P3, P4, P5) \ | |
| 923 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \ | |
| 924 P3 p3, P4 p4, P5 p5) { \ | |
| 925 return new (zone) I(p1, p2, p3, p4, p5); \ | |
| 926 } | |
| 927 | |
| 928 #define DECLARE_INSTRUCTION_FACTORY_P6(I, P1, P2, P3, P4, P5, P6) \ | |
| 929 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \ | |
| 930 P3 p3, P4 p4, P5 p5, P6 p6) { \ | |
| 931 return new (zone) I(p1, p2, p3, p4, p5, p6); \ | |
| 932 } | |
| 933 | |
| 934 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P0(I) \ | |
| 935 static I* New(Isolate* isolate, Zone* zone, HValue* context) { \ | |
| 936 return new (zone) I(context); \ | |
| 937 } | |
| 938 | |
| 939 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(I, P1) \ | |
| 940 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1) { \ | |
| 941 return new (zone) I(context, p1); \ | |
| 942 } | |
| 943 | |
| 944 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(I, P1, P2) \ | |
| 945 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2) { \ | |
| 946 return new (zone) I(context, p1, p2); \ | |
| 947 } | |
| 948 | |
| 949 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(I, P1, P2, P3) \ | |
| 950 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \ | |
| 951 P3 p3) { \ | |
| 952 return new (zone) I(context, p1, p2, p3); \ | |
| 953 } | |
| 954 | |
| 955 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(I, P1, P2, P3, P4) \ | |
| 956 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \ | |
| 957 P3 p3, P4 p4) { \ | |
| 958 return new (zone) I(context, p1, p2, p3, p4); \ | |
| 959 } | |
| 960 | |
| 961 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(I, P1, P2, P3, P4, P5) \ | |
| 962 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \ | |
| 963 P3 p3, P4 p4, P5 p5) { \ | |
| 964 return new (zone) I(context, p1, p2, p3, p4, p5); \ | |
| 965 } | |
| 966 | |
| 967 #define DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P6(I, P1, P2, P3, P4, P5, P6) \ | |
| 968 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \ | |
| 969 P3 p3, P4 p4, P5 p5, P6 p6) { \ | |
| 970 return new (zone) I(context, p1, p2, p3, p4, p5, p6); \ | |
| 971 } | |
| 972 | |
| 973 | |
| 974 // A helper class to represent per-operand position information attached to | |
| 975 // the HInstruction in the compact form. Uses tagging to distinguish between | |
| 976 // case when only instruction's position is available and case when operands' | |
| 977 // positions are also available. | |
| 978 // In the first case it contains intruction's position as a tagged value. | |
| 979 // In the second case it points to an array which contains instruction's | |
| 980 // position and operands' positions. | |
| 981 class HPositionInfo { | |
| 982 public: | |
| 983 explicit HPositionInfo(int pos) : data_(TagPosition(pos)) { } | |
| 984 | |
| 985 SourcePosition position() const { | |
| 986 if (has_operand_positions()) { | |
| 987 return operand_positions()[kInstructionPosIndex]; | |
| 988 } | |
| 989 return SourcePosition::FromRaw(static_cast<int>(UntagPosition(data_))); | |
| 990 } | |
| 991 | |
| 992 void set_position(SourcePosition pos) { | |
| 993 if (has_operand_positions()) { | |
| 994 operand_positions()[kInstructionPosIndex] = pos; | |
| 995 } else { | |
| 996 data_ = TagPosition(pos.raw()); | |
| 997 } | |
| 998 } | |
| 999 | |
| 1000 void ensure_storage_for_operand_positions(Zone* zone, int operand_count) { | |
| 1001 if (has_operand_positions()) { | |
| 1002 return; | |
| 1003 } | |
| 1004 | |
| 1005 const int length = kFirstOperandPosIndex + operand_count; | |
| 1006 SourcePosition* positions = zone->NewArray<SourcePosition>(length); | |
| 1007 for (int i = 0; i < length; i++) { | |
| 1008 positions[i] = SourcePosition::Unknown(); | |
| 1009 } | |
| 1010 | |
| 1011 const SourcePosition pos = position(); | |
| 1012 data_ = reinterpret_cast<intptr_t>(positions); | |
| 1013 set_position(pos); | |
| 1014 | |
| 1015 DCHECK(has_operand_positions()); | |
| 1016 } | |
| 1017 | |
| 1018 SourcePosition operand_position(int idx) const { | |
| 1019 if (!has_operand_positions()) { | |
| 1020 return position(); | |
| 1021 } | |
| 1022 return *operand_position_slot(idx); | |
| 1023 } | |
| 1024 | |
| 1025 void set_operand_position(int idx, SourcePosition pos) { | |
| 1026 *operand_position_slot(idx) = pos; | |
| 1027 } | |
| 1028 | |
| 1029 private: | |
| 1030 static const intptr_t kInstructionPosIndex = 0; | |
| 1031 static const intptr_t kFirstOperandPosIndex = 1; | |
| 1032 | |
| 1033 SourcePosition* operand_position_slot(int idx) const { | |
| 1034 DCHECK(has_operand_positions()); | |
| 1035 return &(operand_positions()[kFirstOperandPosIndex + idx]); | |
| 1036 } | |
| 1037 | |
| 1038 bool has_operand_positions() const { | |
| 1039 return !IsTaggedPosition(data_); | |
| 1040 } | |
| 1041 | |
| 1042 SourcePosition* operand_positions() const { | |
| 1043 DCHECK(has_operand_positions()); | |
| 1044 return reinterpret_cast<SourcePosition*>(data_); | |
| 1045 } | |
| 1046 | |
| 1047 static const intptr_t kPositionTag = 1; | |
| 1048 static const intptr_t kPositionShift = 1; | |
| 1049 static bool IsTaggedPosition(intptr_t val) { | |
| 1050 return (val & kPositionTag) != 0; | |
| 1051 } | |
| 1052 static intptr_t UntagPosition(intptr_t val) { | |
| 1053 DCHECK(IsTaggedPosition(val)); | |
| 1054 return val >> kPositionShift; | |
| 1055 } | |
| 1056 static intptr_t TagPosition(intptr_t val) { | |
| 1057 const intptr_t result = (val << kPositionShift) | kPositionTag; | |
| 1058 DCHECK(UntagPosition(result) == val); | |
| 1059 return result; | |
| 1060 } | |
| 1061 | |
| 1062 intptr_t data_; | |
| 1063 }; | |
| 1064 | |
| 1065 | |
| 1066 class HInstruction : public HValue { | |
| 1067 public: | |
| 1068 HInstruction* next() const { return next_; } | |
| 1069 HInstruction* previous() const { return previous_; } | |
| 1070 | |
| 1071 std::ostream& PrintTo(std::ostream& os) const override; // NOLINT | |
| 1072 virtual std::ostream& PrintDataTo(std::ostream& os) const; // NOLINT | |
| 1073 | |
| 1074 bool IsLinked() const { return block() != NULL; } | |
| 1075 void Unlink(); | |
| 1076 | |
| 1077 void InsertBefore(HInstruction* next); | |
| 1078 | |
| 1079 template<class T> T* Prepend(T* instr) { | |
| 1080 instr->InsertBefore(this); | |
| 1081 return instr; | |
| 1082 } | |
| 1083 | |
| 1084 void InsertAfter(HInstruction* previous); | |
| 1085 | |
| 1086 template<class T> T* Append(T* instr) { | |
| 1087 instr->InsertAfter(this); | |
| 1088 return instr; | |
| 1089 } | |
| 1090 | |
| 1091 // The position is a write-once variable. | |
| 1092 SourcePosition position() const override { | |
| 1093 return SourcePosition(position_.position()); | |
| 1094 } | |
| 1095 bool has_position() const { | |
| 1096 return !position().IsUnknown(); | |
| 1097 } | |
| 1098 void set_position(SourcePosition position) { | |
| 1099 DCHECK(!has_position()); | |
| 1100 DCHECK(!position.IsUnknown()); | |
| 1101 position_.set_position(position); | |
| 1102 } | |
| 1103 | |
| 1104 SourcePosition operand_position(int index) const override { | |
| 1105 const SourcePosition pos = position_.operand_position(index); | |
| 1106 return pos.IsUnknown() ? position() : pos; | |
| 1107 } | |
| 1108 void set_operand_position(Zone* zone, int index, SourcePosition pos) { | |
| 1109 DCHECK(0 <= index && index < OperandCount()); | |
| 1110 position_.ensure_storage_for_operand_positions(zone, OperandCount()); | |
| 1111 position_.set_operand_position(index, pos); | |
| 1112 } | |
| 1113 | |
| 1114 bool Dominates(HInstruction* other); | |
| 1115 bool CanTruncateToSmi() const { return CheckFlag(kTruncatingToSmi); } | |
| 1116 bool CanTruncateToInt32() const { return CheckFlag(kTruncatingToInt32); } | |
| 1117 | |
| 1118 virtual LInstruction* CompileToLithium(LChunkBuilder* builder) = 0; | |
| 1119 | |
| 1120 #ifdef DEBUG | |
| 1121 void Verify() override; | |
| 1122 #endif | |
| 1123 | |
| 1124 bool CanDeoptimize(); | |
| 1125 | |
| 1126 virtual bool HasStackCheck() { return false; } | |
| 1127 | |
| 1128 DECLARE_ABSTRACT_INSTRUCTION(Instruction) | |
| 1129 | |
| 1130 protected: | |
| 1131 explicit HInstruction(HType type = HType::Tagged()) | |
| 1132 : HValue(type), | |
| 1133 next_(NULL), | |
| 1134 previous_(NULL), | |
| 1135 position_(RelocInfo::kNoPosition) { | |
| 1136 SetDependsOnFlag(kOsrEntries); | |
| 1137 } | |
| 1138 | |
| 1139 void DeleteFromGraph() override { Unlink(); } | |
| 1140 | |
| 1141 private: | |
| 1142 void InitializeAsFirst(HBasicBlock* block) { | |
| 1143 DCHECK(!IsLinked()); | |
| 1144 SetBlock(block); | |
| 1145 } | |
| 1146 | |
| 1147 HInstruction* next_; | |
| 1148 HInstruction* previous_; | |
| 1149 HPositionInfo position_; | |
| 1150 | |
| 1151 friend class HBasicBlock; | |
| 1152 }; | |
| 1153 | |
| 1154 | |
| 1155 template<int V> | |
| 1156 class HTemplateInstruction : public HInstruction { | |
| 1157 public: | |
| 1158 int OperandCount() const final { return V; } | |
| 1159 HValue* OperandAt(int i) const final { return inputs_[i]; } | |
| 1160 | |
| 1161 protected: | |
| 1162 explicit HTemplateInstruction(HType type = HType::Tagged()) | |
| 1163 : HInstruction(type) {} | |
| 1164 | |
| 1165 void InternalSetOperandAt(int i, HValue* value) final { inputs_[i] = value; } | |
| 1166 | |
| 1167 private: | |
| 1168 EmbeddedContainer<HValue*, V> inputs_; | |
| 1169 }; | |
| 1170 | |
| 1171 | |
| 1172 class HControlInstruction : public HInstruction { | |
| 1173 public: | |
| 1174 virtual HBasicBlock* SuccessorAt(int i) const = 0; | |
| 1175 virtual int SuccessorCount() const = 0; | |
| 1176 virtual void SetSuccessorAt(int i, HBasicBlock* block) = 0; | |
| 1177 | |
| 1178 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 1179 | |
| 1180 virtual bool KnownSuccessorBlock(HBasicBlock** block) { | |
| 1181 *block = NULL; | |
| 1182 return false; | |
| 1183 } | |
| 1184 | |
| 1185 HBasicBlock* FirstSuccessor() { | |
| 1186 return SuccessorCount() > 0 ? SuccessorAt(0) : NULL; | |
| 1187 } | |
| 1188 HBasicBlock* SecondSuccessor() { | |
| 1189 return SuccessorCount() > 1 ? SuccessorAt(1) : NULL; | |
| 1190 } | |
| 1191 | |
| 1192 void Not() { | |
| 1193 HBasicBlock* swap = SuccessorAt(0); | |
| 1194 SetSuccessorAt(0, SuccessorAt(1)); | |
| 1195 SetSuccessorAt(1, swap); | |
| 1196 } | |
| 1197 | |
| 1198 DECLARE_ABSTRACT_INSTRUCTION(ControlInstruction) | |
| 1199 }; | |
| 1200 | |
| 1201 | |
| 1202 class HSuccessorIterator final BASE_EMBEDDED { | |
| 1203 public: | |
| 1204 explicit HSuccessorIterator(const HControlInstruction* instr) | |
| 1205 : instr_(instr), current_(0) {} | |
| 1206 | |
| 1207 bool Done() { return current_ >= instr_->SuccessorCount(); } | |
| 1208 HBasicBlock* Current() { return instr_->SuccessorAt(current_); } | |
| 1209 void Advance() { current_++; } | |
| 1210 | |
| 1211 private: | |
| 1212 const HControlInstruction* instr_; | |
| 1213 int current_; | |
| 1214 }; | |
| 1215 | |
| 1216 | |
| 1217 template<int S, int V> | |
| 1218 class HTemplateControlInstruction : public HControlInstruction { | |
| 1219 public: | |
| 1220 int SuccessorCount() const override { return S; } | |
| 1221 HBasicBlock* SuccessorAt(int i) const override { return successors_[i]; } | |
| 1222 void SetSuccessorAt(int i, HBasicBlock* block) override { | |
| 1223 successors_[i] = block; | |
| 1224 } | |
| 1225 | |
| 1226 int OperandCount() const override { return V; } | |
| 1227 HValue* OperandAt(int i) const override { return inputs_[i]; } | |
| 1228 | |
| 1229 | |
| 1230 protected: | |
| 1231 void InternalSetOperandAt(int i, HValue* value) override { | |
| 1232 inputs_[i] = value; | |
| 1233 } | |
| 1234 | |
| 1235 private: | |
| 1236 EmbeddedContainer<HBasicBlock*, S> successors_; | |
| 1237 EmbeddedContainer<HValue*, V> inputs_; | |
| 1238 }; | |
| 1239 | |
| 1240 | |
| 1241 class HBlockEntry final : public HTemplateInstruction<0> { | |
| 1242 public: | |
| 1243 Representation RequiredInputRepresentation(int index) override { | |
| 1244 return Representation::None(); | |
| 1245 } | |
| 1246 | |
| 1247 DECLARE_CONCRETE_INSTRUCTION(BlockEntry) | |
| 1248 }; | |
| 1249 | |
| 1250 | |
| 1251 class HDummyUse final : public HTemplateInstruction<1> { | |
| 1252 public: | |
| 1253 explicit HDummyUse(HValue* value) | |
| 1254 : HTemplateInstruction<1>(HType::Smi()) { | |
| 1255 SetOperandAt(0, value); | |
| 1256 // Pretend to be a Smi so that the HChange instructions inserted | |
| 1257 // before any use generate as little code as possible. | |
| 1258 set_representation(Representation::Tagged()); | |
| 1259 } | |
| 1260 | |
| 1261 HValue* value() const { return OperandAt(0); } | |
| 1262 | |
| 1263 bool HasEscapingOperandAt(int index) override { return false; } | |
| 1264 Representation RequiredInputRepresentation(int index) override { | |
| 1265 return Representation::None(); | |
| 1266 } | |
| 1267 | |
| 1268 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 1269 | |
| 1270 DECLARE_CONCRETE_INSTRUCTION(DummyUse); | |
| 1271 }; | |
| 1272 | |
| 1273 | |
| 1274 // Inserts an int3/stop break instruction for debugging purposes. | |
| 1275 class HDebugBreak final : public HTemplateInstruction<0> { | |
| 1276 public: | |
| 1277 DECLARE_INSTRUCTION_FACTORY_P0(HDebugBreak); | |
| 1278 | |
| 1279 Representation RequiredInputRepresentation(int index) override { | |
| 1280 return Representation::None(); | |
| 1281 } | |
| 1282 | |
| 1283 DECLARE_CONCRETE_INSTRUCTION(DebugBreak) | |
| 1284 }; | |
| 1285 | |
| 1286 | |
| 1287 class HPrologue final : public HTemplateInstruction<0> { | |
| 1288 public: | |
| 1289 static HPrologue* New(Zone* zone) { return new (zone) HPrologue(); } | |
| 1290 | |
| 1291 Representation RequiredInputRepresentation(int index) override { | |
| 1292 return Representation::None(); | |
| 1293 } | |
| 1294 | |
| 1295 DECLARE_CONCRETE_INSTRUCTION(Prologue) | |
| 1296 }; | |
| 1297 | |
| 1298 | |
| 1299 class HGoto final : public HTemplateControlInstruction<1, 0> { | |
| 1300 public: | |
| 1301 explicit HGoto(HBasicBlock* target) { | |
| 1302 SetSuccessorAt(0, target); | |
| 1303 } | |
| 1304 | |
| 1305 bool KnownSuccessorBlock(HBasicBlock** block) override { | |
| 1306 *block = FirstSuccessor(); | |
| 1307 return true; | |
| 1308 } | |
| 1309 | |
| 1310 Representation RequiredInputRepresentation(int index) override { | |
| 1311 return Representation::None(); | |
| 1312 } | |
| 1313 | |
| 1314 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 1315 | |
| 1316 DECLARE_CONCRETE_INSTRUCTION(Goto) | |
| 1317 }; | |
| 1318 | |
| 1319 | |
| 1320 class HDeoptimize final : public HTemplateControlInstruction<1, 0> { | |
| 1321 public: | |
| 1322 static HDeoptimize* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 1323 Deoptimizer::DeoptReason reason, | |
| 1324 Deoptimizer::BailoutType type, | |
| 1325 HBasicBlock* unreachable_continuation) { | |
| 1326 return new(zone) HDeoptimize(reason, type, unreachable_continuation); | |
| 1327 } | |
| 1328 | |
| 1329 bool KnownSuccessorBlock(HBasicBlock** block) override { | |
| 1330 *block = NULL; | |
| 1331 return true; | |
| 1332 } | |
| 1333 | |
| 1334 Representation RequiredInputRepresentation(int index) override { | |
| 1335 return Representation::None(); | |
| 1336 } | |
| 1337 | |
| 1338 Deoptimizer::DeoptReason reason() const { return reason_; } | |
| 1339 Deoptimizer::BailoutType type() { return type_; } | |
| 1340 | |
| 1341 DECLARE_CONCRETE_INSTRUCTION(Deoptimize) | |
| 1342 | |
| 1343 private: | |
| 1344 explicit HDeoptimize(Deoptimizer::DeoptReason reason, | |
| 1345 Deoptimizer::BailoutType type, | |
| 1346 HBasicBlock* unreachable_continuation) | |
| 1347 : reason_(reason), type_(type) { | |
| 1348 SetSuccessorAt(0, unreachable_continuation); | |
| 1349 } | |
| 1350 | |
| 1351 Deoptimizer::DeoptReason reason_; | |
| 1352 Deoptimizer::BailoutType type_; | |
| 1353 }; | |
| 1354 | |
| 1355 | |
| 1356 class HUnaryControlInstruction : public HTemplateControlInstruction<2, 1> { | |
| 1357 public: | |
| 1358 HUnaryControlInstruction(HValue* value, | |
| 1359 HBasicBlock* true_target, | |
| 1360 HBasicBlock* false_target) { | |
| 1361 SetOperandAt(0, value); | |
| 1362 SetSuccessorAt(0, true_target); | |
| 1363 SetSuccessorAt(1, false_target); | |
| 1364 } | |
| 1365 | |
| 1366 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 1367 | |
| 1368 HValue* value() const { return OperandAt(0); } | |
| 1369 }; | |
| 1370 | |
| 1371 | |
| 1372 class HBranch final : public HUnaryControlInstruction { | |
| 1373 public: | |
| 1374 DECLARE_INSTRUCTION_FACTORY_P1(HBranch, HValue*); | |
| 1375 DECLARE_INSTRUCTION_FACTORY_P2(HBranch, HValue*, | |
| 1376 ToBooleanStub::Types); | |
| 1377 DECLARE_INSTRUCTION_FACTORY_P4(HBranch, HValue*, | |
| 1378 ToBooleanStub::Types, | |
| 1379 HBasicBlock*, HBasicBlock*); | |
| 1380 | |
| 1381 Representation RequiredInputRepresentation(int index) override { | |
| 1382 return Representation::None(); | |
| 1383 } | |
| 1384 Representation observed_input_representation(int index) override; | |
| 1385 | |
| 1386 bool KnownSuccessorBlock(HBasicBlock** block) override; | |
| 1387 | |
| 1388 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 1389 | |
| 1390 ToBooleanStub::Types expected_input_types() const { | |
| 1391 return expected_input_types_; | |
| 1392 } | |
| 1393 | |
| 1394 DECLARE_CONCRETE_INSTRUCTION(Branch) | |
| 1395 | |
| 1396 private: | |
| 1397 HBranch(HValue* value, | |
| 1398 ToBooleanStub::Types expected_input_types = ToBooleanStub::Types(), | |
| 1399 HBasicBlock* true_target = NULL, | |
| 1400 HBasicBlock* false_target = NULL) | |
| 1401 : HUnaryControlInstruction(value, true_target, false_target), | |
| 1402 expected_input_types_(expected_input_types) { | |
| 1403 SetFlag(kAllowUndefinedAsNaN); | |
| 1404 } | |
| 1405 | |
| 1406 ToBooleanStub::Types expected_input_types_; | |
| 1407 }; | |
| 1408 | |
| 1409 | |
| 1410 class HCompareMap final : public HUnaryControlInstruction { | |
| 1411 public: | |
| 1412 DECLARE_INSTRUCTION_FACTORY_P2(HCompareMap, HValue*, Handle<Map>); | |
| 1413 DECLARE_INSTRUCTION_FACTORY_P4(HCompareMap, HValue*, Handle<Map>, | |
| 1414 HBasicBlock*, HBasicBlock*); | |
| 1415 | |
| 1416 bool KnownSuccessorBlock(HBasicBlock** block) override { | |
| 1417 if (known_successor_index() != kNoKnownSuccessorIndex) { | |
| 1418 *block = SuccessorAt(known_successor_index()); | |
| 1419 return true; | |
| 1420 } | |
| 1421 *block = NULL; | |
| 1422 return false; | |
| 1423 } | |
| 1424 | |
| 1425 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 1426 | |
| 1427 static const int kNoKnownSuccessorIndex = -1; | |
| 1428 int known_successor_index() const { | |
| 1429 return KnownSuccessorIndexField::decode(bit_field_) - | |
| 1430 kInternalKnownSuccessorOffset; | |
| 1431 } | |
| 1432 void set_known_successor_index(int index) { | |
| 1433 DCHECK(index >= 0 - kInternalKnownSuccessorOffset); | |
| 1434 bit_field_ = KnownSuccessorIndexField::update( | |
| 1435 bit_field_, index + kInternalKnownSuccessorOffset); | |
| 1436 } | |
| 1437 | |
| 1438 Unique<Map> map() const { return map_; } | |
| 1439 bool map_is_stable() const { return MapIsStableField::decode(bit_field_); } | |
| 1440 | |
| 1441 Representation RequiredInputRepresentation(int index) override { | |
| 1442 return Representation::Tagged(); | |
| 1443 } | |
| 1444 | |
| 1445 DECLARE_CONCRETE_INSTRUCTION(CompareMap) | |
| 1446 | |
| 1447 protected: | |
| 1448 int RedefinedOperandIndex() override { return 0; } | |
| 1449 | |
| 1450 private: | |
| 1451 HCompareMap(HValue* value, Handle<Map> map, HBasicBlock* true_target = NULL, | |
| 1452 HBasicBlock* false_target = NULL) | |
| 1453 : HUnaryControlInstruction(value, true_target, false_target), | |
| 1454 bit_field_(KnownSuccessorIndexField::encode( | |
| 1455 kNoKnownSuccessorIndex + kInternalKnownSuccessorOffset) | | |
| 1456 MapIsStableField::encode(map->is_stable())), | |
| 1457 map_(Unique<Map>::CreateImmovable(map)) { | |
| 1458 set_representation(Representation::Tagged()); | |
| 1459 } | |
| 1460 | |
| 1461 // BitFields can only store unsigned values, so use an offset. | |
| 1462 // Adding kInternalKnownSuccessorOffset must yield an unsigned value. | |
| 1463 static const int kInternalKnownSuccessorOffset = 1; | |
| 1464 STATIC_ASSERT(kNoKnownSuccessorIndex + kInternalKnownSuccessorOffset >= 0); | |
| 1465 | |
| 1466 class KnownSuccessorIndexField : public BitField<int, 0, 31> {}; | |
| 1467 class MapIsStableField : public BitField<bool, 31, 1> {}; | |
| 1468 | |
| 1469 uint32_t bit_field_; | |
| 1470 Unique<Map> map_; | |
| 1471 }; | |
| 1472 | |
| 1473 | |
| 1474 class HContext final : public HTemplateInstruction<0> { | |
| 1475 public: | |
| 1476 static HContext* New(Zone* zone) { | |
| 1477 return new(zone) HContext(); | |
| 1478 } | |
| 1479 | |
| 1480 Representation RequiredInputRepresentation(int index) override { | |
| 1481 return Representation::None(); | |
| 1482 } | |
| 1483 | |
| 1484 DECLARE_CONCRETE_INSTRUCTION(Context) | |
| 1485 | |
| 1486 protected: | |
| 1487 bool DataEquals(HValue* other) override { return true; } | |
| 1488 | |
| 1489 private: | |
| 1490 HContext() { | |
| 1491 set_representation(Representation::Tagged()); | |
| 1492 SetFlag(kUseGVN); | |
| 1493 } | |
| 1494 | |
| 1495 bool IsDeletable() const override { return true; } | |
| 1496 }; | |
| 1497 | |
| 1498 | |
| 1499 class HReturn final : public HTemplateControlInstruction<0, 3> { | |
| 1500 public: | |
| 1501 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HReturn, HValue*, HValue*); | |
| 1502 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HReturn, HValue*); | |
| 1503 | |
| 1504 Representation RequiredInputRepresentation(int index) override { | |
| 1505 // TODO(titzer): require an Int32 input for faster returns. | |
| 1506 if (index == 2) return Representation::Smi(); | |
| 1507 return Representation::Tagged(); | |
| 1508 } | |
| 1509 | |
| 1510 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 1511 | |
| 1512 HValue* value() const { return OperandAt(0); } | |
| 1513 HValue* context() const { return OperandAt(1); } | |
| 1514 HValue* parameter_count() const { return OperandAt(2); } | |
| 1515 | |
| 1516 DECLARE_CONCRETE_INSTRUCTION(Return) | |
| 1517 | |
| 1518 private: | |
| 1519 HReturn(HValue* context, HValue* value, HValue* parameter_count = 0) { | |
| 1520 SetOperandAt(0, value); | |
| 1521 SetOperandAt(1, context); | |
| 1522 SetOperandAt(2, parameter_count); | |
| 1523 } | |
| 1524 }; | |
| 1525 | |
| 1526 | |
| 1527 class HAbnormalExit final : public HTemplateControlInstruction<0, 0> { | |
| 1528 public: | |
| 1529 DECLARE_INSTRUCTION_FACTORY_P0(HAbnormalExit); | |
| 1530 | |
| 1531 Representation RequiredInputRepresentation(int index) override { | |
| 1532 return Representation::None(); | |
| 1533 } | |
| 1534 | |
| 1535 DECLARE_CONCRETE_INSTRUCTION(AbnormalExit) | |
| 1536 private: | |
| 1537 HAbnormalExit() {} | |
| 1538 }; | |
| 1539 | |
| 1540 | |
| 1541 class HUnaryOperation : public HTemplateInstruction<1> { | |
| 1542 public: | |
| 1543 explicit HUnaryOperation(HValue* value, HType type = HType::Tagged()) | |
| 1544 : HTemplateInstruction<1>(type) { | |
| 1545 SetOperandAt(0, value); | |
| 1546 } | |
| 1547 | |
| 1548 static HUnaryOperation* cast(HValue* value) { | |
| 1549 return reinterpret_cast<HUnaryOperation*>(value); | |
| 1550 } | |
| 1551 | |
| 1552 HValue* value() const { return OperandAt(0); } | |
| 1553 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 1554 }; | |
| 1555 | |
| 1556 | |
| 1557 class HUseConst final : public HUnaryOperation { | |
| 1558 public: | |
| 1559 DECLARE_INSTRUCTION_FACTORY_P1(HUseConst, HValue*); | |
| 1560 | |
| 1561 Representation RequiredInputRepresentation(int index) override { | |
| 1562 return Representation::None(); | |
| 1563 } | |
| 1564 | |
| 1565 DECLARE_CONCRETE_INSTRUCTION(UseConst) | |
| 1566 | |
| 1567 private: | |
| 1568 explicit HUseConst(HValue* old_value) : HUnaryOperation(old_value) { } | |
| 1569 }; | |
| 1570 | |
| 1571 | |
| 1572 class HForceRepresentation final : public HTemplateInstruction<1> { | |
| 1573 public: | |
| 1574 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 1575 HValue* value, | |
| 1576 Representation required_representation); | |
| 1577 | |
| 1578 HValue* value() const { return OperandAt(0); } | |
| 1579 | |
| 1580 Representation observed_input_representation(int index) override { | |
| 1581 // We haven't actually *observed* this, but it's closer to the truth | |
| 1582 // than 'None'. | |
| 1583 return representation(); // Same as the output representation. | |
| 1584 } | |
| 1585 Representation RequiredInputRepresentation(int index) override { | |
| 1586 return representation(); // Same as the output representation. | |
| 1587 } | |
| 1588 | |
| 1589 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 1590 | |
| 1591 DECLARE_CONCRETE_INSTRUCTION(ForceRepresentation) | |
| 1592 | |
| 1593 private: | |
| 1594 HForceRepresentation(HValue* value, Representation required_representation) { | |
| 1595 SetOperandAt(0, value); | |
| 1596 set_representation(required_representation); | |
| 1597 } | |
| 1598 }; | |
| 1599 | |
| 1600 | |
| 1601 class HChange final : public HUnaryOperation { | |
| 1602 public: | |
| 1603 HChange(HValue* value, | |
| 1604 Representation to, | |
| 1605 bool is_truncating_to_smi, | |
| 1606 bool is_truncating_to_int32) | |
| 1607 : HUnaryOperation(value) { | |
| 1608 DCHECK(!value->representation().IsNone()); | |
| 1609 DCHECK(!to.IsNone()); | |
| 1610 DCHECK(!value->representation().Equals(to)); | |
| 1611 set_representation(to); | |
| 1612 SetFlag(kUseGVN); | |
| 1613 SetFlag(kCanOverflow); | |
| 1614 if (is_truncating_to_smi && to.IsSmi()) { | |
| 1615 SetFlag(kTruncatingToSmi); | |
| 1616 SetFlag(kTruncatingToInt32); | |
| 1617 } | |
| 1618 if (is_truncating_to_int32) SetFlag(kTruncatingToInt32); | |
| 1619 if (value->representation().IsSmi() || value->type().IsSmi()) { | |
| 1620 set_type(HType::Smi()); | |
| 1621 } else { | |
| 1622 set_type(HType::TaggedNumber()); | |
| 1623 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion); | |
| 1624 } | |
| 1625 } | |
| 1626 | |
| 1627 bool can_convert_undefined_to_nan() { | |
| 1628 return CheckUsesForFlag(kAllowUndefinedAsNaN); | |
| 1629 } | |
| 1630 | |
| 1631 HType CalculateInferredType() override; | |
| 1632 HValue* Canonicalize() override; | |
| 1633 | |
| 1634 Representation from() const { return value()->representation(); } | |
| 1635 Representation to() const { return representation(); } | |
| 1636 bool deoptimize_on_minus_zero() const { | |
| 1637 return CheckFlag(kBailoutOnMinusZero); | |
| 1638 } | |
| 1639 Representation RequiredInputRepresentation(int index) override { | |
| 1640 return from(); | |
| 1641 } | |
| 1642 | |
| 1643 Range* InferRange(Zone* zone) override; | |
| 1644 | |
| 1645 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 1646 | |
| 1647 DECLARE_CONCRETE_INSTRUCTION(Change) | |
| 1648 | |
| 1649 protected: | |
| 1650 bool DataEquals(HValue* other) override { return true; } | |
| 1651 | |
| 1652 private: | |
| 1653 bool IsDeletable() const override { | |
| 1654 return !from().IsTagged() || value()->type().IsSmi(); | |
| 1655 } | |
| 1656 }; | |
| 1657 | |
| 1658 | |
| 1659 class HClampToUint8 final : public HUnaryOperation { | |
| 1660 public: | |
| 1661 DECLARE_INSTRUCTION_FACTORY_P1(HClampToUint8, HValue*); | |
| 1662 | |
| 1663 Representation RequiredInputRepresentation(int index) override { | |
| 1664 return Representation::None(); | |
| 1665 } | |
| 1666 | |
| 1667 DECLARE_CONCRETE_INSTRUCTION(ClampToUint8) | |
| 1668 | |
| 1669 protected: | |
| 1670 bool DataEquals(HValue* other) override { return true; } | |
| 1671 | |
| 1672 private: | |
| 1673 explicit HClampToUint8(HValue* value) | |
| 1674 : HUnaryOperation(value) { | |
| 1675 set_representation(Representation::Integer32()); | |
| 1676 SetFlag(kAllowUndefinedAsNaN); | |
| 1677 SetFlag(kUseGVN); | |
| 1678 } | |
| 1679 | |
| 1680 bool IsDeletable() const override { return true; } | |
| 1681 }; | |
| 1682 | |
| 1683 | |
| 1684 class HDoubleBits final : public HUnaryOperation { | |
| 1685 public: | |
| 1686 enum Bits { HIGH, LOW }; | |
| 1687 DECLARE_INSTRUCTION_FACTORY_P2(HDoubleBits, HValue*, Bits); | |
| 1688 | |
| 1689 Representation RequiredInputRepresentation(int index) override { | |
| 1690 return Representation::Double(); | |
| 1691 } | |
| 1692 | |
| 1693 DECLARE_CONCRETE_INSTRUCTION(DoubleBits) | |
| 1694 | |
| 1695 Bits bits() { return bits_; } | |
| 1696 | |
| 1697 protected: | |
| 1698 bool DataEquals(HValue* other) override { | |
| 1699 return other->IsDoubleBits() && HDoubleBits::cast(other)->bits() == bits(); | |
| 1700 } | |
| 1701 | |
| 1702 private: | |
| 1703 HDoubleBits(HValue* value, Bits bits) | |
| 1704 : HUnaryOperation(value), bits_(bits) { | |
| 1705 set_representation(Representation::Integer32()); | |
| 1706 SetFlag(kUseGVN); | |
| 1707 } | |
| 1708 | |
| 1709 bool IsDeletable() const override { return true; } | |
| 1710 | |
| 1711 Bits bits_; | |
| 1712 }; | |
| 1713 | |
| 1714 | |
| 1715 class HConstructDouble final : public HTemplateInstruction<2> { | |
| 1716 public: | |
| 1717 DECLARE_INSTRUCTION_FACTORY_P2(HConstructDouble, HValue*, HValue*); | |
| 1718 | |
| 1719 Representation RequiredInputRepresentation(int index) override { | |
| 1720 return Representation::Integer32(); | |
| 1721 } | |
| 1722 | |
| 1723 DECLARE_CONCRETE_INSTRUCTION(ConstructDouble) | |
| 1724 | |
| 1725 HValue* hi() { return OperandAt(0); } | |
| 1726 HValue* lo() { return OperandAt(1); } | |
| 1727 | |
| 1728 protected: | |
| 1729 bool DataEquals(HValue* other) override { return true; } | |
| 1730 | |
| 1731 private: | |
| 1732 explicit HConstructDouble(HValue* hi, HValue* lo) { | |
| 1733 set_representation(Representation::Double()); | |
| 1734 SetFlag(kUseGVN); | |
| 1735 SetOperandAt(0, hi); | |
| 1736 SetOperandAt(1, lo); | |
| 1737 } | |
| 1738 | |
| 1739 bool IsDeletable() const override { return true; } | |
| 1740 }; | |
| 1741 | |
| 1742 | |
| 1743 enum RemovableSimulate { | |
| 1744 REMOVABLE_SIMULATE, | |
| 1745 FIXED_SIMULATE | |
| 1746 }; | |
| 1747 | |
| 1748 | |
| 1749 class HSimulate final : public HInstruction { | |
| 1750 public: | |
| 1751 HSimulate(BailoutId ast_id, int pop_count, Zone* zone, | |
| 1752 RemovableSimulate removable) | |
| 1753 : ast_id_(ast_id), | |
| 1754 pop_count_(pop_count), | |
| 1755 values_(2, zone), | |
| 1756 assigned_indexes_(2, zone), | |
| 1757 zone_(zone), | |
| 1758 bit_field_(RemovableField::encode(removable) | | |
| 1759 DoneWithReplayField::encode(false)) {} | |
| 1760 ~HSimulate() {} | |
| 1761 | |
| 1762 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 1763 | |
| 1764 bool HasAstId() const { return !ast_id_.IsNone(); } | |
| 1765 BailoutId ast_id() const { return ast_id_; } | |
| 1766 void set_ast_id(BailoutId id) { | |
| 1767 DCHECK(!HasAstId()); | |
| 1768 ast_id_ = id; | |
| 1769 } | |
| 1770 | |
| 1771 int pop_count() const { return pop_count_; } | |
| 1772 const ZoneList<HValue*>* values() const { return &values_; } | |
| 1773 int GetAssignedIndexAt(int index) const { | |
| 1774 DCHECK(HasAssignedIndexAt(index)); | |
| 1775 return assigned_indexes_[index]; | |
| 1776 } | |
| 1777 bool HasAssignedIndexAt(int index) const { | |
| 1778 return assigned_indexes_[index] != kNoIndex; | |
| 1779 } | |
| 1780 void AddAssignedValue(int index, HValue* value) { | |
| 1781 AddValue(index, value); | |
| 1782 } | |
| 1783 void AddPushedValue(HValue* value) { | |
| 1784 AddValue(kNoIndex, value); | |
| 1785 } | |
| 1786 int ToOperandIndex(int environment_index) { | |
| 1787 for (int i = 0; i < assigned_indexes_.length(); ++i) { | |
| 1788 if (assigned_indexes_[i] == environment_index) return i; | |
| 1789 } | |
| 1790 return -1; | |
| 1791 } | |
| 1792 int OperandCount() const override { return values_.length(); } | |
| 1793 HValue* OperandAt(int index) const override { return values_[index]; } | |
| 1794 | |
| 1795 bool HasEscapingOperandAt(int index) override { return false; } | |
| 1796 Representation RequiredInputRepresentation(int index) override { | |
| 1797 return Representation::None(); | |
| 1798 } | |
| 1799 | |
| 1800 void MergeWith(ZoneList<HSimulate*>* list); | |
| 1801 bool is_candidate_for_removal() { | |
| 1802 return RemovableField::decode(bit_field_) == REMOVABLE_SIMULATE; | |
| 1803 } | |
| 1804 | |
| 1805 // Replay effects of this instruction on the given environment. | |
| 1806 void ReplayEnvironment(HEnvironment* env); | |
| 1807 | |
| 1808 DECLARE_CONCRETE_INSTRUCTION(Simulate) | |
| 1809 | |
| 1810 #ifdef DEBUG | |
| 1811 void Verify() override; | |
| 1812 void set_closure(Handle<JSFunction> closure) { closure_ = closure; } | |
| 1813 Handle<JSFunction> closure() const { return closure_; } | |
| 1814 #endif | |
| 1815 | |
| 1816 protected: | |
| 1817 void InternalSetOperandAt(int index, HValue* value) override { | |
| 1818 values_[index] = value; | |
| 1819 } | |
| 1820 | |
| 1821 private: | |
| 1822 static const int kNoIndex = -1; | |
| 1823 void AddValue(int index, HValue* value) { | |
| 1824 assigned_indexes_.Add(index, zone_); | |
| 1825 // Resize the list of pushed values. | |
| 1826 values_.Add(NULL, zone_); | |
| 1827 // Set the operand through the base method in HValue to make sure that the | |
| 1828 // use lists are correctly updated. | |
| 1829 SetOperandAt(values_.length() - 1, value); | |
| 1830 } | |
| 1831 bool HasValueForIndex(int index) { | |
| 1832 for (int i = 0; i < assigned_indexes_.length(); ++i) { | |
| 1833 if (assigned_indexes_[i] == index) return true; | |
| 1834 } | |
| 1835 return false; | |
| 1836 } | |
| 1837 bool is_done_with_replay() const { | |
| 1838 return DoneWithReplayField::decode(bit_field_); | |
| 1839 } | |
| 1840 void set_done_with_replay() { | |
| 1841 bit_field_ = DoneWithReplayField::update(bit_field_, true); | |
| 1842 } | |
| 1843 | |
| 1844 class RemovableField : public BitField<RemovableSimulate, 0, 1> {}; | |
| 1845 class DoneWithReplayField : public BitField<bool, 1, 1> {}; | |
| 1846 | |
| 1847 BailoutId ast_id_; | |
| 1848 int pop_count_; | |
| 1849 ZoneList<HValue*> values_; | |
| 1850 ZoneList<int> assigned_indexes_; | |
| 1851 Zone* zone_; | |
| 1852 uint32_t bit_field_; | |
| 1853 | |
| 1854 #ifdef DEBUG | |
| 1855 Handle<JSFunction> closure_; | |
| 1856 #endif | |
| 1857 }; | |
| 1858 | |
| 1859 | |
| 1860 class HEnvironmentMarker final : public HTemplateInstruction<1> { | |
| 1861 public: | |
| 1862 enum Kind { BIND, LOOKUP }; | |
| 1863 | |
| 1864 DECLARE_INSTRUCTION_FACTORY_P2(HEnvironmentMarker, Kind, int); | |
| 1865 | |
| 1866 Kind kind() const { return kind_; } | |
| 1867 int index() const { return index_; } | |
| 1868 HSimulate* next_simulate() { return next_simulate_; } | |
| 1869 void set_next_simulate(HSimulate* simulate) { | |
| 1870 next_simulate_ = simulate; | |
| 1871 } | |
| 1872 | |
| 1873 Representation RequiredInputRepresentation(int index) override { | |
| 1874 return Representation::None(); | |
| 1875 } | |
| 1876 | |
| 1877 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 1878 | |
| 1879 #ifdef DEBUG | |
| 1880 void set_closure(Handle<JSFunction> closure) { | |
| 1881 DCHECK(closure_.is_null()); | |
| 1882 DCHECK(!closure.is_null()); | |
| 1883 closure_ = closure; | |
| 1884 } | |
| 1885 Handle<JSFunction> closure() const { return closure_; } | |
| 1886 #endif | |
| 1887 | |
| 1888 DECLARE_CONCRETE_INSTRUCTION(EnvironmentMarker); | |
| 1889 | |
| 1890 private: | |
| 1891 HEnvironmentMarker(Kind kind, int index) | |
| 1892 : kind_(kind), index_(index), next_simulate_(NULL) { } | |
| 1893 | |
| 1894 Kind kind_; | |
| 1895 int index_; | |
| 1896 HSimulate* next_simulate_; | |
| 1897 | |
| 1898 #ifdef DEBUG | |
| 1899 Handle<JSFunction> closure_; | |
| 1900 #endif | |
| 1901 }; | |
| 1902 | |
| 1903 | |
| 1904 class HStackCheck final : public HTemplateInstruction<1> { | |
| 1905 public: | |
| 1906 enum Type { | |
| 1907 kFunctionEntry, | |
| 1908 kBackwardsBranch | |
| 1909 }; | |
| 1910 | |
| 1911 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HStackCheck, Type); | |
| 1912 | |
| 1913 HValue* context() { return OperandAt(0); } | |
| 1914 | |
| 1915 Representation RequiredInputRepresentation(int index) override { | |
| 1916 return Representation::Tagged(); | |
| 1917 } | |
| 1918 | |
| 1919 void Eliminate() { | |
| 1920 // The stack check eliminator might try to eliminate the same stack | |
| 1921 // check instruction multiple times. | |
| 1922 if (IsLinked()) { | |
| 1923 DeleteAndReplaceWith(NULL); | |
| 1924 } | |
| 1925 } | |
| 1926 | |
| 1927 bool is_function_entry() { return type_ == kFunctionEntry; } | |
| 1928 bool is_backwards_branch() { return type_ == kBackwardsBranch; } | |
| 1929 | |
| 1930 DECLARE_CONCRETE_INSTRUCTION(StackCheck) | |
| 1931 | |
| 1932 private: | |
| 1933 HStackCheck(HValue* context, Type type) : type_(type) { | |
| 1934 SetOperandAt(0, context); | |
| 1935 SetChangesFlag(kNewSpacePromotion); | |
| 1936 } | |
| 1937 | |
| 1938 Type type_; | |
| 1939 }; | |
| 1940 | |
| 1941 | |
| 1942 enum InliningKind { | |
| 1943 NORMAL_RETURN, // Drop the function from the environment on return. | |
| 1944 CONSTRUCT_CALL_RETURN, // Either use allocated receiver or return value. | |
| 1945 GETTER_CALL_RETURN, // Returning from a getter, need to restore context. | |
| 1946 SETTER_CALL_RETURN // Use the RHS of the assignment as the return value. | |
| 1947 }; | |
| 1948 | |
| 1949 | |
| 1950 class HArgumentsObject; | |
| 1951 class HConstant; | |
| 1952 | |
| 1953 | |
| 1954 class HEnterInlined final : public HTemplateInstruction<0> { | |
| 1955 public: | |
| 1956 static HEnterInlined* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 1957 BailoutId return_id, Handle<JSFunction> closure, | |
| 1958 HConstant* closure_context, int arguments_count, | |
| 1959 FunctionLiteral* function, | |
| 1960 InliningKind inlining_kind, Variable* arguments_var, | |
| 1961 HArgumentsObject* arguments_object) { | |
| 1962 return new (zone) HEnterInlined(return_id, closure, closure_context, | |
| 1963 arguments_count, function, inlining_kind, | |
| 1964 arguments_var, arguments_object, zone); | |
| 1965 } | |
| 1966 | |
| 1967 void RegisterReturnTarget(HBasicBlock* return_target, Zone* zone); | |
| 1968 ZoneList<HBasicBlock*>* return_targets() { return &return_targets_; } | |
| 1969 | |
| 1970 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 1971 | |
| 1972 Handle<SharedFunctionInfo> shared() const { return shared_; } | |
| 1973 Handle<JSFunction> closure() const { return closure_; } | |
| 1974 HConstant* closure_context() const { return closure_context_; } | |
| 1975 int arguments_count() const { return arguments_count_; } | |
| 1976 bool arguments_pushed() const { return arguments_pushed_; } | |
| 1977 void set_arguments_pushed() { arguments_pushed_ = true; } | |
| 1978 FunctionLiteral* function() const { return function_; } | |
| 1979 InliningKind inlining_kind() const { return inlining_kind_; } | |
| 1980 BailoutId ReturnId() const { return return_id_; } | |
| 1981 int inlining_id() const { return inlining_id_; } | |
| 1982 void set_inlining_id(int inlining_id) { inlining_id_ = inlining_id; } | |
| 1983 | |
| 1984 Representation RequiredInputRepresentation(int index) override { | |
| 1985 return Representation::None(); | |
| 1986 } | |
| 1987 | |
| 1988 Variable* arguments_var() { return arguments_var_; } | |
| 1989 HArgumentsObject* arguments_object() { return arguments_object_; } | |
| 1990 | |
| 1991 DECLARE_CONCRETE_INSTRUCTION(EnterInlined) | |
| 1992 | |
| 1993 private: | |
| 1994 HEnterInlined(BailoutId return_id, Handle<JSFunction> closure, | |
| 1995 HConstant* closure_context, int arguments_count, | |
| 1996 FunctionLiteral* function, InliningKind inlining_kind, | |
| 1997 Variable* arguments_var, HArgumentsObject* arguments_object, | |
| 1998 Zone* zone) | |
| 1999 : return_id_(return_id), | |
| 2000 shared_(handle(closure->shared())), | |
| 2001 closure_(closure), | |
| 2002 closure_context_(closure_context), | |
| 2003 arguments_count_(arguments_count), | |
| 2004 arguments_pushed_(false), | |
| 2005 function_(function), | |
| 2006 inlining_kind_(inlining_kind), | |
| 2007 inlining_id_(0), | |
| 2008 arguments_var_(arguments_var), | |
| 2009 arguments_object_(arguments_object), | |
| 2010 return_targets_(2, zone) {} | |
| 2011 | |
| 2012 BailoutId return_id_; | |
| 2013 Handle<SharedFunctionInfo> shared_; | |
| 2014 Handle<JSFunction> closure_; | |
| 2015 HConstant* closure_context_; | |
| 2016 int arguments_count_; | |
| 2017 bool arguments_pushed_; | |
| 2018 FunctionLiteral* function_; | |
| 2019 InliningKind inlining_kind_; | |
| 2020 int inlining_id_; | |
| 2021 Variable* arguments_var_; | |
| 2022 HArgumentsObject* arguments_object_; | |
| 2023 ZoneList<HBasicBlock*> return_targets_; | |
| 2024 }; | |
| 2025 | |
| 2026 | |
| 2027 class HLeaveInlined final : public HTemplateInstruction<0> { | |
| 2028 public: | |
| 2029 HLeaveInlined(HEnterInlined* entry, | |
| 2030 int drop_count) | |
| 2031 : entry_(entry), | |
| 2032 drop_count_(drop_count) { } | |
| 2033 | |
| 2034 Representation RequiredInputRepresentation(int index) override { | |
| 2035 return Representation::None(); | |
| 2036 } | |
| 2037 | |
| 2038 int argument_delta() const override { | |
| 2039 return entry_->arguments_pushed() ? -drop_count_ : 0; | |
| 2040 } | |
| 2041 | |
| 2042 DECLARE_CONCRETE_INSTRUCTION(LeaveInlined) | |
| 2043 | |
| 2044 private: | |
| 2045 HEnterInlined* entry_; | |
| 2046 int drop_count_; | |
| 2047 }; | |
| 2048 | |
| 2049 | |
| 2050 class HPushArguments final : public HInstruction { | |
| 2051 public: | |
| 2052 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context) { | |
| 2053 return new(zone) HPushArguments(zone); | |
| 2054 } | |
| 2055 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 2056 HValue* arg1) { | |
| 2057 HPushArguments* instr = new(zone) HPushArguments(zone); | |
| 2058 instr->AddInput(arg1); | |
| 2059 return instr; | |
| 2060 } | |
| 2061 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 2062 HValue* arg1, HValue* arg2) { | |
| 2063 HPushArguments* instr = new(zone) HPushArguments(zone); | |
| 2064 instr->AddInput(arg1); | |
| 2065 instr->AddInput(arg2); | |
| 2066 return instr; | |
| 2067 } | |
| 2068 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 2069 HValue* arg1, HValue* arg2, HValue* arg3) { | |
| 2070 HPushArguments* instr = new(zone) HPushArguments(zone); | |
| 2071 instr->AddInput(arg1); | |
| 2072 instr->AddInput(arg2); | |
| 2073 instr->AddInput(arg3); | |
| 2074 return instr; | |
| 2075 } | |
| 2076 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 2077 HValue* arg1, HValue* arg2, HValue* arg3, | |
| 2078 HValue* arg4) { | |
| 2079 HPushArguments* instr = new(zone) HPushArguments(zone); | |
| 2080 instr->AddInput(arg1); | |
| 2081 instr->AddInput(arg2); | |
| 2082 instr->AddInput(arg3); | |
| 2083 instr->AddInput(arg4); | |
| 2084 return instr; | |
| 2085 } | |
| 2086 | |
| 2087 Representation RequiredInputRepresentation(int index) override { | |
| 2088 return Representation::Tagged(); | |
| 2089 } | |
| 2090 | |
| 2091 int argument_delta() const override { return inputs_.length(); } | |
| 2092 HValue* argument(int i) { return OperandAt(i); } | |
| 2093 | |
| 2094 int OperandCount() const final { return inputs_.length(); } | |
| 2095 HValue* OperandAt(int i) const final { return inputs_[i]; } | |
| 2096 | |
| 2097 void AddInput(HValue* value); | |
| 2098 | |
| 2099 DECLARE_CONCRETE_INSTRUCTION(PushArguments) | |
| 2100 | |
| 2101 protected: | |
| 2102 void InternalSetOperandAt(int i, HValue* value) final { inputs_[i] = value; } | |
| 2103 | |
| 2104 private: | |
| 2105 explicit HPushArguments(Zone* zone) | |
| 2106 : HInstruction(HType::Tagged()), inputs_(4, zone) { | |
| 2107 set_representation(Representation::Tagged()); | |
| 2108 } | |
| 2109 | |
| 2110 ZoneList<HValue*> inputs_; | |
| 2111 }; | |
| 2112 | |
| 2113 | |
| 2114 class HThisFunction final : public HTemplateInstruction<0> { | |
| 2115 public: | |
| 2116 DECLARE_INSTRUCTION_FACTORY_P0(HThisFunction); | |
| 2117 | |
| 2118 Representation RequiredInputRepresentation(int index) override { | |
| 2119 return Representation::None(); | |
| 2120 } | |
| 2121 | |
| 2122 DECLARE_CONCRETE_INSTRUCTION(ThisFunction) | |
| 2123 | |
| 2124 protected: | |
| 2125 bool DataEquals(HValue* other) override { return true; } | |
| 2126 | |
| 2127 private: | |
| 2128 HThisFunction() { | |
| 2129 set_representation(Representation::Tagged()); | |
| 2130 SetFlag(kUseGVN); | |
| 2131 } | |
| 2132 | |
| 2133 bool IsDeletable() const override { return true; } | |
| 2134 }; | |
| 2135 | |
| 2136 | |
| 2137 class HDeclareGlobals final : public HUnaryOperation { | |
| 2138 public: | |
| 2139 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HDeclareGlobals, | |
| 2140 Handle<FixedArray>, | |
| 2141 int); | |
| 2142 | |
| 2143 HValue* context() { return OperandAt(0); } | |
| 2144 Handle<FixedArray> pairs() const { return pairs_; } | |
| 2145 int flags() const { return flags_; } | |
| 2146 | |
| 2147 DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals) | |
| 2148 | |
| 2149 Representation RequiredInputRepresentation(int index) override { | |
| 2150 return Representation::Tagged(); | |
| 2151 } | |
| 2152 | |
| 2153 private: | |
| 2154 HDeclareGlobals(HValue* context, | |
| 2155 Handle<FixedArray> pairs, | |
| 2156 int flags) | |
| 2157 : HUnaryOperation(context), | |
| 2158 pairs_(pairs), | |
| 2159 flags_(flags) { | |
| 2160 set_representation(Representation::Tagged()); | |
| 2161 SetAllSideEffects(); | |
| 2162 } | |
| 2163 | |
| 2164 Handle<FixedArray> pairs_; | |
| 2165 int flags_; | |
| 2166 }; | |
| 2167 | |
| 2168 | |
| 2169 template <int V> | |
| 2170 class HCall : public HTemplateInstruction<V> { | |
| 2171 public: | |
| 2172 // The argument count includes the receiver. | |
| 2173 explicit HCall<V>(int argument_count) : argument_count_(argument_count) { | |
| 2174 this->set_representation(Representation::Tagged()); | |
| 2175 this->SetAllSideEffects(); | |
| 2176 } | |
| 2177 | |
| 2178 HType CalculateInferredType() final { return HType::Tagged(); } | |
| 2179 | |
| 2180 virtual int argument_count() const { | |
| 2181 return argument_count_; | |
| 2182 } | |
| 2183 | |
| 2184 int argument_delta() const override { return -argument_count(); } | |
| 2185 | |
| 2186 private: | |
| 2187 int argument_count_; | |
| 2188 }; | |
| 2189 | |
| 2190 | |
| 2191 class HUnaryCall : public HCall<1> { | |
| 2192 public: | |
| 2193 HUnaryCall(HValue* value, int argument_count) | |
| 2194 : HCall<1>(argument_count) { | |
| 2195 SetOperandAt(0, value); | |
| 2196 } | |
| 2197 | |
| 2198 Representation RequiredInputRepresentation(int index) final { | |
| 2199 return Representation::Tagged(); | |
| 2200 } | |
| 2201 | |
| 2202 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 2203 | |
| 2204 HValue* value() const { return OperandAt(0); } | |
| 2205 }; | |
| 2206 | |
| 2207 | |
| 2208 class HBinaryCall : public HCall<2> { | |
| 2209 public: | |
| 2210 HBinaryCall(HValue* first, HValue* second, int argument_count) | |
| 2211 : HCall<2>(argument_count) { | |
| 2212 SetOperandAt(0, first); | |
| 2213 SetOperandAt(1, second); | |
| 2214 } | |
| 2215 | |
| 2216 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 2217 | |
| 2218 Representation RequiredInputRepresentation(int index) final { | |
| 2219 return Representation::Tagged(); | |
| 2220 } | |
| 2221 | |
| 2222 HValue* first() const { return OperandAt(0); } | |
| 2223 HValue* second() const { return OperandAt(1); } | |
| 2224 }; | |
| 2225 | |
| 2226 | |
| 2227 class HCallJSFunction final : public HCall<1> { | |
| 2228 public: | |
| 2229 static HCallJSFunction* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 2230 HValue* function, int argument_count); | |
| 2231 | |
| 2232 HValue* function() const { return OperandAt(0); } | |
| 2233 | |
| 2234 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 2235 | |
| 2236 Representation RequiredInputRepresentation(int index) final { | |
| 2237 DCHECK(index == 0); | |
| 2238 return Representation::Tagged(); | |
| 2239 } | |
| 2240 | |
| 2241 bool HasStackCheck() final { return has_stack_check_; } | |
| 2242 | |
| 2243 DECLARE_CONCRETE_INSTRUCTION(CallJSFunction) | |
| 2244 | |
| 2245 private: | |
| 2246 // The argument count includes the receiver. | |
| 2247 HCallJSFunction(HValue* function, | |
| 2248 int argument_count, | |
| 2249 bool has_stack_check) | |
| 2250 : HCall<1>(argument_count), | |
| 2251 has_stack_check_(has_stack_check) { | |
| 2252 SetOperandAt(0, function); | |
| 2253 } | |
| 2254 | |
| 2255 bool has_stack_check_; | |
| 2256 }; | |
| 2257 | |
| 2258 | |
| 2259 enum CallMode { NORMAL_CALL, TAIL_CALL }; | |
| 2260 | |
| 2261 | |
| 2262 class HCallWithDescriptor final : public HInstruction { | |
| 2263 public: | |
| 2264 static HCallWithDescriptor* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 2265 HValue* target, int argument_count, | |
| 2266 CallInterfaceDescriptor descriptor, | |
| 2267 const Vector<HValue*>& operands, | |
| 2268 CallMode call_mode = NORMAL_CALL) { | |
| 2269 HCallWithDescriptor* res = new (zone) HCallWithDescriptor( | |
| 2270 target, argument_count, descriptor, operands, call_mode, zone); | |
| 2271 DCHECK(operands.length() == res->GetParameterCount()); | |
| 2272 return res; | |
| 2273 } | |
| 2274 | |
| 2275 int OperandCount() const final { return values_.length(); } | |
| 2276 HValue* OperandAt(int index) const final { return values_[index]; } | |
| 2277 | |
| 2278 Representation RequiredInputRepresentation(int index) final { | |
| 2279 if (index == 0 || index == 1) { | |
| 2280 // Target + context | |
| 2281 return Representation::Tagged(); | |
| 2282 } else { | |
| 2283 int par_index = index - 2; | |
| 2284 DCHECK(par_index < GetParameterCount()); | |
| 2285 return RepresentationFromType(descriptor_.GetParameterType(par_index)); | |
| 2286 } | |
| 2287 } | |
| 2288 | |
| 2289 DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor) | |
| 2290 | |
| 2291 HType CalculateInferredType() final { return HType::Tagged(); } | |
| 2292 | |
| 2293 bool IsTailCall() const { return call_mode_ == TAIL_CALL; } | |
| 2294 | |
| 2295 virtual int argument_count() const { | |
| 2296 return argument_count_; | |
| 2297 } | |
| 2298 | |
| 2299 int argument_delta() const override { return -argument_count_; } | |
| 2300 | |
| 2301 CallInterfaceDescriptor descriptor() const { return descriptor_; } | |
| 2302 | |
| 2303 HValue* target() { | |
| 2304 return OperandAt(0); | |
| 2305 } | |
| 2306 | |
| 2307 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 2308 | |
| 2309 private: | |
| 2310 // The argument count includes the receiver. | |
| 2311 HCallWithDescriptor(HValue* target, int argument_count, | |
| 2312 CallInterfaceDescriptor descriptor, | |
| 2313 const Vector<HValue*>& operands, CallMode call_mode, | |
| 2314 Zone* zone) | |
| 2315 : descriptor_(descriptor), | |
| 2316 values_(GetParameterCount() + 1, zone), | |
| 2317 argument_count_(argument_count), | |
| 2318 call_mode_(call_mode) { | |
| 2319 // We can only tail call without any stack arguments. | |
| 2320 DCHECK(call_mode != TAIL_CALL || argument_count == 0); | |
| 2321 AddOperand(target, zone); | |
| 2322 for (int i = 0; i < operands.length(); i++) { | |
| 2323 AddOperand(operands[i], zone); | |
| 2324 } | |
| 2325 this->set_representation(Representation::Tagged()); | |
| 2326 this->SetAllSideEffects(); | |
| 2327 } | |
| 2328 | |
| 2329 void AddOperand(HValue* v, Zone* zone) { | |
| 2330 values_.Add(NULL, zone); | |
| 2331 SetOperandAt(values_.length() - 1, v); | |
| 2332 } | |
| 2333 | |
| 2334 int GetParameterCount() const { | |
| 2335 return descriptor_.GetRegisterParameterCount() + 1; | |
| 2336 } | |
| 2337 | |
| 2338 void InternalSetOperandAt(int index, HValue* value) final { | |
| 2339 values_[index] = value; | |
| 2340 } | |
| 2341 | |
| 2342 CallInterfaceDescriptor descriptor_; | |
| 2343 ZoneList<HValue*> values_; | |
| 2344 int argument_count_; | |
| 2345 CallMode call_mode_; | |
| 2346 }; | |
| 2347 | |
| 2348 | |
| 2349 class HInvokeFunction final : public HBinaryCall { | |
| 2350 public: | |
| 2351 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInvokeFunction, HValue*, int); | |
| 2352 | |
| 2353 HInvokeFunction(HValue* context, | |
| 2354 HValue* function, | |
| 2355 Handle<JSFunction> known_function, | |
| 2356 int argument_count) | |
| 2357 : HBinaryCall(context, function, argument_count), | |
| 2358 known_function_(known_function) { | |
| 2359 formal_parameter_count_ = | |
| 2360 known_function.is_null() | |
| 2361 ? 0 | |
| 2362 : known_function->shared()->internal_formal_parameter_count(); | |
| 2363 has_stack_check_ = !known_function.is_null() && | |
| 2364 (known_function->code()->kind() == Code::FUNCTION || | |
| 2365 known_function->code()->kind() == Code::OPTIMIZED_FUNCTION); | |
| 2366 } | |
| 2367 | |
| 2368 static HInvokeFunction* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 2369 HValue* function, | |
| 2370 Handle<JSFunction> known_function, | |
| 2371 int argument_count) { | |
| 2372 return new(zone) HInvokeFunction(context, function, | |
| 2373 known_function, argument_count); | |
| 2374 } | |
| 2375 | |
| 2376 HValue* context() { return first(); } | |
| 2377 HValue* function() { return second(); } | |
| 2378 Handle<JSFunction> known_function() { return known_function_; } | |
| 2379 int formal_parameter_count() const { return formal_parameter_count_; } | |
| 2380 | |
| 2381 bool HasStackCheck() final { return has_stack_check_; } | |
| 2382 | |
| 2383 DECLARE_CONCRETE_INSTRUCTION(InvokeFunction) | |
| 2384 | |
| 2385 private: | |
| 2386 HInvokeFunction(HValue* context, HValue* function, int argument_count) | |
| 2387 : HBinaryCall(context, function, argument_count), | |
| 2388 has_stack_check_(false) { | |
| 2389 } | |
| 2390 | |
| 2391 Handle<JSFunction> known_function_; | |
| 2392 int formal_parameter_count_; | |
| 2393 bool has_stack_check_; | |
| 2394 }; | |
| 2395 | |
| 2396 | |
| 2397 class HCallFunction final : public HBinaryCall { | |
| 2398 public: | |
| 2399 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallFunction, HValue*, int); | |
| 2400 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3( | |
| 2401 HCallFunction, HValue*, int, CallFunctionFlags); | |
| 2402 | |
| 2403 HValue* context() const { return first(); } | |
| 2404 HValue* function() const { return second(); } | |
| 2405 CallFunctionFlags function_flags() const { return function_flags_; } | |
| 2406 | |
| 2407 FeedbackVectorSlot slot() const { return slot_; } | |
| 2408 Handle<TypeFeedbackVector> feedback_vector() const { | |
| 2409 return feedback_vector_; | |
| 2410 } | |
| 2411 bool HasVectorAndSlot() const { return !feedback_vector_.is_null(); } | |
| 2412 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector, | |
| 2413 FeedbackVectorSlot slot) { | |
| 2414 feedback_vector_ = vector; | |
| 2415 slot_ = slot; | |
| 2416 } | |
| 2417 | |
| 2418 DECLARE_CONCRETE_INSTRUCTION(CallFunction) | |
| 2419 | |
| 2420 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 2421 | |
| 2422 int argument_delta() const override { return -argument_count(); } | |
| 2423 | |
| 2424 private: | |
| 2425 HCallFunction(HValue* context, HValue* function, int argument_count, | |
| 2426 CallFunctionFlags flags = NO_CALL_FUNCTION_FLAGS) | |
| 2427 : HBinaryCall(context, function, argument_count), | |
| 2428 function_flags_(flags) {} | |
| 2429 CallFunctionFlags function_flags_; | |
| 2430 Handle<TypeFeedbackVector> feedback_vector_; | |
| 2431 FeedbackVectorSlot slot_; | |
| 2432 }; | |
| 2433 | |
| 2434 | |
| 2435 class HCallNew final : public HBinaryCall { | |
| 2436 public: | |
| 2437 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallNew, HValue*, int); | |
| 2438 | |
| 2439 HValue* context() { return first(); } | |
| 2440 HValue* constructor() { return second(); } | |
| 2441 | |
| 2442 DECLARE_CONCRETE_INSTRUCTION(CallNew) | |
| 2443 | |
| 2444 private: | |
| 2445 HCallNew(HValue* context, HValue* constructor, int argument_count) | |
| 2446 : HBinaryCall(context, constructor, argument_count) {} | |
| 2447 }; | |
| 2448 | |
| 2449 | |
| 2450 class HCallNewArray final : public HBinaryCall { | |
| 2451 public: | |
| 2452 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HCallNewArray, HValue*, int, | |
| 2453 ElementsKind, | |
| 2454 Handle<AllocationSite>); | |
| 2455 | |
| 2456 HValue* context() { return first(); } | |
| 2457 HValue* constructor() { return second(); } | |
| 2458 | |
| 2459 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 2460 | |
| 2461 ElementsKind elements_kind() const { return elements_kind_; } | |
| 2462 Handle<AllocationSite> site() const { return site_; } | |
| 2463 | |
| 2464 DECLARE_CONCRETE_INSTRUCTION(CallNewArray) | |
| 2465 | |
| 2466 private: | |
| 2467 HCallNewArray(HValue* context, HValue* constructor, int argument_count, | |
| 2468 ElementsKind elements_kind, Handle<AllocationSite> site) | |
| 2469 : HBinaryCall(context, constructor, argument_count), | |
| 2470 elements_kind_(elements_kind), | |
| 2471 site_(site) {} | |
| 2472 | |
| 2473 ElementsKind elements_kind_; | |
| 2474 Handle<AllocationSite> site_; | |
| 2475 }; | |
| 2476 | |
| 2477 | |
| 2478 class HCallRuntime final : public HCall<1> { | |
| 2479 public: | |
| 2480 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallRuntime, | |
| 2481 const Runtime::Function*, int); | |
| 2482 | |
| 2483 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 2484 | |
| 2485 HValue* context() { return OperandAt(0); } | |
| 2486 const Runtime::Function* function() const { return c_function_; } | |
| 2487 SaveFPRegsMode save_doubles() const { return save_doubles_; } | |
| 2488 void set_save_doubles(SaveFPRegsMode save_doubles) { | |
| 2489 save_doubles_ = save_doubles; | |
| 2490 } | |
| 2491 | |
| 2492 Representation RequiredInputRepresentation(int index) override { | |
| 2493 return Representation::Tagged(); | |
| 2494 } | |
| 2495 | |
| 2496 DECLARE_CONCRETE_INSTRUCTION(CallRuntime) | |
| 2497 | |
| 2498 private: | |
| 2499 HCallRuntime(HValue* context, const Runtime::Function* c_function, | |
| 2500 int argument_count) | |
| 2501 : HCall<1>(argument_count), | |
| 2502 c_function_(c_function), | |
| 2503 save_doubles_(kDontSaveFPRegs) { | |
| 2504 SetOperandAt(0, context); | |
| 2505 } | |
| 2506 | |
| 2507 const Runtime::Function* c_function_; | |
| 2508 SaveFPRegsMode save_doubles_; | |
| 2509 }; | |
| 2510 | |
| 2511 | |
| 2512 class HMapEnumLength final : public HUnaryOperation { | |
| 2513 public: | |
| 2514 DECLARE_INSTRUCTION_FACTORY_P1(HMapEnumLength, HValue*); | |
| 2515 | |
| 2516 Representation RequiredInputRepresentation(int index) override { | |
| 2517 return Representation::Tagged(); | |
| 2518 } | |
| 2519 | |
| 2520 DECLARE_CONCRETE_INSTRUCTION(MapEnumLength) | |
| 2521 | |
| 2522 protected: | |
| 2523 bool DataEquals(HValue* other) override { return true; } | |
| 2524 | |
| 2525 private: | |
| 2526 explicit HMapEnumLength(HValue* value) | |
| 2527 : HUnaryOperation(value, HType::Smi()) { | |
| 2528 set_representation(Representation::Smi()); | |
| 2529 SetFlag(kUseGVN); | |
| 2530 SetDependsOnFlag(kMaps); | |
| 2531 } | |
| 2532 | |
| 2533 bool IsDeletable() const override { return true; } | |
| 2534 }; | |
| 2535 | |
| 2536 | |
| 2537 class HUnaryMathOperation final : public HTemplateInstruction<2> { | |
| 2538 public: | |
| 2539 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 2540 HValue* value, BuiltinFunctionId op); | |
| 2541 | |
| 2542 HValue* context() const { return OperandAt(0); } | |
| 2543 HValue* value() const { return OperandAt(1); } | |
| 2544 | |
| 2545 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 2546 | |
| 2547 Representation RequiredInputRepresentation(int index) override { | |
| 2548 if (index == 0) { | |
| 2549 return Representation::Tagged(); | |
| 2550 } else { | |
| 2551 switch (op_) { | |
| 2552 case kMathFloor: | |
| 2553 case kMathRound: | |
| 2554 case kMathFround: | |
| 2555 case kMathSqrt: | |
| 2556 case kMathPowHalf: | |
| 2557 case kMathLog: | |
| 2558 case kMathExp: | |
| 2559 return Representation::Double(); | |
| 2560 case kMathAbs: | |
| 2561 return representation(); | |
| 2562 case kMathClz32: | |
| 2563 return Representation::Integer32(); | |
| 2564 default: | |
| 2565 UNREACHABLE(); | |
| 2566 return Representation::None(); | |
| 2567 } | |
| 2568 } | |
| 2569 } | |
| 2570 | |
| 2571 Range* InferRange(Zone* zone) override; | |
| 2572 | |
| 2573 HValue* Canonicalize() override; | |
| 2574 Representation RepresentationFromUses() override; | |
| 2575 Representation RepresentationFromInputs() override; | |
| 2576 | |
| 2577 BuiltinFunctionId op() const { return op_; } | |
| 2578 const char* OpName() const; | |
| 2579 | |
| 2580 DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation) | |
| 2581 | |
| 2582 protected: | |
| 2583 bool DataEquals(HValue* other) override { | |
| 2584 HUnaryMathOperation* b = HUnaryMathOperation::cast(other); | |
| 2585 return op_ == b->op(); | |
| 2586 } | |
| 2587 | |
| 2588 private: | |
| 2589 // Indicates if we support a double (and int32) output for Math.floor and | |
| 2590 // Math.round. | |
| 2591 bool SupportsFlexibleFloorAndRound() const { | |
| 2592 #ifdef V8_TARGET_ARCH_ARM64 | |
| 2593 // TODO(rmcilroy): Re-enable this for Arm64 once http://crbug.com/476477 is | |
| 2594 // fixed. | |
| 2595 return false; | |
| 2596 #else | |
| 2597 return false; | |
| 2598 #endif | |
| 2599 } | |
| 2600 HUnaryMathOperation(HValue* context, HValue* value, BuiltinFunctionId op) | |
| 2601 : HTemplateInstruction<2>(HType::TaggedNumber()), op_(op) { | |
| 2602 SetOperandAt(0, context); | |
| 2603 SetOperandAt(1, value); | |
| 2604 switch (op) { | |
| 2605 case kMathFloor: | |
| 2606 case kMathRound: | |
| 2607 if (SupportsFlexibleFloorAndRound()) { | |
| 2608 SetFlag(kFlexibleRepresentation); | |
| 2609 } else { | |
| 2610 set_representation(Representation::Integer32()); | |
| 2611 } | |
| 2612 break; | |
| 2613 case kMathClz32: | |
| 2614 set_representation(Representation::Integer32()); | |
| 2615 break; | |
| 2616 case kMathAbs: | |
| 2617 // Not setting representation here: it is None intentionally. | |
| 2618 SetFlag(kFlexibleRepresentation); | |
| 2619 // TODO(svenpanne) This flag is actually only needed if representation() | |
| 2620 // is tagged, and not when it is an unboxed double or unboxed integer. | |
| 2621 SetChangesFlag(kNewSpacePromotion); | |
| 2622 break; | |
| 2623 case kMathFround: | |
| 2624 case kMathLog: | |
| 2625 case kMathExp: | |
| 2626 case kMathSqrt: | |
| 2627 case kMathPowHalf: | |
| 2628 set_representation(Representation::Double()); | |
| 2629 break; | |
| 2630 default: | |
| 2631 UNREACHABLE(); | |
| 2632 } | |
| 2633 SetFlag(kUseGVN); | |
| 2634 SetFlag(kAllowUndefinedAsNaN); | |
| 2635 } | |
| 2636 | |
| 2637 bool IsDeletable() const override { | |
| 2638 // TODO(crankshaft): This should be true, however the semantics of this | |
| 2639 // instruction also include the ToNumber conversion that is mentioned in the | |
| 2640 // spec, which is of course observable. | |
| 2641 return false; | |
| 2642 } | |
| 2643 | |
| 2644 HValue* SimplifiedDividendForMathFloorOfDiv(HDiv* hdiv); | |
| 2645 HValue* SimplifiedDivisorForMathFloorOfDiv(HDiv* hdiv); | |
| 2646 | |
| 2647 BuiltinFunctionId op_; | |
| 2648 }; | |
| 2649 | |
| 2650 | |
| 2651 class HLoadRoot final : public HTemplateInstruction<0> { | |
| 2652 public: | |
| 2653 DECLARE_INSTRUCTION_FACTORY_P1(HLoadRoot, Heap::RootListIndex); | |
| 2654 DECLARE_INSTRUCTION_FACTORY_P2(HLoadRoot, Heap::RootListIndex, HType); | |
| 2655 | |
| 2656 Representation RequiredInputRepresentation(int index) override { | |
| 2657 return Representation::None(); | |
| 2658 } | |
| 2659 | |
| 2660 Heap::RootListIndex index() const { return index_; } | |
| 2661 | |
| 2662 DECLARE_CONCRETE_INSTRUCTION(LoadRoot) | |
| 2663 | |
| 2664 protected: | |
| 2665 bool DataEquals(HValue* other) override { | |
| 2666 HLoadRoot* b = HLoadRoot::cast(other); | |
| 2667 return index_ == b->index_; | |
| 2668 } | |
| 2669 | |
| 2670 private: | |
| 2671 explicit HLoadRoot(Heap::RootListIndex index, HType type = HType::Tagged()) | |
| 2672 : HTemplateInstruction<0>(type), index_(index) { | |
| 2673 SetFlag(kUseGVN); | |
| 2674 // TODO(bmeurer): We'll need kDependsOnRoots once we add the | |
| 2675 // corresponding HStoreRoot instruction. | |
| 2676 SetDependsOnFlag(kCalls); | |
| 2677 set_representation(Representation::Tagged()); | |
| 2678 } | |
| 2679 | |
| 2680 bool IsDeletable() const override { return true; } | |
| 2681 | |
| 2682 const Heap::RootListIndex index_; | |
| 2683 }; | |
| 2684 | |
| 2685 | |
| 2686 class HCheckMaps final : public HTemplateInstruction<2> { | |
| 2687 public: | |
| 2688 static HCheckMaps* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 2689 HValue* value, Handle<Map> map, | |
| 2690 HValue* typecheck = NULL) { | |
| 2691 return new(zone) HCheckMaps(value, new(zone) UniqueSet<Map>( | |
| 2692 Unique<Map>::CreateImmovable(map), zone), typecheck); | |
| 2693 } | |
| 2694 static HCheckMaps* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 2695 HValue* value, SmallMapList* map_list, | |
| 2696 HValue* typecheck = NULL) { | |
| 2697 UniqueSet<Map>* maps = new(zone) UniqueSet<Map>(map_list->length(), zone); | |
| 2698 for (int i = 0; i < map_list->length(); ++i) { | |
| 2699 maps->Add(Unique<Map>::CreateImmovable(map_list->at(i)), zone); | |
| 2700 } | |
| 2701 return new(zone) HCheckMaps(value, maps, typecheck); | |
| 2702 } | |
| 2703 | |
| 2704 bool IsStabilityCheck() const { | |
| 2705 return IsStabilityCheckField::decode(bit_field_); | |
| 2706 } | |
| 2707 void MarkAsStabilityCheck() { | |
| 2708 bit_field_ = MapsAreStableField::encode(true) | | |
| 2709 HasMigrationTargetField::encode(false) | | |
| 2710 IsStabilityCheckField::encode(true); | |
| 2711 ClearChangesFlag(kNewSpacePromotion); | |
| 2712 ClearDependsOnFlag(kElementsKind); | |
| 2713 ClearDependsOnFlag(kMaps); | |
| 2714 } | |
| 2715 | |
| 2716 bool HasEscapingOperandAt(int index) override { return false; } | |
| 2717 Representation RequiredInputRepresentation(int index) override { | |
| 2718 return Representation::Tagged(); | |
| 2719 } | |
| 2720 | |
| 2721 HType CalculateInferredType() override { | |
| 2722 if (value()->type().IsHeapObject()) return value()->type(); | |
| 2723 return HType::HeapObject(); | |
| 2724 } | |
| 2725 | |
| 2726 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 2727 | |
| 2728 HValue* value() const { return OperandAt(0); } | |
| 2729 HValue* typecheck() const { return OperandAt(1); } | |
| 2730 | |
| 2731 const UniqueSet<Map>* maps() const { return maps_; } | |
| 2732 void set_maps(const UniqueSet<Map>* maps) { maps_ = maps; } | |
| 2733 | |
| 2734 bool maps_are_stable() const { | |
| 2735 return MapsAreStableField::decode(bit_field_); | |
| 2736 } | |
| 2737 | |
| 2738 bool HasMigrationTarget() const { | |
| 2739 return HasMigrationTargetField::decode(bit_field_); | |
| 2740 } | |
| 2741 | |
| 2742 HValue* Canonicalize() override; | |
| 2743 | |
| 2744 static HCheckMaps* CreateAndInsertAfter(Zone* zone, | |
| 2745 HValue* value, | |
| 2746 Unique<Map> map, | |
| 2747 bool map_is_stable, | |
| 2748 HInstruction* instr) { | |
| 2749 return instr->Append(new(zone) HCheckMaps( | |
| 2750 value, new(zone) UniqueSet<Map>(map, zone), map_is_stable)); | |
| 2751 } | |
| 2752 | |
| 2753 static HCheckMaps* CreateAndInsertBefore(Zone* zone, | |
| 2754 HValue* value, | |
| 2755 const UniqueSet<Map>* maps, | |
| 2756 bool maps_are_stable, | |
| 2757 HInstruction* instr) { | |
| 2758 return instr->Prepend(new(zone) HCheckMaps(value, maps, maps_are_stable)); | |
| 2759 } | |
| 2760 | |
| 2761 DECLARE_CONCRETE_INSTRUCTION(CheckMaps) | |
| 2762 | |
| 2763 protected: | |
| 2764 bool DataEquals(HValue* other) override { | |
| 2765 return this->maps()->Equals(HCheckMaps::cast(other)->maps()); | |
| 2766 } | |
| 2767 | |
| 2768 int RedefinedOperandIndex() override { return 0; } | |
| 2769 | |
| 2770 private: | |
| 2771 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, bool maps_are_stable) | |
| 2772 : HTemplateInstruction<2>(HType::HeapObject()), | |
| 2773 maps_(maps), | |
| 2774 bit_field_(HasMigrationTargetField::encode(false) | | |
| 2775 IsStabilityCheckField::encode(false) | | |
| 2776 MapsAreStableField::encode(maps_are_stable)) { | |
| 2777 DCHECK_NE(0, maps->size()); | |
| 2778 SetOperandAt(0, value); | |
| 2779 // Use the object value for the dependency. | |
| 2780 SetOperandAt(1, value); | |
| 2781 set_representation(Representation::Tagged()); | |
| 2782 SetFlag(kUseGVN); | |
| 2783 SetDependsOnFlag(kMaps); | |
| 2784 SetDependsOnFlag(kElementsKind); | |
| 2785 } | |
| 2786 | |
| 2787 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, HValue* typecheck) | |
| 2788 : HTemplateInstruction<2>(HType::HeapObject()), | |
| 2789 maps_(maps), | |
| 2790 bit_field_(HasMigrationTargetField::encode(false) | | |
| 2791 IsStabilityCheckField::encode(false) | | |
| 2792 MapsAreStableField::encode(true)) { | |
| 2793 DCHECK_NE(0, maps->size()); | |
| 2794 SetOperandAt(0, value); | |
| 2795 // Use the object value for the dependency if NULL is passed. | |
| 2796 SetOperandAt(1, typecheck ? typecheck : value); | |
| 2797 set_representation(Representation::Tagged()); | |
| 2798 SetFlag(kUseGVN); | |
| 2799 SetDependsOnFlag(kMaps); | |
| 2800 SetDependsOnFlag(kElementsKind); | |
| 2801 for (int i = 0; i < maps->size(); ++i) { | |
| 2802 Handle<Map> map = maps->at(i).handle(); | |
| 2803 if (map->is_migration_target()) { | |
| 2804 bit_field_ = HasMigrationTargetField::update(bit_field_, true); | |
| 2805 } | |
| 2806 if (!map->is_stable()) { | |
| 2807 bit_field_ = MapsAreStableField::update(bit_field_, false); | |
| 2808 } | |
| 2809 } | |
| 2810 if (HasMigrationTarget()) SetChangesFlag(kNewSpacePromotion); | |
| 2811 } | |
| 2812 | |
| 2813 class HasMigrationTargetField : public BitField<bool, 0, 1> {}; | |
| 2814 class IsStabilityCheckField : public BitField<bool, 1, 1> {}; | |
| 2815 class MapsAreStableField : public BitField<bool, 2, 1> {}; | |
| 2816 | |
| 2817 const UniqueSet<Map>* maps_; | |
| 2818 uint32_t bit_field_; | |
| 2819 }; | |
| 2820 | |
| 2821 | |
| 2822 class HCheckValue final : public HUnaryOperation { | |
| 2823 public: | |
| 2824 static HCheckValue* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 2825 HValue* value, Handle<JSFunction> func) { | |
| 2826 bool in_new_space = isolate->heap()->InNewSpace(*func); | |
| 2827 // NOTE: We create an uninitialized Unique and initialize it later. | |
| 2828 // This is because a JSFunction can move due to GC during graph creation. | |
| 2829 // TODO(titzer): This is a migration crutch. Replace with some kind of | |
| 2830 // Uniqueness scope later. | |
| 2831 Unique<JSFunction> target = Unique<JSFunction>::CreateUninitialized(func); | |
| 2832 HCheckValue* check = new(zone) HCheckValue(value, target, in_new_space); | |
| 2833 return check; | |
| 2834 } | |
| 2835 static HCheckValue* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 2836 HValue* value, Unique<HeapObject> target, | |
| 2837 bool object_in_new_space) { | |
| 2838 return new(zone) HCheckValue(value, target, object_in_new_space); | |
| 2839 } | |
| 2840 | |
| 2841 void FinalizeUniqueness() override { | |
| 2842 object_ = Unique<HeapObject>(object_.handle()); | |
| 2843 } | |
| 2844 | |
| 2845 Representation RequiredInputRepresentation(int index) override { | |
| 2846 return Representation::Tagged(); | |
| 2847 } | |
| 2848 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 2849 | |
| 2850 HValue* Canonicalize() override; | |
| 2851 | |
| 2852 #ifdef DEBUG | |
| 2853 void Verify() override; | |
| 2854 #endif | |
| 2855 | |
| 2856 Unique<HeapObject> object() const { return object_; } | |
| 2857 bool object_in_new_space() const { return object_in_new_space_; } | |
| 2858 | |
| 2859 DECLARE_CONCRETE_INSTRUCTION(CheckValue) | |
| 2860 | |
| 2861 protected: | |
| 2862 bool DataEquals(HValue* other) override { | |
| 2863 HCheckValue* b = HCheckValue::cast(other); | |
| 2864 return object_ == b->object_; | |
| 2865 } | |
| 2866 | |
| 2867 private: | |
| 2868 HCheckValue(HValue* value, Unique<HeapObject> object, | |
| 2869 bool object_in_new_space) | |
| 2870 : HUnaryOperation(value, value->type()), | |
| 2871 object_(object), | |
| 2872 object_in_new_space_(object_in_new_space) { | |
| 2873 set_representation(Representation::Tagged()); | |
| 2874 SetFlag(kUseGVN); | |
| 2875 } | |
| 2876 | |
| 2877 Unique<HeapObject> object_; | |
| 2878 bool object_in_new_space_; | |
| 2879 }; | |
| 2880 | |
| 2881 | |
| 2882 class HCheckInstanceType final : public HUnaryOperation { | |
| 2883 public: | |
| 2884 enum Check { | |
| 2885 IS_SPEC_OBJECT, | |
| 2886 IS_JS_ARRAY, | |
| 2887 IS_JS_DATE, | |
| 2888 IS_STRING, | |
| 2889 IS_INTERNALIZED_STRING, | |
| 2890 LAST_INTERVAL_CHECK = IS_JS_DATE | |
| 2891 }; | |
| 2892 | |
| 2893 DECLARE_INSTRUCTION_FACTORY_P2(HCheckInstanceType, HValue*, Check); | |
| 2894 | |
| 2895 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 2896 | |
| 2897 Representation RequiredInputRepresentation(int index) override { | |
| 2898 return Representation::Tagged(); | |
| 2899 } | |
| 2900 | |
| 2901 HType CalculateInferredType() override { | |
| 2902 switch (check_) { | |
| 2903 case IS_SPEC_OBJECT: return HType::JSObject(); | |
| 2904 case IS_JS_ARRAY: return HType::JSArray(); | |
| 2905 case IS_JS_DATE: | |
| 2906 return HType::JSObject(); | |
| 2907 case IS_STRING: return HType::String(); | |
| 2908 case IS_INTERNALIZED_STRING: return HType::String(); | |
| 2909 } | |
| 2910 UNREACHABLE(); | |
| 2911 return HType::Tagged(); | |
| 2912 } | |
| 2913 | |
| 2914 HValue* Canonicalize() override; | |
| 2915 | |
| 2916 bool is_interval_check() const { return check_ <= LAST_INTERVAL_CHECK; } | |
| 2917 void GetCheckInterval(InstanceType* first, InstanceType* last); | |
| 2918 void GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag); | |
| 2919 | |
| 2920 Check check() const { return check_; } | |
| 2921 | |
| 2922 DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType) | |
| 2923 | |
| 2924 protected: | |
| 2925 // TODO(ager): It could be nice to allow the ommision of instance | |
| 2926 // type checks if we have already performed an instance type check | |
| 2927 // with a larger range. | |
| 2928 bool DataEquals(HValue* other) override { | |
| 2929 HCheckInstanceType* b = HCheckInstanceType::cast(other); | |
| 2930 return check_ == b->check_; | |
| 2931 } | |
| 2932 | |
| 2933 int RedefinedOperandIndex() override { return 0; } | |
| 2934 | |
| 2935 private: | |
| 2936 const char* GetCheckName() const; | |
| 2937 | |
| 2938 HCheckInstanceType(HValue* value, Check check) | |
| 2939 : HUnaryOperation(value, HType::HeapObject()), check_(check) { | |
| 2940 set_representation(Representation::Tagged()); | |
| 2941 SetFlag(kUseGVN); | |
| 2942 } | |
| 2943 | |
| 2944 const Check check_; | |
| 2945 }; | |
| 2946 | |
| 2947 | |
| 2948 class HCheckSmi final : public HUnaryOperation { | |
| 2949 public: | |
| 2950 DECLARE_INSTRUCTION_FACTORY_P1(HCheckSmi, HValue*); | |
| 2951 | |
| 2952 Representation RequiredInputRepresentation(int index) override { | |
| 2953 return Representation::Tagged(); | |
| 2954 } | |
| 2955 | |
| 2956 HValue* Canonicalize() override { | |
| 2957 HType value_type = value()->type(); | |
| 2958 if (value_type.IsSmi()) { | |
| 2959 return NULL; | |
| 2960 } | |
| 2961 return this; | |
| 2962 } | |
| 2963 | |
| 2964 DECLARE_CONCRETE_INSTRUCTION(CheckSmi) | |
| 2965 | |
| 2966 protected: | |
| 2967 bool DataEquals(HValue* other) override { return true; } | |
| 2968 | |
| 2969 private: | |
| 2970 explicit HCheckSmi(HValue* value) : HUnaryOperation(value, HType::Smi()) { | |
| 2971 set_representation(Representation::Smi()); | |
| 2972 SetFlag(kUseGVN); | |
| 2973 } | |
| 2974 }; | |
| 2975 | |
| 2976 | |
| 2977 class HCheckArrayBufferNotNeutered final : public HUnaryOperation { | |
| 2978 public: | |
| 2979 DECLARE_INSTRUCTION_FACTORY_P1(HCheckArrayBufferNotNeutered, HValue*); | |
| 2980 | |
| 2981 bool HasEscapingOperandAt(int index) override { return false; } | |
| 2982 Representation RequiredInputRepresentation(int index) override { | |
| 2983 return Representation::Tagged(); | |
| 2984 } | |
| 2985 | |
| 2986 HType CalculateInferredType() override { | |
| 2987 if (value()->type().IsHeapObject()) return value()->type(); | |
| 2988 return HType::HeapObject(); | |
| 2989 } | |
| 2990 | |
| 2991 DECLARE_CONCRETE_INSTRUCTION(CheckArrayBufferNotNeutered) | |
| 2992 | |
| 2993 protected: | |
| 2994 bool DataEquals(HValue* other) override { return true; } | |
| 2995 int RedefinedOperandIndex() override { return 0; } | |
| 2996 | |
| 2997 private: | |
| 2998 explicit HCheckArrayBufferNotNeutered(HValue* value) | |
| 2999 : HUnaryOperation(value) { | |
| 3000 set_representation(Representation::Tagged()); | |
| 3001 SetFlag(kUseGVN); | |
| 3002 SetDependsOnFlag(kCalls); | |
| 3003 } | |
| 3004 }; | |
| 3005 | |
| 3006 | |
| 3007 class HCheckHeapObject final : public HUnaryOperation { | |
| 3008 public: | |
| 3009 DECLARE_INSTRUCTION_FACTORY_P1(HCheckHeapObject, HValue*); | |
| 3010 | |
| 3011 bool HasEscapingOperandAt(int index) override { return false; } | |
| 3012 Representation RequiredInputRepresentation(int index) override { | |
| 3013 return Representation::Tagged(); | |
| 3014 } | |
| 3015 | |
| 3016 HType CalculateInferredType() override { | |
| 3017 if (value()->type().IsHeapObject()) return value()->type(); | |
| 3018 return HType::HeapObject(); | |
| 3019 } | |
| 3020 | |
| 3021 #ifdef DEBUG | |
| 3022 void Verify() override; | |
| 3023 #endif | |
| 3024 | |
| 3025 HValue* Canonicalize() override { | |
| 3026 return value()->type().IsHeapObject() ? NULL : this; | |
| 3027 } | |
| 3028 | |
| 3029 DECLARE_CONCRETE_INSTRUCTION(CheckHeapObject) | |
| 3030 | |
| 3031 protected: | |
| 3032 bool DataEquals(HValue* other) override { return true; } | |
| 3033 | |
| 3034 private: | |
| 3035 explicit HCheckHeapObject(HValue* value) : HUnaryOperation(value) { | |
| 3036 set_representation(Representation::Tagged()); | |
| 3037 SetFlag(kUseGVN); | |
| 3038 } | |
| 3039 }; | |
| 3040 | |
| 3041 | |
| 3042 class InductionVariableData; | |
| 3043 | |
| 3044 | |
| 3045 struct InductionVariableLimitUpdate { | |
| 3046 InductionVariableData* updated_variable; | |
| 3047 HValue* limit; | |
| 3048 bool limit_is_upper; | |
| 3049 bool limit_is_included; | |
| 3050 | |
| 3051 InductionVariableLimitUpdate() | |
| 3052 : updated_variable(NULL), limit(NULL), | |
| 3053 limit_is_upper(false), limit_is_included(false) {} | |
| 3054 }; | |
| 3055 | |
| 3056 | |
| 3057 class HBoundsCheck; | |
| 3058 class HPhi; | |
| 3059 class HBitwise; | |
| 3060 | |
| 3061 | |
| 3062 class InductionVariableData final : public ZoneObject { | |
| 3063 public: | |
| 3064 class InductionVariableCheck : public ZoneObject { | |
| 3065 public: | |
| 3066 HBoundsCheck* check() { return check_; } | |
| 3067 InductionVariableCheck* next() { return next_; } | |
| 3068 bool HasUpperLimit() { return upper_limit_ >= 0; } | |
| 3069 int32_t upper_limit() { | |
| 3070 DCHECK(HasUpperLimit()); | |
| 3071 return upper_limit_; | |
| 3072 } | |
| 3073 void set_upper_limit(int32_t upper_limit) { | |
| 3074 upper_limit_ = upper_limit; | |
| 3075 } | |
| 3076 | |
| 3077 bool processed() { return processed_; } | |
| 3078 void set_processed() { processed_ = true; } | |
| 3079 | |
| 3080 InductionVariableCheck(HBoundsCheck* check, | |
| 3081 InductionVariableCheck* next, | |
| 3082 int32_t upper_limit = kNoLimit) | |
| 3083 : check_(check), next_(next), upper_limit_(upper_limit), | |
| 3084 processed_(false) {} | |
| 3085 | |
| 3086 private: | |
| 3087 HBoundsCheck* check_; | |
| 3088 InductionVariableCheck* next_; | |
| 3089 int32_t upper_limit_; | |
| 3090 bool processed_; | |
| 3091 }; | |
| 3092 | |
| 3093 class ChecksRelatedToLength : public ZoneObject { | |
| 3094 public: | |
| 3095 HValue* length() { return length_; } | |
| 3096 ChecksRelatedToLength* next() { return next_; } | |
| 3097 InductionVariableCheck* checks() { return checks_; } | |
| 3098 | |
| 3099 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit); | |
| 3100 void CloseCurrentBlock(); | |
| 3101 | |
| 3102 ChecksRelatedToLength(HValue* length, ChecksRelatedToLength* next) | |
| 3103 : length_(length), next_(next), checks_(NULL), | |
| 3104 first_check_in_block_(NULL), | |
| 3105 added_index_(NULL), | |
| 3106 added_constant_(NULL), | |
| 3107 current_and_mask_in_block_(0), | |
| 3108 current_or_mask_in_block_(0) {} | |
| 3109 | |
| 3110 private: | |
| 3111 void UseNewIndexInCurrentBlock(Token::Value token, | |
| 3112 int32_t mask, | |
| 3113 HValue* index_base, | |
| 3114 HValue* context); | |
| 3115 | |
| 3116 HBoundsCheck* first_check_in_block() { return first_check_in_block_; } | |
| 3117 HBitwise* added_index() { return added_index_; } | |
| 3118 void set_added_index(HBitwise* index) { added_index_ = index; } | |
| 3119 HConstant* added_constant() { return added_constant_; } | |
| 3120 void set_added_constant(HConstant* constant) { added_constant_ = constant; } | |
| 3121 int32_t current_and_mask_in_block() { return current_and_mask_in_block_; } | |
| 3122 int32_t current_or_mask_in_block() { return current_or_mask_in_block_; } | |
| 3123 int32_t current_upper_limit() { return current_upper_limit_; } | |
| 3124 | |
| 3125 HValue* length_; | |
| 3126 ChecksRelatedToLength* next_; | |
| 3127 InductionVariableCheck* checks_; | |
| 3128 | |
| 3129 HBoundsCheck* first_check_in_block_; | |
| 3130 HBitwise* added_index_; | |
| 3131 HConstant* added_constant_; | |
| 3132 int32_t current_and_mask_in_block_; | |
| 3133 int32_t current_or_mask_in_block_; | |
| 3134 int32_t current_upper_limit_; | |
| 3135 }; | |
| 3136 | |
| 3137 struct LimitFromPredecessorBlock { | |
| 3138 InductionVariableData* variable; | |
| 3139 Token::Value token; | |
| 3140 HValue* limit; | |
| 3141 HBasicBlock* other_target; | |
| 3142 | |
| 3143 bool LimitIsValid() { return token != Token::ILLEGAL; } | |
| 3144 | |
| 3145 bool LimitIsIncluded() { | |
| 3146 return Token::IsEqualityOp(token) || | |
| 3147 token == Token::GTE || token == Token::LTE; | |
| 3148 } | |
| 3149 bool LimitIsUpper() { | |
| 3150 return token == Token::LTE || token == Token::LT || token == Token::NE; | |
| 3151 } | |
| 3152 | |
| 3153 LimitFromPredecessorBlock() | |
| 3154 : variable(NULL), | |
| 3155 token(Token::ILLEGAL), | |
| 3156 limit(NULL), | |
| 3157 other_target(NULL) {} | |
| 3158 }; | |
| 3159 | |
| 3160 static const int32_t kNoLimit = -1; | |
| 3161 | |
| 3162 static InductionVariableData* ExaminePhi(HPhi* phi); | |
| 3163 static void ComputeLimitFromPredecessorBlock( | |
| 3164 HBasicBlock* block, | |
| 3165 LimitFromPredecessorBlock* result); | |
| 3166 static bool ComputeInductionVariableLimit( | |
| 3167 HBasicBlock* block, | |
| 3168 InductionVariableLimitUpdate* additional_limit); | |
| 3169 | |
| 3170 struct BitwiseDecompositionResult { | |
| 3171 HValue* base; | |
| 3172 int32_t and_mask; | |
| 3173 int32_t or_mask; | |
| 3174 HValue* context; | |
| 3175 | |
| 3176 BitwiseDecompositionResult() | |
| 3177 : base(NULL), and_mask(0), or_mask(0), context(NULL) {} | |
| 3178 }; | |
| 3179 static void DecomposeBitwise(HValue* value, | |
| 3180 BitwiseDecompositionResult* result); | |
| 3181 | |
| 3182 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit); | |
| 3183 | |
| 3184 bool CheckIfBranchIsLoopGuard(Token::Value token, | |
| 3185 HBasicBlock* current_branch, | |
| 3186 HBasicBlock* other_branch); | |
| 3187 | |
| 3188 void UpdateAdditionalLimit(InductionVariableLimitUpdate* update); | |
| 3189 | |
| 3190 HPhi* phi() { return phi_; } | |
| 3191 HValue* base() { return base_; } | |
| 3192 int32_t increment() { return increment_; } | |
| 3193 HValue* limit() { return limit_; } | |
| 3194 bool limit_included() { return limit_included_; } | |
| 3195 HBasicBlock* limit_validity() { return limit_validity_; } | |
| 3196 HBasicBlock* induction_exit_block() { return induction_exit_block_; } | |
| 3197 HBasicBlock* induction_exit_target() { return induction_exit_target_; } | |
| 3198 ChecksRelatedToLength* checks() { return checks_; } | |
| 3199 HValue* additional_upper_limit() { return additional_upper_limit_; } | |
| 3200 bool additional_upper_limit_is_included() { | |
| 3201 return additional_upper_limit_is_included_; | |
| 3202 } | |
| 3203 HValue* additional_lower_limit() { return additional_lower_limit_; } | |
| 3204 bool additional_lower_limit_is_included() { | |
| 3205 return additional_lower_limit_is_included_; | |
| 3206 } | |
| 3207 | |
| 3208 bool LowerLimitIsNonNegativeConstant() { | |
| 3209 if (base()->IsInteger32Constant() && base()->GetInteger32Constant() >= 0) { | |
| 3210 return true; | |
| 3211 } | |
| 3212 if (additional_lower_limit() != NULL && | |
| 3213 additional_lower_limit()->IsInteger32Constant() && | |
| 3214 additional_lower_limit()->GetInteger32Constant() >= 0) { | |
| 3215 // Ignoring the corner case of !additional_lower_limit_is_included() | |
| 3216 // is safe, handling it adds unneeded complexity. | |
| 3217 return true; | |
| 3218 } | |
| 3219 return false; | |
| 3220 } | |
| 3221 | |
| 3222 int32_t ComputeUpperLimit(int32_t and_mask, int32_t or_mask); | |
| 3223 | |
| 3224 private: | |
| 3225 template <class T> void swap(T* a, T* b) { | |
| 3226 T c(*a); | |
| 3227 *a = *b; | |
| 3228 *b = c; | |
| 3229 } | |
| 3230 | |
| 3231 InductionVariableData(HPhi* phi, HValue* base, int32_t increment) | |
| 3232 : phi_(phi), base_(IgnoreOsrValue(base)), increment_(increment), | |
| 3233 limit_(NULL), limit_included_(false), limit_validity_(NULL), | |
| 3234 induction_exit_block_(NULL), induction_exit_target_(NULL), | |
| 3235 checks_(NULL), | |
| 3236 additional_upper_limit_(NULL), | |
| 3237 additional_upper_limit_is_included_(false), | |
| 3238 additional_lower_limit_(NULL), | |
| 3239 additional_lower_limit_is_included_(false) {} | |
| 3240 | |
| 3241 static int32_t ComputeIncrement(HPhi* phi, HValue* phi_operand); | |
| 3242 | |
| 3243 static HValue* IgnoreOsrValue(HValue* v); | |
| 3244 static InductionVariableData* GetInductionVariableData(HValue* v); | |
| 3245 | |
| 3246 HPhi* phi_; | |
| 3247 HValue* base_; | |
| 3248 int32_t increment_; | |
| 3249 HValue* limit_; | |
| 3250 bool limit_included_; | |
| 3251 HBasicBlock* limit_validity_; | |
| 3252 HBasicBlock* induction_exit_block_; | |
| 3253 HBasicBlock* induction_exit_target_; | |
| 3254 ChecksRelatedToLength* checks_; | |
| 3255 HValue* additional_upper_limit_; | |
| 3256 bool additional_upper_limit_is_included_; | |
| 3257 HValue* additional_lower_limit_; | |
| 3258 bool additional_lower_limit_is_included_; | |
| 3259 }; | |
| 3260 | |
| 3261 | |
| 3262 class HPhi final : public HValue { | |
| 3263 public: | |
| 3264 HPhi(int merged_index, Zone* zone) | |
| 3265 : inputs_(2, zone), merged_index_(merged_index) { | |
| 3266 DCHECK(merged_index >= 0 || merged_index == kInvalidMergedIndex); | |
| 3267 SetFlag(kFlexibleRepresentation); | |
| 3268 SetFlag(kAllowUndefinedAsNaN); | |
| 3269 } | |
| 3270 | |
| 3271 Representation RepresentationFromInputs() override; | |
| 3272 | |
| 3273 Range* InferRange(Zone* zone) override; | |
| 3274 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override; | |
| 3275 Representation RequiredInputRepresentation(int index) override { | |
| 3276 return representation(); | |
| 3277 } | |
| 3278 Representation KnownOptimalRepresentation() override { | |
| 3279 return representation(); | |
| 3280 } | |
| 3281 HType CalculateInferredType() override; | |
| 3282 int OperandCount() const override { return inputs_.length(); } | |
| 3283 HValue* OperandAt(int index) const override { return inputs_[index]; } | |
| 3284 HValue* GetRedundantReplacement(); | |
| 3285 void AddInput(HValue* value); | |
| 3286 bool HasRealUses(); | |
| 3287 | |
| 3288 bool IsReceiver() const { return merged_index_ == 0; } | |
| 3289 bool HasMergedIndex() const { return merged_index_ != kInvalidMergedIndex; } | |
| 3290 | |
| 3291 SourcePosition position() const override; | |
| 3292 | |
| 3293 int merged_index() const { return merged_index_; } | |
| 3294 | |
| 3295 InductionVariableData* induction_variable_data() { | |
| 3296 return induction_variable_data_; | |
| 3297 } | |
| 3298 bool IsInductionVariable() { | |
| 3299 return induction_variable_data_ != NULL; | |
| 3300 } | |
| 3301 bool IsLimitedInductionVariable() { | |
| 3302 return IsInductionVariable() && | |
| 3303 induction_variable_data_->limit() != NULL; | |
| 3304 } | |
| 3305 void DetectInductionVariable() { | |
| 3306 DCHECK(induction_variable_data_ == NULL); | |
| 3307 induction_variable_data_ = InductionVariableData::ExaminePhi(this); | |
| 3308 } | |
| 3309 | |
| 3310 std::ostream& PrintTo(std::ostream& os) const override; // NOLINT | |
| 3311 | |
| 3312 #ifdef DEBUG | |
| 3313 void Verify() override; | |
| 3314 #endif | |
| 3315 | |
| 3316 void InitRealUses(int id); | |
| 3317 void AddNonPhiUsesFrom(HPhi* other); | |
| 3318 | |
| 3319 Representation representation_from_indirect_uses() const { | |
| 3320 return representation_from_indirect_uses_; | |
| 3321 } | |
| 3322 | |
| 3323 bool has_type_feedback_from_uses() const { | |
| 3324 return has_type_feedback_from_uses_; | |
| 3325 } | |
| 3326 | |
| 3327 int phi_id() { return phi_id_; } | |
| 3328 | |
| 3329 static HPhi* cast(HValue* value) { | |
| 3330 DCHECK(value->IsPhi()); | |
| 3331 return reinterpret_cast<HPhi*>(value); | |
| 3332 } | |
| 3333 Opcode opcode() const override { return HValue::kPhi; } | |
| 3334 | |
| 3335 void SimplifyConstantInputs(); | |
| 3336 | |
| 3337 // Marker value representing an invalid merge index. | |
| 3338 static const int kInvalidMergedIndex = -1; | |
| 3339 | |
| 3340 protected: | |
| 3341 void DeleteFromGraph() override; | |
| 3342 void InternalSetOperandAt(int index, HValue* value) override { | |
| 3343 inputs_[index] = value; | |
| 3344 } | |
| 3345 | |
| 3346 private: | |
| 3347 Representation representation_from_non_phi_uses() const { | |
| 3348 return representation_from_non_phi_uses_; | |
| 3349 } | |
| 3350 | |
| 3351 ZoneList<HValue*> inputs_; | |
| 3352 int merged_index_ = 0; | |
| 3353 | |
| 3354 int phi_id_ = -1; | |
| 3355 InductionVariableData* induction_variable_data_ = nullptr; | |
| 3356 | |
| 3357 Representation representation_from_indirect_uses_ = Representation::None(); | |
| 3358 Representation representation_from_non_phi_uses_ = Representation::None(); | |
| 3359 bool has_type_feedback_from_uses_ = false; | |
| 3360 | |
| 3361 // TODO(titzer): we can't eliminate the receiver for generating backtraces | |
| 3362 bool IsDeletable() const override { return !IsReceiver(); } | |
| 3363 }; | |
| 3364 | |
| 3365 | |
| 3366 // Common base class for HArgumentsObject and HCapturedObject. | |
| 3367 class HDematerializedObject : public HInstruction { | |
| 3368 public: | |
| 3369 HDematerializedObject(int count, Zone* zone) : values_(count, zone) {} | |
| 3370 | |
| 3371 int OperandCount() const final { return values_.length(); } | |
| 3372 HValue* OperandAt(int index) const final { return values_[index]; } | |
| 3373 | |
| 3374 bool HasEscapingOperandAt(int index) final { return false; } | |
| 3375 Representation RequiredInputRepresentation(int index) final { | |
| 3376 return Representation::None(); | |
| 3377 } | |
| 3378 | |
| 3379 protected: | |
| 3380 void InternalSetOperandAt(int index, HValue* value) final { | |
| 3381 values_[index] = value; | |
| 3382 } | |
| 3383 | |
| 3384 // List of values tracked by this marker. | |
| 3385 ZoneList<HValue*> values_; | |
| 3386 }; | |
| 3387 | |
| 3388 | |
| 3389 class HArgumentsObject final : public HDematerializedObject { | |
| 3390 public: | |
| 3391 static HArgumentsObject* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 3392 int count) { | |
| 3393 return new(zone) HArgumentsObject(count, zone); | |
| 3394 } | |
| 3395 | |
| 3396 // The values contain a list of all elements in the arguments object | |
| 3397 // including the receiver object, which is skipped when materializing. | |
| 3398 const ZoneList<HValue*>* arguments_values() const { return &values_; } | |
| 3399 int arguments_count() const { return values_.length(); } | |
| 3400 | |
| 3401 void AddArgument(HValue* argument, Zone* zone) { | |
| 3402 values_.Add(NULL, zone); // Resize list. | |
| 3403 SetOperandAt(values_.length() - 1, argument); | |
| 3404 } | |
| 3405 | |
| 3406 DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject) | |
| 3407 | |
| 3408 private: | |
| 3409 HArgumentsObject(int count, Zone* zone) | |
| 3410 : HDematerializedObject(count, zone) { | |
| 3411 set_representation(Representation::Tagged()); | |
| 3412 SetFlag(kIsArguments); | |
| 3413 } | |
| 3414 }; | |
| 3415 | |
| 3416 | |
| 3417 class HCapturedObject final : public HDematerializedObject { | |
| 3418 public: | |
| 3419 HCapturedObject(int length, int id, Zone* zone) | |
| 3420 : HDematerializedObject(length, zone), capture_id_(id) { | |
| 3421 set_representation(Representation::Tagged()); | |
| 3422 values_.AddBlock(NULL, length, zone); // Resize list. | |
| 3423 } | |
| 3424 | |
| 3425 // The values contain a list of all in-object properties inside the | |
| 3426 // captured object and is index by field index. Properties in the | |
| 3427 // properties or elements backing store are not tracked here. | |
| 3428 const ZoneList<HValue*>* values() const { return &values_; } | |
| 3429 int length() const { return values_.length(); } | |
| 3430 int capture_id() const { return capture_id_; } | |
| 3431 | |
| 3432 // Shortcut for the map value of this captured object. | |
| 3433 HValue* map_value() const { return values()->first(); } | |
| 3434 | |
| 3435 void ReuseSideEffectsFromStore(HInstruction* store) { | |
| 3436 DCHECK(store->HasObservableSideEffects()); | |
| 3437 DCHECK(store->IsStoreNamedField()); | |
| 3438 changes_flags_.Add(store->ChangesFlags()); | |
| 3439 } | |
| 3440 | |
| 3441 // Replay effects of this instruction on the given environment. | |
| 3442 void ReplayEnvironment(HEnvironment* env); | |
| 3443 | |
| 3444 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 3445 | |
| 3446 DECLARE_CONCRETE_INSTRUCTION(CapturedObject) | |
| 3447 | |
| 3448 private: | |
| 3449 int capture_id_; | |
| 3450 | |
| 3451 // Note that we cannot DCE captured objects as they are used to replay | |
| 3452 // the environment. This method is here as an explicit reminder. | |
| 3453 // TODO(mstarzinger): Turn HSimulates into full snapshots maybe? | |
| 3454 bool IsDeletable() const final { return false; } | |
| 3455 }; | |
| 3456 | |
| 3457 | |
| 3458 class HConstant final : public HTemplateInstruction<0> { | |
| 3459 public: | |
| 3460 enum Special { kHoleNaN }; | |
| 3461 | |
| 3462 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Special); | |
| 3463 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, int32_t); | |
| 3464 DECLARE_INSTRUCTION_FACTORY_P2(HConstant, int32_t, Representation); | |
| 3465 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, double); | |
| 3466 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Handle<Object>); | |
| 3467 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, ExternalReference); | |
| 3468 | |
| 3469 static HConstant* CreateAndInsertAfter(Isolate* isolate, Zone* zone, | |
| 3470 HValue* context, int32_t value, | |
| 3471 Representation representation, | |
| 3472 HInstruction* instruction) { | |
| 3473 return instruction->Append( | |
| 3474 HConstant::New(isolate, zone, context, value, representation)); | |
| 3475 } | |
| 3476 | |
| 3477 Handle<Map> GetMonomorphicJSObjectMap() override { | |
| 3478 Handle<Object> object = object_.handle(); | |
| 3479 if (!object.is_null() && object->IsHeapObject()) { | |
| 3480 return v8::internal::handle(HeapObject::cast(*object)->map()); | |
| 3481 } | |
| 3482 return Handle<Map>(); | |
| 3483 } | |
| 3484 | |
| 3485 static HConstant* CreateAndInsertBefore(Isolate* isolate, Zone* zone, | |
| 3486 HValue* context, int32_t value, | |
| 3487 Representation representation, | |
| 3488 HInstruction* instruction) { | |
| 3489 return instruction->Prepend( | |
| 3490 HConstant::New(isolate, zone, context, value, representation)); | |
| 3491 } | |
| 3492 | |
| 3493 static HConstant* CreateAndInsertBefore(Zone* zone, | |
| 3494 Unique<Map> map, | |
| 3495 bool map_is_stable, | |
| 3496 HInstruction* instruction) { | |
| 3497 return instruction->Prepend(new(zone) HConstant( | |
| 3498 map, Unique<Map>(Handle<Map>::null()), map_is_stable, | |
| 3499 Representation::Tagged(), HType::HeapObject(), true, | |
| 3500 false, false, MAP_TYPE)); | |
| 3501 } | |
| 3502 | |
| 3503 static HConstant* CreateAndInsertAfter(Zone* zone, | |
| 3504 Unique<Map> map, | |
| 3505 bool map_is_stable, | |
| 3506 HInstruction* instruction) { | |
| 3507 return instruction->Append(new(zone) HConstant( | |
| 3508 map, Unique<Map>(Handle<Map>::null()), map_is_stable, | |
| 3509 Representation::Tagged(), HType::HeapObject(), true, | |
| 3510 false, false, MAP_TYPE)); | |
| 3511 } | |
| 3512 | |
| 3513 Handle<Object> handle(Isolate* isolate) { | |
| 3514 if (object_.handle().is_null()) { | |
| 3515 // Default arguments to is_not_in_new_space depend on this heap number | |
| 3516 // to be tenured so that it's guaranteed not to be located in new space. | |
| 3517 object_ = Unique<Object>::CreateUninitialized( | |
| 3518 isolate->factory()->NewNumber(double_value_, TENURED)); | |
| 3519 } | |
| 3520 AllowDeferredHandleDereference smi_check; | |
| 3521 DCHECK(HasInteger32Value() || !object_.handle()->IsSmi()); | |
| 3522 return object_.handle(); | |
| 3523 } | |
| 3524 | |
| 3525 bool IsSpecialDouble() const { | |
| 3526 return HasDoubleValue() && | |
| 3527 (bit_cast<int64_t>(double_value_) == bit_cast<int64_t>(-0.0) || | |
| 3528 std::isnan(double_value_)); | |
| 3529 } | |
| 3530 | |
| 3531 bool NotInNewSpace() const { | |
| 3532 return IsNotInNewSpaceField::decode(bit_field_); | |
| 3533 } | |
| 3534 | |
| 3535 bool ImmortalImmovable() const; | |
| 3536 | |
| 3537 bool IsCell() const { | |
| 3538 InstanceType instance_type = GetInstanceType(); | |
| 3539 return instance_type == CELL_TYPE; | |
| 3540 } | |
| 3541 | |
| 3542 Representation RequiredInputRepresentation(int index) override { | |
| 3543 return Representation::None(); | |
| 3544 } | |
| 3545 | |
| 3546 Representation KnownOptimalRepresentation() override { | |
| 3547 if (HasSmiValue() && SmiValuesAre31Bits()) return Representation::Smi(); | |
| 3548 if (HasInteger32Value()) return Representation::Integer32(); | |
| 3549 if (HasNumberValue()) return Representation::Double(); | |
| 3550 if (HasExternalReferenceValue()) return Representation::External(); | |
| 3551 return Representation::Tagged(); | |
| 3552 } | |
| 3553 | |
| 3554 bool EmitAtUses() override; | |
| 3555 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 3556 HConstant* CopyToRepresentation(Representation r, Zone* zone) const; | |
| 3557 Maybe<HConstant*> CopyToTruncatedInt32(Zone* zone); | |
| 3558 Maybe<HConstant*> CopyToTruncatedNumber(Isolate* isolate, Zone* zone); | |
| 3559 bool HasInteger32Value() const { | |
| 3560 return HasInt32ValueField::decode(bit_field_); | |
| 3561 } | |
| 3562 int32_t Integer32Value() const { | |
| 3563 DCHECK(HasInteger32Value()); | |
| 3564 return int32_value_; | |
| 3565 } | |
| 3566 bool HasSmiValue() const { return HasSmiValueField::decode(bit_field_); } | |
| 3567 bool HasDoubleValue() const { | |
| 3568 return HasDoubleValueField::decode(bit_field_); | |
| 3569 } | |
| 3570 double DoubleValue() const { | |
| 3571 DCHECK(HasDoubleValue()); | |
| 3572 return double_value_; | |
| 3573 } | |
| 3574 uint64_t DoubleValueAsBits() const { | |
| 3575 uint64_t bits; | |
| 3576 DCHECK(HasDoubleValue()); | |
| 3577 STATIC_ASSERT(sizeof(bits) == sizeof(double_value_)); | |
| 3578 std::memcpy(&bits, &double_value_, sizeof(bits)); | |
| 3579 return bits; | |
| 3580 } | |
| 3581 bool IsTheHole() const { | |
| 3582 if (HasDoubleValue() && DoubleValueAsBits() == kHoleNanInt64) { | |
| 3583 return true; | |
| 3584 } | |
| 3585 return object_.IsInitialized() && | |
| 3586 object_.IsKnownGlobal(isolate()->heap()->the_hole_value()); | |
| 3587 } | |
| 3588 bool HasNumberValue() const { return HasDoubleValue(); } | |
| 3589 int32_t NumberValueAsInteger32() const { | |
| 3590 DCHECK(HasNumberValue()); | |
| 3591 // Irrespective of whether a numeric HConstant can be safely | |
| 3592 // represented as an int32, we store the (in some cases lossy) | |
| 3593 // representation of the number in int32_value_. | |
| 3594 return int32_value_; | |
| 3595 } | |
| 3596 bool HasStringValue() const { | |
| 3597 if (HasNumberValue()) return false; | |
| 3598 DCHECK(!object_.handle().is_null()); | |
| 3599 return GetInstanceType() < FIRST_NONSTRING_TYPE; | |
| 3600 } | |
| 3601 Handle<String> StringValue() const { | |
| 3602 DCHECK(HasStringValue()); | |
| 3603 return Handle<String>::cast(object_.handle()); | |
| 3604 } | |
| 3605 bool HasInternalizedStringValue() const { | |
| 3606 return HasStringValue() && StringShape(GetInstanceType()).IsInternalized(); | |
| 3607 } | |
| 3608 | |
| 3609 bool HasExternalReferenceValue() const { | |
| 3610 return HasExternalReferenceValueField::decode(bit_field_); | |
| 3611 } | |
| 3612 ExternalReference ExternalReferenceValue() const { | |
| 3613 return external_reference_value_; | |
| 3614 } | |
| 3615 | |
| 3616 bool HasBooleanValue() const { return type_.IsBoolean(); } | |
| 3617 bool BooleanValue() const { return BooleanValueField::decode(bit_field_); } | |
| 3618 bool IsCallable() const { return IsCallableField::decode(bit_field_); } | |
| 3619 bool IsUndetectable() const { | |
| 3620 return IsUndetectableField::decode(bit_field_); | |
| 3621 } | |
| 3622 InstanceType GetInstanceType() const { | |
| 3623 return InstanceTypeField::decode(bit_field_); | |
| 3624 } | |
| 3625 | |
| 3626 bool HasMapValue() const { return GetInstanceType() == MAP_TYPE; } | |
| 3627 Unique<Map> MapValue() const { | |
| 3628 DCHECK(HasMapValue()); | |
| 3629 return Unique<Map>::cast(GetUnique()); | |
| 3630 } | |
| 3631 bool HasStableMapValue() const { | |
| 3632 DCHECK(HasMapValue() || !HasStableMapValueField::decode(bit_field_)); | |
| 3633 return HasStableMapValueField::decode(bit_field_); | |
| 3634 } | |
| 3635 | |
| 3636 bool HasObjectMap() const { return !object_map_.IsNull(); } | |
| 3637 Unique<Map> ObjectMap() const { | |
| 3638 DCHECK(HasObjectMap()); | |
| 3639 return object_map_; | |
| 3640 } | |
| 3641 | |
| 3642 intptr_t Hashcode() override { | |
| 3643 if (HasInteger32Value()) { | |
| 3644 return static_cast<intptr_t>(int32_value_); | |
| 3645 } else if (HasDoubleValue()) { | |
| 3646 uint64_t bits = DoubleValueAsBits(); | |
| 3647 if (sizeof(bits) > sizeof(intptr_t)) { | |
| 3648 bits ^= (bits >> 32); | |
| 3649 } | |
| 3650 return static_cast<intptr_t>(bits); | |
| 3651 } else if (HasExternalReferenceValue()) { | |
| 3652 return reinterpret_cast<intptr_t>(external_reference_value_.address()); | |
| 3653 } else { | |
| 3654 DCHECK(!object_.handle().is_null()); | |
| 3655 return object_.Hashcode(); | |
| 3656 } | |
| 3657 } | |
| 3658 | |
| 3659 void FinalizeUniqueness() override { | |
| 3660 if (!HasDoubleValue() && !HasExternalReferenceValue()) { | |
| 3661 DCHECK(!object_.handle().is_null()); | |
| 3662 object_ = Unique<Object>(object_.handle()); | |
| 3663 } | |
| 3664 } | |
| 3665 | |
| 3666 Unique<Object> GetUnique() const { | |
| 3667 return object_; | |
| 3668 } | |
| 3669 | |
| 3670 bool EqualsUnique(Unique<Object> other) const { | |
| 3671 return object_.IsInitialized() && object_ == other; | |
| 3672 } | |
| 3673 | |
| 3674 bool DataEquals(HValue* other) override { | |
| 3675 HConstant* other_constant = HConstant::cast(other); | |
| 3676 if (HasInteger32Value()) { | |
| 3677 return other_constant->HasInteger32Value() && | |
| 3678 int32_value_ == other_constant->int32_value_; | |
| 3679 } else if (HasDoubleValue()) { | |
| 3680 return other_constant->HasDoubleValue() && | |
| 3681 std::memcmp(&double_value_, &other_constant->double_value_, | |
| 3682 sizeof(double_value_)) == 0; | |
| 3683 } else if (HasExternalReferenceValue()) { | |
| 3684 return other_constant->HasExternalReferenceValue() && | |
| 3685 external_reference_value_ == | |
| 3686 other_constant->external_reference_value_; | |
| 3687 } else { | |
| 3688 if (other_constant->HasInteger32Value() || | |
| 3689 other_constant->HasDoubleValue() || | |
| 3690 other_constant->HasExternalReferenceValue()) { | |
| 3691 return false; | |
| 3692 } | |
| 3693 DCHECK(!object_.handle().is_null()); | |
| 3694 return other_constant->object_ == object_; | |
| 3695 } | |
| 3696 } | |
| 3697 | |
| 3698 #ifdef DEBUG | |
| 3699 void Verify() override {} | |
| 3700 #endif | |
| 3701 | |
| 3702 DECLARE_CONCRETE_INSTRUCTION(Constant) | |
| 3703 | |
| 3704 protected: | |
| 3705 Range* InferRange(Zone* zone) override; | |
| 3706 | |
| 3707 private: | |
| 3708 friend class HGraph; | |
| 3709 explicit HConstant(Special special); | |
| 3710 explicit HConstant(Handle<Object> handle, | |
| 3711 Representation r = Representation::None()); | |
| 3712 HConstant(int32_t value, | |
| 3713 Representation r = Representation::None(), | |
| 3714 bool is_not_in_new_space = true, | |
| 3715 Unique<Object> optional = Unique<Object>(Handle<Object>::null())); | |
| 3716 HConstant(double value, | |
| 3717 Representation r = Representation::None(), | |
| 3718 bool is_not_in_new_space = true, | |
| 3719 Unique<Object> optional = Unique<Object>(Handle<Object>::null())); | |
| 3720 HConstant(Unique<Object> object, | |
| 3721 Unique<Map> object_map, | |
| 3722 bool has_stable_map_value, | |
| 3723 Representation r, | |
| 3724 HType type, | |
| 3725 bool is_not_in_new_space, | |
| 3726 bool boolean_value, | |
| 3727 bool is_undetectable, | |
| 3728 InstanceType instance_type); | |
| 3729 | |
| 3730 explicit HConstant(ExternalReference reference); | |
| 3731 | |
| 3732 void Initialize(Representation r); | |
| 3733 | |
| 3734 bool IsDeletable() const override { return true; } | |
| 3735 | |
| 3736 // If object_ is a map, this indicates whether the map is stable. | |
| 3737 class HasStableMapValueField : public BitField<bool, 0, 1> {}; | |
| 3738 | |
| 3739 // We store the HConstant in the most specific form safely possible. | |
| 3740 // These flags tell us if the respective member fields hold valid, safe | |
| 3741 // representations of the constant. More specific flags imply more general | |
| 3742 // flags, but not the converse (i.e. smi => int32 => double). | |
| 3743 class HasSmiValueField : public BitField<bool, 1, 1> {}; | |
| 3744 class HasInt32ValueField : public BitField<bool, 2, 1> {}; | |
| 3745 class HasDoubleValueField : public BitField<bool, 3, 1> {}; | |
| 3746 | |
| 3747 class HasExternalReferenceValueField : public BitField<bool, 4, 1> {}; | |
| 3748 class IsNotInNewSpaceField : public BitField<bool, 5, 1> {}; | |
| 3749 class BooleanValueField : public BitField<bool, 6, 1> {}; | |
| 3750 class IsUndetectableField : public BitField<bool, 7, 1> {}; | |
| 3751 class IsCallableField : public BitField<bool, 8, 1> {}; | |
| 3752 | |
| 3753 static const InstanceType kUnknownInstanceType = FILLER_TYPE; | |
| 3754 class InstanceTypeField : public BitField<InstanceType, 16, 8> {}; | |
| 3755 | |
| 3756 // If this is a numerical constant, object_ either points to the | |
| 3757 // HeapObject the constant originated from or is null. If the | |
| 3758 // constant is non-numeric, object_ always points to a valid | |
| 3759 // constant HeapObject. | |
| 3760 Unique<Object> object_; | |
| 3761 | |
| 3762 // If object_ is a heap object, this points to the stable map of the object. | |
| 3763 Unique<Map> object_map_; | |
| 3764 | |
| 3765 uint32_t bit_field_; | |
| 3766 | |
| 3767 int32_t int32_value_; | |
| 3768 double double_value_; | |
| 3769 ExternalReference external_reference_value_; | |
| 3770 }; | |
| 3771 | |
| 3772 | |
| 3773 class HBinaryOperation : public HTemplateInstruction<3> { | |
| 3774 public: | |
| 3775 HBinaryOperation(HValue* context, HValue* left, HValue* right, | |
| 3776 Strength strength, HType type = HType::Tagged()) | |
| 3777 : HTemplateInstruction<3>(type), | |
| 3778 strength_(strength), | |
| 3779 observed_output_representation_(Representation::None()) { | |
| 3780 DCHECK(left != NULL && right != NULL); | |
| 3781 SetOperandAt(0, context); | |
| 3782 SetOperandAt(1, left); | |
| 3783 SetOperandAt(2, right); | |
| 3784 observed_input_representation_[0] = Representation::None(); | |
| 3785 observed_input_representation_[1] = Representation::None(); | |
| 3786 } | |
| 3787 | |
| 3788 HValue* context() const { return OperandAt(0); } | |
| 3789 HValue* left() const { return OperandAt(1); } | |
| 3790 HValue* right() const { return OperandAt(2); } | |
| 3791 Strength strength() const { return strength_; } | |
| 3792 | |
| 3793 // True if switching left and right operands likely generates better code. | |
| 3794 bool AreOperandsBetterSwitched() { | |
| 3795 if (!IsCommutative()) return false; | |
| 3796 | |
| 3797 // Constant operands are better off on the right, they can be inlined in | |
| 3798 // many situations on most platforms. | |
| 3799 if (left()->IsConstant()) return true; | |
| 3800 if (right()->IsConstant()) return false; | |
| 3801 | |
| 3802 // Otherwise, if there is only one use of the right operand, it would be | |
| 3803 // better off on the left for platforms that only have 2-arg arithmetic | |
| 3804 // ops (e.g ia32, x64) that clobber the left operand. | |
| 3805 return right()->HasOneUse(); | |
| 3806 } | |
| 3807 | |
| 3808 HValue* BetterLeftOperand() { | |
| 3809 return AreOperandsBetterSwitched() ? right() : left(); | |
| 3810 } | |
| 3811 | |
| 3812 HValue* BetterRightOperand() { | |
| 3813 return AreOperandsBetterSwitched() ? left() : right(); | |
| 3814 } | |
| 3815 | |
| 3816 void set_observed_input_representation(int index, Representation rep) { | |
| 3817 DCHECK(index >= 1 && index <= 2); | |
| 3818 observed_input_representation_[index - 1] = rep; | |
| 3819 } | |
| 3820 | |
| 3821 virtual void initialize_output_representation(Representation observed) { | |
| 3822 observed_output_representation_ = observed; | |
| 3823 } | |
| 3824 | |
| 3825 Representation observed_input_representation(int index) override { | |
| 3826 if (index == 0) return Representation::Tagged(); | |
| 3827 return observed_input_representation_[index - 1]; | |
| 3828 } | |
| 3829 | |
| 3830 virtual void UpdateRepresentation(Representation new_rep, | |
| 3831 HInferRepresentationPhase* h_infer, | |
| 3832 const char* reason) override { | |
| 3833 Representation rep = !FLAG_smi_binop && new_rep.IsSmi() | |
| 3834 ? Representation::Integer32() : new_rep; | |
| 3835 HValue::UpdateRepresentation(rep, h_infer, reason); | |
| 3836 } | |
| 3837 | |
| 3838 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override; | |
| 3839 Representation RepresentationFromInputs() override; | |
| 3840 Representation RepresentationFromOutput(); | |
| 3841 void AssumeRepresentation(Representation r) override; | |
| 3842 | |
| 3843 virtual bool IsCommutative() const { return false; } | |
| 3844 | |
| 3845 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 3846 | |
| 3847 Representation RequiredInputRepresentation(int index) override { | |
| 3848 if (index == 0) return Representation::Tagged(); | |
| 3849 return representation(); | |
| 3850 } | |
| 3851 | |
| 3852 void SetOperandPositions(Zone* zone, SourcePosition left_pos, | |
| 3853 SourcePosition right_pos) { | |
| 3854 set_operand_position(zone, 1, left_pos); | |
| 3855 set_operand_position(zone, 2, right_pos); | |
| 3856 } | |
| 3857 | |
| 3858 bool RightIsPowerOf2() { | |
| 3859 if (!right()->IsInteger32Constant()) return false; | |
| 3860 int32_t value = right()->GetInteger32Constant(); | |
| 3861 if (value < 0) { | |
| 3862 return base::bits::IsPowerOfTwo32(static_cast<uint32_t>(-value)); | |
| 3863 } | |
| 3864 return base::bits::IsPowerOfTwo32(static_cast<uint32_t>(value)); | |
| 3865 } | |
| 3866 | |
| 3867 Strength strength() { return strength_; } | |
| 3868 | |
| 3869 DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation) | |
| 3870 | |
| 3871 private: | |
| 3872 bool IgnoreObservedOutputRepresentation(Representation current_rep); | |
| 3873 Strength strength_; | |
| 3874 | |
| 3875 Representation observed_input_representation_[2]; | |
| 3876 Representation observed_output_representation_; | |
| 3877 }; | |
| 3878 | |
| 3879 | |
| 3880 class HWrapReceiver final : public HTemplateInstruction<2> { | |
| 3881 public: | |
| 3882 DECLARE_INSTRUCTION_FACTORY_P2(HWrapReceiver, HValue*, HValue*); | |
| 3883 | |
| 3884 bool DataEquals(HValue* other) override { return true; } | |
| 3885 | |
| 3886 Representation RequiredInputRepresentation(int index) override { | |
| 3887 return Representation::Tagged(); | |
| 3888 } | |
| 3889 | |
| 3890 HValue* receiver() const { return OperandAt(0); } | |
| 3891 HValue* function() const { return OperandAt(1); } | |
| 3892 | |
| 3893 HValue* Canonicalize() override; | |
| 3894 | |
| 3895 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 3896 bool known_function() const { return known_function_; } | |
| 3897 | |
| 3898 DECLARE_CONCRETE_INSTRUCTION(WrapReceiver) | |
| 3899 | |
| 3900 private: | |
| 3901 HWrapReceiver(HValue* receiver, HValue* function) { | |
| 3902 known_function_ = function->IsConstant() && | |
| 3903 HConstant::cast(function)->handle(function->isolate())->IsJSFunction(); | |
| 3904 set_representation(Representation::Tagged()); | |
| 3905 SetOperandAt(0, receiver); | |
| 3906 SetOperandAt(1, function); | |
| 3907 SetFlag(kUseGVN); | |
| 3908 } | |
| 3909 | |
| 3910 bool known_function_; | |
| 3911 }; | |
| 3912 | |
| 3913 | |
| 3914 class HApplyArguments final : public HTemplateInstruction<4> { | |
| 3915 public: | |
| 3916 DECLARE_INSTRUCTION_FACTORY_P4(HApplyArguments, HValue*, HValue*, HValue*, | |
| 3917 HValue*); | |
| 3918 | |
| 3919 Representation RequiredInputRepresentation(int index) override { | |
| 3920 // The length is untagged, all other inputs are tagged. | |
| 3921 return (index == 2) | |
| 3922 ? Representation::Integer32() | |
| 3923 : Representation::Tagged(); | |
| 3924 } | |
| 3925 | |
| 3926 HValue* function() { return OperandAt(0); } | |
| 3927 HValue* receiver() { return OperandAt(1); } | |
| 3928 HValue* length() { return OperandAt(2); } | |
| 3929 HValue* elements() { return OperandAt(3); } | |
| 3930 | |
| 3931 DECLARE_CONCRETE_INSTRUCTION(ApplyArguments) | |
| 3932 | |
| 3933 private: | |
| 3934 HApplyArguments(HValue* function, | |
| 3935 HValue* receiver, | |
| 3936 HValue* length, | |
| 3937 HValue* elements) { | |
| 3938 set_representation(Representation::Tagged()); | |
| 3939 SetOperandAt(0, function); | |
| 3940 SetOperandAt(1, receiver); | |
| 3941 SetOperandAt(2, length); | |
| 3942 SetOperandAt(3, elements); | |
| 3943 SetAllSideEffects(); | |
| 3944 } | |
| 3945 }; | |
| 3946 | |
| 3947 | |
| 3948 class HArgumentsElements final : public HTemplateInstruction<0> { | |
| 3949 public: | |
| 3950 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsElements, bool); | |
| 3951 | |
| 3952 DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements) | |
| 3953 | |
| 3954 Representation RequiredInputRepresentation(int index) override { | |
| 3955 return Representation::None(); | |
| 3956 } | |
| 3957 | |
| 3958 bool from_inlined() const { return from_inlined_; } | |
| 3959 | |
| 3960 protected: | |
| 3961 bool DataEquals(HValue* other) override { return true; } | |
| 3962 | |
| 3963 private: | |
| 3964 explicit HArgumentsElements(bool from_inlined) : from_inlined_(from_inlined) { | |
| 3965 // The value produced by this instruction is a pointer into the stack | |
| 3966 // that looks as if it was a smi because of alignment. | |
| 3967 set_representation(Representation::Tagged()); | |
| 3968 SetFlag(kUseGVN); | |
| 3969 } | |
| 3970 | |
| 3971 bool IsDeletable() const override { return true; } | |
| 3972 | |
| 3973 bool from_inlined_; | |
| 3974 }; | |
| 3975 | |
| 3976 | |
| 3977 class HArgumentsLength final : public HUnaryOperation { | |
| 3978 public: | |
| 3979 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsLength, HValue*); | |
| 3980 | |
| 3981 Representation RequiredInputRepresentation(int index) override { | |
| 3982 return Representation::Tagged(); | |
| 3983 } | |
| 3984 | |
| 3985 DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength) | |
| 3986 | |
| 3987 protected: | |
| 3988 bool DataEquals(HValue* other) override { return true; } | |
| 3989 | |
| 3990 private: | |
| 3991 explicit HArgumentsLength(HValue* value) : HUnaryOperation(value) { | |
| 3992 set_representation(Representation::Integer32()); | |
| 3993 SetFlag(kUseGVN); | |
| 3994 } | |
| 3995 | |
| 3996 bool IsDeletable() const override { return true; } | |
| 3997 }; | |
| 3998 | |
| 3999 | |
| 4000 class HAccessArgumentsAt final : public HTemplateInstruction<3> { | |
| 4001 public: | |
| 4002 DECLARE_INSTRUCTION_FACTORY_P3(HAccessArgumentsAt, HValue*, HValue*, HValue*); | |
| 4003 | |
| 4004 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 4005 | |
| 4006 Representation RequiredInputRepresentation(int index) override { | |
| 4007 // The arguments elements is considered tagged. | |
| 4008 return index == 0 | |
| 4009 ? Representation::Tagged() | |
| 4010 : Representation::Integer32(); | |
| 4011 } | |
| 4012 | |
| 4013 HValue* arguments() const { return OperandAt(0); } | |
| 4014 HValue* length() const { return OperandAt(1); } | |
| 4015 HValue* index() const { return OperandAt(2); } | |
| 4016 | |
| 4017 DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt) | |
| 4018 | |
| 4019 private: | |
| 4020 HAccessArgumentsAt(HValue* arguments, HValue* length, HValue* index) { | |
| 4021 set_representation(Representation::Tagged()); | |
| 4022 SetFlag(kUseGVN); | |
| 4023 SetOperandAt(0, arguments); | |
| 4024 SetOperandAt(1, length); | |
| 4025 SetOperandAt(2, index); | |
| 4026 } | |
| 4027 | |
| 4028 bool DataEquals(HValue* other) override { return true; } | |
| 4029 }; | |
| 4030 | |
| 4031 | |
| 4032 class HBoundsCheckBaseIndexInformation; | |
| 4033 | |
| 4034 | |
| 4035 class HBoundsCheck final : public HTemplateInstruction<2> { | |
| 4036 public: | |
| 4037 DECLARE_INSTRUCTION_FACTORY_P2(HBoundsCheck, HValue*, HValue*); | |
| 4038 | |
| 4039 bool skip_check() const { return skip_check_; } | |
| 4040 void set_skip_check() { skip_check_ = true; } | |
| 4041 | |
| 4042 HValue* base() const { return base_; } | |
| 4043 int offset() const { return offset_; } | |
| 4044 int scale() const { return scale_; } | |
| 4045 | |
| 4046 void ApplyIndexChange(); | |
| 4047 bool DetectCompoundIndex() { | |
| 4048 DCHECK(base() == NULL); | |
| 4049 | |
| 4050 DecompositionResult decomposition; | |
| 4051 if (index()->TryDecompose(&decomposition)) { | |
| 4052 base_ = decomposition.base(); | |
| 4053 offset_ = decomposition.offset(); | |
| 4054 scale_ = decomposition.scale(); | |
| 4055 return true; | |
| 4056 } else { | |
| 4057 base_ = index(); | |
| 4058 offset_ = 0; | |
| 4059 scale_ = 0; | |
| 4060 return false; | |
| 4061 } | |
| 4062 } | |
| 4063 | |
| 4064 Representation RequiredInputRepresentation(int index) override { | |
| 4065 return representation(); | |
| 4066 } | |
| 4067 | |
| 4068 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 4069 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override; | |
| 4070 | |
| 4071 HValue* index() const { return OperandAt(0); } | |
| 4072 HValue* length() const { return OperandAt(1); } | |
| 4073 bool allow_equality() const { return allow_equality_; } | |
| 4074 void set_allow_equality(bool v) { allow_equality_ = v; } | |
| 4075 | |
| 4076 int RedefinedOperandIndex() override { return 0; } | |
| 4077 bool IsPurelyInformativeDefinition() override { return skip_check(); } | |
| 4078 | |
| 4079 DECLARE_CONCRETE_INSTRUCTION(BoundsCheck) | |
| 4080 | |
| 4081 protected: | |
| 4082 friend class HBoundsCheckBaseIndexInformation; | |
| 4083 | |
| 4084 Range* InferRange(Zone* zone) override; | |
| 4085 | |
| 4086 bool DataEquals(HValue* other) override { return true; } | |
| 4087 bool skip_check_; | |
| 4088 HValue* base_; | |
| 4089 int offset_; | |
| 4090 int scale_; | |
| 4091 bool allow_equality_; | |
| 4092 | |
| 4093 private: | |
| 4094 // Normally HBoundsCheck should be created using the | |
| 4095 // HGraphBuilder::AddBoundsCheck() helper. | |
| 4096 // However when building stubs, where we know that the arguments are Int32, | |
| 4097 // it makes sense to invoke this constructor directly. | |
| 4098 HBoundsCheck(HValue* index, HValue* length) | |
| 4099 : skip_check_(false), | |
| 4100 base_(NULL), offset_(0), scale_(0), | |
| 4101 allow_equality_(false) { | |
| 4102 SetOperandAt(0, index); | |
| 4103 SetOperandAt(1, length); | |
| 4104 SetFlag(kFlexibleRepresentation); | |
| 4105 SetFlag(kUseGVN); | |
| 4106 } | |
| 4107 | |
| 4108 bool IsDeletable() const override { return skip_check() && !FLAG_debug_code; } | |
| 4109 }; | |
| 4110 | |
| 4111 | |
| 4112 class HBoundsCheckBaseIndexInformation final : public HTemplateInstruction<2> { | |
| 4113 public: | |
| 4114 explicit HBoundsCheckBaseIndexInformation(HBoundsCheck* check) { | |
| 4115 DecompositionResult decomposition; | |
| 4116 if (check->index()->TryDecompose(&decomposition)) { | |
| 4117 SetOperandAt(0, decomposition.base()); | |
| 4118 SetOperandAt(1, check); | |
| 4119 } else { | |
| 4120 UNREACHABLE(); | |
| 4121 } | |
| 4122 } | |
| 4123 | |
| 4124 HValue* base_index() const { return OperandAt(0); } | |
| 4125 HBoundsCheck* bounds_check() { return HBoundsCheck::cast(OperandAt(1)); } | |
| 4126 | |
| 4127 DECLARE_CONCRETE_INSTRUCTION(BoundsCheckBaseIndexInformation) | |
| 4128 | |
| 4129 Representation RequiredInputRepresentation(int index) override { | |
| 4130 return representation(); | |
| 4131 } | |
| 4132 | |
| 4133 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 4134 | |
| 4135 int RedefinedOperandIndex() override { return 0; } | |
| 4136 bool IsPurelyInformativeDefinition() override { return true; } | |
| 4137 }; | |
| 4138 | |
| 4139 | |
| 4140 class HBitwiseBinaryOperation : public HBinaryOperation { | |
| 4141 public: | |
| 4142 HBitwiseBinaryOperation(HValue* context, HValue* left, HValue* right, | |
| 4143 Strength strength, HType type = HType::TaggedNumber()) | |
| 4144 : HBinaryOperation(context, left, right, strength, type) { | |
| 4145 SetFlag(kFlexibleRepresentation); | |
| 4146 SetFlag(kTruncatingToInt32); | |
| 4147 if (!is_strong(strength)) SetFlag(kAllowUndefinedAsNaN); | |
| 4148 SetAllSideEffects(); | |
| 4149 } | |
| 4150 | |
| 4151 void RepresentationChanged(Representation to) override { | |
| 4152 if (to.IsTagged() && | |
| 4153 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) { | |
| 4154 SetAllSideEffects(); | |
| 4155 ClearFlag(kUseGVN); | |
| 4156 } else { | |
| 4157 ClearAllSideEffects(); | |
| 4158 SetFlag(kUseGVN); | |
| 4159 } | |
| 4160 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion); | |
| 4161 } | |
| 4162 | |
| 4163 virtual void UpdateRepresentation(Representation new_rep, | |
| 4164 HInferRepresentationPhase* h_infer, | |
| 4165 const char* reason) override { | |
| 4166 // We only generate either int32 or generic tagged bitwise operations. | |
| 4167 if (new_rep.IsDouble()) new_rep = Representation::Integer32(); | |
| 4168 HBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); | |
| 4169 } | |
| 4170 | |
| 4171 Representation observed_input_representation(int index) override { | |
| 4172 Representation r = HBinaryOperation::observed_input_representation(index); | |
| 4173 if (r.IsDouble()) return Representation::Integer32(); | |
| 4174 return r; | |
| 4175 } | |
| 4176 | |
| 4177 virtual void initialize_output_representation( | |
| 4178 Representation observed) override { | |
| 4179 if (observed.IsDouble()) observed = Representation::Integer32(); | |
| 4180 HBinaryOperation::initialize_output_representation(observed); | |
| 4181 } | |
| 4182 | |
| 4183 DECLARE_ABSTRACT_INSTRUCTION(BitwiseBinaryOperation) | |
| 4184 | |
| 4185 private: | |
| 4186 bool IsDeletable() const override { return true; } | |
| 4187 }; | |
| 4188 | |
| 4189 | |
| 4190 class HMathFloorOfDiv final : public HBinaryOperation { | |
| 4191 public: | |
| 4192 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HMathFloorOfDiv, | |
| 4193 HValue*, | |
| 4194 HValue*); | |
| 4195 | |
| 4196 DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv) | |
| 4197 | |
| 4198 protected: | |
| 4199 bool DataEquals(HValue* other) override { return true; } | |
| 4200 | |
| 4201 private: | |
| 4202 HMathFloorOfDiv(HValue* context, HValue* left, HValue* right) | |
| 4203 : HBinaryOperation(context, left, right, Strength::WEAK) { | |
| 4204 set_representation(Representation::Integer32()); | |
| 4205 SetFlag(kUseGVN); | |
| 4206 SetFlag(kCanOverflow); | |
| 4207 SetFlag(kCanBeDivByZero); | |
| 4208 SetFlag(kLeftCanBeMinInt); | |
| 4209 SetFlag(kLeftCanBeNegative); | |
| 4210 SetFlag(kLeftCanBePositive); | |
| 4211 SetFlag(kAllowUndefinedAsNaN); | |
| 4212 } | |
| 4213 | |
| 4214 Range* InferRange(Zone* zone) override; | |
| 4215 | |
| 4216 bool IsDeletable() const override { return true; } | |
| 4217 }; | |
| 4218 | |
| 4219 | |
| 4220 class HArithmeticBinaryOperation : public HBinaryOperation { | |
| 4221 public: | |
| 4222 HArithmeticBinaryOperation(HValue* context, HValue* left, HValue* right, | |
| 4223 Strength strength) | |
| 4224 : HBinaryOperation(context, left, right, strength, | |
| 4225 HType::TaggedNumber()) { | |
| 4226 SetAllSideEffects(); | |
| 4227 SetFlag(kFlexibleRepresentation); | |
| 4228 if (!is_strong(strength)) SetFlag(kAllowUndefinedAsNaN); | |
| 4229 } | |
| 4230 | |
| 4231 void RepresentationChanged(Representation to) override { | |
| 4232 if (to.IsTagged() && | |
| 4233 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) { | |
| 4234 SetAllSideEffects(); | |
| 4235 ClearFlag(kUseGVN); | |
| 4236 } else { | |
| 4237 ClearAllSideEffects(); | |
| 4238 SetFlag(kUseGVN); | |
| 4239 } | |
| 4240 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion); | |
| 4241 } | |
| 4242 | |
| 4243 DECLARE_ABSTRACT_INSTRUCTION(ArithmeticBinaryOperation) | |
| 4244 | |
| 4245 private: | |
| 4246 bool IsDeletable() const override { return true; } | |
| 4247 }; | |
| 4248 | |
| 4249 | |
| 4250 class HCompareGeneric final : public HBinaryOperation { | |
| 4251 public: | |
| 4252 static HCompareGeneric* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 4253 HValue* left, HValue* right, Token::Value token, | |
| 4254 Strength strength = Strength::WEAK) { | |
| 4255 return new (zone) HCompareGeneric(context, left, right, token, strength); | |
| 4256 } | |
| 4257 | |
| 4258 Representation RequiredInputRepresentation(int index) override { | |
| 4259 return index == 0 | |
| 4260 ? Representation::Tagged() | |
| 4261 : representation(); | |
| 4262 } | |
| 4263 | |
| 4264 Token::Value token() const { return token_; } | |
| 4265 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 4266 | |
| 4267 DECLARE_CONCRETE_INSTRUCTION(CompareGeneric) | |
| 4268 | |
| 4269 private: | |
| 4270 HCompareGeneric(HValue* context, HValue* left, HValue* right, | |
| 4271 Token::Value token, Strength strength) | |
| 4272 : HBinaryOperation(context, left, right, strength, HType::Boolean()), | |
| 4273 token_(token) { | |
| 4274 DCHECK(Token::IsCompareOp(token)); | |
| 4275 set_representation(Representation::Tagged()); | |
| 4276 SetAllSideEffects(); | |
| 4277 } | |
| 4278 | |
| 4279 Token::Value token_; | |
| 4280 }; | |
| 4281 | |
| 4282 | |
| 4283 class HCompareNumericAndBranch : public HTemplateControlInstruction<2, 2> { | |
| 4284 public: | |
| 4285 static HCompareNumericAndBranch* New(Isolate* isolate, Zone* zone, | |
| 4286 HValue* context, HValue* left, | |
| 4287 HValue* right, Token::Value token, | |
| 4288 HBasicBlock* true_target = NULL, | |
| 4289 HBasicBlock* false_target = NULL, | |
| 4290 Strength strength = Strength::WEAK) { | |
| 4291 return new (zone) HCompareNumericAndBranch(left, right, token, true_target, | |
| 4292 false_target, strength); | |
| 4293 } | |
| 4294 static HCompareNumericAndBranch* New(Isolate* isolate, Zone* zone, | |
| 4295 HValue* context, HValue* left, | |
| 4296 HValue* right, Token::Value token, | |
| 4297 Strength strength) { | |
| 4298 return new (zone) | |
| 4299 HCompareNumericAndBranch(left, right, token, NULL, NULL, strength); | |
| 4300 } | |
| 4301 | |
| 4302 HValue* left() const { return OperandAt(0); } | |
| 4303 HValue* right() const { return OperandAt(1); } | |
| 4304 Token::Value token() const { return token_; } | |
| 4305 | |
| 4306 void set_observed_input_representation(Representation left, | |
| 4307 Representation right) { | |
| 4308 observed_input_representation_[0] = left; | |
| 4309 observed_input_representation_[1] = right; | |
| 4310 } | |
| 4311 | |
| 4312 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override; | |
| 4313 | |
| 4314 Representation RequiredInputRepresentation(int index) override { | |
| 4315 return representation(); | |
| 4316 } | |
| 4317 Representation observed_input_representation(int index) override { | |
| 4318 return observed_input_representation_[index]; | |
| 4319 } | |
| 4320 | |
| 4321 bool KnownSuccessorBlock(HBasicBlock** block) override; | |
| 4322 | |
| 4323 Strength strength() const { return strength_; } | |
| 4324 | |
| 4325 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 4326 | |
| 4327 void SetOperandPositions(Zone* zone, SourcePosition left_pos, | |
| 4328 SourcePosition right_pos) { | |
| 4329 set_operand_position(zone, 0, left_pos); | |
| 4330 set_operand_position(zone, 1, right_pos); | |
| 4331 } | |
| 4332 | |
| 4333 DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch) | |
| 4334 | |
| 4335 private: | |
| 4336 HCompareNumericAndBranch(HValue* left, HValue* right, Token::Value token, | |
| 4337 HBasicBlock* true_target, HBasicBlock* false_target, | |
| 4338 Strength strength) | |
| 4339 : token_(token), strength_(strength) { | |
| 4340 SetFlag(kFlexibleRepresentation); | |
| 4341 DCHECK(Token::IsCompareOp(token)); | |
| 4342 SetOperandAt(0, left); | |
| 4343 SetOperandAt(1, right); | |
| 4344 SetSuccessorAt(0, true_target); | |
| 4345 SetSuccessorAt(1, false_target); | |
| 4346 } | |
| 4347 | |
| 4348 Representation observed_input_representation_[2]; | |
| 4349 Token::Value token_; | |
| 4350 Strength strength_; | |
| 4351 }; | |
| 4352 | |
| 4353 | |
| 4354 class HCompareHoleAndBranch final : public HUnaryControlInstruction { | |
| 4355 public: | |
| 4356 DECLARE_INSTRUCTION_FACTORY_P1(HCompareHoleAndBranch, HValue*); | |
| 4357 DECLARE_INSTRUCTION_FACTORY_P3(HCompareHoleAndBranch, HValue*, | |
| 4358 HBasicBlock*, HBasicBlock*); | |
| 4359 | |
| 4360 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override; | |
| 4361 | |
| 4362 Representation RequiredInputRepresentation(int index) override { | |
| 4363 return representation(); | |
| 4364 } | |
| 4365 | |
| 4366 DECLARE_CONCRETE_INSTRUCTION(CompareHoleAndBranch) | |
| 4367 | |
| 4368 private: | |
| 4369 HCompareHoleAndBranch(HValue* value, | |
| 4370 HBasicBlock* true_target = NULL, | |
| 4371 HBasicBlock* false_target = NULL) | |
| 4372 : HUnaryControlInstruction(value, true_target, false_target) { | |
| 4373 SetFlag(kFlexibleRepresentation); | |
| 4374 SetFlag(kAllowUndefinedAsNaN); | |
| 4375 } | |
| 4376 }; | |
| 4377 | |
| 4378 | |
| 4379 class HCompareMinusZeroAndBranch final : public HUnaryControlInstruction { | |
| 4380 public: | |
| 4381 DECLARE_INSTRUCTION_FACTORY_P1(HCompareMinusZeroAndBranch, HValue*); | |
| 4382 | |
| 4383 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override; | |
| 4384 | |
| 4385 Representation RequiredInputRepresentation(int index) override { | |
| 4386 return representation(); | |
| 4387 } | |
| 4388 | |
| 4389 bool KnownSuccessorBlock(HBasicBlock** block) override; | |
| 4390 | |
| 4391 DECLARE_CONCRETE_INSTRUCTION(CompareMinusZeroAndBranch) | |
| 4392 | |
| 4393 private: | |
| 4394 explicit HCompareMinusZeroAndBranch(HValue* value) | |
| 4395 : HUnaryControlInstruction(value, NULL, NULL) { | |
| 4396 } | |
| 4397 }; | |
| 4398 | |
| 4399 | |
| 4400 class HCompareObjectEqAndBranch : public HTemplateControlInstruction<2, 2> { | |
| 4401 public: | |
| 4402 DECLARE_INSTRUCTION_FACTORY_P2(HCompareObjectEqAndBranch, HValue*, HValue*); | |
| 4403 DECLARE_INSTRUCTION_FACTORY_P4(HCompareObjectEqAndBranch, HValue*, HValue*, | |
| 4404 HBasicBlock*, HBasicBlock*); | |
| 4405 | |
| 4406 bool KnownSuccessorBlock(HBasicBlock** block) override; | |
| 4407 | |
| 4408 static const int kNoKnownSuccessorIndex = -1; | |
| 4409 int known_successor_index() const { return known_successor_index_; } | |
| 4410 void set_known_successor_index(int known_successor_index) { | |
| 4411 known_successor_index_ = known_successor_index; | |
| 4412 } | |
| 4413 | |
| 4414 HValue* left() const { return OperandAt(0); } | |
| 4415 HValue* right() const { return OperandAt(1); } | |
| 4416 | |
| 4417 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 4418 | |
| 4419 Representation RequiredInputRepresentation(int index) override { | |
| 4420 return Representation::Tagged(); | |
| 4421 } | |
| 4422 | |
| 4423 Representation observed_input_representation(int index) override { | |
| 4424 return Representation::Tagged(); | |
| 4425 } | |
| 4426 | |
| 4427 DECLARE_CONCRETE_INSTRUCTION(CompareObjectEqAndBranch) | |
| 4428 | |
| 4429 private: | |
| 4430 HCompareObjectEqAndBranch(HValue* left, | |
| 4431 HValue* right, | |
| 4432 HBasicBlock* true_target = NULL, | |
| 4433 HBasicBlock* false_target = NULL) | |
| 4434 : known_successor_index_(kNoKnownSuccessorIndex) { | |
| 4435 SetOperandAt(0, left); | |
| 4436 SetOperandAt(1, right); | |
| 4437 SetSuccessorAt(0, true_target); | |
| 4438 SetSuccessorAt(1, false_target); | |
| 4439 } | |
| 4440 | |
| 4441 int known_successor_index_; | |
| 4442 }; | |
| 4443 | |
| 4444 | |
| 4445 class HIsStringAndBranch final : public HUnaryControlInstruction { | |
| 4446 public: | |
| 4447 DECLARE_INSTRUCTION_FACTORY_P1(HIsStringAndBranch, HValue*); | |
| 4448 DECLARE_INSTRUCTION_FACTORY_P3(HIsStringAndBranch, HValue*, | |
| 4449 HBasicBlock*, HBasicBlock*); | |
| 4450 | |
| 4451 Representation RequiredInputRepresentation(int index) override { | |
| 4452 return Representation::Tagged(); | |
| 4453 } | |
| 4454 | |
| 4455 bool KnownSuccessorBlock(HBasicBlock** block) override; | |
| 4456 | |
| 4457 static const int kNoKnownSuccessorIndex = -1; | |
| 4458 int known_successor_index() const { return known_successor_index_; } | |
| 4459 void set_known_successor_index(int known_successor_index) { | |
| 4460 known_successor_index_ = known_successor_index; | |
| 4461 } | |
| 4462 | |
| 4463 DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch) | |
| 4464 | |
| 4465 protected: | |
| 4466 int RedefinedOperandIndex() override { return 0; } | |
| 4467 | |
| 4468 private: | |
| 4469 HIsStringAndBranch(HValue* value, HBasicBlock* true_target = NULL, | |
| 4470 HBasicBlock* false_target = NULL) | |
| 4471 : HUnaryControlInstruction(value, true_target, false_target), | |
| 4472 known_successor_index_(kNoKnownSuccessorIndex) { | |
| 4473 set_representation(Representation::Tagged()); | |
| 4474 } | |
| 4475 | |
| 4476 int known_successor_index_; | |
| 4477 }; | |
| 4478 | |
| 4479 | |
| 4480 class HIsSmiAndBranch final : public HUnaryControlInstruction { | |
| 4481 public: | |
| 4482 DECLARE_INSTRUCTION_FACTORY_P1(HIsSmiAndBranch, HValue*); | |
| 4483 DECLARE_INSTRUCTION_FACTORY_P3(HIsSmiAndBranch, HValue*, | |
| 4484 HBasicBlock*, HBasicBlock*); | |
| 4485 | |
| 4486 DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch) | |
| 4487 | |
| 4488 Representation RequiredInputRepresentation(int index) override { | |
| 4489 return Representation::Tagged(); | |
| 4490 } | |
| 4491 | |
| 4492 protected: | |
| 4493 bool DataEquals(HValue* other) override { return true; } | |
| 4494 int RedefinedOperandIndex() override { return 0; } | |
| 4495 | |
| 4496 private: | |
| 4497 HIsSmiAndBranch(HValue* value, | |
| 4498 HBasicBlock* true_target = NULL, | |
| 4499 HBasicBlock* false_target = NULL) | |
| 4500 : HUnaryControlInstruction(value, true_target, false_target) { | |
| 4501 set_representation(Representation::Tagged()); | |
| 4502 } | |
| 4503 }; | |
| 4504 | |
| 4505 | |
| 4506 class HIsUndetectableAndBranch final : public HUnaryControlInstruction { | |
| 4507 public: | |
| 4508 DECLARE_INSTRUCTION_FACTORY_P1(HIsUndetectableAndBranch, HValue*); | |
| 4509 DECLARE_INSTRUCTION_FACTORY_P3(HIsUndetectableAndBranch, HValue*, | |
| 4510 HBasicBlock*, HBasicBlock*); | |
| 4511 | |
| 4512 Representation RequiredInputRepresentation(int index) override { | |
| 4513 return Representation::Tagged(); | |
| 4514 } | |
| 4515 | |
| 4516 bool KnownSuccessorBlock(HBasicBlock** block) override; | |
| 4517 | |
| 4518 DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch) | |
| 4519 | |
| 4520 private: | |
| 4521 HIsUndetectableAndBranch(HValue* value, | |
| 4522 HBasicBlock* true_target = NULL, | |
| 4523 HBasicBlock* false_target = NULL) | |
| 4524 : HUnaryControlInstruction(value, true_target, false_target) {} | |
| 4525 }; | |
| 4526 | |
| 4527 | |
| 4528 class HStringCompareAndBranch final : public HTemplateControlInstruction<2, 3> { | |
| 4529 public: | |
| 4530 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HStringCompareAndBranch, | |
| 4531 HValue*, | |
| 4532 HValue*, | |
| 4533 Token::Value); | |
| 4534 | |
| 4535 HValue* context() const { return OperandAt(0); } | |
| 4536 HValue* left() const { return OperandAt(1); } | |
| 4537 HValue* right() const { return OperandAt(2); } | |
| 4538 Token::Value token() const { return token_; } | |
| 4539 | |
| 4540 std::ostream& PrintDataTo(std::ostream& os) const final; // NOLINT | |
| 4541 | |
| 4542 Representation RequiredInputRepresentation(int index) final { | |
| 4543 return Representation::Tagged(); | |
| 4544 } | |
| 4545 | |
| 4546 DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch) | |
| 4547 | |
| 4548 private: | |
| 4549 HStringCompareAndBranch(HValue* context, HValue* left, HValue* right, | |
| 4550 Token::Value token) | |
| 4551 : token_(token) { | |
| 4552 DCHECK(Token::IsCompareOp(token)); | |
| 4553 SetOperandAt(0, context); | |
| 4554 SetOperandAt(1, left); | |
| 4555 SetOperandAt(2, right); | |
| 4556 set_representation(Representation::Tagged()); | |
| 4557 SetChangesFlag(kNewSpacePromotion); | |
| 4558 SetDependsOnFlag(kStringChars); | |
| 4559 SetDependsOnFlag(kStringLengths); | |
| 4560 } | |
| 4561 | |
| 4562 Token::Value const token_; | |
| 4563 }; | |
| 4564 | |
| 4565 | |
| 4566 class HIsConstructCallAndBranch : public HTemplateControlInstruction<2, 0> { | |
| 4567 public: | |
| 4568 DECLARE_INSTRUCTION_FACTORY_P0(HIsConstructCallAndBranch); | |
| 4569 | |
| 4570 Representation RequiredInputRepresentation(int index) override { | |
| 4571 return Representation::None(); | |
| 4572 } | |
| 4573 | |
| 4574 DECLARE_CONCRETE_INSTRUCTION(IsConstructCallAndBranch) | |
| 4575 private: | |
| 4576 HIsConstructCallAndBranch() {} | |
| 4577 }; | |
| 4578 | |
| 4579 | |
| 4580 class HHasInstanceTypeAndBranch final : public HUnaryControlInstruction { | |
| 4581 public: | |
| 4582 DECLARE_INSTRUCTION_FACTORY_P2( | |
| 4583 HHasInstanceTypeAndBranch, HValue*, InstanceType); | |
| 4584 DECLARE_INSTRUCTION_FACTORY_P3( | |
| 4585 HHasInstanceTypeAndBranch, HValue*, InstanceType, InstanceType); | |
| 4586 | |
| 4587 InstanceType from() { return from_; } | |
| 4588 InstanceType to() { return to_; } | |
| 4589 | |
| 4590 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 4591 | |
| 4592 Representation RequiredInputRepresentation(int index) override { | |
| 4593 return Representation::Tagged(); | |
| 4594 } | |
| 4595 | |
| 4596 bool KnownSuccessorBlock(HBasicBlock** block) override; | |
| 4597 | |
| 4598 DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch) | |
| 4599 | |
| 4600 private: | |
| 4601 HHasInstanceTypeAndBranch(HValue* value, InstanceType type) | |
| 4602 : HUnaryControlInstruction(value, NULL, NULL), from_(type), to_(type) { } | |
| 4603 HHasInstanceTypeAndBranch(HValue* value, InstanceType from, InstanceType to) | |
| 4604 : HUnaryControlInstruction(value, NULL, NULL), from_(from), to_(to) { | |
| 4605 DCHECK(to == LAST_TYPE); // Others not implemented yet in backend. | |
| 4606 } | |
| 4607 | |
| 4608 InstanceType from_; | |
| 4609 InstanceType to_; // Inclusive range, not all combinations work. | |
| 4610 }; | |
| 4611 | |
| 4612 | |
| 4613 class HHasCachedArrayIndexAndBranch final : public HUnaryControlInstruction { | |
| 4614 public: | |
| 4615 DECLARE_INSTRUCTION_FACTORY_P1(HHasCachedArrayIndexAndBranch, HValue*); | |
| 4616 | |
| 4617 Representation RequiredInputRepresentation(int index) override { | |
| 4618 return Representation::Tagged(); | |
| 4619 } | |
| 4620 | |
| 4621 DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch) | |
| 4622 private: | |
| 4623 explicit HHasCachedArrayIndexAndBranch(HValue* value) | |
| 4624 : HUnaryControlInstruction(value, NULL, NULL) { } | |
| 4625 }; | |
| 4626 | |
| 4627 | |
| 4628 class HGetCachedArrayIndex final : public HUnaryOperation { | |
| 4629 public: | |
| 4630 DECLARE_INSTRUCTION_FACTORY_P1(HGetCachedArrayIndex, HValue*); | |
| 4631 | |
| 4632 Representation RequiredInputRepresentation(int index) override { | |
| 4633 return Representation::Tagged(); | |
| 4634 } | |
| 4635 | |
| 4636 DECLARE_CONCRETE_INSTRUCTION(GetCachedArrayIndex) | |
| 4637 | |
| 4638 protected: | |
| 4639 bool DataEquals(HValue* other) override { return true; } | |
| 4640 | |
| 4641 private: | |
| 4642 explicit HGetCachedArrayIndex(HValue* value) : HUnaryOperation(value) { | |
| 4643 set_representation(Representation::Tagged()); | |
| 4644 SetFlag(kUseGVN); | |
| 4645 } | |
| 4646 | |
| 4647 bool IsDeletable() const override { return true; } | |
| 4648 }; | |
| 4649 | |
| 4650 | |
| 4651 class HClassOfTestAndBranch final : public HUnaryControlInstruction { | |
| 4652 public: | |
| 4653 DECLARE_INSTRUCTION_FACTORY_P2(HClassOfTestAndBranch, HValue*, | |
| 4654 Handle<String>); | |
| 4655 | |
| 4656 DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch) | |
| 4657 | |
| 4658 Representation RequiredInputRepresentation(int index) override { | |
| 4659 return Representation::Tagged(); | |
| 4660 } | |
| 4661 | |
| 4662 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 4663 | |
| 4664 Handle<String> class_name() const { return class_name_; } | |
| 4665 | |
| 4666 private: | |
| 4667 HClassOfTestAndBranch(HValue* value, Handle<String> class_name) | |
| 4668 : HUnaryControlInstruction(value, NULL, NULL), | |
| 4669 class_name_(class_name) { } | |
| 4670 | |
| 4671 Handle<String> class_name_; | |
| 4672 }; | |
| 4673 | |
| 4674 | |
| 4675 class HTypeofIsAndBranch final : public HUnaryControlInstruction { | |
| 4676 public: | |
| 4677 DECLARE_INSTRUCTION_FACTORY_P2(HTypeofIsAndBranch, HValue*, Handle<String>); | |
| 4678 | |
| 4679 Handle<String> type_literal() const { return type_literal_.handle(); } | |
| 4680 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 4681 | |
| 4682 DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch) | |
| 4683 | |
| 4684 Representation RequiredInputRepresentation(int index) override { | |
| 4685 return Representation::None(); | |
| 4686 } | |
| 4687 | |
| 4688 bool KnownSuccessorBlock(HBasicBlock** block) override; | |
| 4689 | |
| 4690 void FinalizeUniqueness() override { | |
| 4691 type_literal_ = Unique<String>(type_literal_.handle()); | |
| 4692 } | |
| 4693 | |
| 4694 private: | |
| 4695 HTypeofIsAndBranch(HValue* value, Handle<String> type_literal) | |
| 4696 : HUnaryControlInstruction(value, NULL, NULL), | |
| 4697 type_literal_(Unique<String>::CreateUninitialized(type_literal)) { } | |
| 4698 | |
| 4699 Unique<String> type_literal_; | |
| 4700 }; | |
| 4701 | |
| 4702 | |
| 4703 class HInstanceOf final : public HBinaryOperation { | |
| 4704 public: | |
| 4705 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInstanceOf, HValue*, HValue*); | |
| 4706 | |
| 4707 Representation RequiredInputRepresentation(int index) override { | |
| 4708 return Representation::Tagged(); | |
| 4709 } | |
| 4710 | |
| 4711 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 4712 | |
| 4713 DECLARE_CONCRETE_INSTRUCTION(InstanceOf) | |
| 4714 | |
| 4715 private: | |
| 4716 HInstanceOf(HValue* context, HValue* left, HValue* right) | |
| 4717 : HBinaryOperation(context, left, right, Strength::WEAK, | |
| 4718 HType::Boolean()) { | |
| 4719 set_representation(Representation::Tagged()); | |
| 4720 SetAllSideEffects(); | |
| 4721 } | |
| 4722 }; | |
| 4723 | |
| 4724 | |
| 4725 class HHasInPrototypeChainAndBranch final | |
| 4726 : public HTemplateControlInstruction<2, 2> { | |
| 4727 public: | |
| 4728 DECLARE_INSTRUCTION_FACTORY_P2(HHasInPrototypeChainAndBranch, HValue*, | |
| 4729 HValue*); | |
| 4730 | |
| 4731 HValue* object() const { return OperandAt(0); } | |
| 4732 HValue* prototype() const { return OperandAt(1); } | |
| 4733 | |
| 4734 Representation RequiredInputRepresentation(int index) override { | |
| 4735 return Representation::Tagged(); | |
| 4736 } | |
| 4737 | |
| 4738 bool ObjectNeedsSmiCheck() const { | |
| 4739 return !object()->type().IsHeapObject() && | |
| 4740 !object()->representation().IsHeapObject(); | |
| 4741 } | |
| 4742 | |
| 4743 DECLARE_CONCRETE_INSTRUCTION(HasInPrototypeChainAndBranch) | |
| 4744 | |
| 4745 private: | |
| 4746 HHasInPrototypeChainAndBranch(HValue* object, HValue* prototype) { | |
| 4747 SetOperandAt(0, object); | |
| 4748 SetOperandAt(1, prototype); | |
| 4749 SetDependsOnFlag(kCalls); | |
| 4750 } | |
| 4751 }; | |
| 4752 | |
| 4753 | |
| 4754 class HPower final : public HTemplateInstruction<2> { | |
| 4755 public: | |
| 4756 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 4757 HValue* left, HValue* right); | |
| 4758 | |
| 4759 HValue* left() { return OperandAt(0); } | |
| 4760 HValue* right() const { return OperandAt(1); } | |
| 4761 | |
| 4762 Representation RequiredInputRepresentation(int index) override { | |
| 4763 return index == 0 | |
| 4764 ? Representation::Double() | |
| 4765 : Representation::None(); | |
| 4766 } | |
| 4767 Representation observed_input_representation(int index) override { | |
| 4768 return RequiredInputRepresentation(index); | |
| 4769 } | |
| 4770 | |
| 4771 DECLARE_CONCRETE_INSTRUCTION(Power) | |
| 4772 | |
| 4773 protected: | |
| 4774 bool DataEquals(HValue* other) override { return true; } | |
| 4775 | |
| 4776 private: | |
| 4777 HPower(HValue* left, HValue* right) { | |
| 4778 SetOperandAt(0, left); | |
| 4779 SetOperandAt(1, right); | |
| 4780 set_representation(Representation::Double()); | |
| 4781 SetFlag(kUseGVN); | |
| 4782 SetChangesFlag(kNewSpacePromotion); | |
| 4783 } | |
| 4784 | |
| 4785 bool IsDeletable() const override { | |
| 4786 return !right()->representation().IsTagged(); | |
| 4787 } | |
| 4788 }; | |
| 4789 | |
| 4790 | |
| 4791 enum ExternalAddType { | |
| 4792 AddOfExternalAndTagged, | |
| 4793 AddOfExternalAndInt32, | |
| 4794 NoExternalAdd | |
| 4795 }; | |
| 4796 | |
| 4797 | |
| 4798 class HAdd final : public HArithmeticBinaryOperation { | |
| 4799 public: | |
| 4800 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 4801 HValue* left, HValue* right, | |
| 4802 Strength strength = Strength::WEAK); | |
| 4803 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 4804 HValue* left, HValue* right, Strength strength, | |
| 4805 ExternalAddType external_add_type); | |
| 4806 | |
| 4807 // Add is only commutative if two integer values are added and not if two | |
| 4808 // tagged values are added (because it might be a String concatenation). | |
| 4809 // We also do not commute (pointer + offset). | |
| 4810 bool IsCommutative() const override { | |
| 4811 return !representation().IsTagged() && !representation().IsExternal(); | |
| 4812 } | |
| 4813 | |
| 4814 HValue* Canonicalize() override; | |
| 4815 | |
| 4816 bool TryDecompose(DecompositionResult* decomposition) override { | |
| 4817 if (left()->IsInteger32Constant()) { | |
| 4818 decomposition->Apply(right(), left()->GetInteger32Constant()); | |
| 4819 return true; | |
| 4820 } else if (right()->IsInteger32Constant()) { | |
| 4821 decomposition->Apply(left(), right()->GetInteger32Constant()); | |
| 4822 return true; | |
| 4823 } else { | |
| 4824 return false; | |
| 4825 } | |
| 4826 } | |
| 4827 | |
| 4828 void RepresentationChanged(Representation to) override { | |
| 4829 if (to.IsTagged() && | |
| 4830 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved() || | |
| 4831 left()->ToStringCanBeObserved() || right()->ToStringCanBeObserved())) { | |
| 4832 SetAllSideEffects(); | |
| 4833 ClearFlag(kUseGVN); | |
| 4834 } else { | |
| 4835 ClearAllSideEffects(); | |
| 4836 SetFlag(kUseGVN); | |
| 4837 } | |
| 4838 if (to.IsTagged()) { | |
| 4839 SetChangesFlag(kNewSpacePromotion); | |
| 4840 ClearFlag(kAllowUndefinedAsNaN); | |
| 4841 } | |
| 4842 } | |
| 4843 | |
| 4844 Representation RepresentationFromInputs() override; | |
| 4845 | |
| 4846 Representation RequiredInputRepresentation(int index) override; | |
| 4847 | |
| 4848 bool IsConsistentExternalRepresentation() { | |
| 4849 return left()->representation().IsExternal() && | |
| 4850 ((external_add_type_ == AddOfExternalAndInt32 && | |
| 4851 right()->representation().IsInteger32()) || | |
| 4852 (external_add_type_ == AddOfExternalAndTagged && | |
| 4853 right()->representation().IsTagged())); | |
| 4854 } | |
| 4855 | |
| 4856 ExternalAddType external_add_type() const { return external_add_type_; } | |
| 4857 | |
| 4858 DECLARE_CONCRETE_INSTRUCTION(Add) | |
| 4859 | |
| 4860 protected: | |
| 4861 bool DataEquals(HValue* other) override { return true; } | |
| 4862 | |
| 4863 Range* InferRange(Zone* zone) override; | |
| 4864 | |
| 4865 private: | |
| 4866 HAdd(HValue* context, HValue* left, HValue* right, Strength strength, | |
| 4867 ExternalAddType external_add_type = NoExternalAdd) | |
| 4868 : HArithmeticBinaryOperation(context, left, right, strength), | |
| 4869 external_add_type_(external_add_type) { | |
| 4870 SetFlag(kCanOverflow); | |
| 4871 switch (external_add_type_) { | |
| 4872 case AddOfExternalAndTagged: | |
| 4873 DCHECK(left->representation().IsExternal()); | |
| 4874 DCHECK(right->representation().IsTagged()); | |
| 4875 SetDependsOnFlag(kNewSpacePromotion); | |
| 4876 ClearFlag(HValue::kCanOverflow); | |
| 4877 SetFlag(kHasNoObservableSideEffects); | |
| 4878 break; | |
| 4879 | |
| 4880 case NoExternalAdd: | |
| 4881 // This is a bit of a hack: The call to this constructor is generated | |
| 4882 // by a macro that also supports sub and mul, so it doesn't pass in | |
| 4883 // a value for external_add_type but uses the default. | |
| 4884 if (left->representation().IsExternal()) { | |
| 4885 external_add_type_ = AddOfExternalAndInt32; | |
| 4886 } | |
| 4887 break; | |
| 4888 | |
| 4889 case AddOfExternalAndInt32: | |
| 4890 // See comment above. | |
| 4891 UNREACHABLE(); | |
| 4892 break; | |
| 4893 } | |
| 4894 } | |
| 4895 | |
| 4896 ExternalAddType external_add_type_; | |
| 4897 }; | |
| 4898 | |
| 4899 | |
| 4900 class HSub final : public HArithmeticBinaryOperation { | |
| 4901 public: | |
| 4902 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 4903 HValue* left, HValue* right, | |
| 4904 Strength strength = Strength::WEAK); | |
| 4905 | |
| 4906 HValue* Canonicalize() override; | |
| 4907 | |
| 4908 bool TryDecompose(DecompositionResult* decomposition) override { | |
| 4909 if (right()->IsInteger32Constant()) { | |
| 4910 decomposition->Apply(left(), -right()->GetInteger32Constant()); | |
| 4911 return true; | |
| 4912 } else { | |
| 4913 return false; | |
| 4914 } | |
| 4915 } | |
| 4916 | |
| 4917 DECLARE_CONCRETE_INSTRUCTION(Sub) | |
| 4918 | |
| 4919 protected: | |
| 4920 bool DataEquals(HValue* other) override { return true; } | |
| 4921 | |
| 4922 Range* InferRange(Zone* zone) override; | |
| 4923 | |
| 4924 private: | |
| 4925 HSub(HValue* context, HValue* left, HValue* right, Strength strength) | |
| 4926 : HArithmeticBinaryOperation(context, left, right, strength) { | |
| 4927 SetFlag(kCanOverflow); | |
| 4928 } | |
| 4929 }; | |
| 4930 | |
| 4931 | |
| 4932 class HMul final : public HArithmeticBinaryOperation { | |
| 4933 public: | |
| 4934 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 4935 HValue* left, HValue* right, | |
| 4936 Strength strength = Strength::WEAK); | |
| 4937 | |
| 4938 static HInstruction* NewImul(Isolate* isolate, Zone* zone, HValue* context, | |
| 4939 HValue* left, HValue* right, | |
| 4940 Strength strength = Strength::WEAK) { | |
| 4941 HInstruction* instr = | |
| 4942 HMul::New(isolate, zone, context, left, right, strength); | |
| 4943 if (!instr->IsMul()) return instr; | |
| 4944 HMul* mul = HMul::cast(instr); | |
| 4945 // TODO(mstarzinger): Prevent bailout on minus zero for imul. | |
| 4946 mul->AssumeRepresentation(Representation::Integer32()); | |
| 4947 mul->ClearFlag(HValue::kCanOverflow); | |
| 4948 return mul; | |
| 4949 } | |
| 4950 | |
| 4951 HValue* Canonicalize() override; | |
| 4952 | |
| 4953 // Only commutative if it is certain that not two objects are multiplicated. | |
| 4954 bool IsCommutative() const override { return !representation().IsTagged(); } | |
| 4955 | |
| 4956 virtual void UpdateRepresentation(Representation new_rep, | |
| 4957 HInferRepresentationPhase* h_infer, | |
| 4958 const char* reason) override { | |
| 4959 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); | |
| 4960 } | |
| 4961 | |
| 4962 bool MulMinusOne(); | |
| 4963 | |
| 4964 DECLARE_CONCRETE_INSTRUCTION(Mul) | |
| 4965 | |
| 4966 protected: | |
| 4967 bool DataEquals(HValue* other) override { return true; } | |
| 4968 | |
| 4969 Range* InferRange(Zone* zone) override; | |
| 4970 | |
| 4971 private: | |
| 4972 HMul(HValue* context, HValue* left, HValue* right, Strength strength) | |
| 4973 : HArithmeticBinaryOperation(context, left, right, strength) { | |
| 4974 SetFlag(kCanOverflow); | |
| 4975 } | |
| 4976 }; | |
| 4977 | |
| 4978 | |
| 4979 class HMod final : public HArithmeticBinaryOperation { | |
| 4980 public: | |
| 4981 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 4982 HValue* left, HValue* right, | |
| 4983 Strength strength = Strength::WEAK); | |
| 4984 | |
| 4985 HValue* Canonicalize() override; | |
| 4986 | |
| 4987 virtual void UpdateRepresentation(Representation new_rep, | |
| 4988 HInferRepresentationPhase* h_infer, | |
| 4989 const char* reason) override { | |
| 4990 if (new_rep.IsSmi()) new_rep = Representation::Integer32(); | |
| 4991 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); | |
| 4992 } | |
| 4993 | |
| 4994 DECLARE_CONCRETE_INSTRUCTION(Mod) | |
| 4995 | |
| 4996 protected: | |
| 4997 bool DataEquals(HValue* other) override { return true; } | |
| 4998 | |
| 4999 Range* InferRange(Zone* zone) override; | |
| 5000 | |
| 5001 private: | |
| 5002 HMod(HValue* context, HValue* left, HValue* right, Strength strength) | |
| 5003 : HArithmeticBinaryOperation(context, left, right, strength) { | |
| 5004 SetFlag(kCanBeDivByZero); | |
| 5005 SetFlag(kCanOverflow); | |
| 5006 SetFlag(kLeftCanBeNegative); | |
| 5007 } | |
| 5008 }; | |
| 5009 | |
| 5010 | |
| 5011 class HDiv final : public HArithmeticBinaryOperation { | |
| 5012 public: | |
| 5013 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 5014 HValue* left, HValue* right, | |
| 5015 Strength strength = Strength::WEAK); | |
| 5016 | |
| 5017 HValue* Canonicalize() override; | |
| 5018 | |
| 5019 virtual void UpdateRepresentation(Representation new_rep, | |
| 5020 HInferRepresentationPhase* h_infer, | |
| 5021 const char* reason) override { | |
| 5022 if (new_rep.IsSmi()) new_rep = Representation::Integer32(); | |
| 5023 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); | |
| 5024 } | |
| 5025 | |
| 5026 DECLARE_CONCRETE_INSTRUCTION(Div) | |
| 5027 | |
| 5028 protected: | |
| 5029 bool DataEquals(HValue* other) override { return true; } | |
| 5030 | |
| 5031 Range* InferRange(Zone* zone) override; | |
| 5032 | |
| 5033 private: | |
| 5034 HDiv(HValue* context, HValue* left, HValue* right, Strength strength) | |
| 5035 : HArithmeticBinaryOperation(context, left, right, strength) { | |
| 5036 SetFlag(kCanBeDivByZero); | |
| 5037 SetFlag(kCanOverflow); | |
| 5038 } | |
| 5039 }; | |
| 5040 | |
| 5041 | |
| 5042 class HMathMinMax final : public HArithmeticBinaryOperation { | |
| 5043 public: | |
| 5044 enum Operation { kMathMin, kMathMax }; | |
| 5045 | |
| 5046 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 5047 HValue* left, HValue* right, Operation op); | |
| 5048 | |
| 5049 Representation observed_input_representation(int index) override { | |
| 5050 return RequiredInputRepresentation(index); | |
| 5051 } | |
| 5052 | |
| 5053 virtual void InferRepresentation(HInferRepresentationPhase* h_infer) override; | |
| 5054 | |
| 5055 Representation RepresentationFromInputs() override { | |
| 5056 Representation left_rep = left()->representation(); | |
| 5057 Representation right_rep = right()->representation(); | |
| 5058 Representation result = Representation::Smi(); | |
| 5059 result = result.generalize(left_rep); | |
| 5060 result = result.generalize(right_rep); | |
| 5061 if (result.IsTagged()) return Representation::Double(); | |
| 5062 return result; | |
| 5063 } | |
| 5064 | |
| 5065 bool IsCommutative() const override { return true; } | |
| 5066 | |
| 5067 Operation operation() { return operation_; } | |
| 5068 | |
| 5069 DECLARE_CONCRETE_INSTRUCTION(MathMinMax) | |
| 5070 | |
| 5071 protected: | |
| 5072 bool DataEquals(HValue* other) override { | |
| 5073 return other->IsMathMinMax() && | |
| 5074 HMathMinMax::cast(other)->operation_ == operation_; | |
| 5075 } | |
| 5076 | |
| 5077 Range* InferRange(Zone* zone) override; | |
| 5078 | |
| 5079 private: | |
| 5080 HMathMinMax(HValue* context, HValue* left, HValue* right, Operation op) | |
| 5081 : HArithmeticBinaryOperation(context, left, right, Strength::WEAK), | |
| 5082 operation_(op) {} | |
| 5083 | |
| 5084 Operation operation_; | |
| 5085 }; | |
| 5086 | |
| 5087 | |
| 5088 class HBitwise final : public HBitwiseBinaryOperation { | |
| 5089 public: | |
| 5090 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 5091 Token::Value op, HValue* left, HValue* right, | |
| 5092 Strength strength = Strength::WEAK); | |
| 5093 | |
| 5094 Token::Value op() const { return op_; } | |
| 5095 | |
| 5096 bool IsCommutative() const override { return true; } | |
| 5097 | |
| 5098 HValue* Canonicalize() override; | |
| 5099 | |
| 5100 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 5101 | |
| 5102 DECLARE_CONCRETE_INSTRUCTION(Bitwise) | |
| 5103 | |
| 5104 protected: | |
| 5105 bool DataEquals(HValue* other) override { | |
| 5106 return op() == HBitwise::cast(other)->op(); | |
| 5107 } | |
| 5108 | |
| 5109 Range* InferRange(Zone* zone) override; | |
| 5110 | |
| 5111 private: | |
| 5112 HBitwise(HValue* context, Token::Value op, HValue* left, HValue* right, | |
| 5113 Strength strength) | |
| 5114 : HBitwiseBinaryOperation(context, left, right, strength), op_(op) { | |
| 5115 DCHECK(op == Token::BIT_AND || op == Token::BIT_OR || op == Token::BIT_XOR); | |
| 5116 // BIT_AND with a smi-range positive value will always unset the | |
| 5117 // entire sign-extension of the smi-sign. | |
| 5118 if (op == Token::BIT_AND && | |
| 5119 ((left->IsConstant() && | |
| 5120 left->representation().IsSmi() && | |
| 5121 HConstant::cast(left)->Integer32Value() >= 0) || | |
| 5122 (right->IsConstant() && | |
| 5123 right->representation().IsSmi() && | |
| 5124 HConstant::cast(right)->Integer32Value() >= 0))) { | |
| 5125 SetFlag(kTruncatingToSmi); | |
| 5126 SetFlag(kTruncatingToInt32); | |
| 5127 // BIT_OR with a smi-range negative value will always set the entire | |
| 5128 // sign-extension of the smi-sign. | |
| 5129 } else if (op == Token::BIT_OR && | |
| 5130 ((left->IsConstant() && | |
| 5131 left->representation().IsSmi() && | |
| 5132 HConstant::cast(left)->Integer32Value() < 0) || | |
| 5133 (right->IsConstant() && | |
| 5134 right->representation().IsSmi() && | |
| 5135 HConstant::cast(right)->Integer32Value() < 0))) { | |
| 5136 SetFlag(kTruncatingToSmi); | |
| 5137 SetFlag(kTruncatingToInt32); | |
| 5138 } | |
| 5139 } | |
| 5140 | |
| 5141 Token::Value op_; | |
| 5142 }; | |
| 5143 | |
| 5144 | |
| 5145 class HShl final : public HBitwiseBinaryOperation { | |
| 5146 public: | |
| 5147 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 5148 HValue* left, HValue* right, | |
| 5149 Strength strength = Strength::WEAK); | |
| 5150 | |
| 5151 Range* InferRange(Zone* zone) override; | |
| 5152 | |
| 5153 virtual void UpdateRepresentation(Representation new_rep, | |
| 5154 HInferRepresentationPhase* h_infer, | |
| 5155 const char* reason) override { | |
| 5156 if (new_rep.IsSmi() && | |
| 5157 !(right()->IsInteger32Constant() && | |
| 5158 right()->GetInteger32Constant() >= 0)) { | |
| 5159 new_rep = Representation::Integer32(); | |
| 5160 } | |
| 5161 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); | |
| 5162 } | |
| 5163 | |
| 5164 DECLARE_CONCRETE_INSTRUCTION(Shl) | |
| 5165 | |
| 5166 protected: | |
| 5167 bool DataEquals(HValue* other) override { return true; } | |
| 5168 | |
| 5169 private: | |
| 5170 HShl(HValue* context, HValue* left, HValue* right, Strength strength) | |
| 5171 : HBitwiseBinaryOperation(context, left, right, strength) {} | |
| 5172 }; | |
| 5173 | |
| 5174 | |
| 5175 class HShr final : public HBitwiseBinaryOperation { | |
| 5176 public: | |
| 5177 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 5178 HValue* left, HValue* right, | |
| 5179 Strength strength = Strength::WEAK); | |
| 5180 | |
| 5181 bool TryDecompose(DecompositionResult* decomposition) override { | |
| 5182 if (right()->IsInteger32Constant()) { | |
| 5183 if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) { | |
| 5184 // This is intended to look for HAdd and HSub, to handle compounds | |
| 5185 // like ((base + offset) >> scale) with one single decomposition. | |
| 5186 left()->TryDecompose(decomposition); | |
| 5187 return true; | |
| 5188 } | |
| 5189 } | |
| 5190 return false; | |
| 5191 } | |
| 5192 | |
| 5193 Range* InferRange(Zone* zone) override; | |
| 5194 | |
| 5195 virtual void UpdateRepresentation(Representation new_rep, | |
| 5196 HInferRepresentationPhase* h_infer, | |
| 5197 const char* reason) override { | |
| 5198 if (new_rep.IsSmi()) new_rep = Representation::Integer32(); | |
| 5199 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); | |
| 5200 } | |
| 5201 | |
| 5202 DECLARE_CONCRETE_INSTRUCTION(Shr) | |
| 5203 | |
| 5204 protected: | |
| 5205 bool DataEquals(HValue* other) override { return true; } | |
| 5206 | |
| 5207 private: | |
| 5208 HShr(HValue* context, HValue* left, HValue* right, Strength strength) | |
| 5209 : HBitwiseBinaryOperation(context, left, right, strength) {} | |
| 5210 }; | |
| 5211 | |
| 5212 | |
| 5213 class HSar final : public HBitwiseBinaryOperation { | |
| 5214 public: | |
| 5215 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 5216 HValue* left, HValue* right, | |
| 5217 Strength strength = Strength::WEAK); | |
| 5218 | |
| 5219 bool TryDecompose(DecompositionResult* decomposition) override { | |
| 5220 if (right()->IsInteger32Constant()) { | |
| 5221 if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) { | |
| 5222 // This is intended to look for HAdd and HSub, to handle compounds | |
| 5223 // like ((base + offset) >> scale) with one single decomposition. | |
| 5224 left()->TryDecompose(decomposition); | |
| 5225 return true; | |
| 5226 } | |
| 5227 } | |
| 5228 return false; | |
| 5229 } | |
| 5230 | |
| 5231 Range* InferRange(Zone* zone) override; | |
| 5232 | |
| 5233 virtual void UpdateRepresentation(Representation new_rep, | |
| 5234 HInferRepresentationPhase* h_infer, | |
| 5235 const char* reason) override { | |
| 5236 if (new_rep.IsSmi()) new_rep = Representation::Integer32(); | |
| 5237 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); | |
| 5238 } | |
| 5239 | |
| 5240 DECLARE_CONCRETE_INSTRUCTION(Sar) | |
| 5241 | |
| 5242 protected: | |
| 5243 bool DataEquals(HValue* other) override { return true; } | |
| 5244 | |
| 5245 private: | |
| 5246 HSar(HValue* context, HValue* left, HValue* right, Strength strength) | |
| 5247 : HBitwiseBinaryOperation(context, left, right, strength) {} | |
| 5248 }; | |
| 5249 | |
| 5250 | |
| 5251 class HRor final : public HBitwiseBinaryOperation { | |
| 5252 public: | |
| 5253 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 5254 HValue* left, HValue* right, | |
| 5255 Strength strength = Strength::WEAK) { | |
| 5256 return new (zone) HRor(context, left, right, strength); | |
| 5257 } | |
| 5258 | |
| 5259 virtual void UpdateRepresentation(Representation new_rep, | |
| 5260 HInferRepresentationPhase* h_infer, | |
| 5261 const char* reason) override { | |
| 5262 if (new_rep.IsSmi()) new_rep = Representation::Integer32(); | |
| 5263 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason); | |
| 5264 } | |
| 5265 | |
| 5266 DECLARE_CONCRETE_INSTRUCTION(Ror) | |
| 5267 | |
| 5268 protected: | |
| 5269 bool DataEquals(HValue* other) override { return true; } | |
| 5270 | |
| 5271 private: | |
| 5272 HRor(HValue* context, HValue* left, HValue* right, Strength strength) | |
| 5273 : HBitwiseBinaryOperation(context, left, right, strength) { | |
| 5274 ChangeRepresentation(Representation::Integer32()); | |
| 5275 } | |
| 5276 }; | |
| 5277 | |
| 5278 | |
| 5279 class HOsrEntry final : public HTemplateInstruction<0> { | |
| 5280 public: | |
| 5281 DECLARE_INSTRUCTION_FACTORY_P1(HOsrEntry, BailoutId); | |
| 5282 | |
| 5283 BailoutId ast_id() const { return ast_id_; } | |
| 5284 | |
| 5285 Representation RequiredInputRepresentation(int index) override { | |
| 5286 return Representation::None(); | |
| 5287 } | |
| 5288 | |
| 5289 DECLARE_CONCRETE_INSTRUCTION(OsrEntry) | |
| 5290 | |
| 5291 private: | |
| 5292 explicit HOsrEntry(BailoutId ast_id) : ast_id_(ast_id) { | |
| 5293 SetChangesFlag(kOsrEntries); | |
| 5294 SetChangesFlag(kNewSpacePromotion); | |
| 5295 } | |
| 5296 | |
| 5297 BailoutId ast_id_; | |
| 5298 }; | |
| 5299 | |
| 5300 | |
| 5301 class HParameter final : public HTemplateInstruction<0> { | |
| 5302 public: | |
| 5303 enum ParameterKind { | |
| 5304 STACK_PARAMETER, | |
| 5305 REGISTER_PARAMETER | |
| 5306 }; | |
| 5307 | |
| 5308 DECLARE_INSTRUCTION_FACTORY_P1(HParameter, unsigned); | |
| 5309 DECLARE_INSTRUCTION_FACTORY_P2(HParameter, unsigned, ParameterKind); | |
| 5310 DECLARE_INSTRUCTION_FACTORY_P3(HParameter, unsigned, ParameterKind, | |
| 5311 Representation); | |
| 5312 | |
| 5313 unsigned index() const { return index_; } | |
| 5314 ParameterKind kind() const { return kind_; } | |
| 5315 | |
| 5316 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 5317 | |
| 5318 Representation RequiredInputRepresentation(int index) override { | |
| 5319 return Representation::None(); | |
| 5320 } | |
| 5321 | |
| 5322 Representation KnownOptimalRepresentation() override { | |
| 5323 // If a parameter is an input to a phi, that phi should not | |
| 5324 // choose any more optimistic representation than Tagged. | |
| 5325 return Representation::Tagged(); | |
| 5326 } | |
| 5327 | |
| 5328 DECLARE_CONCRETE_INSTRUCTION(Parameter) | |
| 5329 | |
| 5330 private: | |
| 5331 explicit HParameter(unsigned index, | |
| 5332 ParameterKind kind = STACK_PARAMETER) | |
| 5333 : index_(index), | |
| 5334 kind_(kind) { | |
| 5335 set_representation(Representation::Tagged()); | |
| 5336 } | |
| 5337 | |
| 5338 explicit HParameter(unsigned index, | |
| 5339 ParameterKind kind, | |
| 5340 Representation r) | |
| 5341 : index_(index), | |
| 5342 kind_(kind) { | |
| 5343 set_representation(r); | |
| 5344 } | |
| 5345 | |
| 5346 unsigned index_; | |
| 5347 ParameterKind kind_; | |
| 5348 }; | |
| 5349 | |
| 5350 | |
| 5351 class HCallStub final : public HUnaryCall { | |
| 5352 public: | |
| 5353 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallStub, CodeStub::Major, int); | |
| 5354 CodeStub::Major major_key() { return major_key_; } | |
| 5355 | |
| 5356 HValue* context() { return value(); } | |
| 5357 | |
| 5358 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 5359 | |
| 5360 DECLARE_CONCRETE_INSTRUCTION(CallStub) | |
| 5361 | |
| 5362 private: | |
| 5363 HCallStub(HValue* context, CodeStub::Major major_key, int argument_count) | |
| 5364 : HUnaryCall(context, argument_count), | |
| 5365 major_key_(major_key) { | |
| 5366 } | |
| 5367 | |
| 5368 CodeStub::Major major_key_; | |
| 5369 }; | |
| 5370 | |
| 5371 | |
| 5372 class HUnknownOSRValue final : public HTemplateInstruction<0> { | |
| 5373 public: | |
| 5374 DECLARE_INSTRUCTION_FACTORY_P2(HUnknownOSRValue, HEnvironment*, int); | |
| 5375 | |
| 5376 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 5377 | |
| 5378 Representation RequiredInputRepresentation(int index) override { | |
| 5379 return Representation::None(); | |
| 5380 } | |
| 5381 | |
| 5382 void set_incoming_value(HPhi* value) { incoming_value_ = value; } | |
| 5383 HPhi* incoming_value() { return incoming_value_; } | |
| 5384 HEnvironment *environment() { return environment_; } | |
| 5385 int index() { return index_; } | |
| 5386 | |
| 5387 Representation KnownOptimalRepresentation() override { | |
| 5388 if (incoming_value_ == NULL) return Representation::None(); | |
| 5389 return incoming_value_->KnownOptimalRepresentation(); | |
| 5390 } | |
| 5391 | |
| 5392 DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue) | |
| 5393 | |
| 5394 private: | |
| 5395 HUnknownOSRValue(HEnvironment* environment, int index) | |
| 5396 : environment_(environment), | |
| 5397 index_(index), | |
| 5398 incoming_value_(NULL) { | |
| 5399 set_representation(Representation::Tagged()); | |
| 5400 } | |
| 5401 | |
| 5402 HEnvironment* environment_; | |
| 5403 int index_; | |
| 5404 HPhi* incoming_value_; | |
| 5405 }; | |
| 5406 | |
| 5407 | |
| 5408 class HLoadGlobalGeneric final : public HTemplateInstruction<2> { | |
| 5409 public: | |
| 5410 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HLoadGlobalGeneric, HValue*, | |
| 5411 Handle<String>, TypeofMode); | |
| 5412 | |
| 5413 HValue* context() { return OperandAt(0); } | |
| 5414 HValue* global_object() { return OperandAt(1); } | |
| 5415 Handle<String> name() const { return name_; } | |
| 5416 TypeofMode typeof_mode() const { return typeof_mode_; } | |
| 5417 FeedbackVectorSlot slot() const { return slot_; } | |
| 5418 Handle<TypeFeedbackVector> feedback_vector() const { | |
| 5419 return feedback_vector_; | |
| 5420 } | |
| 5421 bool HasVectorAndSlot() const { return true; } | |
| 5422 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector, | |
| 5423 FeedbackVectorSlot slot) { | |
| 5424 feedback_vector_ = vector; | |
| 5425 slot_ = slot; | |
| 5426 } | |
| 5427 | |
| 5428 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 5429 | |
| 5430 Representation RequiredInputRepresentation(int index) override { | |
| 5431 return Representation::Tagged(); | |
| 5432 } | |
| 5433 | |
| 5434 DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric) | |
| 5435 | |
| 5436 private: | |
| 5437 HLoadGlobalGeneric(HValue* context, HValue* global_object, | |
| 5438 Handle<String> name, TypeofMode typeof_mode) | |
| 5439 : name_(name), typeof_mode_(typeof_mode) { | |
| 5440 SetOperandAt(0, context); | |
| 5441 SetOperandAt(1, global_object); | |
| 5442 set_representation(Representation::Tagged()); | |
| 5443 SetAllSideEffects(); | |
| 5444 } | |
| 5445 | |
| 5446 Handle<String> name_; | |
| 5447 TypeofMode typeof_mode_; | |
| 5448 Handle<TypeFeedbackVector> feedback_vector_; | |
| 5449 FeedbackVectorSlot slot_; | |
| 5450 }; | |
| 5451 | |
| 5452 | |
| 5453 class HLoadGlobalViaContext final : public HTemplateInstruction<1> { | |
| 5454 public: | |
| 5455 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HLoadGlobalViaContext, int, int); | |
| 5456 | |
| 5457 HValue* context() { return OperandAt(0); } | |
| 5458 int depth() const { return depth_; } | |
| 5459 int slot_index() const { return slot_index_; } | |
| 5460 | |
| 5461 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 5462 | |
| 5463 Representation RequiredInputRepresentation(int index) override { | |
| 5464 return Representation::Tagged(); | |
| 5465 } | |
| 5466 | |
| 5467 DECLARE_CONCRETE_INSTRUCTION(LoadGlobalViaContext) | |
| 5468 | |
| 5469 private: | |
| 5470 HLoadGlobalViaContext(HValue* context, int depth, int slot_index) | |
| 5471 : depth_(depth), slot_index_(slot_index) { | |
| 5472 SetOperandAt(0, context); | |
| 5473 set_representation(Representation::Tagged()); | |
| 5474 SetAllSideEffects(); | |
| 5475 } | |
| 5476 | |
| 5477 int const depth_; | |
| 5478 int const slot_index_; | |
| 5479 }; | |
| 5480 | |
| 5481 | |
| 5482 class HAllocate final : public HTemplateInstruction<2> { | |
| 5483 public: | |
| 5484 static bool CompatibleInstanceTypes(InstanceType type1, | |
| 5485 InstanceType type2) { | |
| 5486 return ComputeFlags(TENURED, type1) == ComputeFlags(TENURED, type2) && | |
| 5487 ComputeFlags(NOT_TENURED, type1) == ComputeFlags(NOT_TENURED, type2); | |
| 5488 } | |
| 5489 | |
| 5490 static HAllocate* New( | |
| 5491 Isolate* isolate, Zone* zone, HValue* context, HValue* size, HType type, | |
| 5492 PretenureFlag pretenure_flag, InstanceType instance_type, | |
| 5493 Handle<AllocationSite> allocation_site = Handle<AllocationSite>::null()) { | |
| 5494 return new(zone) HAllocate(context, size, type, pretenure_flag, | |
| 5495 instance_type, allocation_site); | |
| 5496 } | |
| 5497 | |
| 5498 // Maximum instance size for which allocations will be inlined. | |
| 5499 static const int kMaxInlineSize = 64 * kPointerSize; | |
| 5500 | |
| 5501 HValue* context() const { return OperandAt(0); } | |
| 5502 HValue* size() const { return OperandAt(1); } | |
| 5503 | |
| 5504 bool has_size_upper_bound() { return size_upper_bound_ != NULL; } | |
| 5505 HConstant* size_upper_bound() { return size_upper_bound_; } | |
| 5506 void set_size_upper_bound(HConstant* value) { | |
| 5507 DCHECK(size_upper_bound_ == NULL); | |
| 5508 size_upper_bound_ = value; | |
| 5509 } | |
| 5510 | |
| 5511 Representation RequiredInputRepresentation(int index) override { | |
| 5512 if (index == 0) { | |
| 5513 return Representation::Tagged(); | |
| 5514 } else { | |
| 5515 return Representation::Integer32(); | |
| 5516 } | |
| 5517 } | |
| 5518 | |
| 5519 Handle<Map> GetMonomorphicJSObjectMap() override { | |
| 5520 return known_initial_map_; | |
| 5521 } | |
| 5522 | |
| 5523 void set_known_initial_map(Handle<Map> known_initial_map) { | |
| 5524 known_initial_map_ = known_initial_map; | |
| 5525 } | |
| 5526 | |
| 5527 bool IsNewSpaceAllocation() const { | |
| 5528 return (flags_ & ALLOCATE_IN_NEW_SPACE) != 0; | |
| 5529 } | |
| 5530 | |
| 5531 bool IsOldSpaceAllocation() const { | |
| 5532 return (flags_ & ALLOCATE_IN_OLD_SPACE) != 0; | |
| 5533 } | |
| 5534 | |
| 5535 bool MustAllocateDoubleAligned() const { | |
| 5536 return (flags_ & ALLOCATE_DOUBLE_ALIGNED) != 0; | |
| 5537 } | |
| 5538 | |
| 5539 bool MustPrefillWithFiller() const { | |
| 5540 return (flags_ & PREFILL_WITH_FILLER) != 0; | |
| 5541 } | |
| 5542 | |
| 5543 void MakePrefillWithFiller() { | |
| 5544 flags_ = static_cast<HAllocate::Flags>(flags_ | PREFILL_WITH_FILLER); | |
| 5545 } | |
| 5546 | |
| 5547 bool MustClearNextMapWord() const { | |
| 5548 return (flags_ & CLEAR_NEXT_MAP_WORD) != 0; | |
| 5549 } | |
| 5550 | |
| 5551 void MakeDoubleAligned() { | |
| 5552 flags_ = static_cast<HAllocate::Flags>(flags_ | ALLOCATE_DOUBLE_ALIGNED); | |
| 5553 } | |
| 5554 | |
| 5555 virtual bool HandleSideEffectDominator(GVNFlag side_effect, | |
| 5556 HValue* dominator) override; | |
| 5557 | |
| 5558 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 5559 | |
| 5560 DECLARE_CONCRETE_INSTRUCTION(Allocate) | |
| 5561 | |
| 5562 private: | |
| 5563 enum Flags { | |
| 5564 ALLOCATE_IN_NEW_SPACE = 1 << 0, | |
| 5565 ALLOCATE_IN_OLD_SPACE = 1 << 2, | |
| 5566 ALLOCATE_DOUBLE_ALIGNED = 1 << 3, | |
| 5567 PREFILL_WITH_FILLER = 1 << 4, | |
| 5568 CLEAR_NEXT_MAP_WORD = 1 << 5 | |
| 5569 }; | |
| 5570 | |
| 5571 HAllocate(HValue* context, | |
| 5572 HValue* size, | |
| 5573 HType type, | |
| 5574 PretenureFlag pretenure_flag, | |
| 5575 InstanceType instance_type, | |
| 5576 Handle<AllocationSite> allocation_site = | |
| 5577 Handle<AllocationSite>::null()) | |
| 5578 : HTemplateInstruction<2>(type), | |
| 5579 flags_(ComputeFlags(pretenure_flag, instance_type)), | |
| 5580 dominating_allocate_(NULL), | |
| 5581 filler_free_space_size_(NULL), | |
| 5582 size_upper_bound_(NULL) { | |
| 5583 SetOperandAt(0, context); | |
| 5584 UpdateSize(size); | |
| 5585 set_representation(Representation::Tagged()); | |
| 5586 SetFlag(kTrackSideEffectDominators); | |
| 5587 SetChangesFlag(kNewSpacePromotion); | |
| 5588 SetDependsOnFlag(kNewSpacePromotion); | |
| 5589 | |
| 5590 if (FLAG_trace_pretenuring) { | |
| 5591 PrintF("HAllocate with AllocationSite %p %s\n", | |
| 5592 allocation_site.is_null() | |
| 5593 ? static_cast<void*>(NULL) | |
| 5594 : static_cast<void*>(*allocation_site), | |
| 5595 pretenure_flag == TENURED ? "tenured" : "not tenured"); | |
| 5596 } | |
| 5597 } | |
| 5598 | |
| 5599 static Flags ComputeFlags(PretenureFlag pretenure_flag, | |
| 5600 InstanceType instance_type) { | |
| 5601 Flags flags = pretenure_flag == TENURED ? ALLOCATE_IN_OLD_SPACE | |
| 5602 : ALLOCATE_IN_NEW_SPACE; | |
| 5603 if (instance_type == FIXED_DOUBLE_ARRAY_TYPE) { | |
| 5604 flags = static_cast<Flags>(flags | ALLOCATE_DOUBLE_ALIGNED); | |
| 5605 } | |
| 5606 // We have to fill the allocated object with one word fillers if we do | |
| 5607 // not use allocation folding since some allocations may depend on each | |
| 5608 // other, i.e., have a pointer to each other. A GC in between these | |
| 5609 // allocations may leave such objects behind in a not completely initialized | |
| 5610 // state. | |
| 5611 if (!FLAG_use_gvn || !FLAG_use_allocation_folding) { | |
| 5612 flags = static_cast<Flags>(flags | PREFILL_WITH_FILLER); | |
| 5613 } | |
| 5614 if (pretenure_flag == NOT_TENURED && | |
| 5615 AllocationSite::CanTrack(instance_type)) { | |
| 5616 flags = static_cast<Flags>(flags | CLEAR_NEXT_MAP_WORD); | |
| 5617 } | |
| 5618 return flags; | |
| 5619 } | |
| 5620 | |
| 5621 void UpdateClearNextMapWord(bool clear_next_map_word) { | |
| 5622 flags_ = static_cast<Flags>(clear_next_map_word | |
| 5623 ? flags_ | CLEAR_NEXT_MAP_WORD | |
| 5624 : flags_ & ~CLEAR_NEXT_MAP_WORD); | |
| 5625 } | |
| 5626 | |
| 5627 void UpdateSize(HValue* size) { | |
| 5628 SetOperandAt(1, size); | |
| 5629 if (size->IsInteger32Constant()) { | |
| 5630 size_upper_bound_ = HConstant::cast(size); | |
| 5631 } else { | |
| 5632 size_upper_bound_ = NULL; | |
| 5633 } | |
| 5634 } | |
| 5635 | |
| 5636 HAllocate* GetFoldableDominator(HAllocate* dominator); | |
| 5637 | |
| 5638 void UpdateFreeSpaceFiller(int32_t filler_size); | |
| 5639 | |
| 5640 void CreateFreeSpaceFiller(int32_t filler_size); | |
| 5641 | |
| 5642 bool IsFoldable(HAllocate* allocate) { | |
| 5643 return (IsNewSpaceAllocation() && allocate->IsNewSpaceAllocation()) || | |
| 5644 (IsOldSpaceAllocation() && allocate->IsOldSpaceAllocation()); | |
| 5645 } | |
| 5646 | |
| 5647 void ClearNextMapWord(int offset); | |
| 5648 | |
| 5649 Flags flags_; | |
| 5650 Handle<Map> known_initial_map_; | |
| 5651 HAllocate* dominating_allocate_; | |
| 5652 HStoreNamedField* filler_free_space_size_; | |
| 5653 HConstant* size_upper_bound_; | |
| 5654 }; | |
| 5655 | |
| 5656 | |
| 5657 class HStoreCodeEntry final : public HTemplateInstruction<2> { | |
| 5658 public: | |
| 5659 static HStoreCodeEntry* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 5660 HValue* function, HValue* code) { | |
| 5661 return new(zone) HStoreCodeEntry(function, code); | |
| 5662 } | |
| 5663 | |
| 5664 Representation RequiredInputRepresentation(int index) override { | |
| 5665 return Representation::Tagged(); | |
| 5666 } | |
| 5667 | |
| 5668 HValue* function() { return OperandAt(0); } | |
| 5669 HValue* code_object() { return OperandAt(1); } | |
| 5670 | |
| 5671 DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry) | |
| 5672 | |
| 5673 private: | |
| 5674 HStoreCodeEntry(HValue* function, HValue* code) { | |
| 5675 SetOperandAt(0, function); | |
| 5676 SetOperandAt(1, code); | |
| 5677 } | |
| 5678 }; | |
| 5679 | |
| 5680 | |
| 5681 class HInnerAllocatedObject final : public HTemplateInstruction<2> { | |
| 5682 public: | |
| 5683 static HInnerAllocatedObject* New(Isolate* isolate, Zone* zone, | |
| 5684 HValue* context, HValue* value, | |
| 5685 HValue* offset, HType type) { | |
| 5686 return new(zone) HInnerAllocatedObject(value, offset, type); | |
| 5687 } | |
| 5688 | |
| 5689 HValue* base_object() const { return OperandAt(0); } | |
| 5690 HValue* offset() const { return OperandAt(1); } | |
| 5691 | |
| 5692 Representation RequiredInputRepresentation(int index) override { | |
| 5693 return index == 0 ? Representation::Tagged() : Representation::Integer32(); | |
| 5694 } | |
| 5695 | |
| 5696 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 5697 | |
| 5698 DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject) | |
| 5699 | |
| 5700 private: | |
| 5701 HInnerAllocatedObject(HValue* value, | |
| 5702 HValue* offset, | |
| 5703 HType type) : HTemplateInstruction<2>(type) { | |
| 5704 DCHECK(value->IsAllocate()); | |
| 5705 DCHECK(type.IsHeapObject()); | |
| 5706 SetOperandAt(0, value); | |
| 5707 SetOperandAt(1, offset); | |
| 5708 set_representation(Representation::Tagged()); | |
| 5709 } | |
| 5710 }; | |
| 5711 | |
| 5712 | |
| 5713 inline bool StoringValueNeedsWriteBarrier(HValue* value) { | |
| 5714 return !value->type().IsSmi() | |
| 5715 && !value->type().IsNull() | |
| 5716 && !value->type().IsBoolean() | |
| 5717 && !value->type().IsUndefined() | |
| 5718 && !(value->IsConstant() && HConstant::cast(value)->ImmortalImmovable()); | |
| 5719 } | |
| 5720 | |
| 5721 | |
| 5722 inline bool ReceiverObjectNeedsWriteBarrier(HValue* object, | |
| 5723 HValue* value, | |
| 5724 HValue* dominator) { | |
| 5725 while (object->IsInnerAllocatedObject()) { | |
| 5726 object = HInnerAllocatedObject::cast(object)->base_object(); | |
| 5727 } | |
| 5728 if (object->IsConstant() && | |
| 5729 HConstant::cast(object)->HasExternalReferenceValue()) { | |
| 5730 // Stores to external references require no write barriers | |
| 5731 return false; | |
| 5732 } | |
| 5733 // We definitely need a write barrier unless the object is the allocation | |
| 5734 // dominator. | |
| 5735 if (object == dominator && object->IsAllocate()) { | |
| 5736 // Stores to new space allocations require no write barriers. | |
| 5737 if (HAllocate::cast(object)->IsNewSpaceAllocation()) { | |
| 5738 return false; | |
| 5739 } | |
| 5740 // Stores to old space allocations require no write barriers if the value is | |
| 5741 // a constant provably not in new space. | |
| 5742 if (value->IsConstant() && HConstant::cast(value)->NotInNewSpace()) { | |
| 5743 return false; | |
| 5744 } | |
| 5745 // Stores to old space allocations require no write barriers if the value is | |
| 5746 // an old space allocation. | |
| 5747 while (value->IsInnerAllocatedObject()) { | |
| 5748 value = HInnerAllocatedObject::cast(value)->base_object(); | |
| 5749 } | |
| 5750 if (value->IsAllocate() && | |
| 5751 !HAllocate::cast(value)->IsNewSpaceAllocation()) { | |
| 5752 return false; | |
| 5753 } | |
| 5754 } | |
| 5755 return true; | |
| 5756 } | |
| 5757 | |
| 5758 | |
| 5759 inline PointersToHereCheck PointersToHereCheckForObject(HValue* object, | |
| 5760 HValue* dominator) { | |
| 5761 while (object->IsInnerAllocatedObject()) { | |
| 5762 object = HInnerAllocatedObject::cast(object)->base_object(); | |
| 5763 } | |
| 5764 if (object == dominator && | |
| 5765 object->IsAllocate() && | |
| 5766 HAllocate::cast(object)->IsNewSpaceAllocation()) { | |
| 5767 return kPointersToHereAreAlwaysInteresting; | |
| 5768 } | |
| 5769 return kPointersToHereMaybeInteresting; | |
| 5770 } | |
| 5771 | |
| 5772 | |
| 5773 class HLoadContextSlot final : public HUnaryOperation { | |
| 5774 public: | |
| 5775 enum Mode { | |
| 5776 // Perform a normal load of the context slot without checking its value. | |
| 5777 kNoCheck, | |
| 5778 // Load and check the value of the context slot. Deoptimize if it's the | |
| 5779 // hole value. This is used for checking for loading of uninitialized | |
| 5780 // harmony bindings where we deoptimize into full-codegen generated code | |
| 5781 // which will subsequently throw a reference error. | |
| 5782 kCheckDeoptimize, | |
| 5783 // Load and check the value of the context slot. Return undefined if it's | |
| 5784 // the hole value. This is used for non-harmony const assignments | |
| 5785 kCheckReturnUndefined | |
| 5786 }; | |
| 5787 | |
| 5788 HLoadContextSlot(HValue* context, int slot_index, Mode mode) | |
| 5789 : HUnaryOperation(context), slot_index_(slot_index), mode_(mode) { | |
| 5790 set_representation(Representation::Tagged()); | |
| 5791 SetFlag(kUseGVN); | |
| 5792 SetDependsOnFlag(kContextSlots); | |
| 5793 } | |
| 5794 | |
| 5795 int slot_index() const { return slot_index_; } | |
| 5796 Mode mode() const { return mode_; } | |
| 5797 | |
| 5798 bool DeoptimizesOnHole() { | |
| 5799 return mode_ == kCheckDeoptimize; | |
| 5800 } | |
| 5801 | |
| 5802 bool RequiresHoleCheck() const { | |
| 5803 return mode_ != kNoCheck; | |
| 5804 } | |
| 5805 | |
| 5806 Representation RequiredInputRepresentation(int index) override { | |
| 5807 return Representation::Tagged(); | |
| 5808 } | |
| 5809 | |
| 5810 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 5811 | |
| 5812 DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot) | |
| 5813 | |
| 5814 protected: | |
| 5815 bool DataEquals(HValue* other) override { | |
| 5816 HLoadContextSlot* b = HLoadContextSlot::cast(other); | |
| 5817 return (slot_index() == b->slot_index()); | |
| 5818 } | |
| 5819 | |
| 5820 private: | |
| 5821 bool IsDeletable() const override { return !RequiresHoleCheck(); } | |
| 5822 | |
| 5823 int slot_index_; | |
| 5824 Mode mode_; | |
| 5825 }; | |
| 5826 | |
| 5827 | |
| 5828 class HStoreContextSlot final : public HTemplateInstruction<2> { | |
| 5829 public: | |
| 5830 enum Mode { | |
| 5831 // Perform a normal store to the context slot without checking its previous | |
| 5832 // value. | |
| 5833 kNoCheck, | |
| 5834 // Check the previous value of the context slot and deoptimize if it's the | |
| 5835 // hole value. This is used for checking for assignments to uninitialized | |
| 5836 // harmony bindings where we deoptimize into full-codegen generated code | |
| 5837 // which will subsequently throw a reference error. | |
| 5838 kCheckDeoptimize, | |
| 5839 // Check the previous value and ignore assignment if it isn't a hole value | |
| 5840 kCheckIgnoreAssignment | |
| 5841 }; | |
| 5842 | |
| 5843 DECLARE_INSTRUCTION_FACTORY_P4(HStoreContextSlot, HValue*, int, | |
| 5844 Mode, HValue*); | |
| 5845 | |
| 5846 HValue* context() const { return OperandAt(0); } | |
| 5847 HValue* value() const { return OperandAt(1); } | |
| 5848 int slot_index() const { return slot_index_; } | |
| 5849 Mode mode() const { return mode_; } | |
| 5850 | |
| 5851 bool NeedsWriteBarrier() { | |
| 5852 return StoringValueNeedsWriteBarrier(value()); | |
| 5853 } | |
| 5854 | |
| 5855 bool DeoptimizesOnHole() { | |
| 5856 return mode_ == kCheckDeoptimize; | |
| 5857 } | |
| 5858 | |
| 5859 bool RequiresHoleCheck() { | |
| 5860 return mode_ != kNoCheck; | |
| 5861 } | |
| 5862 | |
| 5863 Representation RequiredInputRepresentation(int index) override { | |
| 5864 return Representation::Tagged(); | |
| 5865 } | |
| 5866 | |
| 5867 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 5868 | |
| 5869 DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot) | |
| 5870 | |
| 5871 private: | |
| 5872 HStoreContextSlot(HValue* context, int slot_index, Mode mode, HValue* value) | |
| 5873 : slot_index_(slot_index), mode_(mode) { | |
| 5874 SetOperandAt(0, context); | |
| 5875 SetOperandAt(1, value); | |
| 5876 SetChangesFlag(kContextSlots); | |
| 5877 } | |
| 5878 | |
| 5879 int slot_index_; | |
| 5880 Mode mode_; | |
| 5881 }; | |
| 5882 | |
| 5883 | |
| 5884 // Represents an access to a portion of an object, such as the map pointer, | |
| 5885 // array elements pointer, etc, but not accesses to array elements themselves. | |
| 5886 class HObjectAccess final { | |
| 5887 public: | |
| 5888 inline bool IsInobject() const { | |
| 5889 return portion() != kBackingStore && portion() != kExternalMemory; | |
| 5890 } | |
| 5891 | |
| 5892 inline bool IsExternalMemory() const { | |
| 5893 return portion() == kExternalMemory; | |
| 5894 } | |
| 5895 | |
| 5896 inline bool IsStringLength() const { | |
| 5897 return portion() == kStringLengths; | |
| 5898 } | |
| 5899 | |
| 5900 inline bool IsMap() const { | |
| 5901 return portion() == kMaps; | |
| 5902 } | |
| 5903 | |
| 5904 inline int offset() const { | |
| 5905 return OffsetField::decode(value_); | |
| 5906 } | |
| 5907 | |
| 5908 inline Representation representation() const { | |
| 5909 return Representation::FromKind(RepresentationField::decode(value_)); | |
| 5910 } | |
| 5911 | |
| 5912 inline Handle<Name> name() const { return name_; } | |
| 5913 | |
| 5914 inline bool immutable() const { | |
| 5915 return ImmutableField::decode(value_); | |
| 5916 } | |
| 5917 | |
| 5918 // Returns true if access is being made to an in-object property that | |
| 5919 // was already added to the object. | |
| 5920 inline bool existing_inobject_property() const { | |
| 5921 return ExistingInobjectPropertyField::decode(value_); | |
| 5922 } | |
| 5923 | |
| 5924 inline HObjectAccess WithRepresentation(Representation representation) { | |
| 5925 return HObjectAccess(portion(), offset(), representation, name(), | |
| 5926 immutable(), existing_inobject_property()); | |
| 5927 } | |
| 5928 | |
| 5929 static HObjectAccess ForHeapNumberValue() { | |
| 5930 return HObjectAccess( | |
| 5931 kDouble, HeapNumber::kValueOffset, Representation::Double()); | |
| 5932 } | |
| 5933 | |
| 5934 static HObjectAccess ForHeapNumberValueLowestBits() { | |
| 5935 return HObjectAccess(kDouble, | |
| 5936 HeapNumber::kValueOffset, | |
| 5937 Representation::Integer32()); | |
| 5938 } | |
| 5939 | |
| 5940 static HObjectAccess ForHeapNumberValueHighestBits() { | |
| 5941 return HObjectAccess(kDouble, | |
| 5942 HeapNumber::kValueOffset + kIntSize, | |
| 5943 Representation::Integer32()); | |
| 5944 } | |
| 5945 | |
| 5946 static HObjectAccess ForOddballToNumber( | |
| 5947 Representation representation = Representation::Tagged()) { | |
| 5948 return HObjectAccess(kInobject, Oddball::kToNumberOffset, representation); | |
| 5949 } | |
| 5950 | |
| 5951 static HObjectAccess ForOddballTypeOf() { | |
| 5952 return HObjectAccess(kInobject, Oddball::kTypeOfOffset, | |
| 5953 Representation::HeapObject()); | |
| 5954 } | |
| 5955 | |
| 5956 static HObjectAccess ForElementsPointer() { | |
| 5957 return HObjectAccess(kElementsPointer, JSObject::kElementsOffset); | |
| 5958 } | |
| 5959 | |
| 5960 static HObjectAccess ForLiteralsPointer() { | |
| 5961 return HObjectAccess(kInobject, JSFunction::kLiteralsOffset); | |
| 5962 } | |
| 5963 | |
| 5964 static HObjectAccess ForNextFunctionLinkPointer() { | |
| 5965 return HObjectAccess(kInobject, JSFunction::kNextFunctionLinkOffset); | |
| 5966 } | |
| 5967 | |
| 5968 static HObjectAccess ForArrayLength(ElementsKind elements_kind) { | |
| 5969 return HObjectAccess( | |
| 5970 kArrayLengths, | |
| 5971 JSArray::kLengthOffset, | |
| 5972 IsFastElementsKind(elements_kind) | |
| 5973 ? Representation::Smi() : Representation::Tagged()); | |
| 5974 } | |
| 5975 | |
| 5976 static HObjectAccess ForAllocationSiteOffset(int offset); | |
| 5977 | |
| 5978 static HObjectAccess ForAllocationSiteList() { | |
| 5979 return HObjectAccess(kExternalMemory, 0, Representation::Tagged(), | |
| 5980 Handle<Name>::null(), false, false); | |
| 5981 } | |
| 5982 | |
| 5983 static HObjectAccess ForFixedArrayLength() { | |
| 5984 return HObjectAccess( | |
| 5985 kArrayLengths, | |
| 5986 FixedArray::kLengthOffset, | |
| 5987 Representation::Smi()); | |
| 5988 } | |
| 5989 | |
| 5990 static HObjectAccess ForFixedTypedArrayBaseBasePointer() { | |
| 5991 return HObjectAccess(kInobject, FixedTypedArrayBase::kBasePointerOffset, | |
| 5992 Representation::Tagged()); | |
| 5993 } | |
| 5994 | |
| 5995 static HObjectAccess ForFixedTypedArrayBaseExternalPointer() { | |
| 5996 return HObjectAccess::ForObservableJSObjectOffset( | |
| 5997 FixedTypedArrayBase::kExternalPointerOffset, | |
| 5998 Representation::External()); | |
| 5999 } | |
| 6000 | |
| 6001 static HObjectAccess ForStringHashField() { | |
| 6002 return HObjectAccess(kInobject, | |
| 6003 String::kHashFieldOffset, | |
| 6004 Representation::Integer32()); | |
| 6005 } | |
| 6006 | |
| 6007 static HObjectAccess ForStringLength() { | |
| 6008 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue); | |
| 6009 return HObjectAccess( | |
| 6010 kStringLengths, | |
| 6011 String::kLengthOffset, | |
| 6012 Representation::Smi()); | |
| 6013 } | |
| 6014 | |
| 6015 static HObjectAccess ForConsStringFirst() { | |
| 6016 return HObjectAccess(kInobject, ConsString::kFirstOffset); | |
| 6017 } | |
| 6018 | |
| 6019 static HObjectAccess ForConsStringSecond() { | |
| 6020 return HObjectAccess(kInobject, ConsString::kSecondOffset); | |
| 6021 } | |
| 6022 | |
| 6023 static HObjectAccess ForPropertiesPointer() { | |
| 6024 return HObjectAccess(kInobject, JSObject::kPropertiesOffset); | |
| 6025 } | |
| 6026 | |
| 6027 static HObjectAccess ForPrototypeOrInitialMap() { | |
| 6028 return HObjectAccess(kInobject, JSFunction::kPrototypeOrInitialMapOffset); | |
| 6029 } | |
| 6030 | |
| 6031 static HObjectAccess ForSharedFunctionInfoPointer() { | |
| 6032 return HObjectAccess(kInobject, JSFunction::kSharedFunctionInfoOffset); | |
| 6033 } | |
| 6034 | |
| 6035 static HObjectAccess ForCodeEntryPointer() { | |
| 6036 return HObjectAccess(kInobject, JSFunction::kCodeEntryOffset); | |
| 6037 } | |
| 6038 | |
| 6039 static HObjectAccess ForCodeOffset() { | |
| 6040 return HObjectAccess(kInobject, SharedFunctionInfo::kCodeOffset); | |
| 6041 } | |
| 6042 | |
| 6043 static HObjectAccess ForOptimizedCodeMap() { | |
| 6044 return HObjectAccess(kInobject, | |
| 6045 SharedFunctionInfo::kOptimizedCodeMapOffset); | |
| 6046 } | |
| 6047 | |
| 6048 static HObjectAccess ForOptimizedCodeMapSharedCode() { | |
| 6049 return HObjectAccess(kInobject, FixedArray::OffsetOfElementAt( | |
| 6050 SharedFunctionInfo::kSharedCodeIndex)); | |
| 6051 } | |
| 6052 | |
| 6053 static HObjectAccess ForFunctionContextPointer() { | |
| 6054 return HObjectAccess(kInobject, JSFunction::kContextOffset); | |
| 6055 } | |
| 6056 | |
| 6057 static HObjectAccess ForMap() { | |
| 6058 return HObjectAccess(kMaps, JSObject::kMapOffset); | |
| 6059 } | |
| 6060 | |
| 6061 static HObjectAccess ForPrototype() { | |
| 6062 return HObjectAccess(kMaps, Map::kPrototypeOffset); | |
| 6063 } | |
| 6064 | |
| 6065 static HObjectAccess ForMapAsInteger32() { | |
| 6066 return HObjectAccess(kMaps, JSObject::kMapOffset, | |
| 6067 Representation::Integer32()); | |
| 6068 } | |
| 6069 | |
| 6070 static HObjectAccess ForMapInObjectPropertiesOrConstructorFunctionIndex() { | |
| 6071 return HObjectAccess( | |
| 6072 kInobject, Map::kInObjectPropertiesOrConstructorFunctionIndexOffset, | |
| 6073 Representation::UInteger8()); | |
| 6074 } | |
| 6075 | |
| 6076 static HObjectAccess ForMapInstanceType() { | |
| 6077 return HObjectAccess(kInobject, | |
| 6078 Map::kInstanceTypeOffset, | |
| 6079 Representation::UInteger8()); | |
| 6080 } | |
| 6081 | |
| 6082 static HObjectAccess ForMapInstanceSize() { | |
| 6083 return HObjectAccess(kInobject, | |
| 6084 Map::kInstanceSizeOffset, | |
| 6085 Representation::UInteger8()); | |
| 6086 } | |
| 6087 | |
| 6088 static HObjectAccess ForMapBitField() { | |
| 6089 return HObjectAccess(kInobject, | |
| 6090 Map::kBitFieldOffset, | |
| 6091 Representation::UInteger8()); | |
| 6092 } | |
| 6093 | |
| 6094 static HObjectAccess ForMapBitField2() { | |
| 6095 return HObjectAccess(kInobject, | |
| 6096 Map::kBitField2Offset, | |
| 6097 Representation::UInteger8()); | |
| 6098 } | |
| 6099 | |
| 6100 static HObjectAccess ForNameHashField() { | |
| 6101 return HObjectAccess(kInobject, | |
| 6102 Name::kHashFieldOffset, | |
| 6103 Representation::Integer32()); | |
| 6104 } | |
| 6105 | |
| 6106 static HObjectAccess ForMapInstanceTypeAndBitField() { | |
| 6107 STATIC_ASSERT((Map::kInstanceTypeAndBitFieldOffset & 1) == 0); | |
| 6108 // Ensure the two fields share one 16-bit word, endian-independent. | |
| 6109 STATIC_ASSERT((Map::kBitFieldOffset & ~1) == | |
| 6110 (Map::kInstanceTypeOffset & ~1)); | |
| 6111 return HObjectAccess(kInobject, | |
| 6112 Map::kInstanceTypeAndBitFieldOffset, | |
| 6113 Representation::UInteger16()); | |
| 6114 } | |
| 6115 | |
| 6116 static HObjectAccess ForPropertyCellValue() { | |
| 6117 return HObjectAccess(kInobject, PropertyCell::kValueOffset); | |
| 6118 } | |
| 6119 | |
| 6120 static HObjectAccess ForPropertyCellDetails() { | |
| 6121 return HObjectAccess(kInobject, PropertyCell::kDetailsOffset, | |
| 6122 Representation::Smi()); | |
| 6123 } | |
| 6124 | |
| 6125 static HObjectAccess ForCellValue() { | |
| 6126 return HObjectAccess(kInobject, Cell::kValueOffset); | |
| 6127 } | |
| 6128 | |
| 6129 static HObjectAccess ForWeakCellValue() { | |
| 6130 return HObjectAccess(kInobject, WeakCell::kValueOffset); | |
| 6131 } | |
| 6132 | |
| 6133 static HObjectAccess ForWeakCellNext() { | |
| 6134 return HObjectAccess(kInobject, WeakCell::kNextOffset); | |
| 6135 } | |
| 6136 | |
| 6137 static HObjectAccess ForAllocationMementoSite() { | |
| 6138 return HObjectAccess(kInobject, AllocationMemento::kAllocationSiteOffset); | |
| 6139 } | |
| 6140 | |
| 6141 static HObjectAccess ForCounter() { | |
| 6142 return HObjectAccess(kExternalMemory, 0, Representation::Integer32(), | |
| 6143 Handle<Name>::null(), false, false); | |
| 6144 } | |
| 6145 | |
| 6146 static HObjectAccess ForExternalUInteger8() { | |
| 6147 return HObjectAccess(kExternalMemory, 0, Representation::UInteger8(), | |
| 6148 Handle<Name>::null(), false, false); | |
| 6149 } | |
| 6150 | |
| 6151 // Create an access to an offset in a fixed array header. | |
| 6152 static HObjectAccess ForFixedArrayHeader(int offset); | |
| 6153 | |
| 6154 // Create an access to an in-object property in a JSObject. | |
| 6155 // This kind of access must be used when the object |map| is known and | |
| 6156 // in-object properties are being accessed. Accesses of the in-object | |
| 6157 // properties can have different semantics depending on whether corresponding | |
| 6158 // property was added to the map or not. | |
| 6159 static HObjectAccess ForMapAndOffset(Handle<Map> map, int offset, | |
| 6160 Representation representation = Representation::Tagged()); | |
| 6161 | |
| 6162 // Create an access to an in-object property in a JSObject. | |
| 6163 // This kind of access can be used for accessing object header fields or | |
| 6164 // in-object properties if the map of the object is not known. | |
| 6165 static HObjectAccess ForObservableJSObjectOffset(int offset, | |
| 6166 Representation representation = Representation::Tagged()) { | |
| 6167 return ForMapAndOffset(Handle<Map>::null(), offset, representation); | |
| 6168 } | |
| 6169 | |
| 6170 // Create an access to an in-object property in a JSArray. | |
| 6171 static HObjectAccess ForJSArrayOffset(int offset); | |
| 6172 | |
| 6173 static HObjectAccess ForContextSlot(int index); | |
| 6174 | |
| 6175 static HObjectAccess ForScriptContext(int index); | |
| 6176 | |
| 6177 // Create an access to the backing store of an object. | |
| 6178 static HObjectAccess ForBackingStoreOffset(int offset, | |
| 6179 Representation representation = Representation::Tagged()); | |
| 6180 | |
| 6181 // Create an access to a resolved field (in-object or backing store). | |
| 6182 static HObjectAccess ForField(Handle<Map> map, int index, | |
| 6183 Representation representation, | |
| 6184 Handle<Name> name); | |
| 6185 | |
| 6186 static HObjectAccess ForJSTypedArrayLength() { | |
| 6187 return HObjectAccess::ForObservableJSObjectOffset( | |
| 6188 JSTypedArray::kLengthOffset); | |
| 6189 } | |
| 6190 | |
| 6191 static HObjectAccess ForJSArrayBufferBackingStore() { | |
| 6192 return HObjectAccess::ForObservableJSObjectOffset( | |
| 6193 JSArrayBuffer::kBackingStoreOffset, Representation::External()); | |
| 6194 } | |
| 6195 | |
| 6196 static HObjectAccess ForJSArrayBufferByteLength() { | |
| 6197 return HObjectAccess::ForObservableJSObjectOffset( | |
| 6198 JSArrayBuffer::kByteLengthOffset, Representation::Tagged()); | |
| 6199 } | |
| 6200 | |
| 6201 static HObjectAccess ForJSArrayBufferBitField() { | |
| 6202 return HObjectAccess::ForObservableJSObjectOffset( | |
| 6203 JSArrayBuffer::kBitFieldOffset, Representation::Integer32()); | |
| 6204 } | |
| 6205 | |
| 6206 static HObjectAccess ForJSArrayBufferBitFieldSlot() { | |
| 6207 return HObjectAccess::ForObservableJSObjectOffset( | |
| 6208 JSArrayBuffer::kBitFieldSlot, Representation::Smi()); | |
| 6209 } | |
| 6210 | |
| 6211 static HObjectAccess ForJSArrayBufferViewBuffer() { | |
| 6212 return HObjectAccess::ForObservableJSObjectOffset( | |
| 6213 JSArrayBufferView::kBufferOffset); | |
| 6214 } | |
| 6215 | |
| 6216 static HObjectAccess ForJSArrayBufferViewByteOffset() { | |
| 6217 return HObjectAccess::ForObservableJSObjectOffset( | |
| 6218 JSArrayBufferView::kByteOffsetOffset); | |
| 6219 } | |
| 6220 | |
| 6221 static HObjectAccess ForJSArrayBufferViewByteLength() { | |
| 6222 return HObjectAccess::ForObservableJSObjectOffset( | |
| 6223 JSArrayBufferView::kByteLengthOffset); | |
| 6224 } | |
| 6225 | |
| 6226 static HObjectAccess ForGlobalObjectNativeContext() { | |
| 6227 return HObjectAccess(kInobject, GlobalObject::kNativeContextOffset); | |
| 6228 } | |
| 6229 | |
| 6230 static HObjectAccess ForJSCollectionTable() { | |
| 6231 return HObjectAccess::ForObservableJSObjectOffset( | |
| 6232 JSCollection::kTableOffset); | |
| 6233 } | |
| 6234 | |
| 6235 template <typename CollectionType> | |
| 6236 static HObjectAccess ForOrderedHashTableNumberOfBuckets() { | |
| 6237 return HObjectAccess(kInobject, CollectionType::kNumberOfBucketsOffset, | |
| 6238 Representation::Smi()); | |
| 6239 } | |
| 6240 | |
| 6241 template <typename CollectionType> | |
| 6242 static HObjectAccess ForOrderedHashTableNumberOfElements() { | |
| 6243 return HObjectAccess(kInobject, CollectionType::kNumberOfElementsOffset, | |
| 6244 Representation::Smi()); | |
| 6245 } | |
| 6246 | |
| 6247 template <typename CollectionType> | |
| 6248 static HObjectAccess ForOrderedHashTableNumberOfDeletedElements() { | |
| 6249 return HObjectAccess(kInobject, | |
| 6250 CollectionType::kNumberOfDeletedElementsOffset, | |
| 6251 Representation::Smi()); | |
| 6252 } | |
| 6253 | |
| 6254 template <typename CollectionType> | |
| 6255 static HObjectAccess ForOrderedHashTableNextTable() { | |
| 6256 return HObjectAccess(kInobject, CollectionType::kNextTableOffset); | |
| 6257 } | |
| 6258 | |
| 6259 template <typename CollectionType> | |
| 6260 static HObjectAccess ForOrderedHashTableBucket(int bucket) { | |
| 6261 return HObjectAccess(kInobject, CollectionType::kHashTableStartOffset + | |
| 6262 (bucket * kPointerSize), | |
| 6263 Representation::Smi()); | |
| 6264 } | |
| 6265 | |
| 6266 // Access into the data table of an OrderedHashTable with a | |
| 6267 // known-at-compile-time bucket count. | |
| 6268 template <typename CollectionType, int kBucketCount> | |
| 6269 static HObjectAccess ForOrderedHashTableDataTableIndex(int index) { | |
| 6270 return HObjectAccess(kInobject, CollectionType::kHashTableStartOffset + | |
| 6271 (kBucketCount * kPointerSize) + | |
| 6272 (index * kPointerSize)); | |
| 6273 } | |
| 6274 | |
| 6275 inline bool Equals(HObjectAccess that) const { | |
| 6276 return value_ == that.value_; // portion and offset must match | |
| 6277 } | |
| 6278 | |
| 6279 protected: | |
| 6280 void SetGVNFlags(HValue *instr, PropertyAccessType access_type); | |
| 6281 | |
| 6282 private: | |
| 6283 // internal use only; different parts of an object or array | |
| 6284 enum Portion { | |
| 6285 kMaps, // map of an object | |
| 6286 kArrayLengths, // the length of an array | |
| 6287 kStringLengths, // the length of a string | |
| 6288 kElementsPointer, // elements pointer | |
| 6289 kBackingStore, // some field in the backing store | |
| 6290 kDouble, // some double field | |
| 6291 kInobject, // some other in-object field | |
| 6292 kExternalMemory // some field in external memory | |
| 6293 }; | |
| 6294 | |
| 6295 HObjectAccess() : value_(0) {} | |
| 6296 | |
| 6297 HObjectAccess(Portion portion, int offset, | |
| 6298 Representation representation = Representation::Tagged(), | |
| 6299 Handle<Name> name = Handle<Name>::null(), | |
| 6300 bool immutable = false, bool existing_inobject_property = true) | |
| 6301 : value_(PortionField::encode(portion) | | |
| 6302 RepresentationField::encode(representation.kind()) | | |
| 6303 ImmutableField::encode(immutable ? 1 : 0) | | |
| 6304 ExistingInobjectPropertyField::encode( | |
| 6305 existing_inobject_property ? 1 : 0) | | |
| 6306 OffsetField::encode(offset)), | |
| 6307 name_(name) { | |
| 6308 // assert that the fields decode correctly | |
| 6309 DCHECK(this->offset() == offset); | |
| 6310 DCHECK(this->portion() == portion); | |
| 6311 DCHECK(this->immutable() == immutable); | |
| 6312 DCHECK(this->existing_inobject_property() == existing_inobject_property); | |
| 6313 DCHECK(RepresentationField::decode(value_) == representation.kind()); | |
| 6314 DCHECK(!this->existing_inobject_property() || IsInobject()); | |
| 6315 } | |
| 6316 | |
| 6317 class PortionField : public BitField<Portion, 0, 3> {}; | |
| 6318 class RepresentationField : public BitField<Representation::Kind, 3, 4> {}; | |
| 6319 class ImmutableField : public BitField<bool, 7, 1> {}; | |
| 6320 class ExistingInobjectPropertyField : public BitField<bool, 8, 1> {}; | |
| 6321 class OffsetField : public BitField<int, 9, 23> {}; | |
| 6322 | |
| 6323 uint32_t value_; // encodes portion, representation, immutable, and offset | |
| 6324 Handle<Name> name_; | |
| 6325 | |
| 6326 friend class HLoadNamedField; | |
| 6327 friend class HStoreNamedField; | |
| 6328 friend class SideEffectsTracker; | |
| 6329 friend std::ostream& operator<<(std::ostream& os, | |
| 6330 const HObjectAccess& access); | |
| 6331 | |
| 6332 inline Portion portion() const { | |
| 6333 return PortionField::decode(value_); | |
| 6334 } | |
| 6335 }; | |
| 6336 | |
| 6337 | |
| 6338 std::ostream& operator<<(std::ostream& os, const HObjectAccess& access); | |
| 6339 | |
| 6340 | |
| 6341 class HLoadNamedField final : public HTemplateInstruction<2> { | |
| 6342 public: | |
| 6343 DECLARE_INSTRUCTION_FACTORY_P3(HLoadNamedField, HValue*, | |
| 6344 HValue*, HObjectAccess); | |
| 6345 DECLARE_INSTRUCTION_FACTORY_P5(HLoadNamedField, HValue*, HValue*, | |
| 6346 HObjectAccess, const UniqueSet<Map>*, HType); | |
| 6347 | |
| 6348 HValue* object() const { return OperandAt(0); } | |
| 6349 HValue* dependency() const { | |
| 6350 DCHECK(HasDependency()); | |
| 6351 return OperandAt(1); | |
| 6352 } | |
| 6353 bool HasDependency() const { return OperandAt(0) != OperandAt(1); } | |
| 6354 HObjectAccess access() const { return access_; } | |
| 6355 Representation field_representation() const { | |
| 6356 return access_.representation(); | |
| 6357 } | |
| 6358 | |
| 6359 const UniqueSet<Map>* maps() const { return maps_; } | |
| 6360 | |
| 6361 bool HasEscapingOperandAt(int index) override { return false; } | |
| 6362 bool HasOutOfBoundsAccess(int size) override { | |
| 6363 return !access().IsInobject() || access().offset() >= size; | |
| 6364 } | |
| 6365 Representation RequiredInputRepresentation(int index) override { | |
| 6366 if (index == 0) { | |
| 6367 // object must be external in case of external memory access | |
| 6368 return access().IsExternalMemory() ? Representation::External() | |
| 6369 : Representation::Tagged(); | |
| 6370 } | |
| 6371 DCHECK(index == 1); | |
| 6372 return Representation::None(); | |
| 6373 } | |
| 6374 Range* InferRange(Zone* zone) override; | |
| 6375 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 6376 | |
| 6377 bool CanBeReplacedWith(HValue* other) const { | |
| 6378 if (!CheckFlag(HValue::kCantBeReplaced)) return false; | |
| 6379 if (!type().Equals(other->type())) return false; | |
| 6380 if (!representation().Equals(other->representation())) return false; | |
| 6381 if (!other->IsLoadNamedField()) return true; | |
| 6382 HLoadNamedField* that = HLoadNamedField::cast(other); | |
| 6383 if (this->maps_ == that->maps_) return true; | |
| 6384 if (this->maps_ == NULL || that->maps_ == NULL) return false; | |
| 6385 return this->maps_->IsSubset(that->maps_); | |
| 6386 } | |
| 6387 | |
| 6388 DECLARE_CONCRETE_INSTRUCTION(LoadNamedField) | |
| 6389 | |
| 6390 protected: | |
| 6391 bool DataEquals(HValue* other) override { | |
| 6392 HLoadNamedField* that = HLoadNamedField::cast(other); | |
| 6393 if (!this->access_.Equals(that->access_)) return false; | |
| 6394 if (this->maps_ == that->maps_) return true; | |
| 6395 return (this->maps_ != NULL && | |
| 6396 that->maps_ != NULL && | |
| 6397 this->maps_->Equals(that->maps_)); | |
| 6398 } | |
| 6399 | |
| 6400 private: | |
| 6401 HLoadNamedField(HValue* object, | |
| 6402 HValue* dependency, | |
| 6403 HObjectAccess access) | |
| 6404 : access_(access), maps_(NULL) { | |
| 6405 DCHECK_NOT_NULL(object); | |
| 6406 SetOperandAt(0, object); | |
| 6407 SetOperandAt(1, dependency ? dependency : object); | |
| 6408 | |
| 6409 Representation representation = access.representation(); | |
| 6410 if (representation.IsInteger8() || | |
| 6411 representation.IsUInteger8() || | |
| 6412 representation.IsInteger16() || | |
| 6413 representation.IsUInteger16()) { | |
| 6414 set_representation(Representation::Integer32()); | |
| 6415 } else if (representation.IsSmi()) { | |
| 6416 set_type(HType::Smi()); | |
| 6417 if (SmiValuesAre32Bits()) { | |
| 6418 set_representation(Representation::Integer32()); | |
| 6419 } else { | |
| 6420 set_representation(representation); | |
| 6421 } | |
| 6422 } else if (representation.IsDouble() || | |
| 6423 representation.IsExternal() || | |
| 6424 representation.IsInteger32()) { | |
| 6425 set_representation(representation); | |
| 6426 } else if (representation.IsHeapObject()) { | |
| 6427 set_type(HType::HeapObject()); | |
| 6428 set_representation(Representation::Tagged()); | |
| 6429 } else { | |
| 6430 set_representation(Representation::Tagged()); | |
| 6431 } | |
| 6432 access.SetGVNFlags(this, LOAD); | |
| 6433 } | |
| 6434 | |
| 6435 HLoadNamedField(HValue* object, | |
| 6436 HValue* dependency, | |
| 6437 HObjectAccess access, | |
| 6438 const UniqueSet<Map>* maps, | |
| 6439 HType type) | |
| 6440 : HTemplateInstruction<2>(type), access_(access), maps_(maps) { | |
| 6441 DCHECK_NOT_NULL(maps); | |
| 6442 DCHECK_NE(0, maps->size()); | |
| 6443 | |
| 6444 DCHECK_NOT_NULL(object); | |
| 6445 SetOperandAt(0, object); | |
| 6446 SetOperandAt(1, dependency ? dependency : object); | |
| 6447 | |
| 6448 DCHECK(access.representation().IsHeapObject()); | |
| 6449 DCHECK(type.IsHeapObject()); | |
| 6450 set_representation(Representation::Tagged()); | |
| 6451 | |
| 6452 access.SetGVNFlags(this, LOAD); | |
| 6453 } | |
| 6454 | |
| 6455 bool IsDeletable() const override { return true; } | |
| 6456 | |
| 6457 HObjectAccess access_; | |
| 6458 const UniqueSet<Map>* maps_; | |
| 6459 }; | |
| 6460 | |
| 6461 | |
| 6462 class HLoadNamedGeneric final : public HTemplateInstruction<2> { | |
| 6463 public: | |
| 6464 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HLoadNamedGeneric, HValue*, | |
| 6465 Handle<Name>, LanguageMode, | |
| 6466 InlineCacheState); | |
| 6467 | |
| 6468 HValue* context() const { return OperandAt(0); } | |
| 6469 HValue* object() const { return OperandAt(1); } | |
| 6470 Handle<Name> name() const { return name_; } | |
| 6471 | |
| 6472 InlineCacheState initialization_state() const { | |
| 6473 return initialization_state_; | |
| 6474 } | |
| 6475 FeedbackVectorSlot slot() const { return slot_; } | |
| 6476 Handle<TypeFeedbackVector> feedback_vector() const { | |
| 6477 return feedback_vector_; | |
| 6478 } | |
| 6479 bool HasVectorAndSlot() const { return true; } | |
| 6480 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector, | |
| 6481 FeedbackVectorSlot slot) { | |
| 6482 feedback_vector_ = vector; | |
| 6483 slot_ = slot; | |
| 6484 } | |
| 6485 | |
| 6486 Representation RequiredInputRepresentation(int index) override { | |
| 6487 return Representation::Tagged(); | |
| 6488 } | |
| 6489 | |
| 6490 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 6491 | |
| 6492 DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric) | |
| 6493 | |
| 6494 LanguageMode language_mode() const { return language_mode_; } | |
| 6495 | |
| 6496 private: | |
| 6497 HLoadNamedGeneric(HValue* context, HValue* object, Handle<Name> name, | |
| 6498 LanguageMode language_mode, | |
| 6499 InlineCacheState initialization_state) | |
| 6500 : name_(name), | |
| 6501 language_mode_(language_mode), | |
| 6502 initialization_state_(initialization_state) { | |
| 6503 SetOperandAt(0, context); | |
| 6504 SetOperandAt(1, object); | |
| 6505 set_representation(Representation::Tagged()); | |
| 6506 SetAllSideEffects(); | |
| 6507 } | |
| 6508 | |
| 6509 Handle<Name> name_; | |
| 6510 Handle<TypeFeedbackVector> feedback_vector_; | |
| 6511 FeedbackVectorSlot slot_; | |
| 6512 LanguageMode language_mode_; | |
| 6513 InlineCacheState initialization_state_; | |
| 6514 }; | |
| 6515 | |
| 6516 | |
| 6517 class HLoadFunctionPrototype final : public HUnaryOperation { | |
| 6518 public: | |
| 6519 DECLARE_INSTRUCTION_FACTORY_P1(HLoadFunctionPrototype, HValue*); | |
| 6520 | |
| 6521 HValue* function() { return OperandAt(0); } | |
| 6522 | |
| 6523 Representation RequiredInputRepresentation(int index) override { | |
| 6524 return Representation::Tagged(); | |
| 6525 } | |
| 6526 | |
| 6527 DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype) | |
| 6528 | |
| 6529 protected: | |
| 6530 bool DataEquals(HValue* other) override { return true; } | |
| 6531 | |
| 6532 private: | |
| 6533 explicit HLoadFunctionPrototype(HValue* function) | |
| 6534 : HUnaryOperation(function) { | |
| 6535 set_representation(Representation::Tagged()); | |
| 6536 SetFlag(kUseGVN); | |
| 6537 SetDependsOnFlag(kCalls); | |
| 6538 } | |
| 6539 }; | |
| 6540 | |
| 6541 class ArrayInstructionInterface { | |
| 6542 public: | |
| 6543 virtual HValue* GetKey() = 0; | |
| 6544 virtual void SetKey(HValue* key) = 0; | |
| 6545 virtual ElementsKind elements_kind() const = 0; | |
| 6546 // TryIncreaseBaseOffset returns false if overflow would result. | |
| 6547 virtual bool TryIncreaseBaseOffset(uint32_t increase_by_value) = 0; | |
| 6548 virtual bool IsDehoisted() const = 0; | |
| 6549 virtual void SetDehoisted(bool is_dehoisted) = 0; | |
| 6550 virtual ~ArrayInstructionInterface() { } | |
| 6551 | |
| 6552 static Representation KeyedAccessIndexRequirement(Representation r) { | |
| 6553 return r.IsInteger32() || SmiValuesAre32Bits() | |
| 6554 ? Representation::Integer32() : Representation::Smi(); | |
| 6555 } | |
| 6556 }; | |
| 6557 | |
| 6558 | |
| 6559 static const int kDefaultKeyedHeaderOffsetSentinel = -1; | |
| 6560 | |
| 6561 enum LoadKeyedHoleMode { | |
| 6562 NEVER_RETURN_HOLE, | |
| 6563 ALLOW_RETURN_HOLE, | |
| 6564 CONVERT_HOLE_TO_UNDEFINED | |
| 6565 }; | |
| 6566 | |
| 6567 | |
| 6568 class HLoadKeyed final : public HTemplateInstruction<3>, | |
| 6569 public ArrayInstructionInterface { | |
| 6570 public: | |
| 6571 DECLARE_INSTRUCTION_FACTORY_P4(HLoadKeyed, HValue*, HValue*, HValue*, | |
| 6572 ElementsKind); | |
| 6573 DECLARE_INSTRUCTION_FACTORY_P5(HLoadKeyed, HValue*, HValue*, HValue*, | |
| 6574 ElementsKind, LoadKeyedHoleMode); | |
| 6575 DECLARE_INSTRUCTION_FACTORY_P6(HLoadKeyed, HValue*, HValue*, HValue*, | |
| 6576 ElementsKind, LoadKeyedHoleMode, int); | |
| 6577 | |
| 6578 bool is_fixed_typed_array() const { | |
| 6579 return IsFixedTypedArrayElementsKind(elements_kind()); | |
| 6580 } | |
| 6581 HValue* elements() const { return OperandAt(0); } | |
| 6582 HValue* key() const { return OperandAt(1); } | |
| 6583 HValue* dependency() const { | |
| 6584 DCHECK(HasDependency()); | |
| 6585 return OperandAt(2); | |
| 6586 } | |
| 6587 bool HasDependency() const { return OperandAt(0) != OperandAt(2); } | |
| 6588 uint32_t base_offset() const { return BaseOffsetField::decode(bit_field_); } | |
| 6589 bool TryIncreaseBaseOffset(uint32_t increase_by_value) override; | |
| 6590 HValue* GetKey() override { return key(); } | |
| 6591 void SetKey(HValue* key) override { SetOperandAt(1, key); } | |
| 6592 bool IsDehoisted() const override { | |
| 6593 return IsDehoistedField::decode(bit_field_); | |
| 6594 } | |
| 6595 void SetDehoisted(bool is_dehoisted) override { | |
| 6596 bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted); | |
| 6597 } | |
| 6598 ElementsKind elements_kind() const override { | |
| 6599 return ElementsKindField::decode(bit_field_); | |
| 6600 } | |
| 6601 LoadKeyedHoleMode hole_mode() const { | |
| 6602 return HoleModeField::decode(bit_field_); | |
| 6603 } | |
| 6604 | |
| 6605 Representation RequiredInputRepresentation(int index) override { | |
| 6606 // kind_fast: tagged[int32] (none) | |
| 6607 // kind_double: tagged[int32] (none) | |
| 6608 // kind_fixed_typed_array: external[int32] (none) | |
| 6609 // kind_external: external[int32] (none) | |
| 6610 if (index == 0) { | |
| 6611 return is_fixed_typed_array() ? Representation::External() | |
| 6612 : Representation::Tagged(); | |
| 6613 } | |
| 6614 if (index == 1) { | |
| 6615 return ArrayInstructionInterface::KeyedAccessIndexRequirement( | |
| 6616 OperandAt(1)->representation()); | |
| 6617 } | |
| 6618 return Representation::None(); | |
| 6619 } | |
| 6620 | |
| 6621 Representation observed_input_representation(int index) override { | |
| 6622 return RequiredInputRepresentation(index); | |
| 6623 } | |
| 6624 | |
| 6625 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 6626 | |
| 6627 bool UsesMustHandleHole() const; | |
| 6628 bool AllUsesCanTreatHoleAsNaN() const; | |
| 6629 bool RequiresHoleCheck() const; | |
| 6630 | |
| 6631 Range* InferRange(Zone* zone) override; | |
| 6632 | |
| 6633 DECLARE_CONCRETE_INSTRUCTION(LoadKeyed) | |
| 6634 | |
| 6635 protected: | |
| 6636 bool DataEquals(HValue* other) override { | |
| 6637 if (!other->IsLoadKeyed()) return false; | |
| 6638 HLoadKeyed* other_load = HLoadKeyed::cast(other); | |
| 6639 | |
| 6640 if (base_offset() != other_load->base_offset()) return false; | |
| 6641 return elements_kind() == other_load->elements_kind(); | |
| 6642 } | |
| 6643 | |
| 6644 private: | |
| 6645 HLoadKeyed(HValue* obj, HValue* key, HValue* dependency, | |
| 6646 ElementsKind elements_kind, | |
| 6647 LoadKeyedHoleMode mode = NEVER_RETURN_HOLE, | |
| 6648 int offset = kDefaultKeyedHeaderOffsetSentinel) | |
| 6649 : bit_field_(0) { | |
| 6650 offset = offset == kDefaultKeyedHeaderOffsetSentinel | |
| 6651 ? GetDefaultHeaderSizeForElementsKind(elements_kind) | |
| 6652 : offset; | |
| 6653 bit_field_ = ElementsKindField::encode(elements_kind) | | |
| 6654 HoleModeField::encode(mode) | | |
| 6655 BaseOffsetField::encode(offset); | |
| 6656 | |
| 6657 SetOperandAt(0, obj); | |
| 6658 SetOperandAt(1, key); | |
| 6659 SetOperandAt(2, dependency != NULL ? dependency : obj); | |
| 6660 | |
| 6661 if (!is_fixed_typed_array()) { | |
| 6662 // I can detect the case between storing double (holey and fast) and | |
| 6663 // smi/object by looking at elements_kind_. | |
| 6664 DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) || | |
| 6665 IsFastDoubleElementsKind(elements_kind)); | |
| 6666 | |
| 6667 if (IsFastSmiOrObjectElementsKind(elements_kind)) { | |
| 6668 if (IsFastSmiElementsKind(elements_kind) && | |
| 6669 (!IsHoleyElementsKind(elements_kind) || | |
| 6670 mode == NEVER_RETURN_HOLE)) { | |
| 6671 set_type(HType::Smi()); | |
| 6672 if (SmiValuesAre32Bits() && !RequiresHoleCheck()) { | |
| 6673 set_representation(Representation::Integer32()); | |
| 6674 } else { | |
| 6675 set_representation(Representation::Smi()); | |
| 6676 } | |
| 6677 } else { | |
| 6678 set_representation(Representation::Tagged()); | |
| 6679 } | |
| 6680 | |
| 6681 SetDependsOnFlag(kArrayElements); | |
| 6682 } else { | |
| 6683 set_representation(Representation::Double()); | |
| 6684 SetDependsOnFlag(kDoubleArrayElements); | |
| 6685 } | |
| 6686 } else { | |
| 6687 if (elements_kind == FLOAT32_ELEMENTS || | |
| 6688 elements_kind == FLOAT64_ELEMENTS) { | |
| 6689 set_representation(Representation::Double()); | |
| 6690 } else { | |
| 6691 set_representation(Representation::Integer32()); | |
| 6692 } | |
| 6693 | |
| 6694 if (is_fixed_typed_array()) { | |
| 6695 SetDependsOnFlag(kExternalMemory); | |
| 6696 SetDependsOnFlag(kTypedArrayElements); | |
| 6697 } else { | |
| 6698 UNREACHABLE(); | |
| 6699 } | |
| 6700 // Native code could change the specialized array. | |
| 6701 SetDependsOnFlag(kCalls); | |
| 6702 } | |
| 6703 | |
| 6704 SetFlag(kUseGVN); | |
| 6705 } | |
| 6706 | |
| 6707 bool IsDeletable() const override { return !RequiresHoleCheck(); } | |
| 6708 | |
| 6709 // Establish some checks around our packed fields | |
| 6710 enum LoadKeyedBits { | |
| 6711 kBitsForElementsKind = 5, | |
| 6712 kBitsForHoleMode = 2, | |
| 6713 kBitsForBaseOffset = 24, | |
| 6714 kBitsForIsDehoisted = 1, | |
| 6715 | |
| 6716 kStartElementsKind = 0, | |
| 6717 kStartHoleMode = kStartElementsKind + kBitsForElementsKind, | |
| 6718 kStartBaseOffset = kStartHoleMode + kBitsForHoleMode, | |
| 6719 kStartIsDehoisted = kStartBaseOffset + kBitsForBaseOffset | |
| 6720 }; | |
| 6721 | |
| 6722 STATIC_ASSERT((kBitsForElementsKind + kBitsForHoleMode + kBitsForBaseOffset + | |
| 6723 kBitsForIsDehoisted) <= sizeof(uint32_t) * 8); | |
| 6724 STATIC_ASSERT(kElementsKindCount <= (1 << kBitsForElementsKind)); | |
| 6725 class ElementsKindField: | |
| 6726 public BitField<ElementsKind, kStartElementsKind, kBitsForElementsKind> | |
| 6727 {}; // NOLINT | |
| 6728 class HoleModeField: | |
| 6729 public BitField<LoadKeyedHoleMode, kStartHoleMode, kBitsForHoleMode> | |
| 6730 {}; // NOLINT | |
| 6731 class BaseOffsetField: | |
| 6732 public BitField<uint32_t, kStartBaseOffset, kBitsForBaseOffset> | |
| 6733 {}; // NOLINT | |
| 6734 class IsDehoistedField: | |
| 6735 public BitField<bool, kStartIsDehoisted, kBitsForIsDehoisted> | |
| 6736 {}; // NOLINT | |
| 6737 uint32_t bit_field_; | |
| 6738 }; | |
| 6739 | |
| 6740 | |
| 6741 class HLoadKeyedGeneric final : public HTemplateInstruction<3> { | |
| 6742 public: | |
| 6743 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HLoadKeyedGeneric, HValue*, | |
| 6744 HValue*, LanguageMode, | |
| 6745 InlineCacheState); | |
| 6746 HValue* object() const { return OperandAt(0); } | |
| 6747 HValue* key() const { return OperandAt(1); } | |
| 6748 HValue* context() const { return OperandAt(2); } | |
| 6749 InlineCacheState initialization_state() const { | |
| 6750 return initialization_state_; | |
| 6751 } | |
| 6752 FeedbackVectorSlot slot() const { return slot_; } | |
| 6753 Handle<TypeFeedbackVector> feedback_vector() const { | |
| 6754 return feedback_vector_; | |
| 6755 } | |
| 6756 bool HasVectorAndSlot() const { | |
| 6757 DCHECK(initialization_state_ == MEGAMORPHIC || !feedback_vector_.is_null()); | |
| 6758 return !feedback_vector_.is_null(); | |
| 6759 } | |
| 6760 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector, | |
| 6761 FeedbackVectorSlot slot) { | |
| 6762 feedback_vector_ = vector; | |
| 6763 slot_ = slot; | |
| 6764 } | |
| 6765 | |
| 6766 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 6767 | |
| 6768 Representation RequiredInputRepresentation(int index) override { | |
| 6769 // tagged[tagged] | |
| 6770 return Representation::Tagged(); | |
| 6771 } | |
| 6772 | |
| 6773 HValue* Canonicalize() override; | |
| 6774 | |
| 6775 DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric) | |
| 6776 | |
| 6777 LanguageMode language_mode() const { return language_mode_; } | |
| 6778 | |
| 6779 private: | |
| 6780 HLoadKeyedGeneric(HValue* context, HValue* obj, HValue* key, | |
| 6781 LanguageMode language_mode, | |
| 6782 InlineCacheState initialization_state) | |
| 6783 : initialization_state_(initialization_state), | |
| 6784 language_mode_(language_mode) { | |
| 6785 set_representation(Representation::Tagged()); | |
| 6786 SetOperandAt(0, obj); | |
| 6787 SetOperandAt(1, key); | |
| 6788 SetOperandAt(2, context); | |
| 6789 SetAllSideEffects(); | |
| 6790 } | |
| 6791 | |
| 6792 Handle<TypeFeedbackVector> feedback_vector_; | |
| 6793 FeedbackVectorSlot slot_; | |
| 6794 InlineCacheState initialization_state_; | |
| 6795 LanguageMode language_mode_; | |
| 6796 }; | |
| 6797 | |
| 6798 | |
| 6799 // Indicates whether the store is a store to an entry that was previously | |
| 6800 // initialized or not. | |
| 6801 enum StoreFieldOrKeyedMode { | |
| 6802 // The entry could be either previously initialized or not. | |
| 6803 INITIALIZING_STORE, | |
| 6804 // At the time of this store it is guaranteed that the entry is already | |
| 6805 // initialized. | |
| 6806 STORE_TO_INITIALIZED_ENTRY | |
| 6807 }; | |
| 6808 | |
| 6809 | |
| 6810 class HStoreNamedField final : public HTemplateInstruction<3> { | |
| 6811 public: | |
| 6812 DECLARE_INSTRUCTION_FACTORY_P3(HStoreNamedField, HValue*, | |
| 6813 HObjectAccess, HValue*); | |
| 6814 DECLARE_INSTRUCTION_FACTORY_P4(HStoreNamedField, HValue*, | |
| 6815 HObjectAccess, HValue*, StoreFieldOrKeyedMode); | |
| 6816 | |
| 6817 DECLARE_CONCRETE_INSTRUCTION(StoreNamedField) | |
| 6818 | |
| 6819 bool HasEscapingOperandAt(int index) override { return index == 1; } | |
| 6820 bool HasOutOfBoundsAccess(int size) override { | |
| 6821 return !access().IsInobject() || access().offset() >= size; | |
| 6822 } | |
| 6823 Representation RequiredInputRepresentation(int index) override { | |
| 6824 if (index == 0 && access().IsExternalMemory()) { | |
| 6825 // object must be external in case of external memory access | |
| 6826 return Representation::External(); | |
| 6827 } else if (index == 1) { | |
| 6828 if (field_representation().IsInteger8() || | |
| 6829 field_representation().IsUInteger8() || | |
| 6830 field_representation().IsInteger16() || | |
| 6831 field_representation().IsUInteger16() || | |
| 6832 field_representation().IsInteger32()) { | |
| 6833 return Representation::Integer32(); | |
| 6834 } else if (field_representation().IsDouble()) { | |
| 6835 return field_representation(); | |
| 6836 } else if (field_representation().IsSmi()) { | |
| 6837 if (SmiValuesAre32Bits() && | |
| 6838 store_mode() == STORE_TO_INITIALIZED_ENTRY) { | |
| 6839 return Representation::Integer32(); | |
| 6840 } | |
| 6841 return field_representation(); | |
| 6842 } else if (field_representation().IsExternal()) { | |
| 6843 return Representation::External(); | |
| 6844 } | |
| 6845 } | |
| 6846 return Representation::Tagged(); | |
| 6847 } | |
| 6848 virtual bool HandleSideEffectDominator(GVNFlag side_effect, | |
| 6849 HValue* dominator) override { | |
| 6850 DCHECK(side_effect == kNewSpacePromotion); | |
| 6851 if (!FLAG_use_write_barrier_elimination) return false; | |
| 6852 dominator_ = dominator; | |
| 6853 return false; | |
| 6854 } | |
| 6855 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 6856 | |
| 6857 HValue* object() const { return OperandAt(0); } | |
| 6858 HValue* value() const { return OperandAt(1); } | |
| 6859 HValue* transition() const { return OperandAt(2); } | |
| 6860 | |
| 6861 HObjectAccess access() const { return access_; } | |
| 6862 HValue* dominator() const { return dominator_; } | |
| 6863 bool has_transition() const { return HasTransitionField::decode(bit_field_); } | |
| 6864 StoreFieldOrKeyedMode store_mode() const { | |
| 6865 return StoreModeField::decode(bit_field_); | |
| 6866 } | |
| 6867 | |
| 6868 Handle<Map> transition_map() const { | |
| 6869 if (has_transition()) { | |
| 6870 return Handle<Map>::cast( | |
| 6871 HConstant::cast(transition())->handle(isolate())); | |
| 6872 } else { | |
| 6873 return Handle<Map>(); | |
| 6874 } | |
| 6875 } | |
| 6876 | |
| 6877 void SetTransition(HConstant* transition) { | |
| 6878 DCHECK(!has_transition()); // Only set once. | |
| 6879 SetOperandAt(2, transition); | |
| 6880 bit_field_ = HasTransitionField::update(bit_field_, true); | |
| 6881 SetChangesFlag(kMaps); | |
| 6882 } | |
| 6883 | |
| 6884 bool NeedsWriteBarrier() const { | |
| 6885 DCHECK(!field_representation().IsDouble() || | |
| 6886 (FLAG_unbox_double_fields && access_.IsInobject()) || | |
| 6887 !has_transition()); | |
| 6888 if (field_representation().IsDouble()) return false; | |
| 6889 if (field_representation().IsSmi()) return false; | |
| 6890 if (field_representation().IsInteger32()) return false; | |
| 6891 if (field_representation().IsExternal()) return false; | |
| 6892 return StoringValueNeedsWriteBarrier(value()) && | |
| 6893 ReceiverObjectNeedsWriteBarrier(object(), value(), dominator()); | |
| 6894 } | |
| 6895 | |
| 6896 bool NeedsWriteBarrierForMap() { | |
| 6897 return ReceiverObjectNeedsWriteBarrier(object(), transition(), | |
| 6898 dominator()); | |
| 6899 } | |
| 6900 | |
| 6901 SmiCheck SmiCheckForWriteBarrier() const { | |
| 6902 if (field_representation().IsHeapObject()) return OMIT_SMI_CHECK; | |
| 6903 if (value()->type().IsHeapObject()) return OMIT_SMI_CHECK; | |
| 6904 return INLINE_SMI_CHECK; | |
| 6905 } | |
| 6906 | |
| 6907 PointersToHereCheck PointersToHereCheckForValue() const { | |
| 6908 return PointersToHereCheckForObject(value(), dominator()); | |
| 6909 } | |
| 6910 | |
| 6911 Representation field_representation() const { | |
| 6912 return access_.representation(); | |
| 6913 } | |
| 6914 | |
| 6915 void UpdateValue(HValue* value) { | |
| 6916 SetOperandAt(1, value); | |
| 6917 } | |
| 6918 | |
| 6919 bool CanBeReplacedWith(HStoreNamedField* that) const { | |
| 6920 if (!this->access().Equals(that->access())) return false; | |
| 6921 if (SmiValuesAre32Bits() && | |
| 6922 this->field_representation().IsSmi() && | |
| 6923 this->store_mode() == INITIALIZING_STORE && | |
| 6924 that->store_mode() == STORE_TO_INITIALIZED_ENTRY) { | |
| 6925 // We cannot replace an initializing store to a smi field with a store to | |
| 6926 // an initialized entry on 64-bit architectures (with 32-bit smis). | |
| 6927 return false; | |
| 6928 } | |
| 6929 return true; | |
| 6930 } | |
| 6931 | |
| 6932 private: | |
| 6933 HStoreNamedField(HValue* obj, HObjectAccess access, HValue* val, | |
| 6934 StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE) | |
| 6935 : access_(access), | |
| 6936 dominator_(NULL), | |
| 6937 bit_field_(HasTransitionField::encode(false) | | |
| 6938 StoreModeField::encode(store_mode)) { | |
| 6939 // Stores to a non existing in-object property are allowed only to the | |
| 6940 // newly allocated objects (via HAllocate or HInnerAllocatedObject). | |
| 6941 DCHECK(!access.IsInobject() || access.existing_inobject_property() || | |
| 6942 obj->IsAllocate() || obj->IsInnerAllocatedObject()); | |
| 6943 SetOperandAt(0, obj); | |
| 6944 SetOperandAt(1, val); | |
| 6945 SetOperandAt(2, obj); | |
| 6946 access.SetGVNFlags(this, STORE); | |
| 6947 } | |
| 6948 | |
| 6949 class HasTransitionField : public BitField<bool, 0, 1> {}; | |
| 6950 class StoreModeField : public BitField<StoreFieldOrKeyedMode, 1, 1> {}; | |
| 6951 | |
| 6952 HObjectAccess access_; | |
| 6953 HValue* dominator_; | |
| 6954 uint32_t bit_field_; | |
| 6955 }; | |
| 6956 | |
| 6957 | |
| 6958 class HStoreNamedGeneric final : public HTemplateInstruction<3> { | |
| 6959 public: | |
| 6960 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(HStoreNamedGeneric, HValue*, | |
| 6961 Handle<Name>, HValue*, | |
| 6962 LanguageMode, InlineCacheState); | |
| 6963 HValue* object() const { return OperandAt(0); } | |
| 6964 HValue* value() const { return OperandAt(1); } | |
| 6965 HValue* context() const { return OperandAt(2); } | |
| 6966 Handle<Name> name() const { return name_; } | |
| 6967 LanguageMode language_mode() const { return language_mode_; } | |
| 6968 InlineCacheState initialization_state() const { | |
| 6969 return initialization_state_; | |
| 6970 } | |
| 6971 | |
| 6972 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 6973 | |
| 6974 Representation RequiredInputRepresentation(int index) override { | |
| 6975 return Representation::Tagged(); | |
| 6976 } | |
| 6977 | |
| 6978 FeedbackVectorSlot slot() const { return slot_; } | |
| 6979 Handle<TypeFeedbackVector> feedback_vector() const { | |
| 6980 return feedback_vector_; | |
| 6981 } | |
| 6982 bool HasVectorAndSlot() const { return FLAG_vector_stores; } | |
| 6983 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector, | |
| 6984 FeedbackVectorSlot slot) { | |
| 6985 feedback_vector_ = vector; | |
| 6986 slot_ = slot; | |
| 6987 } | |
| 6988 | |
| 6989 DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric) | |
| 6990 | |
| 6991 private: | |
| 6992 HStoreNamedGeneric(HValue* context, HValue* object, Handle<Name> name, | |
| 6993 HValue* value, LanguageMode language_mode, | |
| 6994 InlineCacheState initialization_state) | |
| 6995 : name_(name), | |
| 6996 language_mode_(language_mode), | |
| 6997 initialization_state_(initialization_state) { | |
| 6998 SetOperandAt(0, object); | |
| 6999 SetOperandAt(1, value); | |
| 7000 SetOperandAt(2, context); | |
| 7001 SetAllSideEffects(); | |
| 7002 } | |
| 7003 | |
| 7004 Handle<Name> name_; | |
| 7005 Handle<TypeFeedbackVector> feedback_vector_; | |
| 7006 FeedbackVectorSlot slot_; | |
| 7007 LanguageMode language_mode_; | |
| 7008 InlineCacheState initialization_state_; | |
| 7009 }; | |
| 7010 | |
| 7011 | |
| 7012 class HStoreGlobalViaContext final : public HTemplateInstruction<2> { | |
| 7013 public: | |
| 7014 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HStoreGlobalViaContext, HValue*, | |
| 7015 int, int, LanguageMode); | |
| 7016 HValue* context() const { return OperandAt(0); } | |
| 7017 HValue* value() const { return OperandAt(1); } | |
| 7018 int depth() const { return depth_; } | |
| 7019 int slot_index() const { return slot_index_; } | |
| 7020 LanguageMode language_mode() const { return language_mode_; } | |
| 7021 | |
| 7022 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 7023 | |
| 7024 Representation RequiredInputRepresentation(int index) override { | |
| 7025 return Representation::Tagged(); | |
| 7026 } | |
| 7027 | |
| 7028 DECLARE_CONCRETE_INSTRUCTION(StoreGlobalViaContext) | |
| 7029 | |
| 7030 private: | |
| 7031 HStoreGlobalViaContext(HValue* context, HValue* value, int depth, | |
| 7032 int slot_index, LanguageMode language_mode) | |
| 7033 : depth_(depth), slot_index_(slot_index), language_mode_(language_mode) { | |
| 7034 SetOperandAt(0, context); | |
| 7035 SetOperandAt(1, value); | |
| 7036 SetAllSideEffects(); | |
| 7037 } | |
| 7038 | |
| 7039 int const depth_; | |
| 7040 int const slot_index_; | |
| 7041 LanguageMode const language_mode_; | |
| 7042 }; | |
| 7043 | |
| 7044 | |
| 7045 class HStoreKeyed final : public HTemplateInstruction<3>, | |
| 7046 public ArrayInstructionInterface { | |
| 7047 public: | |
| 7048 DECLARE_INSTRUCTION_FACTORY_P4(HStoreKeyed, HValue*, HValue*, HValue*, | |
| 7049 ElementsKind); | |
| 7050 DECLARE_INSTRUCTION_FACTORY_P5(HStoreKeyed, HValue*, HValue*, HValue*, | |
| 7051 ElementsKind, StoreFieldOrKeyedMode); | |
| 7052 DECLARE_INSTRUCTION_FACTORY_P6(HStoreKeyed, HValue*, HValue*, HValue*, | |
| 7053 ElementsKind, StoreFieldOrKeyedMode, int); | |
| 7054 | |
| 7055 Representation RequiredInputRepresentation(int index) override { | |
| 7056 // kind_fast: tagged[int32] = tagged | |
| 7057 // kind_double: tagged[int32] = double | |
| 7058 // kind_smi : tagged[int32] = smi | |
| 7059 // kind_fixed_typed_array: tagged[int32] = (double | int32) | |
| 7060 // kind_external: external[int32] = (double | int32) | |
| 7061 if (index == 0) { | |
| 7062 return is_fixed_typed_array() ? Representation::External() | |
| 7063 : Representation::Tagged(); | |
| 7064 } else if (index == 1) { | |
| 7065 return ArrayInstructionInterface::KeyedAccessIndexRequirement( | |
| 7066 OperandAt(1)->representation()); | |
| 7067 } | |
| 7068 | |
| 7069 DCHECK_EQ(index, 2); | |
| 7070 return RequiredValueRepresentation(elements_kind(), store_mode()); | |
| 7071 } | |
| 7072 | |
| 7073 static Representation RequiredValueRepresentation( | |
| 7074 ElementsKind kind, StoreFieldOrKeyedMode mode) { | |
| 7075 if (IsDoubleOrFloatElementsKind(kind)) { | |
| 7076 return Representation::Double(); | |
| 7077 } | |
| 7078 | |
| 7079 if (kind == FAST_SMI_ELEMENTS && SmiValuesAre32Bits() && | |
| 7080 mode == STORE_TO_INITIALIZED_ENTRY) { | |
| 7081 return Representation::Integer32(); | |
| 7082 } | |
| 7083 | |
| 7084 if (IsFastSmiElementsKind(kind)) { | |
| 7085 return Representation::Smi(); | |
| 7086 } | |
| 7087 | |
| 7088 if (IsFixedTypedArrayElementsKind(kind)) { | |
| 7089 return Representation::Integer32(); | |
| 7090 } | |
| 7091 return Representation::Tagged(); | |
| 7092 } | |
| 7093 | |
| 7094 bool is_fixed_typed_array() const { | |
| 7095 return IsFixedTypedArrayElementsKind(elements_kind()); | |
| 7096 } | |
| 7097 | |
| 7098 Representation observed_input_representation(int index) override { | |
| 7099 if (index < 2) return RequiredInputRepresentation(index); | |
| 7100 if (IsUninitialized()) { | |
| 7101 return Representation::None(); | |
| 7102 } | |
| 7103 Representation r = | |
| 7104 RequiredValueRepresentation(elements_kind(), store_mode()); | |
| 7105 // For fast object elements kinds, don't assume anything. | |
| 7106 if (r.IsTagged()) return Representation::None(); | |
| 7107 return r; | |
| 7108 } | |
| 7109 | |
| 7110 HValue* elements() const { return OperandAt(0); } | |
| 7111 HValue* key() const { return OperandAt(1); } | |
| 7112 HValue* value() const { return OperandAt(2); } | |
| 7113 bool value_is_smi() const { return IsFastSmiElementsKind(elements_kind()); } | |
| 7114 StoreFieldOrKeyedMode store_mode() const { | |
| 7115 return StoreModeField::decode(bit_field_); | |
| 7116 } | |
| 7117 ElementsKind elements_kind() const override { | |
| 7118 return ElementsKindField::decode(bit_field_); | |
| 7119 } | |
| 7120 uint32_t base_offset() const { return base_offset_; } | |
| 7121 bool TryIncreaseBaseOffset(uint32_t increase_by_value) override; | |
| 7122 HValue* GetKey() override { return key(); } | |
| 7123 void SetKey(HValue* key) override { SetOperandAt(1, key); } | |
| 7124 bool IsDehoisted() const override { | |
| 7125 return IsDehoistedField::decode(bit_field_); | |
| 7126 } | |
| 7127 void SetDehoisted(bool is_dehoisted) override { | |
| 7128 bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted); | |
| 7129 } | |
| 7130 bool IsUninitialized() { return IsUninitializedField::decode(bit_field_); } | |
| 7131 void SetUninitialized(bool is_uninitialized) { | |
| 7132 bit_field_ = IsUninitializedField::update(bit_field_, is_uninitialized); | |
| 7133 } | |
| 7134 | |
| 7135 bool IsConstantHoleStore() { | |
| 7136 return value()->IsConstant() && HConstant::cast(value())->IsTheHole(); | |
| 7137 } | |
| 7138 | |
| 7139 virtual bool HandleSideEffectDominator(GVNFlag side_effect, | |
| 7140 HValue* dominator) override { | |
| 7141 DCHECK(side_effect == kNewSpacePromotion); | |
| 7142 dominator_ = dominator; | |
| 7143 return false; | |
| 7144 } | |
| 7145 | |
| 7146 HValue* dominator() const { return dominator_; } | |
| 7147 | |
| 7148 bool NeedsWriteBarrier() { | |
| 7149 if (value_is_smi()) { | |
| 7150 return false; | |
| 7151 } else { | |
| 7152 return StoringValueNeedsWriteBarrier(value()) && | |
| 7153 ReceiverObjectNeedsWriteBarrier(elements(), value(), dominator()); | |
| 7154 } | |
| 7155 } | |
| 7156 | |
| 7157 PointersToHereCheck PointersToHereCheckForValue() const { | |
| 7158 return PointersToHereCheckForObject(value(), dominator()); | |
| 7159 } | |
| 7160 | |
| 7161 bool NeedsCanonicalization(); | |
| 7162 | |
| 7163 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 7164 | |
| 7165 DECLARE_CONCRETE_INSTRUCTION(StoreKeyed) | |
| 7166 | |
| 7167 private: | |
| 7168 HStoreKeyed(HValue* obj, HValue* key, HValue* val, ElementsKind elements_kind, | |
| 7169 StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE, | |
| 7170 int offset = kDefaultKeyedHeaderOffsetSentinel) | |
| 7171 : base_offset_(offset == kDefaultKeyedHeaderOffsetSentinel | |
| 7172 ? GetDefaultHeaderSizeForElementsKind(elements_kind) | |
| 7173 : offset), | |
| 7174 bit_field_(IsDehoistedField::encode(false) | | |
| 7175 IsUninitializedField::encode(false) | | |
| 7176 StoreModeField::encode(store_mode) | | |
| 7177 ElementsKindField::encode(elements_kind)), | |
| 7178 dominator_(NULL) { | |
| 7179 SetOperandAt(0, obj); | |
| 7180 SetOperandAt(1, key); | |
| 7181 SetOperandAt(2, val); | |
| 7182 | |
| 7183 if (IsFastObjectElementsKind(elements_kind)) { | |
| 7184 SetFlag(kTrackSideEffectDominators); | |
| 7185 SetDependsOnFlag(kNewSpacePromotion); | |
| 7186 } | |
| 7187 if (IsFastDoubleElementsKind(elements_kind)) { | |
| 7188 SetChangesFlag(kDoubleArrayElements); | |
| 7189 } else if (IsFastSmiElementsKind(elements_kind)) { | |
| 7190 SetChangesFlag(kArrayElements); | |
| 7191 } else if (is_fixed_typed_array()) { | |
| 7192 SetChangesFlag(kTypedArrayElements); | |
| 7193 SetChangesFlag(kExternalMemory); | |
| 7194 SetFlag(kAllowUndefinedAsNaN); | |
| 7195 } else { | |
| 7196 SetChangesFlag(kArrayElements); | |
| 7197 } | |
| 7198 | |
| 7199 // {UNSIGNED_,}{BYTE,SHORT,INT}_ELEMENTS are truncating. | |
| 7200 if (elements_kind >= UINT8_ELEMENTS && elements_kind <= INT32_ELEMENTS) { | |
| 7201 SetFlag(kTruncatingToInt32); | |
| 7202 } | |
| 7203 } | |
| 7204 | |
| 7205 class IsDehoistedField : public BitField<bool, 0, 1> {}; | |
| 7206 class IsUninitializedField : public BitField<bool, 1, 1> {}; | |
| 7207 class StoreModeField : public BitField<StoreFieldOrKeyedMode, 2, 1> {}; | |
| 7208 class ElementsKindField : public BitField<ElementsKind, 3, 5> {}; | |
| 7209 | |
| 7210 uint32_t base_offset_; | |
| 7211 uint32_t bit_field_; | |
| 7212 HValue* dominator_; | |
| 7213 }; | |
| 7214 | |
| 7215 | |
| 7216 class HStoreKeyedGeneric final : public HTemplateInstruction<4> { | |
| 7217 public: | |
| 7218 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(HStoreKeyedGeneric, HValue*, | |
| 7219 HValue*, HValue*, LanguageMode, | |
| 7220 InlineCacheState); | |
| 7221 | |
| 7222 HValue* object() const { return OperandAt(0); } | |
| 7223 HValue* key() const { return OperandAt(1); } | |
| 7224 HValue* value() const { return OperandAt(2); } | |
| 7225 HValue* context() const { return OperandAt(3); } | |
| 7226 LanguageMode language_mode() const { return language_mode_; } | |
| 7227 InlineCacheState initialization_state() const { | |
| 7228 return initialization_state_; | |
| 7229 } | |
| 7230 | |
| 7231 Representation RequiredInputRepresentation(int index) override { | |
| 7232 // tagged[tagged] = tagged | |
| 7233 return Representation::Tagged(); | |
| 7234 } | |
| 7235 | |
| 7236 FeedbackVectorSlot slot() const { return slot_; } | |
| 7237 Handle<TypeFeedbackVector> feedback_vector() const { | |
| 7238 return feedback_vector_; | |
| 7239 } | |
| 7240 bool HasVectorAndSlot() const { | |
| 7241 DCHECK(!(FLAG_vector_stores && initialization_state_ != MEGAMORPHIC) || | |
| 7242 !feedback_vector_.is_null()); | |
| 7243 return !feedback_vector_.is_null(); | |
| 7244 } | |
| 7245 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector, | |
| 7246 FeedbackVectorSlot slot) { | |
| 7247 feedback_vector_ = vector; | |
| 7248 slot_ = slot; | |
| 7249 } | |
| 7250 | |
| 7251 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 7252 | |
| 7253 DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric) | |
| 7254 | |
| 7255 private: | |
| 7256 HStoreKeyedGeneric(HValue* context, HValue* object, HValue* key, | |
| 7257 HValue* value, LanguageMode language_mode, | |
| 7258 InlineCacheState initialization_state) | |
| 7259 : language_mode_(language_mode), | |
| 7260 initialization_state_(initialization_state) { | |
| 7261 SetOperandAt(0, object); | |
| 7262 SetOperandAt(1, key); | |
| 7263 SetOperandAt(2, value); | |
| 7264 SetOperandAt(3, context); | |
| 7265 SetAllSideEffects(); | |
| 7266 } | |
| 7267 | |
| 7268 Handle<TypeFeedbackVector> feedback_vector_; | |
| 7269 FeedbackVectorSlot slot_; | |
| 7270 LanguageMode language_mode_; | |
| 7271 InlineCacheState initialization_state_; | |
| 7272 }; | |
| 7273 | |
| 7274 | |
| 7275 class HTransitionElementsKind final : public HTemplateInstruction<2> { | |
| 7276 public: | |
| 7277 inline static HTransitionElementsKind* New(Isolate* isolate, Zone* zone, | |
| 7278 HValue* context, HValue* object, | |
| 7279 Handle<Map> original_map, | |
| 7280 Handle<Map> transitioned_map) { | |
| 7281 return new(zone) HTransitionElementsKind(context, object, | |
| 7282 original_map, transitioned_map); | |
| 7283 } | |
| 7284 | |
| 7285 Representation RequiredInputRepresentation(int index) override { | |
| 7286 return Representation::Tagged(); | |
| 7287 } | |
| 7288 | |
| 7289 HValue* object() const { return OperandAt(0); } | |
| 7290 HValue* context() const { return OperandAt(1); } | |
| 7291 Unique<Map> original_map() const { return original_map_; } | |
| 7292 Unique<Map> transitioned_map() const { return transitioned_map_; } | |
| 7293 ElementsKind from_kind() const { | |
| 7294 return FromElementsKindField::decode(bit_field_); | |
| 7295 } | |
| 7296 ElementsKind to_kind() const { | |
| 7297 return ToElementsKindField::decode(bit_field_); | |
| 7298 } | |
| 7299 bool map_is_stable() const { return MapIsStableField::decode(bit_field_); } | |
| 7300 | |
| 7301 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 7302 | |
| 7303 DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind) | |
| 7304 | |
| 7305 protected: | |
| 7306 bool DataEquals(HValue* other) override { | |
| 7307 HTransitionElementsKind* instr = HTransitionElementsKind::cast(other); | |
| 7308 return original_map_ == instr->original_map_ && | |
| 7309 transitioned_map_ == instr->transitioned_map_; | |
| 7310 } | |
| 7311 | |
| 7312 int RedefinedOperandIndex() override { return 0; } | |
| 7313 | |
| 7314 private: | |
| 7315 HTransitionElementsKind(HValue* context, HValue* object, | |
| 7316 Handle<Map> original_map, | |
| 7317 Handle<Map> transitioned_map) | |
| 7318 : original_map_(Unique<Map>(original_map)), | |
| 7319 transitioned_map_(Unique<Map>(transitioned_map)), | |
| 7320 bit_field_( | |
| 7321 FromElementsKindField::encode(original_map->elements_kind()) | | |
| 7322 ToElementsKindField::encode(transitioned_map->elements_kind()) | | |
| 7323 MapIsStableField::encode(transitioned_map->is_stable())) { | |
| 7324 SetOperandAt(0, object); | |
| 7325 SetOperandAt(1, context); | |
| 7326 SetFlag(kUseGVN); | |
| 7327 SetChangesFlag(kElementsKind); | |
| 7328 if (!IsSimpleMapChangeTransition(from_kind(), to_kind())) { | |
| 7329 SetChangesFlag(kElementsPointer); | |
| 7330 SetChangesFlag(kNewSpacePromotion); | |
| 7331 } | |
| 7332 set_representation(Representation::Tagged()); | |
| 7333 } | |
| 7334 | |
| 7335 class FromElementsKindField : public BitField<ElementsKind, 0, 5> {}; | |
| 7336 class ToElementsKindField : public BitField<ElementsKind, 5, 5> {}; | |
| 7337 class MapIsStableField : public BitField<bool, 10, 1> {}; | |
| 7338 | |
| 7339 Unique<Map> original_map_; | |
| 7340 Unique<Map> transitioned_map_; | |
| 7341 uint32_t bit_field_; | |
| 7342 }; | |
| 7343 | |
| 7344 | |
| 7345 class HStringAdd final : public HBinaryOperation { | |
| 7346 public: | |
| 7347 static HInstruction* New( | |
| 7348 Isolate* isolate, Zone* zone, HValue* context, HValue* left, | |
| 7349 HValue* right, PretenureFlag pretenure_flag = NOT_TENURED, | |
| 7350 StringAddFlags flags = STRING_ADD_CHECK_BOTH, | |
| 7351 Handle<AllocationSite> allocation_site = Handle<AllocationSite>::null()); | |
| 7352 | |
| 7353 StringAddFlags flags() const { return flags_; } | |
| 7354 PretenureFlag pretenure_flag() const { return pretenure_flag_; } | |
| 7355 | |
| 7356 Representation RequiredInputRepresentation(int index) override { | |
| 7357 return Representation::Tagged(); | |
| 7358 } | |
| 7359 | |
| 7360 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 7361 | |
| 7362 DECLARE_CONCRETE_INSTRUCTION(StringAdd) | |
| 7363 | |
| 7364 protected: | |
| 7365 bool DataEquals(HValue* other) override { | |
| 7366 return flags_ == HStringAdd::cast(other)->flags_ && | |
| 7367 pretenure_flag_ == HStringAdd::cast(other)->pretenure_flag_; | |
| 7368 } | |
| 7369 | |
| 7370 private: | |
| 7371 HStringAdd(HValue* context, HValue* left, HValue* right, | |
| 7372 PretenureFlag pretenure_flag, StringAddFlags flags, | |
| 7373 Handle<AllocationSite> allocation_site) | |
| 7374 : HBinaryOperation(context, left, right, Strength::WEAK, HType::String()), | |
| 7375 flags_(flags), | |
| 7376 pretenure_flag_(pretenure_flag) { | |
| 7377 set_representation(Representation::Tagged()); | |
| 7378 if ((flags & STRING_ADD_CONVERT) == STRING_ADD_CONVERT) { | |
| 7379 SetAllSideEffects(); | |
| 7380 ClearFlag(kUseGVN); | |
| 7381 } else { | |
| 7382 SetChangesFlag(kNewSpacePromotion); | |
| 7383 SetFlag(kUseGVN); | |
| 7384 } | |
| 7385 SetDependsOnFlag(kMaps); | |
| 7386 if (FLAG_trace_pretenuring) { | |
| 7387 PrintF("HStringAdd with AllocationSite %p %s\n", | |
| 7388 allocation_site.is_null() | |
| 7389 ? static_cast<void*>(NULL) | |
| 7390 : static_cast<void*>(*allocation_site), | |
| 7391 pretenure_flag == TENURED ? "tenured" : "not tenured"); | |
| 7392 } | |
| 7393 } | |
| 7394 | |
| 7395 bool IsDeletable() const final { | |
| 7396 return (flags_ & STRING_ADD_CONVERT) != STRING_ADD_CONVERT; | |
| 7397 } | |
| 7398 | |
| 7399 const StringAddFlags flags_; | |
| 7400 const PretenureFlag pretenure_flag_; | |
| 7401 }; | |
| 7402 | |
| 7403 | |
| 7404 class HStringCharCodeAt final : public HTemplateInstruction<3> { | |
| 7405 public: | |
| 7406 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HStringCharCodeAt, | |
| 7407 HValue*, | |
| 7408 HValue*); | |
| 7409 | |
| 7410 Representation RequiredInputRepresentation(int index) override { | |
| 7411 // The index is supposed to be Integer32. | |
| 7412 return index == 2 | |
| 7413 ? Representation::Integer32() | |
| 7414 : Representation::Tagged(); | |
| 7415 } | |
| 7416 | |
| 7417 HValue* context() const { return OperandAt(0); } | |
| 7418 HValue* string() const { return OperandAt(1); } | |
| 7419 HValue* index() const { return OperandAt(2); } | |
| 7420 | |
| 7421 DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt) | |
| 7422 | |
| 7423 protected: | |
| 7424 bool DataEquals(HValue* other) override { return true; } | |
| 7425 | |
| 7426 Range* InferRange(Zone* zone) override { | |
| 7427 return new(zone) Range(0, String::kMaxUtf16CodeUnit); | |
| 7428 } | |
| 7429 | |
| 7430 private: | |
| 7431 HStringCharCodeAt(HValue* context, HValue* string, HValue* index) { | |
| 7432 SetOperandAt(0, context); | |
| 7433 SetOperandAt(1, string); | |
| 7434 SetOperandAt(2, index); | |
| 7435 set_representation(Representation::Integer32()); | |
| 7436 SetFlag(kUseGVN); | |
| 7437 SetDependsOnFlag(kMaps); | |
| 7438 SetDependsOnFlag(kStringChars); | |
| 7439 SetChangesFlag(kNewSpacePromotion); | |
| 7440 } | |
| 7441 | |
| 7442 // No side effects: runtime function assumes string + number inputs. | |
| 7443 bool IsDeletable() const override { return true; } | |
| 7444 }; | |
| 7445 | |
| 7446 | |
| 7447 class HStringCharFromCode final : public HTemplateInstruction<2> { | |
| 7448 public: | |
| 7449 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 7450 HValue* char_code); | |
| 7451 | |
| 7452 Representation RequiredInputRepresentation(int index) override { | |
| 7453 return index == 0 | |
| 7454 ? Representation::Tagged() | |
| 7455 : Representation::Integer32(); | |
| 7456 } | |
| 7457 | |
| 7458 HValue* context() const { return OperandAt(0); } | |
| 7459 HValue* value() const { return OperandAt(1); } | |
| 7460 | |
| 7461 bool DataEquals(HValue* other) override { return true; } | |
| 7462 | |
| 7463 DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode) | |
| 7464 | |
| 7465 private: | |
| 7466 HStringCharFromCode(HValue* context, HValue* char_code) | |
| 7467 : HTemplateInstruction<2>(HType::String()) { | |
| 7468 SetOperandAt(0, context); | |
| 7469 SetOperandAt(1, char_code); | |
| 7470 set_representation(Representation::Tagged()); | |
| 7471 SetFlag(kUseGVN); | |
| 7472 SetChangesFlag(kNewSpacePromotion); | |
| 7473 } | |
| 7474 | |
| 7475 bool IsDeletable() const override { | |
| 7476 return !value()->ToNumberCanBeObserved(); | |
| 7477 } | |
| 7478 }; | |
| 7479 | |
| 7480 | |
| 7481 template <int V> | |
| 7482 class HMaterializedLiteral : public HTemplateInstruction<V> { | |
| 7483 public: | |
| 7484 HMaterializedLiteral<V>(int index, int depth, AllocationSiteMode mode) | |
| 7485 : literal_index_(index), depth_(depth), allocation_site_mode_(mode) { | |
| 7486 this->set_representation(Representation::Tagged()); | |
| 7487 } | |
| 7488 | |
| 7489 HMaterializedLiteral<V>(int index, int depth) | |
| 7490 : literal_index_(index), depth_(depth), | |
| 7491 allocation_site_mode_(DONT_TRACK_ALLOCATION_SITE) { | |
| 7492 this->set_representation(Representation::Tagged()); | |
| 7493 } | |
| 7494 | |
| 7495 int literal_index() const { return literal_index_; } | |
| 7496 int depth() const { return depth_; } | |
| 7497 AllocationSiteMode allocation_site_mode() const { | |
| 7498 return allocation_site_mode_; | |
| 7499 } | |
| 7500 | |
| 7501 private: | |
| 7502 bool IsDeletable() const final { return true; } | |
| 7503 | |
| 7504 int literal_index_; | |
| 7505 int depth_; | |
| 7506 AllocationSiteMode allocation_site_mode_; | |
| 7507 }; | |
| 7508 | |
| 7509 | |
| 7510 class HRegExpLiteral final : public HMaterializedLiteral<1> { | |
| 7511 public: | |
| 7512 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HRegExpLiteral, | |
| 7513 Handle<FixedArray>, | |
| 7514 Handle<String>, | |
| 7515 Handle<String>, | |
| 7516 int); | |
| 7517 | |
| 7518 HValue* context() { return OperandAt(0); } | |
| 7519 Handle<FixedArray> literals() { return literals_; } | |
| 7520 Handle<String> pattern() { return pattern_; } | |
| 7521 Handle<String> flags() { return flags_; } | |
| 7522 | |
| 7523 Representation RequiredInputRepresentation(int index) override { | |
| 7524 return Representation::Tagged(); | |
| 7525 } | |
| 7526 | |
| 7527 DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral) | |
| 7528 | |
| 7529 private: | |
| 7530 HRegExpLiteral(HValue* context, | |
| 7531 Handle<FixedArray> literals, | |
| 7532 Handle<String> pattern, | |
| 7533 Handle<String> flags, | |
| 7534 int literal_index) | |
| 7535 : HMaterializedLiteral<1>(literal_index, 0), | |
| 7536 literals_(literals), | |
| 7537 pattern_(pattern), | |
| 7538 flags_(flags) { | |
| 7539 SetOperandAt(0, context); | |
| 7540 SetAllSideEffects(); | |
| 7541 set_type(HType::JSObject()); | |
| 7542 } | |
| 7543 | |
| 7544 Handle<FixedArray> literals_; | |
| 7545 Handle<String> pattern_; | |
| 7546 Handle<String> flags_; | |
| 7547 }; | |
| 7548 | |
| 7549 | |
| 7550 class HTypeof final : public HTemplateInstruction<2> { | |
| 7551 public: | |
| 7552 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HTypeof, HValue*); | |
| 7553 | |
| 7554 HValue* context() const { return OperandAt(0); } | |
| 7555 HValue* value() const { return OperandAt(1); } | |
| 7556 | |
| 7557 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 7558 | |
| 7559 Representation RequiredInputRepresentation(int index) override { | |
| 7560 return Representation::Tagged(); | |
| 7561 } | |
| 7562 | |
| 7563 DECLARE_CONCRETE_INSTRUCTION(Typeof) | |
| 7564 | |
| 7565 private: | |
| 7566 explicit HTypeof(HValue* context, HValue* value) { | |
| 7567 SetOperandAt(0, context); | |
| 7568 SetOperandAt(1, value); | |
| 7569 set_representation(Representation::Tagged()); | |
| 7570 } | |
| 7571 | |
| 7572 bool IsDeletable() const override { return true; } | |
| 7573 }; | |
| 7574 | |
| 7575 | |
| 7576 class HTrapAllocationMemento final : public HTemplateInstruction<1> { | |
| 7577 public: | |
| 7578 DECLARE_INSTRUCTION_FACTORY_P1(HTrapAllocationMemento, HValue*); | |
| 7579 | |
| 7580 Representation RequiredInputRepresentation(int index) override { | |
| 7581 return Representation::Tagged(); | |
| 7582 } | |
| 7583 | |
| 7584 HValue* object() { return OperandAt(0); } | |
| 7585 | |
| 7586 DECLARE_CONCRETE_INSTRUCTION(TrapAllocationMemento) | |
| 7587 | |
| 7588 private: | |
| 7589 explicit HTrapAllocationMemento(HValue* obj) { | |
| 7590 SetOperandAt(0, obj); | |
| 7591 } | |
| 7592 }; | |
| 7593 | |
| 7594 | |
| 7595 class HMaybeGrowElements final : public HTemplateInstruction<5> { | |
| 7596 public: | |
| 7597 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P6(HMaybeGrowElements, HValue*, | |
| 7598 HValue*, HValue*, HValue*, bool, | |
| 7599 ElementsKind); | |
| 7600 | |
| 7601 Representation RequiredInputRepresentation(int index) override { | |
| 7602 if (index < 3) { | |
| 7603 return Representation::Tagged(); | |
| 7604 } | |
| 7605 DCHECK(index == 3 || index == 4); | |
| 7606 return Representation::Integer32(); | |
| 7607 } | |
| 7608 | |
| 7609 HValue* context() const { return OperandAt(0); } | |
| 7610 HValue* object() const { return OperandAt(1); } | |
| 7611 HValue* elements() const { return OperandAt(2); } | |
| 7612 HValue* key() const { return OperandAt(3); } | |
| 7613 HValue* current_capacity() const { return OperandAt(4); } | |
| 7614 | |
| 7615 bool is_js_array() const { return is_js_array_; } | |
| 7616 ElementsKind kind() const { return kind_; } | |
| 7617 | |
| 7618 DECLARE_CONCRETE_INSTRUCTION(MaybeGrowElements) | |
| 7619 | |
| 7620 protected: | |
| 7621 bool DataEquals(HValue* other) override { return true; } | |
| 7622 | |
| 7623 private: | |
| 7624 explicit HMaybeGrowElements(HValue* context, HValue* object, HValue* elements, | |
| 7625 HValue* key, HValue* current_capacity, | |
| 7626 bool is_js_array, ElementsKind kind) { | |
| 7627 is_js_array_ = is_js_array; | |
| 7628 kind_ = kind; | |
| 7629 | |
| 7630 SetOperandAt(0, context); | |
| 7631 SetOperandAt(1, object); | |
| 7632 SetOperandAt(2, elements); | |
| 7633 SetOperandAt(3, key); | |
| 7634 SetOperandAt(4, current_capacity); | |
| 7635 | |
| 7636 SetFlag(kUseGVN); | |
| 7637 SetChangesFlag(kElementsPointer); | |
| 7638 SetChangesFlag(kNewSpacePromotion); | |
| 7639 set_representation(Representation::Tagged()); | |
| 7640 } | |
| 7641 | |
| 7642 bool is_js_array_; | |
| 7643 ElementsKind kind_; | |
| 7644 }; | |
| 7645 | |
| 7646 | |
| 7647 class HToFastProperties final : public HUnaryOperation { | |
| 7648 public: | |
| 7649 DECLARE_INSTRUCTION_FACTORY_P1(HToFastProperties, HValue*); | |
| 7650 | |
| 7651 Representation RequiredInputRepresentation(int index) override { | |
| 7652 return Representation::Tagged(); | |
| 7653 } | |
| 7654 | |
| 7655 DECLARE_CONCRETE_INSTRUCTION(ToFastProperties) | |
| 7656 | |
| 7657 private: | |
| 7658 explicit HToFastProperties(HValue* value) : HUnaryOperation(value) { | |
| 7659 set_representation(Representation::Tagged()); | |
| 7660 SetChangesFlag(kNewSpacePromotion); | |
| 7661 | |
| 7662 // This instruction is not marked as kChangesMaps, but does | |
| 7663 // change the map of the input operand. Use it only when creating | |
| 7664 // object literals via a runtime call. | |
| 7665 DCHECK(value->IsCallRuntime()); | |
| 7666 #ifdef DEBUG | |
| 7667 const Runtime::Function* function = HCallRuntime::cast(value)->function(); | |
| 7668 DCHECK(function->function_id == Runtime::kCreateObjectLiteral); | |
| 7669 #endif | |
| 7670 } | |
| 7671 | |
| 7672 bool IsDeletable() const override { return true; } | |
| 7673 }; | |
| 7674 | |
| 7675 | |
| 7676 class HDateField final : public HUnaryOperation { | |
| 7677 public: | |
| 7678 DECLARE_INSTRUCTION_FACTORY_P2(HDateField, HValue*, Smi*); | |
| 7679 | |
| 7680 Smi* index() const { return index_; } | |
| 7681 | |
| 7682 Representation RequiredInputRepresentation(int index) override { | |
| 7683 return Representation::Tagged(); | |
| 7684 } | |
| 7685 | |
| 7686 DECLARE_CONCRETE_INSTRUCTION(DateField) | |
| 7687 | |
| 7688 private: | |
| 7689 HDateField(HValue* date, Smi* index) | |
| 7690 : HUnaryOperation(date), index_(index) { | |
| 7691 set_representation(Representation::Tagged()); | |
| 7692 } | |
| 7693 | |
| 7694 Smi* index_; | |
| 7695 }; | |
| 7696 | |
| 7697 | |
| 7698 class HSeqStringGetChar final : public HTemplateInstruction<2> { | |
| 7699 public: | |
| 7700 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context, | |
| 7701 String::Encoding encoding, HValue* string, | |
| 7702 HValue* index); | |
| 7703 | |
| 7704 Representation RequiredInputRepresentation(int index) override { | |
| 7705 return (index == 0) ? Representation::Tagged() | |
| 7706 : Representation::Integer32(); | |
| 7707 } | |
| 7708 | |
| 7709 String::Encoding encoding() const { return encoding_; } | |
| 7710 HValue* string() const { return OperandAt(0); } | |
| 7711 HValue* index() const { return OperandAt(1); } | |
| 7712 | |
| 7713 DECLARE_CONCRETE_INSTRUCTION(SeqStringGetChar) | |
| 7714 | |
| 7715 protected: | |
| 7716 bool DataEquals(HValue* other) override { | |
| 7717 return encoding() == HSeqStringGetChar::cast(other)->encoding(); | |
| 7718 } | |
| 7719 | |
| 7720 Range* InferRange(Zone* zone) override { | |
| 7721 if (encoding() == String::ONE_BYTE_ENCODING) { | |
| 7722 return new(zone) Range(0, String::kMaxOneByteCharCode); | |
| 7723 } else { | |
| 7724 DCHECK_EQ(String::TWO_BYTE_ENCODING, encoding()); | |
| 7725 return new(zone) Range(0, String::kMaxUtf16CodeUnit); | |
| 7726 } | |
| 7727 } | |
| 7728 | |
| 7729 private: | |
| 7730 HSeqStringGetChar(String::Encoding encoding, | |
| 7731 HValue* string, | |
| 7732 HValue* index) : encoding_(encoding) { | |
| 7733 SetOperandAt(0, string); | |
| 7734 SetOperandAt(1, index); | |
| 7735 set_representation(Representation::Integer32()); | |
| 7736 SetFlag(kUseGVN); | |
| 7737 SetDependsOnFlag(kStringChars); | |
| 7738 } | |
| 7739 | |
| 7740 bool IsDeletable() const override { return true; } | |
| 7741 | |
| 7742 String::Encoding encoding_; | |
| 7743 }; | |
| 7744 | |
| 7745 | |
| 7746 class HSeqStringSetChar final : public HTemplateInstruction<4> { | |
| 7747 public: | |
| 7748 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4( | |
| 7749 HSeqStringSetChar, String::Encoding, | |
| 7750 HValue*, HValue*, HValue*); | |
| 7751 | |
| 7752 String::Encoding encoding() { return encoding_; } | |
| 7753 HValue* context() { return OperandAt(0); } | |
| 7754 HValue* string() { return OperandAt(1); } | |
| 7755 HValue* index() { return OperandAt(2); } | |
| 7756 HValue* value() { return OperandAt(3); } | |
| 7757 | |
| 7758 Representation RequiredInputRepresentation(int index) override { | |
| 7759 return (index <= 1) ? Representation::Tagged() | |
| 7760 : Representation::Integer32(); | |
| 7761 } | |
| 7762 | |
| 7763 DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar) | |
| 7764 | |
| 7765 private: | |
| 7766 HSeqStringSetChar(HValue* context, | |
| 7767 String::Encoding encoding, | |
| 7768 HValue* string, | |
| 7769 HValue* index, | |
| 7770 HValue* value) : encoding_(encoding) { | |
| 7771 SetOperandAt(0, context); | |
| 7772 SetOperandAt(1, string); | |
| 7773 SetOperandAt(2, index); | |
| 7774 SetOperandAt(3, value); | |
| 7775 set_representation(Representation::Tagged()); | |
| 7776 SetChangesFlag(kStringChars); | |
| 7777 } | |
| 7778 | |
| 7779 String::Encoding encoding_; | |
| 7780 }; | |
| 7781 | |
| 7782 | |
| 7783 class HCheckMapValue final : public HTemplateInstruction<2> { | |
| 7784 public: | |
| 7785 DECLARE_INSTRUCTION_FACTORY_P2(HCheckMapValue, HValue*, HValue*); | |
| 7786 | |
| 7787 Representation RequiredInputRepresentation(int index) override { | |
| 7788 return Representation::Tagged(); | |
| 7789 } | |
| 7790 | |
| 7791 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 7792 | |
| 7793 HType CalculateInferredType() override { | |
| 7794 if (value()->type().IsHeapObject()) return value()->type(); | |
| 7795 return HType::HeapObject(); | |
| 7796 } | |
| 7797 | |
| 7798 HValue* value() const { return OperandAt(0); } | |
| 7799 HValue* map() const { return OperandAt(1); } | |
| 7800 | |
| 7801 HValue* Canonicalize() override; | |
| 7802 | |
| 7803 DECLARE_CONCRETE_INSTRUCTION(CheckMapValue) | |
| 7804 | |
| 7805 protected: | |
| 7806 int RedefinedOperandIndex() override { return 0; } | |
| 7807 | |
| 7808 bool DataEquals(HValue* other) override { return true; } | |
| 7809 | |
| 7810 private: | |
| 7811 HCheckMapValue(HValue* value, HValue* map) | |
| 7812 : HTemplateInstruction<2>(HType::HeapObject()) { | |
| 7813 SetOperandAt(0, value); | |
| 7814 SetOperandAt(1, map); | |
| 7815 set_representation(Representation::Tagged()); | |
| 7816 SetFlag(kUseGVN); | |
| 7817 SetDependsOnFlag(kMaps); | |
| 7818 SetDependsOnFlag(kElementsKind); | |
| 7819 } | |
| 7820 }; | |
| 7821 | |
| 7822 | |
| 7823 class HForInPrepareMap final : public HTemplateInstruction<2> { | |
| 7824 public: | |
| 7825 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P1(HForInPrepareMap, HValue*); | |
| 7826 | |
| 7827 Representation RequiredInputRepresentation(int index) override { | |
| 7828 return Representation::Tagged(); | |
| 7829 } | |
| 7830 | |
| 7831 HValue* context() const { return OperandAt(0); } | |
| 7832 HValue* enumerable() const { return OperandAt(1); } | |
| 7833 | |
| 7834 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 7835 | |
| 7836 HType CalculateInferredType() override { return HType::Tagged(); } | |
| 7837 | |
| 7838 DECLARE_CONCRETE_INSTRUCTION(ForInPrepareMap); | |
| 7839 | |
| 7840 private: | |
| 7841 HForInPrepareMap(HValue* context, | |
| 7842 HValue* object) { | |
| 7843 SetOperandAt(0, context); | |
| 7844 SetOperandAt(1, object); | |
| 7845 set_representation(Representation::Tagged()); | |
| 7846 SetAllSideEffects(); | |
| 7847 } | |
| 7848 }; | |
| 7849 | |
| 7850 | |
| 7851 class HForInCacheArray final : public HTemplateInstruction<2> { | |
| 7852 public: | |
| 7853 DECLARE_INSTRUCTION_FACTORY_P3(HForInCacheArray, HValue*, HValue*, int); | |
| 7854 | |
| 7855 Representation RequiredInputRepresentation(int index) override { | |
| 7856 return Representation::Tagged(); | |
| 7857 } | |
| 7858 | |
| 7859 HValue* enumerable() const { return OperandAt(0); } | |
| 7860 HValue* map() const { return OperandAt(1); } | |
| 7861 int idx() const { return idx_; } | |
| 7862 | |
| 7863 HForInCacheArray* index_cache() { | |
| 7864 return index_cache_; | |
| 7865 } | |
| 7866 | |
| 7867 void set_index_cache(HForInCacheArray* index_cache) { | |
| 7868 index_cache_ = index_cache; | |
| 7869 } | |
| 7870 | |
| 7871 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 7872 | |
| 7873 HType CalculateInferredType() override { return HType::Tagged(); } | |
| 7874 | |
| 7875 DECLARE_CONCRETE_INSTRUCTION(ForInCacheArray); | |
| 7876 | |
| 7877 private: | |
| 7878 HForInCacheArray(HValue* enumerable, | |
| 7879 HValue* keys, | |
| 7880 int idx) : idx_(idx) { | |
| 7881 SetOperandAt(0, enumerable); | |
| 7882 SetOperandAt(1, keys); | |
| 7883 set_representation(Representation::Tagged()); | |
| 7884 } | |
| 7885 | |
| 7886 int idx_; | |
| 7887 HForInCacheArray* index_cache_; | |
| 7888 }; | |
| 7889 | |
| 7890 | |
| 7891 class HLoadFieldByIndex final : public HTemplateInstruction<2> { | |
| 7892 public: | |
| 7893 DECLARE_INSTRUCTION_FACTORY_P2(HLoadFieldByIndex, HValue*, HValue*); | |
| 7894 | |
| 7895 HLoadFieldByIndex(HValue* object, | |
| 7896 HValue* index) { | |
| 7897 SetOperandAt(0, object); | |
| 7898 SetOperandAt(1, index); | |
| 7899 SetChangesFlag(kNewSpacePromotion); | |
| 7900 set_representation(Representation::Tagged()); | |
| 7901 } | |
| 7902 | |
| 7903 Representation RequiredInputRepresentation(int index) override { | |
| 7904 if (index == 1) { | |
| 7905 return Representation::Smi(); | |
| 7906 } else { | |
| 7907 return Representation::Tagged(); | |
| 7908 } | |
| 7909 } | |
| 7910 | |
| 7911 HValue* object() const { return OperandAt(0); } | |
| 7912 HValue* index() const { return OperandAt(1); } | |
| 7913 | |
| 7914 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 7915 | |
| 7916 HType CalculateInferredType() override { return HType::Tagged(); } | |
| 7917 | |
| 7918 DECLARE_CONCRETE_INSTRUCTION(LoadFieldByIndex); | |
| 7919 | |
| 7920 private: | |
| 7921 bool IsDeletable() const override { return true; } | |
| 7922 }; | |
| 7923 | |
| 7924 | |
| 7925 class HStoreFrameContext: public HUnaryOperation { | |
| 7926 public: | |
| 7927 DECLARE_INSTRUCTION_FACTORY_P1(HStoreFrameContext, HValue*); | |
| 7928 | |
| 7929 HValue* context() { return OperandAt(0); } | |
| 7930 | |
| 7931 Representation RequiredInputRepresentation(int index) override { | |
| 7932 return Representation::Tagged(); | |
| 7933 } | |
| 7934 | |
| 7935 DECLARE_CONCRETE_INSTRUCTION(StoreFrameContext) | |
| 7936 private: | |
| 7937 explicit HStoreFrameContext(HValue* context) | |
| 7938 : HUnaryOperation(context) { | |
| 7939 set_representation(Representation::Tagged()); | |
| 7940 SetChangesFlag(kContextSlots); | |
| 7941 } | |
| 7942 }; | |
| 7943 | |
| 7944 | |
| 7945 class HAllocateBlockContext: public HTemplateInstruction<2> { | |
| 7946 public: | |
| 7947 DECLARE_INSTRUCTION_FACTORY_P3(HAllocateBlockContext, HValue*, | |
| 7948 HValue*, Handle<ScopeInfo>); | |
| 7949 HValue* context() const { return OperandAt(0); } | |
| 7950 HValue* function() const { return OperandAt(1); } | |
| 7951 Handle<ScopeInfo> scope_info() const { return scope_info_; } | |
| 7952 | |
| 7953 Representation RequiredInputRepresentation(int index) override { | |
| 7954 return Representation::Tagged(); | |
| 7955 } | |
| 7956 | |
| 7957 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT | |
| 7958 | |
| 7959 DECLARE_CONCRETE_INSTRUCTION(AllocateBlockContext) | |
| 7960 | |
| 7961 private: | |
| 7962 HAllocateBlockContext(HValue* context, | |
| 7963 HValue* function, | |
| 7964 Handle<ScopeInfo> scope_info) | |
| 7965 : scope_info_(scope_info) { | |
| 7966 SetOperandAt(0, context); | |
| 7967 SetOperandAt(1, function); | |
| 7968 set_representation(Representation::Tagged()); | |
| 7969 } | |
| 7970 | |
| 7971 Handle<ScopeInfo> scope_info_; | |
| 7972 }; | |
| 7973 | |
| 7974 | |
| 7975 | |
| 7976 #undef DECLARE_INSTRUCTION | |
| 7977 #undef DECLARE_CONCRETE_INSTRUCTION | |
| 7978 | |
| 7979 } // namespace internal | |
| 7980 } // namespace v8 | |
| 7981 | |
| 7982 #endif // V8_HYDROGEN_INSTRUCTIONS_H_ | |
| OLD | NEW |