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_CRANKSHAFT_HYDROGEN_INSTRUCTIONS_H_
6 #define V8_CRANKSHAFT_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/crankshaft/hydrogen-types.h"
17 #include "src/crankshaft/unique.h"
18 #include "src/deoptimizer.h"
19 #include "src/small-pointer-list.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(CallNewArray) \
66 V(CallRuntime) \
67 V(CallStub) \
68 V(CapturedObject) \
69 V(Change) \
70 V(CheckArrayBufferNotNeutered) \
71 V(CheckHeapObject) \
72 V(CheckInstanceType) \
73 V(CheckMaps) \
74 V(CheckMapValue) \
75 V(CheckSmi) \
76 V(CheckValue) \
77 V(ClampToUint8) \
78 V(ClassOfTestAndBranch) \
79 V(CompareNumericAndBranch) \
80 V(CompareHoleAndBranch) \
81 V(CompareGeneric) \
82 V(CompareMinusZeroAndBranch) \
83 V(CompareObjectEqAndBranch) \
84 V(CompareMap) \
85 V(Constant) \
86 V(ConstructDouble) \
87 V(Context) \
88 V(DebugBreak) \
89 V(DeclareGlobals) \
90 V(Deoptimize) \
91 V(Div) \
92 V(DoubleBits) \
93 V(DummyUse) \
94 V(EnterInlined) \
95 V(EnvironmentMarker) \
96 V(ForceRepresentation) \
97 V(ForInCacheArray) \
98 V(ForInPrepareMap) \
99 V(GetCachedArrayIndex) \
100 V(Goto) \
101 V(HasCachedArrayIndexAndBranch) \
102 V(HasInstanceTypeAndBranch) \
103 V(InnerAllocatedObject) \
104 V(InstanceOf) \
105 V(InvokeFunction) \
106 V(HasInPrototypeChainAndBranch) \
107 V(IsStringAndBranch) \
108 V(IsSmiAndBranch) \
109 V(IsUndetectableAndBranch) \
110 V(LeaveInlined) \
111 V(LoadContextSlot) \
112 V(LoadFieldByIndex) \
113 V(LoadFunctionPrototype) \
114 V(LoadGlobalGeneric) \
115 V(LoadKeyed) \
116 V(LoadKeyedGeneric) \
117 V(LoadNamedField) \
118 V(LoadNamedGeneric) \
119 V(LoadRoot) \
120 V(MapEnumLength) \
121 V(MathFloorOfDiv) \
122 V(MathMinMax) \
123 V(MaybeGrowElements) \
124 V(Mod) \
125 V(Mul) \
126 V(OsrEntry) \
127 V(Parameter) \
128 V(Power) \
129 V(Prologue) \
130 V(PushArguments) \
131 V(Return) \
132 V(Ror) \
133 V(Sar) \
134 V(SeqStringGetChar) \
135 V(SeqStringSetChar) \
136 V(Shl) \
137 V(Shr) \
138 V(Simulate) \
139 V(StackCheck) \
140 V(StoreCodeEntry) \
141 V(StoreContextSlot) \
142 V(StoreFrameContext) \
143 V(StoreKeyed) \
144 V(StoreKeyedGeneric) \
145 V(StoreNamedField) \
146 V(StoreNamedGeneric) \
147 V(StringAdd) \
148 V(StringCharCodeAt) \
149 V(StringCharFromCode) \
150 V(StringCompareAndBranch) \
151 V(Sub) \
152 V(ThisFunction) \
153 V(ToFastProperties) \
154 V(TransitionElementsKind) \
155 V(TrapAllocationMemento) \
156 V(Typeof) \
157 V(TypeofIsAndBranch) \
158 V(UnaryMathOperation) \
159 V(UnknownOSRValue) \
160 V(UseConst) \
161 V(WrapReceiver)
162
163 #define GVN_TRACKED_FLAG_LIST(V) \
164 V(NewSpacePromotion)
165
166 #define GVN_UNTRACKED_FLAG_LIST(V) \
167 V(ArrayElements) \
168 V(ArrayLengths) \
169 V(StringLengths) \
170 V(BackingStoreFields) \
171 V(Calls) \
172 V(ContextSlots) \
173 V(DoubleArrayElements) \
174 V(DoubleFields) \
175 V(ElementsKind) \
176 V(ElementsPointer) \
177 V(GlobalVars) \
178 V(InobjectFields) \
179 V(Maps) \
180 V(OsrEntries) \
181 V(ExternalMemory) \
182 V(StringChars) \
183 V(TypedArrayElements)
184
185
186 #define DECLARE_ABSTRACT_INSTRUCTION(type) \
187 bool Is##type() const final { return true; } \
188 static H##type* cast(HValue* value) { \
189 DCHECK(value->Is##type()); \
190 return reinterpret_cast<H##type*>(value); \
191 }
192
193
194 #define DECLARE_CONCRETE_INSTRUCTION(type) \
195 LInstruction* CompileToLithium(LChunkBuilder* builder) final; \
196 static H##type* cast(HValue* value) { \
197 DCHECK(value->Is##type()); \
198 return reinterpret_cast<H##type*>(value); \
199 } \
200 Opcode opcode() const final { return HValue::k##type; }
201
202
203 enum PropertyAccessType { LOAD, STORE };
204
205
206 class Range final : public ZoneObject {
207 public:
Range()208 Range()
209 : lower_(kMinInt),
210 upper_(kMaxInt),
211 next_(NULL),
212 can_be_minus_zero_(false) { }
213
Range(int32_t lower,int32_t upper)214 Range(int32_t lower, int32_t upper)
215 : lower_(lower),
216 upper_(upper),
217 next_(NULL),
218 can_be_minus_zero_(false) { }
219
upper()220 int32_t upper() const { return upper_; }
lower()221 int32_t lower() const { return lower_; }
next()222 Range* next() const { return next_; }
CopyClearLower(Zone * zone)223 Range* CopyClearLower(Zone* zone) const {
224 return new(zone) Range(kMinInt, upper_);
225 }
CopyClearUpper(Zone * zone)226 Range* CopyClearUpper(Zone* zone) const {
227 return new(zone) Range(lower_, kMaxInt);
228 }
Copy(Zone * zone)229 Range* Copy(Zone* zone) const {
230 Range* result = new(zone) Range(lower_, upper_);
231 result->set_can_be_minus_zero(CanBeMinusZero());
232 return result;
233 }
234 int32_t Mask() const;
set_can_be_minus_zero(bool b)235 void set_can_be_minus_zero(bool b) { can_be_minus_zero_ = b; }
CanBeMinusZero()236 bool CanBeMinusZero() const { return CanBeZero() && can_be_minus_zero_; }
CanBeZero()237 bool CanBeZero() const { return upper_ >= 0 && lower_ <= 0; }
CanBeNegative()238 bool CanBeNegative() const { return lower_ < 0; }
CanBePositive()239 bool CanBePositive() const { return upper_ > 0; }
Includes(int value)240 bool Includes(int value) const { return lower_ <= value && upper_ >= value; }
IsMostGeneric()241 bool IsMostGeneric() const {
242 return lower_ == kMinInt && upper_ == kMaxInt && CanBeMinusZero();
243 }
IsInSmiRange()244 bool IsInSmiRange() const {
245 return lower_ >= Smi::kMinValue && upper_ <= Smi::kMaxValue;
246 }
ClampToSmi()247 void ClampToSmi() {
248 lower_ = Max(lower_, Smi::kMinValue);
249 upper_ = Min(upper_, Smi::kMaxValue);
250 }
251 void KeepOrder();
252 #ifdef DEBUG
253 void Verify() const;
254 #endif
255
StackUpon(Range * other)256 void StackUpon(Range* other) {
257 Intersect(other);
258 next_ = other;
259 }
260
261 void Intersect(Range* other);
262 void Union(Range* other);
263 void CombinedMax(Range* other);
264 void CombinedMin(Range* other);
265
266 void AddConstant(int32_t value);
267 void Sar(int32_t value);
268 void Shl(int32_t value);
269 bool AddAndCheckOverflow(const Representation& r, Range* other);
270 bool SubAndCheckOverflow(const Representation& r, Range* other);
271 bool MulAndCheckOverflow(const Representation& r, Range* other);
272
273 private:
274 int32_t lower_;
275 int32_t upper_;
276 Range* next_;
277 bool can_be_minus_zero_;
278 };
279
280
281 class HUseListNode: public ZoneObject {
282 public:
HUseListNode(HValue * value,int index,HUseListNode * tail)283 HUseListNode(HValue* value, int index, HUseListNode* tail)
284 : tail_(tail), value_(value), index_(index) {
285 }
286
287 HUseListNode* tail();
value()288 HValue* value() const { return value_; }
index()289 int index() const { return index_; }
290
set_tail(HUseListNode * list)291 void set_tail(HUseListNode* list) { tail_ = list; }
292
293 #ifdef DEBUG
Zap()294 void Zap() {
295 tail_ = reinterpret_cast<HUseListNode*>(1);
296 value_ = NULL;
297 index_ = -1;
298 }
299 #endif
300
301 private:
302 HUseListNode* tail_;
303 HValue* value_;
304 int index_;
305 };
306
307
308 // We reuse use list nodes behind the scenes as uses are added and deleted.
309 // This class is the safe way to iterate uses while deleting them.
310 class HUseIterator final BASE_EMBEDDED {
311 public:
Done()312 bool Done() { return current_ == NULL; }
313 void Advance();
314
value()315 HValue* value() {
316 DCHECK(!Done());
317 return value_;
318 }
319
index()320 int index() {
321 DCHECK(!Done());
322 return index_;
323 }
324
325 private:
326 explicit HUseIterator(HUseListNode* head);
327
328 HUseListNode* current_;
329 HUseListNode* next_;
330 HValue* value_;
331 int index_;
332
333 friend class HValue;
334 };
335
336
337 // All tracked flags should appear before untracked ones.
338 enum GVNFlag {
339 // Declare global value numbering flags.
340 #define DECLARE_FLAG(Type) k##Type,
341 GVN_TRACKED_FLAG_LIST(DECLARE_FLAG)
342 GVN_UNTRACKED_FLAG_LIST(DECLARE_FLAG)
343 #undef DECLARE_FLAG
344 #define COUNT_FLAG(Type) + 1
345 kNumberOfTrackedSideEffects = 0 GVN_TRACKED_FLAG_LIST(COUNT_FLAG),
346 kNumberOfUntrackedSideEffects = 0 GVN_UNTRACKED_FLAG_LIST(COUNT_FLAG),
347 #undef COUNT_FLAG
348 kNumberOfFlags = kNumberOfTrackedSideEffects + kNumberOfUntrackedSideEffects
349 };
350
351
GVNFlagFromInt(int i)352 static inline GVNFlag GVNFlagFromInt(int i) {
353 DCHECK(i >= 0);
354 DCHECK(i < kNumberOfFlags);
355 return static_cast<GVNFlag>(i);
356 }
357
358
359 class DecompositionResult final BASE_EMBEDDED {
360 public:
DecompositionResult()361 DecompositionResult() : base_(NULL), offset_(0), scale_(0) {}
362
base()363 HValue* base() { return base_; }
offset()364 int offset() { return offset_; }
scale()365 int scale() { return scale_; }
366
367 bool Apply(HValue* other_base, int other_offset, int other_scale = 0) {
368 if (base_ == NULL) {
369 base_ = other_base;
370 offset_ = other_offset;
371 scale_ = other_scale;
372 return true;
373 } else {
374 if (scale_ == 0) {
375 base_ = other_base;
376 offset_ += other_offset;
377 scale_ = other_scale;
378 return true;
379 } else {
380 return false;
381 }
382 }
383 }
384
SwapValues(HValue ** other_base,int * other_offset,int * other_scale)385 void SwapValues(HValue** other_base, int* other_offset, int* other_scale) {
386 swap(&base_, other_base);
387 swap(&offset_, other_offset);
388 swap(&scale_, other_scale);
389 }
390
391 private:
swap(T * a,T * b)392 template <class T> void swap(T* a, T* b) {
393 T c(*a);
394 *a = *b;
395 *b = c;
396 }
397
398 HValue* base_;
399 int offset_;
400 int scale_;
401 };
402
403
404 typedef EnumSet<GVNFlag, int32_t> GVNFlagSet;
405
406
407 class HValue : public ZoneObject {
408 public:
409 static const int kNoNumber = -1;
410
411 enum Flag {
412 kFlexibleRepresentation,
413 kCannotBeTagged,
414 // Participate in Global Value Numbering, i.e. elimination of
415 // unnecessary recomputations. If an instruction sets this flag, it must
416 // implement DataEquals(), which will be used to determine if other
417 // occurrences of the instruction are indeed the same.
418 kUseGVN,
419 // Track instructions that are dominating side effects. If an instruction
420 // sets this flag, it must implement HandleSideEffectDominator() and should
421 // indicate which side effects to track by setting GVN flags.
422 kTrackSideEffectDominators,
423 kCanOverflow,
424 kBailoutOnMinusZero,
425 kCanBeDivByZero,
426 kLeftCanBeMinInt,
427 kLeftCanBeNegative,
428 kLeftCanBePositive,
429 kAllowUndefinedAsNaN,
430 kIsArguments,
431 kTruncatingToInt32,
432 kAllUsesTruncatingToInt32,
433 kTruncatingToSmi,
434 kAllUsesTruncatingToSmi,
435 // Set after an instruction is killed.
436 kIsDead,
437 // Instructions that are allowed to produce full range unsigned integer
438 // values are marked with kUint32 flag. If arithmetic shift or a load from
439 // EXTERNAL_UINT32_ELEMENTS array is not marked with this flag
440 // it will deoptimize if result does not fit into signed integer range.
441 // HGraph::ComputeSafeUint32Operations is responsible for setting this
442 // flag.
443 kUint32,
444 kHasNoObservableSideEffects,
445 // Indicates an instruction shouldn't be replaced by optimization, this flag
446 // is useful to set in cases where recomputing a value is cheaper than
447 // extending the value's live range and spilling it.
448 kCantBeReplaced,
449 // Indicates the instruction is live during dead code elimination.
450 kIsLive,
451
452 // HEnvironmentMarkers are deleted before dead code
453 // elimination takes place, so they can repurpose the kIsLive flag:
454 kEndsLiveRange = kIsLive,
455
456 // TODO(everyone): Don't forget to update this!
457 kLastFlag = kIsLive
458 };
459
460 STATIC_ASSERT(kLastFlag < kBitsPerInt);
461
cast(HValue * value)462 static HValue* cast(HValue* value) { return value; }
463
464 enum Opcode {
465 // Declare a unique enum value for each hydrogen instruction.
466 #define DECLARE_OPCODE(type) k##type,
467 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_OPCODE)
468 kPhi
469 #undef DECLARE_OPCODE
470 };
471 virtual Opcode opcode() const = 0;
472
473 // Declare a non-virtual predicates for each concrete HInstruction or HValue.
474 #define DECLARE_PREDICATE(type) \
475 bool Is##type() const { return opcode() == k##type; }
HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_PREDICATE)476 HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_PREDICATE)
477 #undef DECLARE_PREDICATE
478 bool IsPhi() const { return opcode() == kPhi; }
479
480 // Declare virtual predicates for abstract HInstruction or HValue
481 #define DECLARE_PREDICATE(type) \
482 virtual bool Is##type() const { return false; }
HYDROGEN_ABSTRACT_INSTRUCTION_LIST(DECLARE_PREDICATE)483 HYDROGEN_ABSTRACT_INSTRUCTION_LIST(DECLARE_PREDICATE)
484 #undef DECLARE_PREDICATE
485
486 bool IsBitwiseBinaryShift() {
487 return IsShl() || IsShr() || IsSar();
488 }
489
490 explicit HValue(HType type = HType::Tagged())
block_(NULL)491 : block_(NULL),
492 id_(kNoNumber),
493 type_(type),
494 use_list_(NULL),
495 range_(NULL),
496 #ifdef DEBUG
497 range_poisoned_(false),
498 #endif
499 flags_(0) {}
~HValue()500 virtual ~HValue() {}
501
position()502 virtual SourcePosition position() const { return SourcePosition::Unknown(); }
operand_position(int index)503 virtual SourcePosition operand_position(int index) const {
504 return position();
505 }
506
block()507 HBasicBlock* block() const { return block_; }
508 void SetBlock(HBasicBlock* block);
509
510 // Note: Never call this method for an unlinked value.
511 Isolate* isolate() const;
512
id()513 int id() const { return id_; }
set_id(int id)514 void set_id(int id) { id_ = id; }
515
uses()516 HUseIterator uses() const { return HUseIterator(use_list_); }
517
EmitAtUses()518 virtual bool EmitAtUses() { return false; }
519
representation()520 Representation representation() const { return representation_; }
ChangeRepresentation(Representation r)521 void ChangeRepresentation(Representation r) {
522 DCHECK(CheckFlag(kFlexibleRepresentation));
523 DCHECK(!CheckFlag(kCannotBeTagged) || !r.IsTagged());
524 RepresentationChanged(r);
525 representation_ = r;
526 if (r.IsTagged()) {
527 // Tagged is the bottom of the lattice, don't go any further.
528 ClearFlag(kFlexibleRepresentation);
529 }
530 }
531 virtual void AssumeRepresentation(Representation r);
532
KnownOptimalRepresentation()533 virtual Representation KnownOptimalRepresentation() {
534 Representation r = representation();
535 if (r.IsTagged()) {
536 HType t = type();
537 if (t.IsSmi()) return Representation::Smi();
538 if (t.IsHeapNumber()) return Representation::Double();
539 if (t.IsHeapObject()) return r;
540 return Representation::None();
541 }
542 return r;
543 }
544
type()545 HType type() const { return type_; }
set_type(HType new_type)546 void set_type(HType new_type) {
547 DCHECK(new_type.IsSubtypeOf(type_));
548 type_ = new_type;
549 }
550
551 // There are HInstructions that do not really change a value, they
552 // only add pieces of information to it (like bounds checks, map checks,
553 // smi checks...).
554 // We call these instructions "informative definitions", or "iDef".
555 // One of the iDef operands is special because it is the value that is
556 // "transferred" to the output, we call it the "redefined operand".
557 // If an HValue is an iDef it must override RedefinedOperandIndex() so that
558 // it does not return kNoRedefinedOperand;
559 static const int kNoRedefinedOperand = -1;
RedefinedOperandIndex()560 virtual int RedefinedOperandIndex() { return kNoRedefinedOperand; }
IsInformativeDefinition()561 bool IsInformativeDefinition() {
562 return RedefinedOperandIndex() != kNoRedefinedOperand;
563 }
RedefinedOperand()564 HValue* RedefinedOperand() {
565 int index = RedefinedOperandIndex();
566 return index == kNoRedefinedOperand ? NULL : OperandAt(index);
567 }
568
569 bool CanReplaceWithDummyUses();
570
argument_delta()571 virtual int argument_delta() const { return 0; }
572
573 // A purely informative definition is an idef that will not emit code and
574 // should therefore be removed from the graph in the RestoreActualValues
575 // phase (so that live ranges will be shorter).
IsPurelyInformativeDefinition()576 virtual bool IsPurelyInformativeDefinition() { return false; }
577
578 // This method must always return the original HValue SSA definition,
579 // regardless of any chain of iDefs of this value.
ActualValue()580 HValue* ActualValue() {
581 HValue* value = this;
582 int index;
583 while ((index = value->RedefinedOperandIndex()) != kNoRedefinedOperand) {
584 value = value->OperandAt(index);
585 }
586 return value;
587 }
588
589 bool IsInteger32Constant();
590 int32_t GetInteger32Constant();
591 bool EqualsInteger32Constant(int32_t value);
592
593 bool IsDefinedAfter(HBasicBlock* other) const;
594
595 // Operands.
596 virtual int OperandCount() const = 0;
597 virtual HValue* OperandAt(int index) const = 0;
598 void SetOperandAt(int index, HValue* value);
599
600 void DeleteAndReplaceWith(HValue* other);
601 void ReplaceAllUsesWith(HValue* other);
HasNoUses()602 bool HasNoUses() const { return use_list_ == NULL; }
HasOneUse()603 bool HasOneUse() const {
604 return use_list_ != NULL && use_list_->tail() == NULL;
605 }
HasMultipleUses()606 bool HasMultipleUses() const {
607 return use_list_ != NULL && use_list_->tail() != NULL;
608 }
609 int UseCount() const;
610
611 // Mark this HValue as dead and to be removed from other HValues' use lists.
612 void Kill();
613
flags()614 int flags() const { return flags_; }
SetFlag(Flag f)615 void SetFlag(Flag f) { flags_ |= (1 << f); }
ClearFlag(Flag f)616 void ClearFlag(Flag f) { flags_ &= ~(1 << f); }
CheckFlag(Flag f)617 bool CheckFlag(Flag f) const { return (flags_ & (1 << f)) != 0; }
CopyFlag(Flag f,HValue * other)618 void CopyFlag(Flag f, HValue* other) {
619 if (other->CheckFlag(f)) SetFlag(f);
620 }
621
622 // Returns true if the flag specified is set for all uses, false otherwise.
623 bool CheckUsesForFlag(Flag f) const;
624 // Same as before and the first one without the flag is returned in value.
625 bool CheckUsesForFlag(Flag f, HValue** value) const;
626 // Returns true if the flag specified is set for all uses, and this set
627 // of uses is non-empty.
628 bool HasAtLeastOneUseWithFlagAndNoneWithout(Flag f) const;
629
ChangesFlags()630 GVNFlagSet ChangesFlags() const { return changes_flags_; }
DependsOnFlags()631 GVNFlagSet DependsOnFlags() const { return depends_on_flags_; }
SetChangesFlag(GVNFlag f)632 void SetChangesFlag(GVNFlag f) { changes_flags_.Add(f); }
SetDependsOnFlag(GVNFlag f)633 void SetDependsOnFlag(GVNFlag f) { depends_on_flags_.Add(f); }
ClearChangesFlag(GVNFlag f)634 void ClearChangesFlag(GVNFlag f) { changes_flags_.Remove(f); }
ClearDependsOnFlag(GVNFlag f)635 void ClearDependsOnFlag(GVNFlag f) { depends_on_flags_.Remove(f); }
CheckChangesFlag(GVNFlag f)636 bool CheckChangesFlag(GVNFlag f) const {
637 return changes_flags_.Contains(f);
638 }
CheckDependsOnFlag(GVNFlag f)639 bool CheckDependsOnFlag(GVNFlag f) const {
640 return depends_on_flags_.Contains(f);
641 }
SetAllSideEffects()642 void SetAllSideEffects() { changes_flags_.Add(AllSideEffectsFlagSet()); }
ClearAllSideEffects()643 void ClearAllSideEffects() {
644 changes_flags_.Remove(AllSideEffectsFlagSet());
645 }
HasSideEffects()646 bool HasSideEffects() const {
647 return changes_flags_.ContainsAnyOf(AllSideEffectsFlagSet());
648 }
HasObservableSideEffects()649 bool HasObservableSideEffects() const {
650 return !CheckFlag(kHasNoObservableSideEffects) &&
651 changes_flags_.ContainsAnyOf(AllObservableSideEffectsFlagSet());
652 }
653
SideEffectFlags()654 GVNFlagSet SideEffectFlags() const {
655 GVNFlagSet result = ChangesFlags();
656 result.Intersect(AllSideEffectsFlagSet());
657 return result;
658 }
659
ObservableChangesFlags()660 GVNFlagSet ObservableChangesFlags() const {
661 GVNFlagSet result = ChangesFlags();
662 result.Intersect(AllObservableSideEffectsFlagSet());
663 return result;
664 }
665
range()666 Range* range() const {
667 DCHECK(!range_poisoned_);
668 return range_;
669 }
HasRange()670 bool HasRange() const {
671 DCHECK(!range_poisoned_);
672 return range_ != NULL;
673 }
674 #ifdef DEBUG
PoisonRange()675 void PoisonRange() { range_poisoned_ = true; }
676 #endif
677 void AddNewRange(Range* r, Zone* zone);
678 void RemoveLastAddedRange();
679 void ComputeInitialRange(Zone* zone);
680
681 // Escape analysis helpers.
HasEscapingOperandAt(int index)682 virtual bool HasEscapingOperandAt(int index) { return true; }
HasOutOfBoundsAccess(int size)683 virtual bool HasOutOfBoundsAccess(int size) { return false; }
684
685 // Representation helpers.
observed_input_representation(int index)686 virtual Representation observed_input_representation(int index) {
687 return Representation::None();
688 }
689 virtual Representation RequiredInputRepresentation(int index) = 0;
690 virtual void InferRepresentation(HInferRepresentationPhase* h_infer);
691
692 // This gives the instruction an opportunity to replace itself with an
693 // instruction that does the same in some better way. To replace an
694 // instruction with a new one, first add the new instruction to the graph,
695 // then return it. Return NULL to have the instruction deleted.
Canonicalize()696 virtual HValue* Canonicalize() { return this; }
697
698 bool Equals(HValue* other);
699 virtual intptr_t Hashcode();
700
701 // Compute unique ids upfront that is safe wrt GC and concurrent compilation.
FinalizeUniqueness()702 virtual void FinalizeUniqueness() { }
703
704 // Printing support.
705 virtual std::ostream& PrintTo(std::ostream& os) const = 0; // NOLINT
706
707 const char* Mnemonic() const;
708
709 // Type information helpers.
710 bool HasMonomorphicJSObjectType();
711
712 // TODO(mstarzinger): For now instructions can override this function to
713 // specify statically known types, once HType can convey more information
714 // it should be based on the HType.
GetMonomorphicJSObjectMap()715 virtual Handle<Map> GetMonomorphicJSObjectMap() { return Handle<Map>(); }
716
717 // Updated the inferred type of this instruction and returns true if
718 // it has changed.
719 bool UpdateInferredType();
720
721 virtual HType CalculateInferredType();
722
723 // This function must be overridden for instructions which have the
724 // kTrackSideEffectDominators flag set, to track instructions that are
725 // dominating side effects.
726 // It returns true if it removed an instruction which had side effects.
HandleSideEffectDominator(GVNFlag side_effect,HValue * dominator)727 virtual bool HandleSideEffectDominator(GVNFlag side_effect,
728 HValue* dominator) {
729 UNREACHABLE();
730 return false;
731 }
732
733 // Check if this instruction has some reason that prevents elimination.
CannotBeEliminated()734 bool CannotBeEliminated() const {
735 return HasObservableSideEffects() || !IsDeletable();
736 }
737
738 #ifdef DEBUG
739 virtual void Verify() = 0;
740 #endif
741
TryDecompose(DecompositionResult * decomposition)742 virtual bool TryDecompose(DecompositionResult* decomposition) {
743 if (RedefinedOperand() != NULL) {
744 return RedefinedOperand()->TryDecompose(decomposition);
745 } else {
746 return false;
747 }
748 }
749
750 // Returns true conservatively if the program might be able to observe a
751 // ToString() operation on this value.
ToStringCanBeObserved()752 bool ToStringCanBeObserved() const {
753 return ToStringOrToNumberCanBeObserved();
754 }
755
756 // Returns true conservatively if the program might be able to observe a
757 // ToNumber() operation on this value.
ToNumberCanBeObserved()758 bool ToNumberCanBeObserved() const {
759 return ToStringOrToNumberCanBeObserved();
760 }
761
GetMinusZeroMode()762 MinusZeroMode GetMinusZeroMode() {
763 return CheckFlag(kBailoutOnMinusZero)
764 ? FAIL_ON_MINUS_ZERO : TREAT_MINUS_ZERO_AS_ZERO;
765 }
766
767 protected:
768 // This function must be overridden for instructions with flag kUseGVN, to
769 // compare the non-Operand parts of the instruction.
DataEquals(HValue * other)770 virtual bool DataEquals(HValue* other) {
771 UNREACHABLE();
772 return false;
773 }
774
ToStringOrToNumberCanBeObserved()775 bool ToStringOrToNumberCanBeObserved() const {
776 if (type().IsTaggedPrimitive()) return false;
777 if (type().IsJSReceiver()) return true;
778 return !representation().IsSmiOrInteger32() && !representation().IsDouble();
779 }
780
RepresentationFromInputs()781 virtual Representation RepresentationFromInputs() {
782 return representation();
783 }
784 virtual Representation RepresentationFromUses();
785 Representation RepresentationFromUseRequirements();
786 bool HasNonSmiUse();
787 virtual void UpdateRepresentation(Representation new_rep,
788 HInferRepresentationPhase* h_infer,
789 const char* reason);
790 void AddDependantsToWorklist(HInferRepresentationPhase* h_infer);
791
RepresentationChanged(Representation to)792 virtual void RepresentationChanged(Representation to) { }
793
794 virtual Range* InferRange(Zone* zone);
795 virtual void DeleteFromGraph() = 0;
796 virtual void InternalSetOperandAt(int index, HValue* value) = 0;
clear_block()797 void clear_block() {
798 DCHECK(block_ != NULL);
799 block_ = NULL;
800 }
801
set_representation(Representation r)802 void set_representation(Representation r) {
803 DCHECK(representation_.IsNone() && !r.IsNone());
804 representation_ = r;
805 }
806
AllFlagSet()807 static GVNFlagSet AllFlagSet() {
808 GVNFlagSet result;
809 #define ADD_FLAG(Type) result.Add(k##Type);
810 GVN_TRACKED_FLAG_LIST(ADD_FLAG)
811 GVN_UNTRACKED_FLAG_LIST(ADD_FLAG)
812 #undef ADD_FLAG
813 return result;
814 }
815
816 // A flag mask to mark an instruction as having arbitrary side effects.
AllSideEffectsFlagSet()817 static GVNFlagSet AllSideEffectsFlagSet() {
818 GVNFlagSet result = AllFlagSet();
819 result.Remove(kOsrEntries);
820 return result;
821 }
822 friend std::ostream& operator<<(std::ostream& os, const ChangesOf& v);
823
824 // A flag mask of all side effects that can make observable changes in
825 // an executing program (i.e. are not safe to repeat, move or remove);
AllObservableSideEffectsFlagSet()826 static GVNFlagSet AllObservableSideEffectsFlagSet() {
827 GVNFlagSet result = AllFlagSet();
828 result.Remove(kNewSpacePromotion);
829 result.Remove(kElementsKind);
830 result.Remove(kElementsPointer);
831 result.Remove(kMaps);
832 return result;
833 }
834
835 // Remove the matching use from the use list if present. Returns the
836 // removed list node or NULL.
837 HUseListNode* RemoveUse(HValue* value, int index);
838
839 void RegisterUse(int index, HValue* new_value);
840
841 HBasicBlock* block_;
842
843 // The id of this instruction in the hydrogen graph, assigned when first
844 // added to the graph. Reflects creation order.
845 int id_;
846
847 Representation representation_;
848 HType type_;
849 HUseListNode* use_list_;
850 Range* range_;
851 #ifdef DEBUG
852 bool range_poisoned_;
853 #endif
854 int flags_;
855 GVNFlagSet changes_flags_;
856 GVNFlagSet depends_on_flags_;
857
858 private:
IsDeletable()859 virtual bool IsDeletable() const { return false; }
860
861 DISALLOW_COPY_AND_ASSIGN(HValue);
862 };
863
864 // Support for printing various aspects of an HValue.
865 struct NameOf {
NameOfNameOf866 explicit NameOf(const HValue* const v) : value(v) {}
867 const HValue* value;
868 };
869
870
871 struct TypeOf {
TypeOfTypeOf872 explicit TypeOf(const HValue* const v) : value(v) {}
873 const HValue* value;
874 };
875
876
877 struct ChangesOf {
ChangesOfChangesOf878 explicit ChangesOf(const HValue* const v) : value(v) {}
879 const HValue* value;
880 };
881
882
883 std::ostream& operator<<(std::ostream& os, const HValue& v);
884 std::ostream& operator<<(std::ostream& os, const NameOf& v);
885 std::ostream& operator<<(std::ostream& os, const TypeOf& v);
886 std::ostream& operator<<(std::ostream& os, const ChangesOf& v);
887
888
889 #define DECLARE_INSTRUCTION_FACTORY_P0(I) \
890 static I* New(Isolate* isolate, Zone* zone, HValue* context) { \
891 return new (zone) I(); \
892 }
893
894 #define DECLARE_INSTRUCTION_FACTORY_P1(I, P1) \
895 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1) { \
896 return new (zone) I(p1); \
897 }
898
899 #define DECLARE_INSTRUCTION_FACTORY_P2(I, P1, P2) \
900 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2) { \
901 return new (zone) I(p1, p2); \
902 }
903
904 #define DECLARE_INSTRUCTION_FACTORY_P3(I, P1, P2, P3) \
905 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
906 P3 p3) { \
907 return new (zone) I(p1, p2, p3); \
908 }
909
910 #define DECLARE_INSTRUCTION_FACTORY_P4(I, P1, P2, P3, P4) \
911 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
912 P3 p3, P4 p4) { \
913 return new (zone) I(p1, p2, p3, p4); \
914 }
915
916 #define DECLARE_INSTRUCTION_FACTORY_P5(I, P1, P2, P3, P4, P5) \
917 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
918 P3 p3, P4 p4, P5 p5) { \
919 return new (zone) I(p1, p2, p3, p4, p5); \
920 }
921
922 #define DECLARE_INSTRUCTION_FACTORY_P6(I, P1, P2, P3, P4, P5, P6) \
923 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
924 P3 p3, P4 p4, P5 p5, P6 p6) { \
925 return new (zone) I(p1, p2, p3, p4, p5, p6); \
926 }
927
928 #define DECLARE_INSTRUCTION_FACTORY_P7(I, P1, P2, P3, P4, P5, P6, P7) \
929 static I* New(Isolate* isolate, Zone* zone, HValue* context, P1 p1, P2 p2, \
930 P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) { \
931 return new (zone) I(p1, p2, p3, p4, p5, p6, p7); \
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:
HPositionInfo(int pos)983 explicit HPositionInfo(int pos) : data_(TagPosition(pos)) { }
984
position()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
set_position(SourcePosition pos)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
ensure_storage_for_operand_positions(Zone * zone,int operand_count)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
operand_position(int idx)1018 SourcePosition operand_position(int idx) const {
1019 if (!has_operand_positions()) {
1020 return position();
1021 }
1022 return *operand_position_slot(idx);
1023 }
1024
set_operand_position(int idx,SourcePosition pos)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
operand_position_slot(int idx)1033 SourcePosition* operand_position_slot(int idx) const {
1034 DCHECK(has_operand_positions());
1035 return &(operand_positions()[kFirstOperandPosIndex + idx]);
1036 }
1037
has_operand_positions()1038 bool has_operand_positions() const {
1039 return !IsTaggedPosition(data_);
1040 }
1041
operand_positions()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;
IsTaggedPosition(intptr_t val)1049 static bool IsTaggedPosition(intptr_t val) {
1050 return (val & kPositionTag) != 0;
1051 }
UntagPosition(intptr_t val)1052 static intptr_t UntagPosition(intptr_t val) {
1053 DCHECK(IsTaggedPosition(val));
1054 return val >> kPositionShift;
1055 }
TagPosition(intptr_t val)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:
next()1068 HInstruction* next() const { return next_; }
previous()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
IsLinked()1074 bool IsLinked() const { return block() != NULL; }
1075 void Unlink();
1076
1077 void InsertBefore(HInstruction* next);
1078
Prepend(T * instr)1079 template<class T> T* Prepend(T* instr) {
1080 instr->InsertBefore(this);
1081 return instr;
1082 }
1083
1084 void InsertAfter(HInstruction* previous);
1085
Append(T * instr)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.
position()1092 SourcePosition position() const override {
1093 return SourcePosition(position_.position());
1094 }
has_position()1095 bool has_position() const {
1096 return !position().IsUnknown();
1097 }
set_position(SourcePosition position)1098 void set_position(SourcePosition position) {
1099 DCHECK(!has_position());
1100 DCHECK(!position.IsUnknown());
1101 position_.set_position(position);
1102 }
1103
operand_position(int index)1104 SourcePosition operand_position(int index) const override {
1105 const SourcePosition pos = position_.operand_position(index);
1106 return pos.IsUnknown() ? position() : pos;
1107 }
set_operand_position(Zone * zone,int index,SourcePosition pos)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);
CanTruncateToSmi()1115 bool CanTruncateToSmi() const { return CheckFlag(kTruncatingToSmi); }
CanTruncateToInt32()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
HasStackCheck()1126 virtual bool HasStackCheck() { return false; }
1127
DECLARE_ABSTRACT_INSTRUCTION(Instruction)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
DeleteFromGraph()1139 void DeleteFromGraph() override { Unlink(); }
1140
1141 private:
InitializeAsFirst(HBasicBlock * block)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:
OperandCount()1158 int OperandCount() const final { return V; }
OperandAt(int i)1159 HValue* OperandAt(int i) const final { return inputs_[i]; }
1160
1161 protected:
1162 explicit HTemplateInstruction(HType type = HType::Tagged())
HInstruction(type)1163 : HInstruction(type) {}
1164
InternalSetOperandAt(int i,HValue * value)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
KnownSuccessorBlock(HBasicBlock ** block)1180 virtual bool KnownSuccessorBlock(HBasicBlock** block) {
1181 *block = NULL;
1182 return false;
1183 }
1184
FirstSuccessor()1185 HBasicBlock* FirstSuccessor() {
1186 return SuccessorCount() > 0 ? SuccessorAt(0) : NULL;
1187 }
SecondSuccessor()1188 HBasicBlock* SecondSuccessor() {
1189 return SuccessorCount() > 1 ? SuccessorAt(1) : NULL;
1190 }
1191
Not()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:
HSuccessorIterator(const HControlInstruction * instr)1204 explicit HSuccessorIterator(const HControlInstruction* instr)
1205 : instr_(instr), current_(0) {}
1206
Done()1207 bool Done() { return current_ >= instr_->SuccessorCount(); }
Current()1208 HBasicBlock* Current() { return instr_->SuccessorAt(current_); }
Advance()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:
SuccessorCount()1220 int SuccessorCount() const override { return S; }
SuccessorAt(int i)1221 HBasicBlock* SuccessorAt(int i) const override { return successors_[i]; }
SetSuccessorAt(int i,HBasicBlock * block)1222 void SetSuccessorAt(int i, HBasicBlock* block) override {
1223 successors_[i] = block;
1224 }
1225
OperandCount()1226 int OperandCount() const override { return V; }
OperandAt(int i)1227 HValue* OperandAt(int i) const override { return inputs_[i]; }
1228
1229
1230 protected:
InternalSetOperandAt(int i,HValue * value)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:
RequiredInputRepresentation(int index)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:
HDummyUse(HValue * value)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
value()1261 HValue* value() const { return OperandAt(0); }
1262
HasEscapingOperandAt(int index)1263 bool HasEscapingOperandAt(int index) override { return false; }
RequiredInputRepresentation(int index)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
RequiredInputRepresentation(int index)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:
New(Zone * zone)1289 static HPrologue* New(Zone* zone) { return new (zone) HPrologue(); }
1290
RequiredInputRepresentation(int index)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:
HGoto(HBasicBlock * target)1301 explicit HGoto(HBasicBlock* target) {
1302 SetSuccessorAt(0, target);
1303 }
1304
KnownSuccessorBlock(HBasicBlock ** block)1305 bool KnownSuccessorBlock(HBasicBlock** block) override {
1306 *block = FirstSuccessor();
1307 return true;
1308 }
1309
RequiredInputRepresentation(int index)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:
New(Isolate * isolate,Zone * zone,HValue * context,Deoptimizer::DeoptReason reason,Deoptimizer::BailoutType type,HBasicBlock * unreachable_continuation)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
KnownSuccessorBlock(HBasicBlock ** block)1329 bool KnownSuccessorBlock(HBasicBlock** block) override {
1330 *block = NULL;
1331 return true;
1332 }
1333
RequiredInputRepresentation(int index)1334 Representation RequiredInputRepresentation(int index) override {
1335 return Representation::None();
1336 }
1337
reason()1338 Deoptimizer::DeoptReason reason() const { return reason_; }
type()1339 Deoptimizer::BailoutType type() { return type_; }
1340
DECLARE_CONCRETE_INSTRUCTION(Deoptimize)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:
HUnaryControlInstruction(HValue * value,HBasicBlock * true_target,HBasicBlock * false_target)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
value()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
RequiredInputRepresentation(int index)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
expected_input_types()1390 ToBooleanStub::Types expected_input_types() const {
1391 return expected_input_types_;
1392 }
1393
DECLARE_CONCRETE_INSTRUCTION(Branch)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
KnownSuccessorBlock(HBasicBlock ** block)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;
known_successor_index()1428 int known_successor_index() const {
1429 return KnownSuccessorIndexField::decode(bit_field_) -
1430 kInternalKnownSuccessorOffset;
1431 }
set_known_successor_index(int index)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
map()1438 Unique<Map> map() const { return map_; }
map_is_stable()1439 bool map_is_stable() const { return MapIsStableField::decode(bit_field_); }
1440
RequiredInputRepresentation(int index)1441 Representation RequiredInputRepresentation(int index) override {
1442 return Representation::Tagged();
1443 }
1444
DECLARE_CONCRETE_INSTRUCTION(CompareMap)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)
HUnaryControlInstruction(value,true_target,false_target)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:
New(Zone * zone)1476 static HContext* New(Zone* zone) {
1477 return new(zone) HContext();
1478 }
1479
RequiredInputRepresentation(int index)1480 Representation RequiredInputRepresentation(int index) override {
1481 return Representation::None();
1482 }
1483
DECLARE_CONCRETE_INSTRUCTION(Context)1484 DECLARE_CONCRETE_INSTRUCTION(Context)
1485
1486 protected:
1487 bool DataEquals(HValue* other) override { return true; }
1488
1489 private:
HContext()1490 HContext() {
1491 set_representation(Representation::Tagged());
1492 SetFlag(kUseGVN);
1493 }
1494
IsDeletable()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
RequiredInputRepresentation(int index)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
value()1512 HValue* value() const { return OperandAt(0); }
context()1513 HValue* context() const { return OperandAt(1); }
parameter_count()1514 HValue* parameter_count() const { return OperandAt(2); }
1515
DECLARE_CONCRETE_INSTRUCTION(Return)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
RequiredInputRepresentation(int index)1531 Representation RequiredInputRepresentation(int index) override {
1532 return Representation::None();
1533 }
1534
DECLARE_CONCRETE_INSTRUCTION(AbnormalExit)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
cast(HValue * value)1548 static HUnaryOperation* cast(HValue* value) {
1549 return reinterpret_cast<HUnaryOperation*>(value);
1550 }
1551
value()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
RequiredInputRepresentation(int index)1561 Representation RequiredInputRepresentation(int index) override {
1562 return Representation::None();
1563 }
1564
DECLARE_CONCRETE_INSTRUCTION(UseConst)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
value()1578 HValue* value() const { return OperandAt(0); }
1579
observed_input_representation(int index)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 }
RequiredInputRepresentation(int index)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
DECLARE_CONCRETE_INSTRUCTION(ForceRepresentation)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:
HChange(HValue * value,Representation to,bool is_truncating_to_smi,bool is_truncating_to_int32)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
can_convert_undefined_to_nan()1627 bool can_convert_undefined_to_nan() {
1628 return CheckUsesForFlag(kAllowUndefinedAsNaN);
1629 }
1630
1631 HType CalculateInferredType() override;
1632 HValue* Canonicalize() override;
1633
from()1634 Representation from() const { return value()->representation(); }
to()1635 Representation to() const { return representation(); }
deoptimize_on_minus_zero()1636 bool deoptimize_on_minus_zero() const {
1637 return CheckFlag(kBailoutOnMinusZero);
1638 }
RequiredInputRepresentation(int index)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
DECLARE_CONCRETE_INSTRUCTION(Change)1647 DECLARE_CONCRETE_INSTRUCTION(Change)
1648
1649 protected:
1650 bool DataEquals(HValue* other) override { return true; }
1651
1652 private:
IsDeletable()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
RequiredInputRepresentation(int index)1663 Representation RequiredInputRepresentation(int index) override {
1664 return Representation::None();
1665 }
1666
DECLARE_CONCRETE_INSTRUCTION(ClampToUint8)1667 DECLARE_CONCRETE_INSTRUCTION(ClampToUint8)
1668
1669 protected:
1670 bool DataEquals(HValue* other) override { return true; }
1671
1672 private:
HClampToUint8(HValue * value)1673 explicit HClampToUint8(HValue* value)
1674 : HUnaryOperation(value) {
1675 set_representation(Representation::Integer32());
1676 SetFlag(kAllowUndefinedAsNaN);
1677 SetFlag(kUseGVN);
1678 }
1679
IsDeletable()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
RequiredInputRepresentation(int index)1689 Representation RequiredInputRepresentation(int index) override {
1690 return Representation::Double();
1691 }
1692
DECLARE_CONCRETE_INSTRUCTION(DoubleBits)1693 DECLARE_CONCRETE_INSTRUCTION(DoubleBits)
1694
1695 Bits bits() { return bits_; }
1696
1697 protected:
DataEquals(HValue * other)1698 bool DataEquals(HValue* other) override {
1699 return other->IsDoubleBits() && HDoubleBits::cast(other)->bits() == bits();
1700 }
1701
1702 private:
HDoubleBits(HValue * value,Bits bits)1703 HDoubleBits(HValue* value, Bits bits)
1704 : HUnaryOperation(value), bits_(bits) {
1705 set_representation(Representation::Integer32());
1706 SetFlag(kUseGVN);
1707 }
1708
IsDeletable()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
RequiredInputRepresentation(int index)1719 Representation RequiredInputRepresentation(int index) override {
1720 return Representation::Integer32();
1721 }
1722
DECLARE_CONCRETE_INSTRUCTION(ConstructDouble)1723 DECLARE_CONCRETE_INSTRUCTION(ConstructDouble)
1724
1725 HValue* hi() { return OperandAt(0); }
lo()1726 HValue* lo() { return OperandAt(1); }
1727
1728 protected:
DataEquals(HValue * other)1729 bool DataEquals(HValue* other) override { return true; }
1730
1731 private:
HConstructDouble(HValue * hi,HValue * lo)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
IsDeletable()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:
HSimulate(BailoutId ast_id,int pop_count,Zone * zone,RemovableSimulate removable)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)) {}
~HSimulate()1760 ~HSimulate() {}
1761
1762 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1763
HasAstId()1764 bool HasAstId() const { return !ast_id_.IsNone(); }
ast_id()1765 BailoutId ast_id() const { return ast_id_; }
set_ast_id(BailoutId id)1766 void set_ast_id(BailoutId id) {
1767 DCHECK(!HasAstId());
1768 ast_id_ = id;
1769 }
1770
pop_count()1771 int pop_count() const { return pop_count_; }
values()1772 const ZoneList<HValue*>* values() const { return &values_; }
GetAssignedIndexAt(int index)1773 int GetAssignedIndexAt(int index) const {
1774 DCHECK(HasAssignedIndexAt(index));
1775 return assigned_indexes_[index];
1776 }
HasAssignedIndexAt(int index)1777 bool HasAssignedIndexAt(int index) const {
1778 return assigned_indexes_[index] != kNoIndex;
1779 }
AddAssignedValue(int index,HValue * value)1780 void AddAssignedValue(int index, HValue* value) {
1781 AddValue(index, value);
1782 }
AddPushedValue(HValue * value)1783 void AddPushedValue(HValue* value) {
1784 AddValue(kNoIndex, value);
1785 }
ToOperandIndex(int environment_index)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 }
OperandCount()1792 int OperandCount() const override { return values_.length(); }
OperandAt(int index)1793 HValue* OperandAt(int index) const override { return values_[index]; }
1794
HasEscapingOperandAt(int index)1795 bool HasEscapingOperandAt(int index) override { return false; }
RequiredInputRepresentation(int index)1796 Representation RequiredInputRepresentation(int index) override {
1797 return Representation::None();
1798 }
1799
1800 void MergeWith(ZoneList<HSimulate*>* list);
is_candidate_for_removal()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;
set_closure(Handle<JSFunction> closure)1812 void set_closure(Handle<JSFunction> closure) { closure_ = closure; }
closure()1813 Handle<JSFunction> closure() const { return closure_; }
1814 #endif
1815
1816 protected:
InternalSetOperandAt(int index,HValue * value)1817 void InternalSetOperandAt(int index, HValue* value) override {
1818 values_[index] = value;
1819 }
1820
1821 private:
1822 static const int kNoIndex = -1;
AddValue(int index,HValue * value)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 }
HasValueForIndex(int index)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 }
is_done_with_replay()1837 bool is_done_with_replay() const {
1838 return DoneWithReplayField::decode(bit_field_);
1839 }
set_done_with_replay()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
kind()1866 Kind kind() const { return kind_; }
index()1867 int index() const { return index_; }
next_simulate()1868 HSimulate* next_simulate() { return next_simulate_; }
set_next_simulate(HSimulate * simulate)1869 void set_next_simulate(HSimulate* simulate) {
1870 next_simulate_ = simulate;
1871 }
1872
RequiredInputRepresentation(int index)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
set_closure(Handle<JSFunction> closure)1880 void set_closure(Handle<JSFunction> closure) {
1881 DCHECK(closure_.is_null());
1882 DCHECK(!closure.is_null());
1883 closure_ = closure;
1884 }
closure()1885 Handle<JSFunction> closure() const { return closure_; }
1886 #endif
1887
1888 DECLARE_CONCRETE_INSTRUCTION(EnvironmentMarker);
1889
1890 private:
HEnvironmentMarker(Kind kind,int index)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
context()1913 HValue* context() { return OperandAt(0); }
1914
RequiredInputRepresentation(int index)1915 Representation RequiredInputRepresentation(int index) override {
1916 return Representation::Tagged();
1917 }
1918
Eliminate()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
is_function_entry()1927 bool is_function_entry() { return type_ == kFunctionEntry; }
is_backwards_branch()1928 bool is_backwards_branch() { return type_ == kBackwardsBranch; }
1929
DECLARE_CONCRETE_INSTRUCTION(StackCheck)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:
New(Isolate * isolate,Zone * zone,HValue * context,BailoutId return_id,Handle<JSFunction> closure,HConstant * closure_context,int arguments_count,FunctionLiteral * function,InliningKind inlining_kind,Variable * arguments_var,HArgumentsObject * arguments_object)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);
return_targets()1968 ZoneList<HBasicBlock*>* return_targets() { return &return_targets_; }
1969
1970 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
1971
shared()1972 Handle<SharedFunctionInfo> shared() const { return shared_; }
closure()1973 Handle<JSFunction> closure() const { return closure_; }
closure_context()1974 HConstant* closure_context() const { return closure_context_; }
arguments_count()1975 int arguments_count() const { return arguments_count_; }
arguments_pushed()1976 bool arguments_pushed() const { return arguments_pushed_; }
set_arguments_pushed()1977 void set_arguments_pushed() { arguments_pushed_ = true; }
function()1978 FunctionLiteral* function() const { return function_; }
inlining_kind()1979 InliningKind inlining_kind() const { return inlining_kind_; }
ReturnId()1980 BailoutId ReturnId() const { return return_id_; }
inlining_id()1981 int inlining_id() const { return inlining_id_; }
set_inlining_id(int inlining_id)1982 void set_inlining_id(int inlining_id) { inlining_id_ = inlining_id; }
1983
RequiredInputRepresentation(int index)1984 Representation RequiredInputRepresentation(int index) override {
1985 return Representation::None();
1986 }
1987
arguments_var()1988 Variable* arguments_var() { return arguments_var_; }
arguments_object()1989 HArgumentsObject* arguments_object() { return arguments_object_; }
1990
DECLARE_CONCRETE_INSTRUCTION(EnterInlined)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:
HLeaveInlined(HEnterInlined * entry,int drop_count)2029 HLeaveInlined(HEnterInlined* entry,
2030 int drop_count)
2031 : entry_(entry),
2032 drop_count_(drop_count) { }
2033
RequiredInputRepresentation(int index)2034 Representation RequiredInputRepresentation(int index) override {
2035 return Representation::None();
2036 }
2037
argument_delta()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:
New(Isolate * isolate,Zone * zone,HValue * context)2052 static HPushArguments* New(Isolate* isolate, Zone* zone, HValue* context) {
2053 return new(zone) HPushArguments(zone);
2054 }
New(Isolate * isolate,Zone * zone,HValue * context,HValue * arg1)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 }
New(Isolate * isolate,Zone * zone,HValue * context,HValue * arg1,HValue * arg2)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 }
New(Isolate * isolate,Zone * zone,HValue * context,HValue * arg1,HValue * arg2,HValue * arg3)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 }
New(Isolate * isolate,Zone * zone,HValue * context,HValue * arg1,HValue * arg2,HValue * arg3,HValue * arg4)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
RequiredInputRepresentation(int index)2087 Representation RequiredInputRepresentation(int index) override {
2088 return Representation::Tagged();
2089 }
2090
argument_delta()2091 int argument_delta() const override { return inputs_.length(); }
argument(int i)2092 HValue* argument(int i) { return OperandAt(i); }
2093
OperandCount()2094 int OperandCount() const final { return inputs_.length(); }
OperandAt(int i)2095 HValue* OperandAt(int i) const final { return inputs_[i]; }
2096
2097 void AddInput(HValue* value);
2098
DECLARE_CONCRETE_INSTRUCTION(PushArguments)2099 DECLARE_CONCRETE_INSTRUCTION(PushArguments)
2100
2101 protected:
2102 void InternalSetOperandAt(int i, HValue* value) final { inputs_[i] = value; }
2103
2104 private:
HPushArguments(Zone * zone)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
RequiredInputRepresentation(int index)2118 Representation RequiredInputRepresentation(int index) override {
2119 return Representation::None();
2120 }
2121
DECLARE_CONCRETE_INSTRUCTION(ThisFunction)2122 DECLARE_CONCRETE_INSTRUCTION(ThisFunction)
2123
2124 protected:
2125 bool DataEquals(HValue* other) override { return true; }
2126
2127 private:
HThisFunction()2128 HThisFunction() {
2129 set_representation(Representation::Tagged());
2130 SetFlag(kUseGVN);
2131 }
2132
IsDeletable()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
context()2143 HValue* context() { return OperandAt(0); }
pairs()2144 Handle<FixedArray> pairs() const { return pairs_; }
flags()2145 int flags() const { return flags_; }
2146
DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals)2147 DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals)
2148
2149 Representation RequiredInputRepresentation(int index) override {
2150 return Representation::Tagged();
2151 }
2152
2153 private:
HDeclareGlobals(HValue * context,Handle<FixedArray> pairs,int flags)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.
argument_count_(argument_count)2173 explicit HCall<V>(int argument_count) : argument_count_(argument_count) {
2174 this->set_representation(Representation::Tagged());
2175 this->SetAllSideEffects();
2176 }
2177
CalculateInferredType()2178 HType CalculateInferredType() final { return HType::Tagged(); }
2179
argument_count()2180 virtual int argument_count() const {
2181 return argument_count_;
2182 }
2183
argument_delta()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:
HUnaryCall(HValue * value,int argument_count)2193 HUnaryCall(HValue* value, int argument_count)
2194 : HCall<1>(argument_count) {
2195 SetOperandAt(0, value);
2196 }
2197
RequiredInputRepresentation(int index)2198 Representation RequiredInputRepresentation(int index) final {
2199 return Representation::Tagged();
2200 }
2201
2202 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2203
value()2204 HValue* value() const { return OperandAt(0); }
2205 };
2206
2207
2208 class HBinaryCall : public HCall<2> {
2209 public:
HBinaryCall(HValue * first,HValue * second,int argument_count)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
RequiredInputRepresentation(int index)2218 Representation RequiredInputRepresentation(int index) final {
2219 return Representation::Tagged();
2220 }
2221
first()2222 HValue* first() const { return OperandAt(0); }
second()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
function()2232 HValue* function() const { return OperandAt(0); }
2233
2234 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2235
RequiredInputRepresentation(int index)2236 Representation RequiredInputRepresentation(int index) final {
2237 DCHECK(index == 0);
2238 return Representation::Tagged();
2239 }
2240
HasStackCheck()2241 bool HasStackCheck() final { return has_stack_check_; }
2242
DECLARE_CONCRETE_INSTRUCTION(CallJSFunction)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
OperandCount()2275 int OperandCount() const final { return values_.length(); }
OperandAt(int index)2276 HValue* OperandAt(int index) const final { return values_[index]; }
2277
RequiredInputRepresentation(int index)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
DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor)2289 DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor)
2290
2291 HType CalculateInferredType() final { return HType::Tagged(); }
2292
IsTailCall()2293 bool IsTailCall() const { return call_mode_ == TAIL_CALL; }
2294
argument_count()2295 virtual int argument_count() const {
2296 return argument_count_;
2297 }
2298
argument_delta()2299 int argument_delta() const override { return -argument_count_; }
2300
descriptor()2301 CallInterfaceDescriptor descriptor() const { return descriptor_; }
2302
target()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.
HCallWithDescriptor(HValue * target,int argument_count,CallInterfaceDescriptor descriptor,const Vector<HValue * > & operands,CallMode call_mode,Zone * zone)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
AddOperand(HValue * v,Zone * zone)2329 void AddOperand(HValue* v, Zone* zone) {
2330 values_.Add(NULL, zone);
2331 SetOperandAt(values_.length() - 1, v);
2332 }
2333
GetParameterCount()2334 int GetParameterCount() const {
2335 return descriptor_.GetRegisterParameterCount() + 1;
2336 }
2337
InternalSetOperandAt(int index,HValue * value)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
HInvokeFunction(HValue * context,HValue * function,Handle<JSFunction> known_function,int argument_count)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
New(Isolate * isolate,Zone * zone,HValue * context,HValue * function,Handle<JSFunction> known_function,int argument_count)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
context()2376 HValue* context() { return first(); }
function()2377 HValue* function() { return second(); }
known_function()2378 Handle<JSFunction> known_function() { return known_function_; }
formal_parameter_count()2379 int formal_parameter_count() const { return formal_parameter_count_; }
2380
HasStackCheck()2381 bool HasStackCheck() final { return has_stack_check_; }
2382
DECLARE_CONCRETE_INSTRUCTION(InvokeFunction)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_P3(HCallFunction, HValue*, int,
2400 ConvertReceiverMode);
2401
context()2402 HValue* context() const { return first(); }
function()2403 HValue* function() const { return second(); }
2404
convert_mode()2405 ConvertReceiverMode convert_mode() const { return convert_mode_; }
slot()2406 FeedbackVectorSlot slot() const { return slot_; }
feedback_vector()2407 Handle<TypeFeedbackVector> feedback_vector() const {
2408 return feedback_vector_;
2409 }
HasVectorAndSlot()2410 bool HasVectorAndSlot() const { return !feedback_vector_.is_null(); }
SetVectorAndSlot(Handle<TypeFeedbackVector> vector,FeedbackVectorSlot slot)2411 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
2412 FeedbackVectorSlot slot) {
2413 feedback_vector_ = vector;
2414 slot_ = slot;
2415 }
2416
2417 DECLARE_CONCRETE_INSTRUCTION(CallFunction)
2418
2419 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2420
argument_delta()2421 int argument_delta() const override { return -argument_count(); }
2422
2423 private:
HCallFunction(HValue * context,HValue * function,int argument_count,ConvertReceiverMode convert_mode)2424 HCallFunction(HValue* context, HValue* function, int argument_count,
2425 ConvertReceiverMode convert_mode)
2426 : HBinaryCall(context, function, argument_count),
2427 convert_mode_(convert_mode) {}
2428 Handle<TypeFeedbackVector> feedback_vector_;
2429 FeedbackVectorSlot slot_;
2430 ConvertReceiverMode convert_mode_;
2431 };
2432
2433
2434 class HCallNewArray final : public HBinaryCall {
2435 public:
2436 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HCallNewArray, HValue*, int,
2437 ElementsKind,
2438 Handle<AllocationSite>);
2439
context()2440 HValue* context() { return first(); }
constructor()2441 HValue* constructor() { return second(); }
2442
2443 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2444
elements_kind()2445 ElementsKind elements_kind() const { return elements_kind_; }
site()2446 Handle<AllocationSite> site() const { return site_; }
2447
DECLARE_CONCRETE_INSTRUCTION(CallNewArray)2448 DECLARE_CONCRETE_INSTRUCTION(CallNewArray)
2449
2450 private:
2451 HCallNewArray(HValue* context, HValue* constructor, int argument_count,
2452 ElementsKind elements_kind, Handle<AllocationSite> site)
2453 : HBinaryCall(context, constructor, argument_count),
2454 elements_kind_(elements_kind),
2455 site_(site) {}
2456
2457 ElementsKind elements_kind_;
2458 Handle<AllocationSite> site_;
2459 };
2460
2461
2462 class HCallRuntime final : public HCall<1> {
2463 public:
2464 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallRuntime,
2465 const Runtime::Function*, int);
2466
2467 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2468
context()2469 HValue* context() { return OperandAt(0); }
function()2470 const Runtime::Function* function() const { return c_function_; }
save_doubles()2471 SaveFPRegsMode save_doubles() const { return save_doubles_; }
set_save_doubles(SaveFPRegsMode save_doubles)2472 void set_save_doubles(SaveFPRegsMode save_doubles) {
2473 save_doubles_ = save_doubles;
2474 }
2475
RequiredInputRepresentation(int index)2476 Representation RequiredInputRepresentation(int index) override {
2477 return Representation::Tagged();
2478 }
2479
DECLARE_CONCRETE_INSTRUCTION(CallRuntime)2480 DECLARE_CONCRETE_INSTRUCTION(CallRuntime)
2481
2482 private:
2483 HCallRuntime(HValue* context, const Runtime::Function* c_function,
2484 int argument_count)
2485 : HCall<1>(argument_count),
2486 c_function_(c_function),
2487 save_doubles_(kDontSaveFPRegs) {
2488 SetOperandAt(0, context);
2489 }
2490
2491 const Runtime::Function* c_function_;
2492 SaveFPRegsMode save_doubles_;
2493 };
2494
2495
2496 class HMapEnumLength final : public HUnaryOperation {
2497 public:
2498 DECLARE_INSTRUCTION_FACTORY_P1(HMapEnumLength, HValue*);
2499
RequiredInputRepresentation(int index)2500 Representation RequiredInputRepresentation(int index) override {
2501 return Representation::Tagged();
2502 }
2503
DECLARE_CONCRETE_INSTRUCTION(MapEnumLength)2504 DECLARE_CONCRETE_INSTRUCTION(MapEnumLength)
2505
2506 protected:
2507 bool DataEquals(HValue* other) override { return true; }
2508
2509 private:
HMapEnumLength(HValue * value)2510 explicit HMapEnumLength(HValue* value)
2511 : HUnaryOperation(value, HType::Smi()) {
2512 set_representation(Representation::Smi());
2513 SetFlag(kUseGVN);
2514 SetDependsOnFlag(kMaps);
2515 }
2516
IsDeletable()2517 bool IsDeletable() const override { return true; }
2518 };
2519
2520
2521 class HUnaryMathOperation final : public HTemplateInstruction<2> {
2522 public:
2523 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
2524 HValue* value, BuiltinFunctionId op);
2525
context()2526 HValue* context() const { return OperandAt(0); }
value()2527 HValue* value() const { return OperandAt(1); }
2528
2529 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2530
RequiredInputRepresentation(int index)2531 Representation RequiredInputRepresentation(int index) override {
2532 if (index == 0) {
2533 return Representation::Tagged();
2534 } else {
2535 switch (op_) {
2536 case kMathFloor:
2537 case kMathRound:
2538 case kMathFround:
2539 case kMathSqrt:
2540 case kMathPowHalf:
2541 case kMathLog:
2542 case kMathExp:
2543 return Representation::Double();
2544 case kMathAbs:
2545 return representation();
2546 case kMathClz32:
2547 return Representation::Integer32();
2548 default:
2549 UNREACHABLE();
2550 return Representation::None();
2551 }
2552 }
2553 }
2554
2555 Range* InferRange(Zone* zone) override;
2556
2557 HValue* Canonicalize() override;
2558 Representation RepresentationFromUses() override;
2559 Representation RepresentationFromInputs() override;
2560
op()2561 BuiltinFunctionId op() const { return op_; }
2562 const char* OpName() const;
2563
DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation)2564 DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation)
2565
2566 protected:
2567 bool DataEquals(HValue* other) override {
2568 HUnaryMathOperation* b = HUnaryMathOperation::cast(other);
2569 return op_ == b->op();
2570 }
2571
2572 private:
2573 // Indicates if we support a double (and int32) output for Math.floor and
2574 // Math.round.
SupportsFlexibleFloorAndRound()2575 bool SupportsFlexibleFloorAndRound() const {
2576 #ifdef V8_TARGET_ARCH_ARM64
2577 // TODO(rmcilroy): Re-enable this for Arm64 once http://crbug.com/476477 is
2578 // fixed.
2579 return false;
2580 #else
2581 return false;
2582 #endif
2583 }
HUnaryMathOperation(HValue * context,HValue * value,BuiltinFunctionId op)2584 HUnaryMathOperation(HValue* context, HValue* value, BuiltinFunctionId op)
2585 : HTemplateInstruction<2>(HType::TaggedNumber()), op_(op) {
2586 SetOperandAt(0, context);
2587 SetOperandAt(1, value);
2588 switch (op) {
2589 case kMathFloor:
2590 case kMathRound:
2591 if (SupportsFlexibleFloorAndRound()) {
2592 SetFlag(kFlexibleRepresentation);
2593 } else {
2594 set_representation(Representation::Integer32());
2595 }
2596 break;
2597 case kMathClz32:
2598 set_representation(Representation::Integer32());
2599 break;
2600 case kMathAbs:
2601 // Not setting representation here: it is None intentionally.
2602 SetFlag(kFlexibleRepresentation);
2603 // TODO(svenpanne) This flag is actually only needed if representation()
2604 // is tagged, and not when it is an unboxed double or unboxed integer.
2605 SetChangesFlag(kNewSpacePromotion);
2606 break;
2607 case kMathFround:
2608 case kMathLog:
2609 case kMathExp:
2610 case kMathSqrt:
2611 case kMathPowHalf:
2612 set_representation(Representation::Double());
2613 break;
2614 default:
2615 UNREACHABLE();
2616 }
2617 SetFlag(kUseGVN);
2618 SetFlag(kAllowUndefinedAsNaN);
2619 }
2620
IsDeletable()2621 bool IsDeletable() const override {
2622 // TODO(crankshaft): This should be true, however the semantics of this
2623 // instruction also include the ToNumber conversion that is mentioned in the
2624 // spec, which is of course observable.
2625 return false;
2626 }
2627
2628 HValue* SimplifiedDividendForMathFloorOfDiv(HDiv* hdiv);
2629 HValue* SimplifiedDivisorForMathFloorOfDiv(HDiv* hdiv);
2630
2631 BuiltinFunctionId op_;
2632 };
2633
2634
2635 class HLoadRoot final : public HTemplateInstruction<0> {
2636 public:
2637 DECLARE_INSTRUCTION_FACTORY_P1(HLoadRoot, Heap::RootListIndex);
2638 DECLARE_INSTRUCTION_FACTORY_P2(HLoadRoot, Heap::RootListIndex, HType);
2639
RequiredInputRepresentation(int index)2640 Representation RequiredInputRepresentation(int index) override {
2641 return Representation::None();
2642 }
2643
index()2644 Heap::RootListIndex index() const { return index_; }
2645
DECLARE_CONCRETE_INSTRUCTION(LoadRoot)2646 DECLARE_CONCRETE_INSTRUCTION(LoadRoot)
2647
2648 protected:
2649 bool DataEquals(HValue* other) override {
2650 HLoadRoot* b = HLoadRoot::cast(other);
2651 return index_ == b->index_;
2652 }
2653
2654 private:
2655 explicit HLoadRoot(Heap::RootListIndex index, HType type = HType::Tagged())
2656 : HTemplateInstruction<0>(type), index_(index) {
2657 SetFlag(kUseGVN);
2658 // TODO(bmeurer): We'll need kDependsOnRoots once we add the
2659 // corresponding HStoreRoot instruction.
2660 SetDependsOnFlag(kCalls);
2661 set_representation(Representation::Tagged());
2662 }
2663
IsDeletable()2664 bool IsDeletable() const override { return true; }
2665
2666 const Heap::RootListIndex index_;
2667 };
2668
2669
2670 class HCheckMaps final : public HTemplateInstruction<2> {
2671 public:
2672 static HCheckMaps* New(Isolate* isolate, Zone* zone, HValue* context,
2673 HValue* value, Handle<Map> map,
2674 HValue* typecheck = NULL) {
2675 return new(zone) HCheckMaps(value, new(zone) UniqueSet<Map>(
2676 Unique<Map>::CreateImmovable(map), zone), typecheck);
2677 }
2678 static HCheckMaps* New(Isolate* isolate, Zone* zone, HValue* context,
2679 HValue* value, SmallMapList* map_list,
2680 HValue* typecheck = NULL) {
2681 UniqueSet<Map>* maps = new(zone) UniqueSet<Map>(map_list->length(), zone);
2682 for (int i = 0; i < map_list->length(); ++i) {
2683 maps->Add(Unique<Map>::CreateImmovable(map_list->at(i)), zone);
2684 }
2685 return new(zone) HCheckMaps(value, maps, typecheck);
2686 }
2687
IsStabilityCheck()2688 bool IsStabilityCheck() const {
2689 return IsStabilityCheckField::decode(bit_field_);
2690 }
MarkAsStabilityCheck()2691 void MarkAsStabilityCheck() {
2692 bit_field_ = MapsAreStableField::encode(true) |
2693 HasMigrationTargetField::encode(false) |
2694 IsStabilityCheckField::encode(true);
2695 ClearChangesFlag(kNewSpacePromotion);
2696 ClearDependsOnFlag(kElementsKind);
2697 ClearDependsOnFlag(kMaps);
2698 }
2699
HasEscapingOperandAt(int index)2700 bool HasEscapingOperandAt(int index) override { return false; }
RequiredInputRepresentation(int index)2701 Representation RequiredInputRepresentation(int index) override {
2702 return Representation::Tagged();
2703 }
2704
CalculateInferredType()2705 HType CalculateInferredType() override {
2706 if (value()->type().IsHeapObject()) return value()->type();
2707 return HType::HeapObject();
2708 }
2709
2710 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2711
value()2712 HValue* value() const { return OperandAt(0); }
typecheck()2713 HValue* typecheck() const { return OperandAt(1); }
2714
maps()2715 const UniqueSet<Map>* maps() const { return maps_; }
set_maps(const UniqueSet<Map> * maps)2716 void set_maps(const UniqueSet<Map>* maps) { maps_ = maps; }
2717
maps_are_stable()2718 bool maps_are_stable() const {
2719 return MapsAreStableField::decode(bit_field_);
2720 }
2721
HasMigrationTarget()2722 bool HasMigrationTarget() const {
2723 return HasMigrationTargetField::decode(bit_field_);
2724 }
2725
2726 HValue* Canonicalize() override;
2727
CreateAndInsertAfter(Zone * zone,HValue * value,Unique<Map> map,bool map_is_stable,HInstruction * instr)2728 static HCheckMaps* CreateAndInsertAfter(Zone* zone,
2729 HValue* value,
2730 Unique<Map> map,
2731 bool map_is_stable,
2732 HInstruction* instr) {
2733 return instr->Append(new(zone) HCheckMaps(
2734 value, new(zone) UniqueSet<Map>(map, zone), map_is_stable));
2735 }
2736
CreateAndInsertBefore(Zone * zone,HValue * value,const UniqueSet<Map> * maps,bool maps_are_stable,HInstruction * instr)2737 static HCheckMaps* CreateAndInsertBefore(Zone* zone,
2738 HValue* value,
2739 const UniqueSet<Map>* maps,
2740 bool maps_are_stable,
2741 HInstruction* instr) {
2742 return instr->Prepend(new(zone) HCheckMaps(value, maps, maps_are_stable));
2743 }
2744
DECLARE_CONCRETE_INSTRUCTION(CheckMaps)2745 DECLARE_CONCRETE_INSTRUCTION(CheckMaps)
2746
2747 protected:
2748 bool DataEquals(HValue* other) override {
2749 return this->maps()->Equals(HCheckMaps::cast(other)->maps());
2750 }
2751
RedefinedOperandIndex()2752 int RedefinedOperandIndex() override { return 0; }
2753
2754 private:
HCheckMaps(HValue * value,const UniqueSet<Map> * maps,bool maps_are_stable)2755 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, bool maps_are_stable)
2756 : HTemplateInstruction<2>(HType::HeapObject()),
2757 maps_(maps),
2758 bit_field_(HasMigrationTargetField::encode(false) |
2759 IsStabilityCheckField::encode(false) |
2760 MapsAreStableField::encode(maps_are_stable)) {
2761 DCHECK_NE(0, maps->size());
2762 SetOperandAt(0, value);
2763 // Use the object value for the dependency.
2764 SetOperandAt(1, value);
2765 set_representation(Representation::Tagged());
2766 SetFlag(kUseGVN);
2767 SetDependsOnFlag(kMaps);
2768 SetDependsOnFlag(kElementsKind);
2769 }
2770
HCheckMaps(HValue * value,const UniqueSet<Map> * maps,HValue * typecheck)2771 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, HValue* typecheck)
2772 : HTemplateInstruction<2>(HType::HeapObject()),
2773 maps_(maps),
2774 bit_field_(HasMigrationTargetField::encode(false) |
2775 IsStabilityCheckField::encode(false) |
2776 MapsAreStableField::encode(true)) {
2777 DCHECK_NE(0, maps->size());
2778 SetOperandAt(0, value);
2779 // Use the object value for the dependency if NULL is passed.
2780 SetOperandAt(1, typecheck ? typecheck : value);
2781 set_representation(Representation::Tagged());
2782 SetFlag(kUseGVN);
2783 SetDependsOnFlag(kMaps);
2784 SetDependsOnFlag(kElementsKind);
2785 for (int i = 0; i < maps->size(); ++i) {
2786 Handle<Map> map = maps->at(i).handle();
2787 if (map->is_migration_target()) {
2788 bit_field_ = HasMigrationTargetField::update(bit_field_, true);
2789 }
2790 if (!map->is_stable()) {
2791 bit_field_ = MapsAreStableField::update(bit_field_, false);
2792 }
2793 }
2794 if (HasMigrationTarget()) SetChangesFlag(kNewSpacePromotion);
2795 }
2796
2797 class HasMigrationTargetField : public BitField<bool, 0, 1> {};
2798 class IsStabilityCheckField : public BitField<bool, 1, 1> {};
2799 class MapsAreStableField : public BitField<bool, 2, 1> {};
2800
2801 const UniqueSet<Map>* maps_;
2802 uint32_t bit_field_;
2803 };
2804
2805
2806 class HCheckValue final : public HUnaryOperation {
2807 public:
New(Isolate * isolate,Zone * zone,HValue * context,HValue * value,Handle<JSFunction> func)2808 static HCheckValue* New(Isolate* isolate, Zone* zone, HValue* context,
2809 HValue* value, Handle<JSFunction> func) {
2810 bool in_new_space = isolate->heap()->InNewSpace(*func);
2811 // NOTE: We create an uninitialized Unique and initialize it later.
2812 // This is because a JSFunction can move due to GC during graph creation.
2813 // TODO(titzer): This is a migration crutch. Replace with some kind of
2814 // Uniqueness scope later.
2815 Unique<JSFunction> target = Unique<JSFunction>::CreateUninitialized(func);
2816 HCheckValue* check = new(zone) HCheckValue(value, target, in_new_space);
2817 return check;
2818 }
New(Isolate * isolate,Zone * zone,HValue * context,HValue * value,Unique<HeapObject> target,bool object_in_new_space)2819 static HCheckValue* New(Isolate* isolate, Zone* zone, HValue* context,
2820 HValue* value, Unique<HeapObject> target,
2821 bool object_in_new_space) {
2822 return new(zone) HCheckValue(value, target, object_in_new_space);
2823 }
2824
FinalizeUniqueness()2825 void FinalizeUniqueness() override {
2826 object_ = Unique<HeapObject>(object_.handle());
2827 }
2828
RequiredInputRepresentation(int index)2829 Representation RequiredInputRepresentation(int index) override {
2830 return Representation::Tagged();
2831 }
2832 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2833
2834 HValue* Canonicalize() override;
2835
2836 #ifdef DEBUG
2837 void Verify() override;
2838 #endif
2839
object()2840 Unique<HeapObject> object() const { return object_; }
object_in_new_space()2841 bool object_in_new_space() const { return object_in_new_space_; }
2842
DECLARE_CONCRETE_INSTRUCTION(CheckValue)2843 DECLARE_CONCRETE_INSTRUCTION(CheckValue)
2844
2845 protected:
2846 bool DataEquals(HValue* other) override {
2847 HCheckValue* b = HCheckValue::cast(other);
2848 return object_ == b->object_;
2849 }
2850
2851 private:
HCheckValue(HValue * value,Unique<HeapObject> object,bool object_in_new_space)2852 HCheckValue(HValue* value, Unique<HeapObject> object,
2853 bool object_in_new_space)
2854 : HUnaryOperation(value, value->type()),
2855 object_(object),
2856 object_in_new_space_(object_in_new_space) {
2857 set_representation(Representation::Tagged());
2858 SetFlag(kUseGVN);
2859 }
2860
2861 Unique<HeapObject> object_;
2862 bool object_in_new_space_;
2863 };
2864
2865
2866 class HCheckInstanceType final : public HUnaryOperation {
2867 public:
2868 enum Check {
2869 IS_JS_RECEIVER,
2870 IS_JS_ARRAY,
2871 IS_JS_DATE,
2872 IS_STRING,
2873 IS_INTERNALIZED_STRING,
2874 LAST_INTERVAL_CHECK = IS_JS_DATE
2875 };
2876
2877 DECLARE_INSTRUCTION_FACTORY_P2(HCheckInstanceType, HValue*, Check);
2878
2879 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2880
RequiredInputRepresentation(int index)2881 Representation RequiredInputRepresentation(int index) override {
2882 return Representation::Tagged();
2883 }
2884
CalculateInferredType()2885 HType CalculateInferredType() override {
2886 switch (check_) {
2887 case IS_JS_RECEIVER: return HType::JSReceiver();
2888 case IS_JS_ARRAY: return HType::JSArray();
2889 case IS_JS_DATE: return HType::JSObject();
2890 case IS_STRING: return HType::String();
2891 case IS_INTERNALIZED_STRING: return HType::String();
2892 }
2893 UNREACHABLE();
2894 return HType::Tagged();
2895 }
2896
2897 HValue* Canonicalize() override;
2898
is_interval_check()2899 bool is_interval_check() const { return check_ <= LAST_INTERVAL_CHECK; }
2900 void GetCheckInterval(InstanceType* first, InstanceType* last);
2901 void GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag);
2902
check()2903 Check check() const { return check_; }
2904
DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType)2905 DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType)
2906
2907 protected:
2908 // TODO(ager): It could be nice to allow the ommision of instance
2909 // type checks if we have already performed an instance type check
2910 // with a larger range.
2911 bool DataEquals(HValue* other) override {
2912 HCheckInstanceType* b = HCheckInstanceType::cast(other);
2913 return check_ == b->check_;
2914 }
2915
RedefinedOperandIndex()2916 int RedefinedOperandIndex() override { return 0; }
2917
2918 private:
2919 const char* GetCheckName() const;
2920
HCheckInstanceType(HValue * value,Check check)2921 HCheckInstanceType(HValue* value, Check check)
2922 : HUnaryOperation(value, HType::HeapObject()), check_(check) {
2923 set_representation(Representation::Tagged());
2924 SetFlag(kUseGVN);
2925 }
2926
2927 const Check check_;
2928 };
2929
2930
2931 class HCheckSmi final : public HUnaryOperation {
2932 public:
2933 DECLARE_INSTRUCTION_FACTORY_P1(HCheckSmi, HValue*);
2934
RequiredInputRepresentation(int index)2935 Representation RequiredInputRepresentation(int index) override {
2936 return Representation::Tagged();
2937 }
2938
Canonicalize()2939 HValue* Canonicalize() override {
2940 HType value_type = value()->type();
2941 if (value_type.IsSmi()) {
2942 return NULL;
2943 }
2944 return this;
2945 }
2946
DECLARE_CONCRETE_INSTRUCTION(CheckSmi)2947 DECLARE_CONCRETE_INSTRUCTION(CheckSmi)
2948
2949 protected:
2950 bool DataEquals(HValue* other) override { return true; }
2951
2952 private:
HCheckSmi(HValue * value)2953 explicit HCheckSmi(HValue* value) : HUnaryOperation(value, HType::Smi()) {
2954 set_representation(Representation::Smi());
2955 SetFlag(kUseGVN);
2956 }
2957 };
2958
2959
2960 class HCheckArrayBufferNotNeutered final : public HUnaryOperation {
2961 public:
2962 DECLARE_INSTRUCTION_FACTORY_P1(HCheckArrayBufferNotNeutered, HValue*);
2963
HasEscapingOperandAt(int index)2964 bool HasEscapingOperandAt(int index) override { return false; }
RequiredInputRepresentation(int index)2965 Representation RequiredInputRepresentation(int index) override {
2966 return Representation::Tagged();
2967 }
2968
CalculateInferredType()2969 HType CalculateInferredType() override {
2970 if (value()->type().IsHeapObject()) return value()->type();
2971 return HType::HeapObject();
2972 }
2973
DECLARE_CONCRETE_INSTRUCTION(CheckArrayBufferNotNeutered)2974 DECLARE_CONCRETE_INSTRUCTION(CheckArrayBufferNotNeutered)
2975
2976 protected:
2977 bool DataEquals(HValue* other) override { return true; }
RedefinedOperandIndex()2978 int RedefinedOperandIndex() override { return 0; }
2979
2980 private:
HCheckArrayBufferNotNeutered(HValue * value)2981 explicit HCheckArrayBufferNotNeutered(HValue* value)
2982 : HUnaryOperation(value) {
2983 set_representation(Representation::Tagged());
2984 SetFlag(kUseGVN);
2985 SetDependsOnFlag(kCalls);
2986 }
2987 };
2988
2989
2990 class HCheckHeapObject final : public HUnaryOperation {
2991 public:
2992 DECLARE_INSTRUCTION_FACTORY_P1(HCheckHeapObject, HValue*);
2993
HasEscapingOperandAt(int index)2994 bool HasEscapingOperandAt(int index) override { return false; }
RequiredInputRepresentation(int index)2995 Representation RequiredInputRepresentation(int index) override {
2996 return Representation::Tagged();
2997 }
2998
CalculateInferredType()2999 HType CalculateInferredType() override {
3000 if (value()->type().IsHeapObject()) return value()->type();
3001 return HType::HeapObject();
3002 }
3003
3004 #ifdef DEBUG
3005 void Verify() override;
3006 #endif
3007
Canonicalize()3008 HValue* Canonicalize() override {
3009 return value()->type().IsHeapObject() ? NULL : this;
3010 }
3011
DECLARE_CONCRETE_INSTRUCTION(CheckHeapObject)3012 DECLARE_CONCRETE_INSTRUCTION(CheckHeapObject)
3013
3014 protected:
3015 bool DataEquals(HValue* other) override { return true; }
3016
3017 private:
HCheckHeapObject(HValue * value)3018 explicit HCheckHeapObject(HValue* value) : HUnaryOperation(value) {
3019 set_representation(Representation::Tagged());
3020 SetFlag(kUseGVN);
3021 }
3022 };
3023
3024
3025 class InductionVariableData;
3026
3027
3028 struct InductionVariableLimitUpdate {
3029 InductionVariableData* updated_variable;
3030 HValue* limit;
3031 bool limit_is_upper;
3032 bool limit_is_included;
3033
InductionVariableLimitUpdateInductionVariableLimitUpdate3034 InductionVariableLimitUpdate()
3035 : updated_variable(NULL), limit(NULL),
3036 limit_is_upper(false), limit_is_included(false) {}
3037 };
3038
3039
3040 class HBoundsCheck;
3041 class HPhi;
3042 class HBitwise;
3043
3044
3045 class InductionVariableData final : public ZoneObject {
3046 public:
3047 class InductionVariableCheck : public ZoneObject {
3048 public:
check()3049 HBoundsCheck* check() { return check_; }
next()3050 InductionVariableCheck* next() { return next_; }
HasUpperLimit()3051 bool HasUpperLimit() { return upper_limit_ >= 0; }
upper_limit()3052 int32_t upper_limit() {
3053 DCHECK(HasUpperLimit());
3054 return upper_limit_;
3055 }
set_upper_limit(int32_t upper_limit)3056 void set_upper_limit(int32_t upper_limit) {
3057 upper_limit_ = upper_limit;
3058 }
3059
processed()3060 bool processed() { return processed_; }
set_processed()3061 void set_processed() { processed_ = true; }
3062
3063 InductionVariableCheck(HBoundsCheck* check,
3064 InductionVariableCheck* next,
3065 int32_t upper_limit = kNoLimit)
check_(check)3066 : check_(check), next_(next), upper_limit_(upper_limit),
3067 processed_(false) {}
3068
3069 private:
3070 HBoundsCheck* check_;
3071 InductionVariableCheck* next_;
3072 int32_t upper_limit_;
3073 bool processed_;
3074 };
3075
3076 class ChecksRelatedToLength : public ZoneObject {
3077 public:
length()3078 HValue* length() { return length_; }
next()3079 ChecksRelatedToLength* next() { return next_; }
checks()3080 InductionVariableCheck* checks() { return checks_; }
3081
3082 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit);
3083 void CloseCurrentBlock();
3084
ChecksRelatedToLength(HValue * length,ChecksRelatedToLength * next)3085 ChecksRelatedToLength(HValue* length, ChecksRelatedToLength* next)
3086 : length_(length), next_(next), checks_(NULL),
3087 first_check_in_block_(NULL),
3088 added_index_(NULL),
3089 added_constant_(NULL),
3090 current_and_mask_in_block_(0),
3091 current_or_mask_in_block_(0) {}
3092
3093 private:
3094 void UseNewIndexInCurrentBlock(Token::Value token,
3095 int32_t mask,
3096 HValue* index_base,
3097 HValue* context);
3098
first_check_in_block()3099 HBoundsCheck* first_check_in_block() { return first_check_in_block_; }
added_index()3100 HBitwise* added_index() { return added_index_; }
set_added_index(HBitwise * index)3101 void set_added_index(HBitwise* index) { added_index_ = index; }
added_constant()3102 HConstant* added_constant() { return added_constant_; }
set_added_constant(HConstant * constant)3103 void set_added_constant(HConstant* constant) { added_constant_ = constant; }
current_and_mask_in_block()3104 int32_t current_and_mask_in_block() { return current_and_mask_in_block_; }
current_or_mask_in_block()3105 int32_t current_or_mask_in_block() { return current_or_mask_in_block_; }
current_upper_limit()3106 int32_t current_upper_limit() { return current_upper_limit_; }
3107
3108 HValue* length_;
3109 ChecksRelatedToLength* next_;
3110 InductionVariableCheck* checks_;
3111
3112 HBoundsCheck* first_check_in_block_;
3113 HBitwise* added_index_;
3114 HConstant* added_constant_;
3115 int32_t current_and_mask_in_block_;
3116 int32_t current_or_mask_in_block_;
3117 int32_t current_upper_limit_;
3118 };
3119
3120 struct LimitFromPredecessorBlock {
3121 InductionVariableData* variable;
3122 Token::Value token;
3123 HValue* limit;
3124 HBasicBlock* other_target;
3125
LimitIsValidLimitFromPredecessorBlock3126 bool LimitIsValid() { return token != Token::ILLEGAL; }
3127
LimitIsIncludedLimitFromPredecessorBlock3128 bool LimitIsIncluded() {
3129 return Token::IsEqualityOp(token) ||
3130 token == Token::GTE || token == Token::LTE;
3131 }
LimitIsUpperLimitFromPredecessorBlock3132 bool LimitIsUpper() {
3133 return token == Token::LTE || token == Token::LT || token == Token::NE;
3134 }
3135
LimitFromPredecessorBlockLimitFromPredecessorBlock3136 LimitFromPredecessorBlock()
3137 : variable(NULL),
3138 token(Token::ILLEGAL),
3139 limit(NULL),
3140 other_target(NULL) {}
3141 };
3142
3143 static const int32_t kNoLimit = -1;
3144
3145 static InductionVariableData* ExaminePhi(HPhi* phi);
3146 static void ComputeLimitFromPredecessorBlock(
3147 HBasicBlock* block,
3148 LimitFromPredecessorBlock* result);
3149 static bool ComputeInductionVariableLimit(
3150 HBasicBlock* block,
3151 InductionVariableLimitUpdate* additional_limit);
3152
3153 struct BitwiseDecompositionResult {
3154 HValue* base;
3155 int32_t and_mask;
3156 int32_t or_mask;
3157 HValue* context;
3158
BitwiseDecompositionResultBitwiseDecompositionResult3159 BitwiseDecompositionResult()
3160 : base(NULL), and_mask(0), or_mask(0), context(NULL) {}
3161 };
3162 static void DecomposeBitwise(HValue* value,
3163 BitwiseDecompositionResult* result);
3164
3165 void AddCheck(HBoundsCheck* check, int32_t upper_limit = kNoLimit);
3166
3167 bool CheckIfBranchIsLoopGuard(Token::Value token,
3168 HBasicBlock* current_branch,
3169 HBasicBlock* other_branch);
3170
3171 void UpdateAdditionalLimit(InductionVariableLimitUpdate* update);
3172
phi()3173 HPhi* phi() { return phi_; }
base()3174 HValue* base() { return base_; }
increment()3175 int32_t increment() { return increment_; }
limit()3176 HValue* limit() { return limit_; }
limit_included()3177 bool limit_included() { return limit_included_; }
limit_validity()3178 HBasicBlock* limit_validity() { return limit_validity_; }
induction_exit_block()3179 HBasicBlock* induction_exit_block() { return induction_exit_block_; }
induction_exit_target()3180 HBasicBlock* induction_exit_target() { return induction_exit_target_; }
checks()3181 ChecksRelatedToLength* checks() { return checks_; }
additional_upper_limit()3182 HValue* additional_upper_limit() { return additional_upper_limit_; }
additional_upper_limit_is_included()3183 bool additional_upper_limit_is_included() {
3184 return additional_upper_limit_is_included_;
3185 }
additional_lower_limit()3186 HValue* additional_lower_limit() { return additional_lower_limit_; }
additional_lower_limit_is_included()3187 bool additional_lower_limit_is_included() {
3188 return additional_lower_limit_is_included_;
3189 }
3190
LowerLimitIsNonNegativeConstant()3191 bool LowerLimitIsNonNegativeConstant() {
3192 if (base()->IsInteger32Constant() && base()->GetInteger32Constant() >= 0) {
3193 return true;
3194 }
3195 if (additional_lower_limit() != NULL &&
3196 additional_lower_limit()->IsInteger32Constant() &&
3197 additional_lower_limit()->GetInteger32Constant() >= 0) {
3198 // Ignoring the corner case of !additional_lower_limit_is_included()
3199 // is safe, handling it adds unneeded complexity.
3200 return true;
3201 }
3202 return false;
3203 }
3204
3205 int32_t ComputeUpperLimit(int32_t and_mask, int32_t or_mask);
3206
3207 private:
swap(T * a,T * b)3208 template <class T> void swap(T* a, T* b) {
3209 T c(*a);
3210 *a = *b;
3211 *b = c;
3212 }
3213
InductionVariableData(HPhi * phi,HValue * base,int32_t increment)3214 InductionVariableData(HPhi* phi, HValue* base, int32_t increment)
3215 : phi_(phi), base_(IgnoreOsrValue(base)), increment_(increment),
3216 limit_(NULL), limit_included_(false), limit_validity_(NULL),
3217 induction_exit_block_(NULL), induction_exit_target_(NULL),
3218 checks_(NULL),
3219 additional_upper_limit_(NULL),
3220 additional_upper_limit_is_included_(false),
3221 additional_lower_limit_(NULL),
3222 additional_lower_limit_is_included_(false) {}
3223
3224 static int32_t ComputeIncrement(HPhi* phi, HValue* phi_operand);
3225
3226 static HValue* IgnoreOsrValue(HValue* v);
3227 static InductionVariableData* GetInductionVariableData(HValue* v);
3228
3229 HPhi* phi_;
3230 HValue* base_;
3231 int32_t increment_;
3232 HValue* limit_;
3233 bool limit_included_;
3234 HBasicBlock* limit_validity_;
3235 HBasicBlock* induction_exit_block_;
3236 HBasicBlock* induction_exit_target_;
3237 ChecksRelatedToLength* checks_;
3238 HValue* additional_upper_limit_;
3239 bool additional_upper_limit_is_included_;
3240 HValue* additional_lower_limit_;
3241 bool additional_lower_limit_is_included_;
3242 };
3243
3244
3245 class HPhi final : public HValue {
3246 public:
HPhi(int merged_index,Zone * zone)3247 HPhi(int merged_index, Zone* zone)
3248 : inputs_(2, zone), merged_index_(merged_index) {
3249 DCHECK(merged_index >= 0 || merged_index == kInvalidMergedIndex);
3250 SetFlag(kFlexibleRepresentation);
3251 SetFlag(kAllowUndefinedAsNaN);
3252 }
3253
3254 Representation RepresentationFromInputs() override;
3255
3256 Range* InferRange(Zone* zone) override;
3257 void InferRepresentation(HInferRepresentationPhase* h_infer) override;
RequiredInputRepresentation(int index)3258 Representation RequiredInputRepresentation(int index) override {
3259 return representation();
3260 }
KnownOptimalRepresentation()3261 Representation KnownOptimalRepresentation() override {
3262 return representation();
3263 }
3264 HType CalculateInferredType() override;
OperandCount()3265 int OperandCount() const override { return inputs_.length(); }
OperandAt(int index)3266 HValue* OperandAt(int index) const override { return inputs_[index]; }
3267 HValue* GetRedundantReplacement();
3268 void AddInput(HValue* value);
3269 bool HasRealUses();
3270
IsReceiver()3271 bool IsReceiver() const { return merged_index_ == 0; }
HasMergedIndex()3272 bool HasMergedIndex() const { return merged_index_ != kInvalidMergedIndex; }
3273
3274 SourcePosition position() const override;
3275
merged_index()3276 int merged_index() const { return merged_index_; }
3277
induction_variable_data()3278 InductionVariableData* induction_variable_data() {
3279 return induction_variable_data_;
3280 }
IsInductionVariable()3281 bool IsInductionVariable() {
3282 return induction_variable_data_ != NULL;
3283 }
IsLimitedInductionVariable()3284 bool IsLimitedInductionVariable() {
3285 return IsInductionVariable() &&
3286 induction_variable_data_->limit() != NULL;
3287 }
DetectInductionVariable()3288 void DetectInductionVariable() {
3289 DCHECK(induction_variable_data_ == NULL);
3290 induction_variable_data_ = InductionVariableData::ExaminePhi(this);
3291 }
3292
3293 std::ostream& PrintTo(std::ostream& os) const override; // NOLINT
3294
3295 #ifdef DEBUG
3296 void Verify() override;
3297 #endif
3298
3299 void InitRealUses(int id);
3300 void AddNonPhiUsesFrom(HPhi* other);
3301
representation_from_indirect_uses()3302 Representation representation_from_indirect_uses() const {
3303 return representation_from_indirect_uses_;
3304 }
3305
has_type_feedback_from_uses()3306 bool has_type_feedback_from_uses() const {
3307 return has_type_feedback_from_uses_;
3308 }
3309
phi_id()3310 int phi_id() { return phi_id_; }
3311
cast(HValue * value)3312 static HPhi* cast(HValue* value) {
3313 DCHECK(value->IsPhi());
3314 return reinterpret_cast<HPhi*>(value);
3315 }
opcode()3316 Opcode opcode() const override { return HValue::kPhi; }
3317
3318 void SimplifyConstantInputs();
3319
3320 // Marker value representing an invalid merge index.
3321 static const int kInvalidMergedIndex = -1;
3322
3323 protected:
3324 void DeleteFromGraph() override;
InternalSetOperandAt(int index,HValue * value)3325 void InternalSetOperandAt(int index, HValue* value) override {
3326 inputs_[index] = value;
3327 }
3328
3329 private:
representation_from_non_phi_uses()3330 Representation representation_from_non_phi_uses() const {
3331 return representation_from_non_phi_uses_;
3332 }
3333
3334 ZoneList<HValue*> inputs_;
3335 int merged_index_ = 0;
3336
3337 int phi_id_ = -1;
3338 InductionVariableData* induction_variable_data_ = nullptr;
3339
3340 Representation representation_from_indirect_uses_ = Representation::None();
3341 Representation representation_from_non_phi_uses_ = Representation::None();
3342 bool has_type_feedback_from_uses_ = false;
3343
3344 // TODO(titzer): we can't eliminate the receiver for generating backtraces
IsDeletable()3345 bool IsDeletable() const override { return !IsReceiver(); }
3346 };
3347
3348
3349 // Common base class for HArgumentsObject and HCapturedObject.
3350 class HDematerializedObject : public HInstruction {
3351 public:
HDematerializedObject(int count,Zone * zone)3352 HDematerializedObject(int count, Zone* zone) : values_(count, zone) {}
3353
OperandCount()3354 int OperandCount() const final { return values_.length(); }
OperandAt(int index)3355 HValue* OperandAt(int index) const final { return values_[index]; }
3356
HasEscapingOperandAt(int index)3357 bool HasEscapingOperandAt(int index) final { return false; }
RequiredInputRepresentation(int index)3358 Representation RequiredInputRepresentation(int index) final {
3359 return Representation::None();
3360 }
3361
3362 protected:
InternalSetOperandAt(int index,HValue * value)3363 void InternalSetOperandAt(int index, HValue* value) final {
3364 values_[index] = value;
3365 }
3366
3367 // List of values tracked by this marker.
3368 ZoneList<HValue*> values_;
3369 };
3370
3371
3372 class HArgumentsObject final : public HDematerializedObject {
3373 public:
New(Isolate * isolate,Zone * zone,HValue * context,int count)3374 static HArgumentsObject* New(Isolate* isolate, Zone* zone, HValue* context,
3375 int count) {
3376 return new(zone) HArgumentsObject(count, zone);
3377 }
3378
3379 // The values contain a list of all elements in the arguments object
3380 // including the receiver object, which is skipped when materializing.
arguments_values()3381 const ZoneList<HValue*>* arguments_values() const { return &values_; }
arguments_count()3382 int arguments_count() const { return values_.length(); }
3383
AddArgument(HValue * argument,Zone * zone)3384 void AddArgument(HValue* argument, Zone* zone) {
3385 values_.Add(NULL, zone); // Resize list.
3386 SetOperandAt(values_.length() - 1, argument);
3387 }
3388
DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject)3389 DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject)
3390
3391 private:
3392 HArgumentsObject(int count, Zone* zone)
3393 : HDematerializedObject(count, zone) {
3394 set_representation(Representation::Tagged());
3395 SetFlag(kIsArguments);
3396 }
3397 };
3398
3399
3400 class HCapturedObject final : public HDematerializedObject {
3401 public:
HCapturedObject(int length,int id,Zone * zone)3402 HCapturedObject(int length, int id, Zone* zone)
3403 : HDematerializedObject(length, zone), capture_id_(id) {
3404 set_representation(Representation::Tagged());
3405 values_.AddBlock(NULL, length, zone); // Resize list.
3406 }
3407
3408 // The values contain a list of all in-object properties inside the
3409 // captured object and is index by field index. Properties in the
3410 // properties or elements backing store are not tracked here.
values()3411 const ZoneList<HValue*>* values() const { return &values_; }
length()3412 int length() const { return values_.length(); }
capture_id()3413 int capture_id() const { return capture_id_; }
3414
3415 // Shortcut for the map value of this captured object.
map_value()3416 HValue* map_value() const { return values()->first(); }
3417
ReuseSideEffectsFromStore(HInstruction * store)3418 void ReuseSideEffectsFromStore(HInstruction* store) {
3419 DCHECK(store->HasObservableSideEffects());
3420 DCHECK(store->IsStoreNamedField());
3421 changes_flags_.Add(store->ChangesFlags());
3422 }
3423
3424 // Replay effects of this instruction on the given environment.
3425 void ReplayEnvironment(HEnvironment* env);
3426
3427 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
3428
DECLARE_CONCRETE_INSTRUCTION(CapturedObject)3429 DECLARE_CONCRETE_INSTRUCTION(CapturedObject)
3430
3431 private:
3432 int capture_id_;
3433
3434 // Note that we cannot DCE captured objects as they are used to replay
3435 // the environment. This method is here as an explicit reminder.
3436 // TODO(mstarzinger): Turn HSimulates into full snapshots maybe?
3437 bool IsDeletable() const final { return false; }
3438 };
3439
3440
3441 class HConstant final : public HTemplateInstruction<0> {
3442 public:
3443 enum Special { kHoleNaN };
3444
3445 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Special);
3446 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, int32_t);
3447 DECLARE_INSTRUCTION_FACTORY_P2(HConstant, int32_t, Representation);
3448 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, double);
3449 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Handle<Object>);
3450 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, ExternalReference);
3451
CreateAndInsertAfter(Isolate * isolate,Zone * zone,HValue * context,int32_t value,Representation representation,HInstruction * instruction)3452 static HConstant* CreateAndInsertAfter(Isolate* isolate, Zone* zone,
3453 HValue* context, int32_t value,
3454 Representation representation,
3455 HInstruction* instruction) {
3456 return instruction->Append(
3457 HConstant::New(isolate, zone, context, value, representation));
3458 }
3459
GetMonomorphicJSObjectMap()3460 Handle<Map> GetMonomorphicJSObjectMap() override {
3461 Handle<Object> object = object_.handle();
3462 if (!object.is_null() && object->IsHeapObject()) {
3463 return v8::internal::handle(HeapObject::cast(*object)->map());
3464 }
3465 return Handle<Map>();
3466 }
3467
CreateAndInsertBefore(Isolate * isolate,Zone * zone,HValue * context,int32_t value,Representation representation,HInstruction * instruction)3468 static HConstant* CreateAndInsertBefore(Isolate* isolate, Zone* zone,
3469 HValue* context, int32_t value,
3470 Representation representation,
3471 HInstruction* instruction) {
3472 return instruction->Prepend(
3473 HConstant::New(isolate, zone, context, value, representation));
3474 }
3475
CreateAndInsertBefore(Zone * zone,Unique<Map> map,bool map_is_stable,HInstruction * instruction)3476 static HConstant* CreateAndInsertBefore(Zone* zone,
3477 Unique<Map> map,
3478 bool map_is_stable,
3479 HInstruction* instruction) {
3480 return instruction->Prepend(new(zone) HConstant(
3481 map, Unique<Map>(Handle<Map>::null()), map_is_stable,
3482 Representation::Tagged(), HType::HeapObject(), true,
3483 false, false, MAP_TYPE));
3484 }
3485
CreateAndInsertAfter(Zone * zone,Unique<Map> map,bool map_is_stable,HInstruction * instruction)3486 static HConstant* CreateAndInsertAfter(Zone* zone,
3487 Unique<Map> map,
3488 bool map_is_stable,
3489 HInstruction* instruction) {
3490 return instruction->Append(new(zone) HConstant(
3491 map, Unique<Map>(Handle<Map>::null()), map_is_stable,
3492 Representation::Tagged(), HType::HeapObject(), true,
3493 false, false, MAP_TYPE));
3494 }
3495
handle(Isolate * isolate)3496 Handle<Object> handle(Isolate* isolate) {
3497 if (object_.handle().is_null()) {
3498 // Default arguments to is_not_in_new_space depend on this heap number
3499 // to be tenured so that it's guaranteed not to be located in new space.
3500 object_ = Unique<Object>::CreateUninitialized(
3501 isolate->factory()->NewNumber(double_value_, TENURED));
3502 }
3503 AllowDeferredHandleDereference smi_check;
3504 DCHECK(HasInteger32Value() || !object_.handle()->IsSmi());
3505 return object_.handle();
3506 }
3507
IsSpecialDouble()3508 bool IsSpecialDouble() const {
3509 return HasDoubleValue() &&
3510 (bit_cast<int64_t>(double_value_) == bit_cast<int64_t>(-0.0) ||
3511 std::isnan(double_value_));
3512 }
3513
NotInNewSpace()3514 bool NotInNewSpace() const {
3515 return IsNotInNewSpaceField::decode(bit_field_);
3516 }
3517
3518 bool ImmortalImmovable() const;
3519
IsCell()3520 bool IsCell() const {
3521 InstanceType instance_type = GetInstanceType();
3522 return instance_type == CELL_TYPE;
3523 }
3524
RequiredInputRepresentation(int index)3525 Representation RequiredInputRepresentation(int index) override {
3526 return Representation::None();
3527 }
3528
KnownOptimalRepresentation()3529 Representation KnownOptimalRepresentation() override {
3530 if (HasSmiValue() && SmiValuesAre31Bits()) return Representation::Smi();
3531 if (HasInteger32Value()) return Representation::Integer32();
3532 if (HasNumberValue()) return Representation::Double();
3533 if (HasExternalReferenceValue()) return Representation::External();
3534 return Representation::Tagged();
3535 }
3536
3537 bool EmitAtUses() override;
3538 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
3539 HConstant* CopyToRepresentation(Representation r, Zone* zone) const;
3540 Maybe<HConstant*> CopyToTruncatedInt32(Zone* zone);
3541 Maybe<HConstant*> CopyToTruncatedNumber(Isolate* isolate, Zone* zone);
HasInteger32Value()3542 bool HasInteger32Value() const {
3543 return HasInt32ValueField::decode(bit_field_);
3544 }
Integer32Value()3545 int32_t Integer32Value() const {
3546 DCHECK(HasInteger32Value());
3547 return int32_value_;
3548 }
HasSmiValue()3549 bool HasSmiValue() const { return HasSmiValueField::decode(bit_field_); }
HasDoubleValue()3550 bool HasDoubleValue() const {
3551 return HasDoubleValueField::decode(bit_field_);
3552 }
DoubleValue()3553 double DoubleValue() const {
3554 DCHECK(HasDoubleValue());
3555 return double_value_;
3556 }
DoubleValueAsBits()3557 uint64_t DoubleValueAsBits() const {
3558 uint64_t bits;
3559 DCHECK(HasDoubleValue());
3560 STATIC_ASSERT(sizeof(bits) == sizeof(double_value_));
3561 std::memcpy(&bits, &double_value_, sizeof(bits));
3562 return bits;
3563 }
IsTheHole()3564 bool IsTheHole() const {
3565 if (HasDoubleValue() && DoubleValueAsBits() == kHoleNanInt64) {
3566 return true;
3567 }
3568 return object_.IsInitialized() &&
3569 object_.IsKnownGlobal(isolate()->heap()->the_hole_value());
3570 }
HasNumberValue()3571 bool HasNumberValue() const { return HasDoubleValue(); }
NumberValueAsInteger32()3572 int32_t NumberValueAsInteger32() const {
3573 DCHECK(HasNumberValue());
3574 // Irrespective of whether a numeric HConstant can be safely
3575 // represented as an int32, we store the (in some cases lossy)
3576 // representation of the number in int32_value_.
3577 return int32_value_;
3578 }
HasStringValue()3579 bool HasStringValue() const {
3580 if (HasNumberValue()) return false;
3581 DCHECK(!object_.handle().is_null());
3582 return GetInstanceType() < FIRST_NONSTRING_TYPE;
3583 }
StringValue()3584 Handle<String> StringValue() const {
3585 DCHECK(HasStringValue());
3586 return Handle<String>::cast(object_.handle());
3587 }
HasInternalizedStringValue()3588 bool HasInternalizedStringValue() const {
3589 return HasStringValue() && StringShape(GetInstanceType()).IsInternalized();
3590 }
3591
HasExternalReferenceValue()3592 bool HasExternalReferenceValue() const {
3593 return HasExternalReferenceValueField::decode(bit_field_);
3594 }
ExternalReferenceValue()3595 ExternalReference ExternalReferenceValue() const {
3596 return external_reference_value_;
3597 }
3598
HasBooleanValue()3599 bool HasBooleanValue() const { return type_.IsBoolean(); }
BooleanValue()3600 bool BooleanValue() const { return BooleanValueField::decode(bit_field_); }
IsCallable()3601 bool IsCallable() const { return IsCallableField::decode(bit_field_); }
IsUndetectable()3602 bool IsUndetectable() const {
3603 return IsUndetectableField::decode(bit_field_);
3604 }
GetInstanceType()3605 InstanceType GetInstanceType() const {
3606 return InstanceTypeField::decode(bit_field_);
3607 }
3608
HasMapValue()3609 bool HasMapValue() const { return GetInstanceType() == MAP_TYPE; }
MapValue()3610 Unique<Map> MapValue() const {
3611 DCHECK(HasMapValue());
3612 return Unique<Map>::cast(GetUnique());
3613 }
HasStableMapValue()3614 bool HasStableMapValue() const {
3615 DCHECK(HasMapValue() || !HasStableMapValueField::decode(bit_field_));
3616 return HasStableMapValueField::decode(bit_field_);
3617 }
3618
HasObjectMap()3619 bool HasObjectMap() const { return !object_map_.IsNull(); }
ObjectMap()3620 Unique<Map> ObjectMap() const {
3621 DCHECK(HasObjectMap());
3622 return object_map_;
3623 }
3624
Hashcode()3625 intptr_t Hashcode() override {
3626 if (HasInteger32Value()) {
3627 return static_cast<intptr_t>(int32_value_);
3628 } else if (HasDoubleValue()) {
3629 uint64_t bits = DoubleValueAsBits();
3630 if (sizeof(bits) > sizeof(intptr_t)) {
3631 bits ^= (bits >> 32);
3632 }
3633 return static_cast<intptr_t>(bits);
3634 } else if (HasExternalReferenceValue()) {
3635 return reinterpret_cast<intptr_t>(external_reference_value_.address());
3636 } else {
3637 DCHECK(!object_.handle().is_null());
3638 return object_.Hashcode();
3639 }
3640 }
3641
FinalizeUniqueness()3642 void FinalizeUniqueness() override {
3643 if (!HasDoubleValue() && !HasExternalReferenceValue()) {
3644 DCHECK(!object_.handle().is_null());
3645 object_ = Unique<Object>(object_.handle());
3646 }
3647 }
3648
GetUnique()3649 Unique<Object> GetUnique() const {
3650 return object_;
3651 }
3652
EqualsUnique(Unique<Object> other)3653 bool EqualsUnique(Unique<Object> other) const {
3654 return object_.IsInitialized() && object_ == other;
3655 }
3656
DataEquals(HValue * other)3657 bool DataEquals(HValue* other) override {
3658 HConstant* other_constant = HConstant::cast(other);
3659 if (HasInteger32Value()) {
3660 return other_constant->HasInteger32Value() &&
3661 int32_value_ == other_constant->int32_value_;
3662 } else if (HasDoubleValue()) {
3663 return other_constant->HasDoubleValue() &&
3664 std::memcmp(&double_value_, &other_constant->double_value_,
3665 sizeof(double_value_)) == 0;
3666 } else if (HasExternalReferenceValue()) {
3667 return other_constant->HasExternalReferenceValue() &&
3668 external_reference_value_ ==
3669 other_constant->external_reference_value_;
3670 } else {
3671 if (other_constant->HasInteger32Value() ||
3672 other_constant->HasDoubleValue() ||
3673 other_constant->HasExternalReferenceValue()) {
3674 return false;
3675 }
3676 DCHECK(!object_.handle().is_null());
3677 return other_constant->object_ == object_;
3678 }
3679 }
3680
3681 #ifdef DEBUG
Verify()3682 void Verify() override {}
3683 #endif
3684
3685 DECLARE_CONCRETE_INSTRUCTION(Constant)
3686
3687 protected:
3688 Range* InferRange(Zone* zone) override;
3689
3690 private:
3691 friend class HGraph;
3692 explicit HConstant(Special special);
3693 explicit HConstant(Handle<Object> handle,
3694 Representation r = Representation::None());
3695 HConstant(int32_t value,
3696 Representation r = Representation::None(),
3697 bool is_not_in_new_space = true,
3698 Unique<Object> optional = Unique<Object>(Handle<Object>::null()));
3699 HConstant(double value,
3700 Representation r = Representation::None(),
3701 bool is_not_in_new_space = true,
3702 Unique<Object> optional = Unique<Object>(Handle<Object>::null()));
3703 HConstant(Unique<Object> object,
3704 Unique<Map> object_map,
3705 bool has_stable_map_value,
3706 Representation r,
3707 HType type,
3708 bool is_not_in_new_space,
3709 bool boolean_value,
3710 bool is_undetectable,
3711 InstanceType instance_type);
3712
3713 explicit HConstant(ExternalReference reference);
3714
3715 void Initialize(Representation r);
3716
IsDeletable()3717 bool IsDeletable() const override { return true; }
3718
3719 // If object_ is a map, this indicates whether the map is stable.
3720 class HasStableMapValueField : public BitField<bool, 0, 1> {};
3721
3722 // We store the HConstant in the most specific form safely possible.
3723 // These flags tell us if the respective member fields hold valid, safe
3724 // representations of the constant. More specific flags imply more general
3725 // flags, but not the converse (i.e. smi => int32 => double).
3726 class HasSmiValueField : public BitField<bool, 1, 1> {};
3727 class HasInt32ValueField : public BitField<bool, 2, 1> {};
3728 class HasDoubleValueField : public BitField<bool, 3, 1> {};
3729
3730 class HasExternalReferenceValueField : public BitField<bool, 4, 1> {};
3731 class IsNotInNewSpaceField : public BitField<bool, 5, 1> {};
3732 class BooleanValueField : public BitField<bool, 6, 1> {};
3733 class IsUndetectableField : public BitField<bool, 7, 1> {};
3734 class IsCallableField : public BitField<bool, 8, 1> {};
3735
3736 static const InstanceType kUnknownInstanceType = FILLER_TYPE;
3737 class InstanceTypeField : public BitField<InstanceType, 16, 8> {};
3738
3739 // If this is a numerical constant, object_ either points to the
3740 // HeapObject the constant originated from or is null. If the
3741 // constant is non-numeric, object_ always points to a valid
3742 // constant HeapObject.
3743 Unique<Object> object_;
3744
3745 // If object_ is a heap object, this points to the stable map of the object.
3746 Unique<Map> object_map_;
3747
3748 uint32_t bit_field_;
3749
3750 int32_t int32_value_;
3751 double double_value_;
3752 ExternalReference external_reference_value_;
3753 };
3754
3755
3756 class HBinaryOperation : public HTemplateInstruction<3> {
3757 public:
3758 HBinaryOperation(HValue* context, HValue* left, HValue* right,
3759 Strength strength, HType type = HType::Tagged())
3760 : HTemplateInstruction<3>(type),
3761 strength_(strength),
3762 observed_output_representation_(Representation::None()) {
3763 DCHECK(left != NULL && right != NULL);
3764 SetOperandAt(0, context);
3765 SetOperandAt(1, left);
3766 SetOperandAt(2, right);
3767 observed_input_representation_[0] = Representation::None();
3768 observed_input_representation_[1] = Representation::None();
3769 }
3770
context()3771 HValue* context() const { return OperandAt(0); }
left()3772 HValue* left() const { return OperandAt(1); }
right()3773 HValue* right() const { return OperandAt(2); }
strength()3774 Strength strength() const { return strength_; }
3775
3776 // True if switching left and right operands likely generates better code.
AreOperandsBetterSwitched()3777 bool AreOperandsBetterSwitched() {
3778 if (!IsCommutative()) return false;
3779
3780 // Constant operands are better off on the right, they can be inlined in
3781 // many situations on most platforms.
3782 if (left()->IsConstant()) return true;
3783 if (right()->IsConstant()) return false;
3784
3785 // Otherwise, if there is only one use of the right operand, it would be
3786 // better off on the left for platforms that only have 2-arg arithmetic
3787 // ops (e.g ia32, x64) that clobber the left operand.
3788 return right()->HasOneUse();
3789 }
3790
BetterLeftOperand()3791 HValue* BetterLeftOperand() {
3792 return AreOperandsBetterSwitched() ? right() : left();
3793 }
3794
BetterRightOperand()3795 HValue* BetterRightOperand() {
3796 return AreOperandsBetterSwitched() ? left() : right();
3797 }
3798
set_observed_input_representation(int index,Representation rep)3799 void set_observed_input_representation(int index, Representation rep) {
3800 DCHECK(index >= 1 && index <= 2);
3801 observed_input_representation_[index - 1] = rep;
3802 }
3803
initialize_output_representation(Representation observed)3804 virtual void initialize_output_representation(Representation observed) {
3805 observed_output_representation_ = observed;
3806 }
3807
observed_input_representation(int index)3808 Representation observed_input_representation(int index) override {
3809 if (index == 0) return Representation::Tagged();
3810 return observed_input_representation_[index - 1];
3811 }
3812
UpdateRepresentation(Representation new_rep,HInferRepresentationPhase * h_infer,const char * reason)3813 void UpdateRepresentation(Representation new_rep,
3814 HInferRepresentationPhase* h_infer,
3815 const char* reason) override {
3816 Representation rep = !FLAG_smi_binop && new_rep.IsSmi()
3817 ? Representation::Integer32() : new_rep;
3818 HValue::UpdateRepresentation(rep, h_infer, reason);
3819 }
3820
3821 void InferRepresentation(HInferRepresentationPhase* h_infer) override;
3822 Representation RepresentationFromInputs() override;
3823 Representation RepresentationFromOutput();
3824 void AssumeRepresentation(Representation r) override;
3825
IsCommutative()3826 virtual bool IsCommutative() const { return false; }
3827
3828 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
3829
RequiredInputRepresentation(int index)3830 Representation RequiredInputRepresentation(int index) override {
3831 if (index == 0) return Representation::Tagged();
3832 return representation();
3833 }
3834
SetOperandPositions(Zone * zone,SourcePosition left_pos,SourcePosition right_pos)3835 void SetOperandPositions(Zone* zone, SourcePosition left_pos,
3836 SourcePosition right_pos) {
3837 set_operand_position(zone, 1, left_pos);
3838 set_operand_position(zone, 2, right_pos);
3839 }
3840
RightIsPowerOf2()3841 bool RightIsPowerOf2() {
3842 if (!right()->IsInteger32Constant()) return false;
3843 int32_t value = right()->GetInteger32Constant();
3844 if (value < 0) {
3845 return base::bits::IsPowerOfTwo32(static_cast<uint32_t>(-value));
3846 }
3847 return base::bits::IsPowerOfTwo32(static_cast<uint32_t>(value));
3848 }
3849
strength()3850 Strength strength() { return strength_; }
3851
3852 DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation)
3853
3854 private:
3855 bool IgnoreObservedOutputRepresentation(Representation current_rep);
3856 Strength strength_;
3857
3858 Representation observed_input_representation_[2];
3859 Representation observed_output_representation_;
3860 };
3861
3862
3863 class HWrapReceiver final : public HTemplateInstruction<2> {
3864 public:
3865 DECLARE_INSTRUCTION_FACTORY_P2(HWrapReceiver, HValue*, HValue*);
3866
DataEquals(HValue * other)3867 bool DataEquals(HValue* other) override { return true; }
3868
RequiredInputRepresentation(int index)3869 Representation RequiredInputRepresentation(int index) override {
3870 return Representation::Tagged();
3871 }
3872
receiver()3873 HValue* receiver() const { return OperandAt(0); }
function()3874 HValue* function() const { return OperandAt(1); }
3875
3876 HValue* Canonicalize() override;
3877
3878 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
known_function()3879 bool known_function() const { return known_function_; }
3880
DECLARE_CONCRETE_INSTRUCTION(WrapReceiver)3881 DECLARE_CONCRETE_INSTRUCTION(WrapReceiver)
3882
3883 private:
3884 HWrapReceiver(HValue* receiver, HValue* function) {
3885 known_function_ = function->IsConstant() &&
3886 HConstant::cast(function)->handle(function->isolate())->IsJSFunction();
3887 set_representation(Representation::Tagged());
3888 SetOperandAt(0, receiver);
3889 SetOperandAt(1, function);
3890 SetFlag(kUseGVN);
3891 }
3892
3893 bool known_function_;
3894 };
3895
3896
3897 class HApplyArguments final : public HTemplateInstruction<4> {
3898 public:
3899 DECLARE_INSTRUCTION_FACTORY_P4(HApplyArguments, HValue*, HValue*, HValue*,
3900 HValue*);
3901
RequiredInputRepresentation(int index)3902 Representation RequiredInputRepresentation(int index) override {
3903 // The length is untagged, all other inputs are tagged.
3904 return (index == 2)
3905 ? Representation::Integer32()
3906 : Representation::Tagged();
3907 }
3908
function()3909 HValue* function() { return OperandAt(0); }
receiver()3910 HValue* receiver() { return OperandAt(1); }
length()3911 HValue* length() { return OperandAt(2); }
elements()3912 HValue* elements() { return OperandAt(3); }
3913
DECLARE_CONCRETE_INSTRUCTION(ApplyArguments)3914 DECLARE_CONCRETE_INSTRUCTION(ApplyArguments)
3915
3916 private:
3917 HApplyArguments(HValue* function,
3918 HValue* receiver,
3919 HValue* length,
3920 HValue* elements) {
3921 set_representation(Representation::Tagged());
3922 SetOperandAt(0, function);
3923 SetOperandAt(1, receiver);
3924 SetOperandAt(2, length);
3925 SetOperandAt(3, elements);
3926 SetAllSideEffects();
3927 }
3928 };
3929
3930
3931 class HArgumentsElements final : public HTemplateInstruction<0> {
3932 public:
3933 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsElements, bool);
3934
DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements)3935 DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements)
3936
3937 Representation RequiredInputRepresentation(int index) override {
3938 return Representation::None();
3939 }
3940
from_inlined()3941 bool from_inlined() const { return from_inlined_; }
3942
3943 protected:
DataEquals(HValue * other)3944 bool DataEquals(HValue* other) override { return true; }
3945
3946 private:
HArgumentsElements(bool from_inlined)3947 explicit HArgumentsElements(bool from_inlined) : from_inlined_(from_inlined) {
3948 // The value produced by this instruction is a pointer into the stack
3949 // that looks as if it was a smi because of alignment.
3950 set_representation(Representation::Tagged());
3951 SetFlag(kUseGVN);
3952 }
3953
IsDeletable()3954 bool IsDeletable() const override { return true; }
3955
3956 bool from_inlined_;
3957 };
3958
3959
3960 class HArgumentsLength final : public HUnaryOperation {
3961 public:
3962 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsLength, HValue*);
3963
RequiredInputRepresentation(int index)3964 Representation RequiredInputRepresentation(int index) override {
3965 return Representation::Tagged();
3966 }
3967
DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength)3968 DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength)
3969
3970 protected:
3971 bool DataEquals(HValue* other) override { return true; }
3972
3973 private:
HArgumentsLength(HValue * value)3974 explicit HArgumentsLength(HValue* value) : HUnaryOperation(value) {
3975 set_representation(Representation::Integer32());
3976 SetFlag(kUseGVN);
3977 }
3978
IsDeletable()3979 bool IsDeletable() const override { return true; }
3980 };
3981
3982
3983 class HAccessArgumentsAt final : public HTemplateInstruction<3> {
3984 public:
3985 DECLARE_INSTRUCTION_FACTORY_P3(HAccessArgumentsAt, HValue*, HValue*, HValue*);
3986
3987 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
3988
RequiredInputRepresentation(int index)3989 Representation RequiredInputRepresentation(int index) override {
3990 // The arguments elements is considered tagged.
3991 return index == 0
3992 ? Representation::Tagged()
3993 : Representation::Integer32();
3994 }
3995
arguments()3996 HValue* arguments() const { return OperandAt(0); }
length()3997 HValue* length() const { return OperandAt(1); }
index()3998 HValue* index() const { return OperandAt(2); }
3999
DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt)4000 DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt)
4001
4002 private:
4003 HAccessArgumentsAt(HValue* arguments, HValue* length, HValue* index) {
4004 set_representation(Representation::Tagged());
4005 SetFlag(kUseGVN);
4006 SetOperandAt(0, arguments);
4007 SetOperandAt(1, length);
4008 SetOperandAt(2, index);
4009 }
4010
DataEquals(HValue * other)4011 bool DataEquals(HValue* other) override { return true; }
4012 };
4013
4014
4015 class HBoundsCheckBaseIndexInformation;
4016
4017
4018 class HBoundsCheck final : public HTemplateInstruction<2> {
4019 public:
4020 DECLARE_INSTRUCTION_FACTORY_P2(HBoundsCheck, HValue*, HValue*);
4021
skip_check()4022 bool skip_check() const { return skip_check_; }
set_skip_check()4023 void set_skip_check() { skip_check_ = true; }
4024
base()4025 HValue* base() const { return base_; }
offset()4026 int offset() const { return offset_; }
scale()4027 int scale() const { return scale_; }
4028
4029 void ApplyIndexChange();
DetectCompoundIndex()4030 bool DetectCompoundIndex() {
4031 DCHECK(base() == NULL);
4032
4033 DecompositionResult decomposition;
4034 if (index()->TryDecompose(&decomposition)) {
4035 base_ = decomposition.base();
4036 offset_ = decomposition.offset();
4037 scale_ = decomposition.scale();
4038 return true;
4039 } else {
4040 base_ = index();
4041 offset_ = 0;
4042 scale_ = 0;
4043 return false;
4044 }
4045 }
4046
RequiredInputRepresentation(int index)4047 Representation RequiredInputRepresentation(int index) override {
4048 return representation();
4049 }
4050
4051 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4052 void InferRepresentation(HInferRepresentationPhase* h_infer) override;
4053
index()4054 HValue* index() const { return OperandAt(0); }
length()4055 HValue* length() const { return OperandAt(1); }
allow_equality()4056 bool allow_equality() const { return allow_equality_; }
set_allow_equality(bool v)4057 void set_allow_equality(bool v) { allow_equality_ = v; }
4058
RedefinedOperandIndex()4059 int RedefinedOperandIndex() override { return 0; }
IsPurelyInformativeDefinition()4060 bool IsPurelyInformativeDefinition() override { return skip_check(); }
4061
4062 DECLARE_CONCRETE_INSTRUCTION(BoundsCheck)
4063
4064 protected:
4065 friend class HBoundsCheckBaseIndexInformation;
4066
4067 Range* InferRange(Zone* zone) override;
4068
DataEquals(HValue * other)4069 bool DataEquals(HValue* other) override { return true; }
4070 bool skip_check_;
4071 HValue* base_;
4072 int offset_;
4073 int scale_;
4074 bool allow_equality_;
4075
4076 private:
4077 // Normally HBoundsCheck should be created using the
4078 // HGraphBuilder::AddBoundsCheck() helper.
4079 // However when building stubs, where we know that the arguments are Int32,
4080 // it makes sense to invoke this constructor directly.
HBoundsCheck(HValue * index,HValue * length)4081 HBoundsCheck(HValue* index, HValue* length)
4082 : skip_check_(false),
4083 base_(NULL), offset_(0), scale_(0),
4084 allow_equality_(false) {
4085 SetOperandAt(0, index);
4086 SetOperandAt(1, length);
4087 SetFlag(kFlexibleRepresentation);
4088 SetFlag(kUseGVN);
4089 }
4090
IsDeletable()4091 bool IsDeletable() const override { return skip_check() && !FLAG_debug_code; }
4092 };
4093
4094
4095 class HBoundsCheckBaseIndexInformation final : public HTemplateInstruction<2> {
4096 public:
HBoundsCheckBaseIndexInformation(HBoundsCheck * check)4097 explicit HBoundsCheckBaseIndexInformation(HBoundsCheck* check) {
4098 DecompositionResult decomposition;
4099 if (check->index()->TryDecompose(&decomposition)) {
4100 SetOperandAt(0, decomposition.base());
4101 SetOperandAt(1, check);
4102 } else {
4103 UNREACHABLE();
4104 }
4105 }
4106
base_index()4107 HValue* base_index() const { return OperandAt(0); }
bounds_check()4108 HBoundsCheck* bounds_check() { return HBoundsCheck::cast(OperandAt(1)); }
4109
DECLARE_CONCRETE_INSTRUCTION(BoundsCheckBaseIndexInformation)4110 DECLARE_CONCRETE_INSTRUCTION(BoundsCheckBaseIndexInformation)
4111
4112 Representation RequiredInputRepresentation(int index) override {
4113 return representation();
4114 }
4115
4116 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4117
RedefinedOperandIndex()4118 int RedefinedOperandIndex() override { return 0; }
IsPurelyInformativeDefinition()4119 bool IsPurelyInformativeDefinition() override { return true; }
4120 };
4121
4122
4123 class HBitwiseBinaryOperation : public HBinaryOperation {
4124 public:
4125 HBitwiseBinaryOperation(HValue* context, HValue* left, HValue* right,
4126 Strength strength, HType type = HType::TaggedNumber())
HBinaryOperation(context,left,right,strength,type)4127 : HBinaryOperation(context, left, right, strength, type) {
4128 SetFlag(kFlexibleRepresentation);
4129 SetFlag(kTruncatingToInt32);
4130 if (!is_strong(strength)) SetFlag(kAllowUndefinedAsNaN);
4131 SetAllSideEffects();
4132 }
4133
RepresentationChanged(Representation to)4134 void RepresentationChanged(Representation to) override {
4135 if (to.IsTagged() &&
4136 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
4137 SetAllSideEffects();
4138 ClearFlag(kUseGVN);
4139 } else {
4140 ClearAllSideEffects();
4141 SetFlag(kUseGVN);
4142 }
4143 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
4144 }
4145
UpdateRepresentation(Representation new_rep,HInferRepresentationPhase * h_infer,const char * reason)4146 void UpdateRepresentation(Representation new_rep,
4147 HInferRepresentationPhase* h_infer,
4148 const char* reason) override {
4149 // We only generate either int32 or generic tagged bitwise operations.
4150 if (new_rep.IsDouble()) new_rep = Representation::Integer32();
4151 HBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4152 }
4153
observed_input_representation(int index)4154 Representation observed_input_representation(int index) override {
4155 Representation r = HBinaryOperation::observed_input_representation(index);
4156 if (r.IsDouble()) return Representation::Integer32();
4157 return r;
4158 }
4159
initialize_output_representation(Representation observed)4160 void initialize_output_representation(Representation observed) override {
4161 if (observed.IsDouble()) observed = Representation::Integer32();
4162 HBinaryOperation::initialize_output_representation(observed);
4163 }
4164
DECLARE_ABSTRACT_INSTRUCTION(BitwiseBinaryOperation)4165 DECLARE_ABSTRACT_INSTRUCTION(BitwiseBinaryOperation)
4166
4167 private:
4168 bool IsDeletable() const override { return true; }
4169 };
4170
4171
4172 class HMathFloorOfDiv final : public HBinaryOperation {
4173 public:
4174 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HMathFloorOfDiv,
4175 HValue*,
4176 HValue*);
4177
DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv)4178 DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv)
4179
4180 protected:
4181 bool DataEquals(HValue* other) override { return true; }
4182
4183 private:
HMathFloorOfDiv(HValue * context,HValue * left,HValue * right)4184 HMathFloorOfDiv(HValue* context, HValue* left, HValue* right)
4185 : HBinaryOperation(context, left, right, Strength::WEAK) {
4186 set_representation(Representation::Integer32());
4187 SetFlag(kUseGVN);
4188 SetFlag(kCanOverflow);
4189 SetFlag(kCanBeDivByZero);
4190 SetFlag(kLeftCanBeMinInt);
4191 SetFlag(kLeftCanBeNegative);
4192 SetFlag(kLeftCanBePositive);
4193 SetFlag(kAllowUndefinedAsNaN);
4194 }
4195
4196 Range* InferRange(Zone* zone) override;
4197
IsDeletable()4198 bool IsDeletable() const override { return true; }
4199 };
4200
4201
4202 class HArithmeticBinaryOperation : public HBinaryOperation {
4203 public:
HArithmeticBinaryOperation(HValue * context,HValue * left,HValue * right,Strength strength)4204 HArithmeticBinaryOperation(HValue* context, HValue* left, HValue* right,
4205 Strength strength)
4206 : HBinaryOperation(context, left, right, strength,
4207 HType::TaggedNumber()) {
4208 SetAllSideEffects();
4209 SetFlag(kFlexibleRepresentation);
4210 if (!is_strong(strength)) SetFlag(kAllowUndefinedAsNaN);
4211 }
4212
RepresentationChanged(Representation to)4213 void RepresentationChanged(Representation to) override {
4214 if (to.IsTagged() &&
4215 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
4216 SetAllSideEffects();
4217 ClearFlag(kUseGVN);
4218 } else {
4219 ClearAllSideEffects();
4220 SetFlag(kUseGVN);
4221 }
4222 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
4223 }
4224
DECLARE_ABSTRACT_INSTRUCTION(ArithmeticBinaryOperation)4225 DECLARE_ABSTRACT_INSTRUCTION(ArithmeticBinaryOperation)
4226
4227 private:
4228 bool IsDeletable() const override { return true; }
4229 };
4230
4231
4232 class HCompareGeneric final : public HBinaryOperation {
4233 public:
4234 static HCompareGeneric* New(Isolate* isolate, Zone* zone, HValue* context,
4235 HValue* left, HValue* right, Token::Value token,
4236 Strength strength = Strength::WEAK) {
4237 return new (zone) HCompareGeneric(context, left, right, token, strength);
4238 }
4239
RequiredInputRepresentation(int index)4240 Representation RequiredInputRepresentation(int index) override {
4241 return index == 0
4242 ? Representation::Tagged()
4243 : representation();
4244 }
4245
token()4246 Token::Value token() const { return token_; }
4247 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4248
DECLARE_CONCRETE_INSTRUCTION(CompareGeneric)4249 DECLARE_CONCRETE_INSTRUCTION(CompareGeneric)
4250
4251 private:
4252 HCompareGeneric(HValue* context, HValue* left, HValue* right,
4253 Token::Value token, Strength strength)
4254 : HBinaryOperation(context, left, right, strength, HType::Boolean()),
4255 token_(token) {
4256 DCHECK(Token::IsCompareOp(token));
4257 set_representation(Representation::Tagged());
4258 SetAllSideEffects();
4259 }
4260
4261 Token::Value token_;
4262 };
4263
4264
4265 class HCompareNumericAndBranch : public HTemplateControlInstruction<2, 2> {
4266 public:
4267 static HCompareNumericAndBranch* New(Isolate* isolate, Zone* zone,
4268 HValue* context, HValue* left,
4269 HValue* right, Token::Value token,
4270 HBasicBlock* true_target = NULL,
4271 HBasicBlock* false_target = NULL,
4272 Strength strength = Strength::WEAK) {
4273 return new (zone) HCompareNumericAndBranch(left, right, token, true_target,
4274 false_target, strength);
4275 }
New(Isolate * isolate,Zone * zone,HValue * context,HValue * left,HValue * right,Token::Value token,Strength strength)4276 static HCompareNumericAndBranch* New(Isolate* isolate, Zone* zone,
4277 HValue* context, HValue* left,
4278 HValue* right, Token::Value token,
4279 Strength strength) {
4280 return new (zone)
4281 HCompareNumericAndBranch(left, right, token, NULL, NULL, strength);
4282 }
4283
left()4284 HValue* left() const { return OperandAt(0); }
right()4285 HValue* right() const { return OperandAt(1); }
token()4286 Token::Value token() const { return token_; }
4287
set_observed_input_representation(Representation left,Representation right)4288 void set_observed_input_representation(Representation left,
4289 Representation right) {
4290 observed_input_representation_[0] = left;
4291 observed_input_representation_[1] = right;
4292 }
4293
4294 void InferRepresentation(HInferRepresentationPhase* h_infer) override;
4295
RequiredInputRepresentation(int index)4296 Representation RequiredInputRepresentation(int index) override {
4297 return representation();
4298 }
observed_input_representation(int index)4299 Representation observed_input_representation(int index) override {
4300 return observed_input_representation_[index];
4301 }
4302
4303 bool KnownSuccessorBlock(HBasicBlock** block) override;
4304
strength()4305 Strength strength() const { return strength_; }
4306
4307 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4308
SetOperandPositions(Zone * zone,SourcePosition left_pos,SourcePosition right_pos)4309 void SetOperandPositions(Zone* zone, SourcePosition left_pos,
4310 SourcePosition right_pos) {
4311 set_operand_position(zone, 0, left_pos);
4312 set_operand_position(zone, 1, right_pos);
4313 }
4314
DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch)4315 DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch)
4316
4317 private:
4318 HCompareNumericAndBranch(HValue* left, HValue* right, Token::Value token,
4319 HBasicBlock* true_target, HBasicBlock* false_target,
4320 Strength strength)
4321 : token_(token), strength_(strength) {
4322 SetFlag(kFlexibleRepresentation);
4323 DCHECK(Token::IsCompareOp(token));
4324 SetOperandAt(0, left);
4325 SetOperandAt(1, right);
4326 SetSuccessorAt(0, true_target);
4327 SetSuccessorAt(1, false_target);
4328 }
4329
4330 Representation observed_input_representation_[2];
4331 Token::Value token_;
4332 Strength strength_;
4333 };
4334
4335
4336 class HCompareHoleAndBranch final : public HUnaryControlInstruction {
4337 public:
4338 DECLARE_INSTRUCTION_FACTORY_P1(HCompareHoleAndBranch, HValue*);
4339 DECLARE_INSTRUCTION_FACTORY_P3(HCompareHoleAndBranch, HValue*,
4340 HBasicBlock*, HBasicBlock*);
4341
4342 void InferRepresentation(HInferRepresentationPhase* h_infer) override;
4343
RequiredInputRepresentation(int index)4344 Representation RequiredInputRepresentation(int index) override {
4345 return representation();
4346 }
4347
DECLARE_CONCRETE_INSTRUCTION(CompareHoleAndBranch)4348 DECLARE_CONCRETE_INSTRUCTION(CompareHoleAndBranch)
4349
4350 private:
4351 HCompareHoleAndBranch(HValue* value,
4352 HBasicBlock* true_target = NULL,
4353 HBasicBlock* false_target = NULL)
4354 : HUnaryControlInstruction(value, true_target, false_target) {
4355 SetFlag(kFlexibleRepresentation);
4356 SetFlag(kAllowUndefinedAsNaN);
4357 }
4358 };
4359
4360
4361 class HCompareMinusZeroAndBranch final : public HUnaryControlInstruction {
4362 public:
4363 DECLARE_INSTRUCTION_FACTORY_P1(HCompareMinusZeroAndBranch, HValue*);
4364
4365 void InferRepresentation(HInferRepresentationPhase* h_infer) override;
4366
RequiredInputRepresentation(int index)4367 Representation RequiredInputRepresentation(int index) override {
4368 return representation();
4369 }
4370
4371 bool KnownSuccessorBlock(HBasicBlock** block) override;
4372
DECLARE_CONCRETE_INSTRUCTION(CompareMinusZeroAndBranch)4373 DECLARE_CONCRETE_INSTRUCTION(CompareMinusZeroAndBranch)
4374
4375 private:
4376 explicit HCompareMinusZeroAndBranch(HValue* value)
4377 : HUnaryControlInstruction(value, NULL, NULL) {
4378 }
4379 };
4380
4381
4382 class HCompareObjectEqAndBranch : public HTemplateControlInstruction<2, 2> {
4383 public:
4384 DECLARE_INSTRUCTION_FACTORY_P2(HCompareObjectEqAndBranch, HValue*, HValue*);
4385 DECLARE_INSTRUCTION_FACTORY_P4(HCompareObjectEqAndBranch, HValue*, HValue*,
4386 HBasicBlock*, HBasicBlock*);
4387
4388 bool KnownSuccessorBlock(HBasicBlock** block) override;
4389
4390 static const int kNoKnownSuccessorIndex = -1;
known_successor_index()4391 int known_successor_index() const { return known_successor_index_; }
set_known_successor_index(int known_successor_index)4392 void set_known_successor_index(int known_successor_index) {
4393 known_successor_index_ = known_successor_index;
4394 }
4395
left()4396 HValue* left() const { return OperandAt(0); }
right()4397 HValue* right() const { return OperandAt(1); }
4398
4399 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4400
RequiredInputRepresentation(int index)4401 Representation RequiredInputRepresentation(int index) override {
4402 return Representation::Tagged();
4403 }
4404
observed_input_representation(int index)4405 Representation observed_input_representation(int index) override {
4406 return Representation::Tagged();
4407 }
4408
DECLARE_CONCRETE_INSTRUCTION(CompareObjectEqAndBranch)4409 DECLARE_CONCRETE_INSTRUCTION(CompareObjectEqAndBranch)
4410
4411 private:
4412 HCompareObjectEqAndBranch(HValue* left,
4413 HValue* right,
4414 HBasicBlock* true_target = NULL,
4415 HBasicBlock* false_target = NULL)
4416 : known_successor_index_(kNoKnownSuccessorIndex) {
4417 SetOperandAt(0, left);
4418 SetOperandAt(1, right);
4419 SetSuccessorAt(0, true_target);
4420 SetSuccessorAt(1, false_target);
4421 }
4422
4423 int known_successor_index_;
4424 };
4425
4426
4427 class HIsStringAndBranch final : public HUnaryControlInstruction {
4428 public:
4429 DECLARE_INSTRUCTION_FACTORY_P1(HIsStringAndBranch, HValue*);
4430 DECLARE_INSTRUCTION_FACTORY_P3(HIsStringAndBranch, HValue*,
4431 HBasicBlock*, HBasicBlock*);
4432
RequiredInputRepresentation(int index)4433 Representation RequiredInputRepresentation(int index) override {
4434 return Representation::Tagged();
4435 }
4436
4437 bool KnownSuccessorBlock(HBasicBlock** block) override;
4438
4439 static const int kNoKnownSuccessorIndex = -1;
known_successor_index()4440 int known_successor_index() const { return known_successor_index_; }
set_known_successor_index(int known_successor_index)4441 void set_known_successor_index(int known_successor_index) {
4442 known_successor_index_ = known_successor_index;
4443 }
4444
DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch)4445 DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch)
4446
4447 protected:
4448 int RedefinedOperandIndex() override { return 0; }
4449
4450 private:
4451 HIsStringAndBranch(HValue* value, HBasicBlock* true_target = NULL,
4452 HBasicBlock* false_target = NULL)
HUnaryControlInstruction(value,true_target,false_target)4453 : HUnaryControlInstruction(value, true_target, false_target),
4454 known_successor_index_(kNoKnownSuccessorIndex) {
4455 set_representation(Representation::Tagged());
4456 }
4457
4458 int known_successor_index_;
4459 };
4460
4461
4462 class HIsSmiAndBranch final : public HUnaryControlInstruction {
4463 public:
4464 DECLARE_INSTRUCTION_FACTORY_P1(HIsSmiAndBranch, HValue*);
4465 DECLARE_INSTRUCTION_FACTORY_P3(HIsSmiAndBranch, HValue*,
4466 HBasicBlock*, HBasicBlock*);
4467
DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch)4468 DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch)
4469
4470 Representation RequiredInputRepresentation(int index) override {
4471 return Representation::Tagged();
4472 }
4473
4474 protected:
DataEquals(HValue * other)4475 bool DataEquals(HValue* other) override { return true; }
RedefinedOperandIndex()4476 int RedefinedOperandIndex() override { return 0; }
4477
4478 private:
4479 HIsSmiAndBranch(HValue* value,
4480 HBasicBlock* true_target = NULL,
4481 HBasicBlock* false_target = NULL)
HUnaryControlInstruction(value,true_target,false_target)4482 : HUnaryControlInstruction(value, true_target, false_target) {
4483 set_representation(Representation::Tagged());
4484 }
4485 };
4486
4487
4488 class HIsUndetectableAndBranch final : public HUnaryControlInstruction {
4489 public:
4490 DECLARE_INSTRUCTION_FACTORY_P1(HIsUndetectableAndBranch, HValue*);
4491 DECLARE_INSTRUCTION_FACTORY_P3(HIsUndetectableAndBranch, HValue*,
4492 HBasicBlock*, HBasicBlock*);
4493
RequiredInputRepresentation(int index)4494 Representation RequiredInputRepresentation(int index) override {
4495 return Representation::Tagged();
4496 }
4497
4498 bool KnownSuccessorBlock(HBasicBlock** block) override;
4499
DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch)4500 DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch)
4501
4502 private:
4503 HIsUndetectableAndBranch(HValue* value,
4504 HBasicBlock* true_target = NULL,
4505 HBasicBlock* false_target = NULL)
4506 : HUnaryControlInstruction(value, true_target, false_target) {}
4507 };
4508
4509
4510 class HStringCompareAndBranch final : public HTemplateControlInstruction<2, 3> {
4511 public:
4512 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HStringCompareAndBranch,
4513 HValue*,
4514 HValue*,
4515 Token::Value);
4516
context()4517 HValue* context() const { return OperandAt(0); }
left()4518 HValue* left() const { return OperandAt(1); }
right()4519 HValue* right() const { return OperandAt(2); }
token()4520 Token::Value token() const { return token_; }
4521
4522 std::ostream& PrintDataTo(std::ostream& os) const final; // NOLINT
4523
RequiredInputRepresentation(int index)4524 Representation RequiredInputRepresentation(int index) final {
4525 return Representation::Tagged();
4526 }
4527
DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch)4528 DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch)
4529
4530 private:
4531 HStringCompareAndBranch(HValue* context, HValue* left, HValue* right,
4532 Token::Value token)
4533 : token_(token) {
4534 DCHECK(Token::IsCompareOp(token));
4535 SetOperandAt(0, context);
4536 SetOperandAt(1, left);
4537 SetOperandAt(2, right);
4538 set_representation(Representation::Tagged());
4539 SetChangesFlag(kNewSpacePromotion);
4540 SetDependsOnFlag(kStringChars);
4541 SetDependsOnFlag(kStringLengths);
4542 }
4543
4544 Token::Value const token_;
4545 };
4546
4547
4548 class HHasInstanceTypeAndBranch final : public HUnaryControlInstruction {
4549 public:
4550 DECLARE_INSTRUCTION_FACTORY_P2(
4551 HHasInstanceTypeAndBranch, HValue*, InstanceType);
4552 DECLARE_INSTRUCTION_FACTORY_P3(
4553 HHasInstanceTypeAndBranch, HValue*, InstanceType, InstanceType);
4554
from()4555 InstanceType from() { return from_; }
to()4556 InstanceType to() { return to_; }
4557
4558 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4559
RequiredInputRepresentation(int index)4560 Representation RequiredInputRepresentation(int index) override {
4561 return Representation::Tagged();
4562 }
4563
4564 bool KnownSuccessorBlock(HBasicBlock** block) override;
4565
DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch)4566 DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch)
4567
4568 private:
4569 HHasInstanceTypeAndBranch(HValue* value, InstanceType type)
4570 : HUnaryControlInstruction(value, NULL, NULL), from_(type), to_(type) { }
HHasInstanceTypeAndBranch(HValue * value,InstanceType from,InstanceType to)4571 HHasInstanceTypeAndBranch(HValue* value, InstanceType from, InstanceType to)
4572 : HUnaryControlInstruction(value, NULL, NULL), from_(from), to_(to) {
4573 DCHECK(to == LAST_TYPE); // Others not implemented yet in backend.
4574 }
4575
4576 InstanceType from_;
4577 InstanceType to_; // Inclusive range, not all combinations work.
4578 };
4579
4580
4581 class HHasCachedArrayIndexAndBranch final : public HUnaryControlInstruction {
4582 public:
4583 DECLARE_INSTRUCTION_FACTORY_P1(HHasCachedArrayIndexAndBranch, HValue*);
4584
RequiredInputRepresentation(int index)4585 Representation RequiredInputRepresentation(int index) override {
4586 return Representation::Tagged();
4587 }
4588
DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch)4589 DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch)
4590 private:
4591 explicit HHasCachedArrayIndexAndBranch(HValue* value)
4592 : HUnaryControlInstruction(value, NULL, NULL) { }
4593 };
4594
4595
4596 class HGetCachedArrayIndex final : public HUnaryOperation {
4597 public:
4598 DECLARE_INSTRUCTION_FACTORY_P1(HGetCachedArrayIndex, HValue*);
4599
RequiredInputRepresentation(int index)4600 Representation RequiredInputRepresentation(int index) override {
4601 return Representation::Tagged();
4602 }
4603
DECLARE_CONCRETE_INSTRUCTION(GetCachedArrayIndex)4604 DECLARE_CONCRETE_INSTRUCTION(GetCachedArrayIndex)
4605
4606 protected:
4607 bool DataEquals(HValue* other) override { return true; }
4608
4609 private:
HGetCachedArrayIndex(HValue * value)4610 explicit HGetCachedArrayIndex(HValue* value) : HUnaryOperation(value) {
4611 set_representation(Representation::Tagged());
4612 SetFlag(kUseGVN);
4613 }
4614
IsDeletable()4615 bool IsDeletable() const override { return true; }
4616 };
4617
4618
4619 class HClassOfTestAndBranch final : public HUnaryControlInstruction {
4620 public:
4621 DECLARE_INSTRUCTION_FACTORY_P2(HClassOfTestAndBranch, HValue*,
4622 Handle<String>);
4623
DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch)4624 DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch)
4625
4626 Representation RequiredInputRepresentation(int index) override {
4627 return Representation::Tagged();
4628 }
4629
4630 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4631
class_name()4632 Handle<String> class_name() const { return class_name_; }
4633
4634 private:
HClassOfTestAndBranch(HValue * value,Handle<String> class_name)4635 HClassOfTestAndBranch(HValue* value, Handle<String> class_name)
4636 : HUnaryControlInstruction(value, NULL, NULL),
4637 class_name_(class_name) { }
4638
4639 Handle<String> class_name_;
4640 };
4641
4642
4643 class HTypeofIsAndBranch final : public HUnaryControlInstruction {
4644 public:
4645 DECLARE_INSTRUCTION_FACTORY_P2(HTypeofIsAndBranch, HValue*, Handle<String>);
4646
type_literal()4647 Handle<String> type_literal() const { return type_literal_.handle(); }
4648 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4649
DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch)4650 DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch)
4651
4652 Representation RequiredInputRepresentation(int index) override {
4653 return Representation::None();
4654 }
4655
4656 bool KnownSuccessorBlock(HBasicBlock** block) override;
4657
FinalizeUniqueness()4658 void FinalizeUniqueness() override {
4659 type_literal_ = Unique<String>(type_literal_.handle());
4660 }
4661
4662 private:
HTypeofIsAndBranch(HValue * value,Handle<String> type_literal)4663 HTypeofIsAndBranch(HValue* value, Handle<String> type_literal)
4664 : HUnaryControlInstruction(value, NULL, NULL),
4665 type_literal_(Unique<String>::CreateUninitialized(type_literal)) { }
4666
4667 Unique<String> type_literal_;
4668 };
4669
4670
4671 class HInstanceOf final : public HBinaryOperation {
4672 public:
4673 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HInstanceOf, HValue*, HValue*);
4674
RequiredInputRepresentation(int index)4675 Representation RequiredInputRepresentation(int index) override {
4676 return Representation::Tagged();
4677 }
4678
4679 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4680
DECLARE_CONCRETE_INSTRUCTION(InstanceOf)4681 DECLARE_CONCRETE_INSTRUCTION(InstanceOf)
4682
4683 private:
4684 HInstanceOf(HValue* context, HValue* left, HValue* right)
4685 : HBinaryOperation(context, left, right, Strength::WEAK,
4686 HType::Boolean()) {
4687 set_representation(Representation::Tagged());
4688 SetAllSideEffects();
4689 }
4690 };
4691
4692
4693 class HHasInPrototypeChainAndBranch final
4694 : public HTemplateControlInstruction<2, 2> {
4695 public:
4696 DECLARE_INSTRUCTION_FACTORY_P2(HHasInPrototypeChainAndBranch, HValue*,
4697 HValue*);
4698
object()4699 HValue* object() const { return OperandAt(0); }
prototype()4700 HValue* prototype() const { return OperandAt(1); }
4701
RequiredInputRepresentation(int index)4702 Representation RequiredInputRepresentation(int index) override {
4703 return Representation::Tagged();
4704 }
4705
ObjectNeedsSmiCheck()4706 bool ObjectNeedsSmiCheck() const {
4707 return !object()->type().IsHeapObject() &&
4708 !object()->representation().IsHeapObject();
4709 }
4710
DECLARE_CONCRETE_INSTRUCTION(HasInPrototypeChainAndBranch)4711 DECLARE_CONCRETE_INSTRUCTION(HasInPrototypeChainAndBranch)
4712
4713 private:
4714 HHasInPrototypeChainAndBranch(HValue* object, HValue* prototype) {
4715 SetOperandAt(0, object);
4716 SetOperandAt(1, prototype);
4717 SetDependsOnFlag(kCalls);
4718 }
4719 };
4720
4721
4722 class HPower final : public HTemplateInstruction<2> {
4723 public:
4724 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4725 HValue* left, HValue* right);
4726
left()4727 HValue* left() { return OperandAt(0); }
right()4728 HValue* right() const { return OperandAt(1); }
4729
RequiredInputRepresentation(int index)4730 Representation RequiredInputRepresentation(int index) override {
4731 return index == 0
4732 ? Representation::Double()
4733 : Representation::None();
4734 }
observed_input_representation(int index)4735 Representation observed_input_representation(int index) override {
4736 return RequiredInputRepresentation(index);
4737 }
4738
DECLARE_CONCRETE_INSTRUCTION(Power)4739 DECLARE_CONCRETE_INSTRUCTION(Power)
4740
4741 protected:
4742 bool DataEquals(HValue* other) override { return true; }
4743
4744 private:
HPower(HValue * left,HValue * right)4745 HPower(HValue* left, HValue* right) {
4746 SetOperandAt(0, left);
4747 SetOperandAt(1, right);
4748 set_representation(Representation::Double());
4749 SetFlag(kUseGVN);
4750 SetChangesFlag(kNewSpacePromotion);
4751 }
4752
IsDeletable()4753 bool IsDeletable() const override {
4754 return !right()->representation().IsTagged();
4755 }
4756 };
4757
4758
4759 enum ExternalAddType {
4760 AddOfExternalAndTagged,
4761 AddOfExternalAndInt32,
4762 NoExternalAdd
4763 };
4764
4765
4766 class HAdd final : public HArithmeticBinaryOperation {
4767 public:
4768 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4769 HValue* left, HValue* right,
4770 Strength strength = Strength::WEAK);
4771 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4772 HValue* left, HValue* right, Strength strength,
4773 ExternalAddType external_add_type);
4774
4775 // Add is only commutative if two integer values are added and not if two
4776 // tagged values are added (because it might be a String concatenation).
4777 // We also do not commute (pointer + offset).
IsCommutative()4778 bool IsCommutative() const override {
4779 return !representation().IsTagged() && !representation().IsExternal();
4780 }
4781
4782 HValue* Canonicalize() override;
4783
TryDecompose(DecompositionResult * decomposition)4784 bool TryDecompose(DecompositionResult* decomposition) override {
4785 if (left()->IsInteger32Constant()) {
4786 decomposition->Apply(right(), left()->GetInteger32Constant());
4787 return true;
4788 } else if (right()->IsInteger32Constant()) {
4789 decomposition->Apply(left(), right()->GetInteger32Constant());
4790 return true;
4791 } else {
4792 return false;
4793 }
4794 }
4795
RepresentationChanged(Representation to)4796 void RepresentationChanged(Representation to) override {
4797 if (to.IsTagged() &&
4798 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved() ||
4799 left()->ToStringCanBeObserved() || right()->ToStringCanBeObserved())) {
4800 SetAllSideEffects();
4801 ClearFlag(kUseGVN);
4802 } else {
4803 ClearAllSideEffects();
4804 SetFlag(kUseGVN);
4805 }
4806 if (to.IsTagged()) {
4807 SetChangesFlag(kNewSpacePromotion);
4808 ClearFlag(kAllowUndefinedAsNaN);
4809 }
4810 }
4811
4812 Representation RepresentationFromInputs() override;
4813
4814 Representation RequiredInputRepresentation(int index) override;
4815
IsConsistentExternalRepresentation()4816 bool IsConsistentExternalRepresentation() {
4817 return left()->representation().IsExternal() &&
4818 ((external_add_type_ == AddOfExternalAndInt32 &&
4819 right()->representation().IsInteger32()) ||
4820 (external_add_type_ == AddOfExternalAndTagged &&
4821 right()->representation().IsTagged()));
4822 }
4823
external_add_type()4824 ExternalAddType external_add_type() const { return external_add_type_; }
4825
DECLARE_CONCRETE_INSTRUCTION(Add)4826 DECLARE_CONCRETE_INSTRUCTION(Add)
4827
4828 protected:
4829 bool DataEquals(HValue* other) override { return true; }
4830
4831 Range* InferRange(Zone* zone) override;
4832
4833 private:
4834 HAdd(HValue* context, HValue* left, HValue* right, Strength strength,
4835 ExternalAddType external_add_type = NoExternalAdd)
HArithmeticBinaryOperation(context,left,right,strength)4836 : HArithmeticBinaryOperation(context, left, right, strength),
4837 external_add_type_(external_add_type) {
4838 SetFlag(kCanOverflow);
4839 switch (external_add_type_) {
4840 case AddOfExternalAndTagged:
4841 DCHECK(left->representation().IsExternal());
4842 DCHECK(right->representation().IsTagged());
4843 SetDependsOnFlag(kNewSpacePromotion);
4844 ClearFlag(HValue::kCanOverflow);
4845 SetFlag(kHasNoObservableSideEffects);
4846 break;
4847
4848 case NoExternalAdd:
4849 // This is a bit of a hack: The call to this constructor is generated
4850 // by a macro that also supports sub and mul, so it doesn't pass in
4851 // a value for external_add_type but uses the default.
4852 if (left->representation().IsExternal()) {
4853 external_add_type_ = AddOfExternalAndInt32;
4854 }
4855 break;
4856
4857 case AddOfExternalAndInt32:
4858 // See comment above.
4859 UNREACHABLE();
4860 break;
4861 }
4862 }
4863
4864 ExternalAddType external_add_type_;
4865 };
4866
4867
4868 class HSub final : public HArithmeticBinaryOperation {
4869 public:
4870 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4871 HValue* left, HValue* right,
4872 Strength strength = Strength::WEAK);
4873
4874 HValue* Canonicalize() override;
4875
TryDecompose(DecompositionResult * decomposition)4876 bool TryDecompose(DecompositionResult* decomposition) override {
4877 if (right()->IsInteger32Constant()) {
4878 decomposition->Apply(left(), -right()->GetInteger32Constant());
4879 return true;
4880 } else {
4881 return false;
4882 }
4883 }
4884
DECLARE_CONCRETE_INSTRUCTION(Sub)4885 DECLARE_CONCRETE_INSTRUCTION(Sub)
4886
4887 protected:
4888 bool DataEquals(HValue* other) override { return true; }
4889
4890 Range* InferRange(Zone* zone) override;
4891
4892 private:
HSub(HValue * context,HValue * left,HValue * right,Strength strength)4893 HSub(HValue* context, HValue* left, HValue* right, Strength strength)
4894 : HArithmeticBinaryOperation(context, left, right, strength) {
4895 SetFlag(kCanOverflow);
4896 }
4897 };
4898
4899
4900 class HMul 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 static HInstruction* NewImul(Isolate* isolate, Zone* zone, HValue* context,
4907 HValue* left, HValue* right,
4908 Strength strength = Strength::WEAK) {
4909 HInstruction* instr =
4910 HMul::New(isolate, zone, context, left, right, strength);
4911 if (!instr->IsMul()) return instr;
4912 HMul* mul = HMul::cast(instr);
4913 // TODO(mstarzinger): Prevent bailout on minus zero for imul.
4914 mul->AssumeRepresentation(Representation::Integer32());
4915 mul->ClearFlag(HValue::kCanOverflow);
4916 return mul;
4917 }
4918
4919 HValue* Canonicalize() override;
4920
4921 // Only commutative if it is certain that not two objects are multiplicated.
IsCommutative()4922 bool IsCommutative() const override { return !representation().IsTagged(); }
4923
UpdateRepresentation(Representation new_rep,HInferRepresentationPhase * h_infer,const char * reason)4924 void UpdateRepresentation(Representation new_rep,
4925 HInferRepresentationPhase* h_infer,
4926 const char* reason) override {
4927 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4928 }
4929
4930 bool MulMinusOne();
4931
DECLARE_CONCRETE_INSTRUCTION(Mul)4932 DECLARE_CONCRETE_INSTRUCTION(Mul)
4933
4934 protected:
4935 bool DataEquals(HValue* other) override { return true; }
4936
4937 Range* InferRange(Zone* zone) override;
4938
4939 private:
HMul(HValue * context,HValue * left,HValue * right,Strength strength)4940 HMul(HValue* context, HValue* left, HValue* right, Strength strength)
4941 : HArithmeticBinaryOperation(context, left, right, strength) {
4942 SetFlag(kCanOverflow);
4943 }
4944 };
4945
4946
4947 class HMod final : public HArithmeticBinaryOperation {
4948 public:
4949 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4950 HValue* left, HValue* right,
4951 Strength strength = Strength::WEAK);
4952
4953 HValue* Canonicalize() override;
4954
UpdateRepresentation(Representation new_rep,HInferRepresentationPhase * h_infer,const char * reason)4955 void UpdateRepresentation(Representation new_rep,
4956 HInferRepresentationPhase* h_infer,
4957 const char* reason) override {
4958 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
4959 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4960 }
4961
DECLARE_CONCRETE_INSTRUCTION(Mod)4962 DECLARE_CONCRETE_INSTRUCTION(Mod)
4963
4964 protected:
4965 bool DataEquals(HValue* other) override { return true; }
4966
4967 Range* InferRange(Zone* zone) override;
4968
4969 private:
HMod(HValue * context,HValue * left,HValue * right,Strength strength)4970 HMod(HValue* context, HValue* left, HValue* right, Strength strength)
4971 : HArithmeticBinaryOperation(context, left, right, strength) {
4972 SetFlag(kCanBeDivByZero);
4973 SetFlag(kCanOverflow);
4974 SetFlag(kLeftCanBeNegative);
4975 }
4976 };
4977
4978
4979 class HDiv 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
UpdateRepresentation(Representation new_rep,HInferRepresentationPhase * h_infer,const char * reason)4987 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
DECLARE_CONCRETE_INSTRUCTION(Div)4994 DECLARE_CONCRETE_INSTRUCTION(Div)
4995
4996 protected:
4997 bool DataEquals(HValue* other) override { return true; }
4998
4999 Range* InferRange(Zone* zone) override;
5000
5001 private:
HDiv(HValue * context,HValue * left,HValue * right,Strength strength)5002 HDiv(HValue* context, HValue* left, HValue* right, Strength strength)
5003 : HArithmeticBinaryOperation(context, left, right, strength) {
5004 SetFlag(kCanBeDivByZero);
5005 SetFlag(kCanOverflow);
5006 }
5007 };
5008
5009
5010 class HMathMinMax final : public HArithmeticBinaryOperation {
5011 public:
5012 enum Operation { kMathMin, kMathMax };
5013
5014 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5015 HValue* left, HValue* right, Operation op);
5016
observed_input_representation(int index)5017 Representation observed_input_representation(int index) override {
5018 return RequiredInputRepresentation(index);
5019 }
5020
5021 void InferRepresentation(HInferRepresentationPhase* h_infer) override;
5022
RepresentationFromInputs()5023 Representation RepresentationFromInputs() override {
5024 Representation left_rep = left()->representation();
5025 Representation right_rep = right()->representation();
5026 Representation result = Representation::Smi();
5027 result = result.generalize(left_rep);
5028 result = result.generalize(right_rep);
5029 if (result.IsTagged()) return Representation::Double();
5030 return result;
5031 }
5032
IsCommutative()5033 bool IsCommutative() const override { return true; }
5034
operation()5035 Operation operation() { return operation_; }
5036
DECLARE_CONCRETE_INSTRUCTION(MathMinMax)5037 DECLARE_CONCRETE_INSTRUCTION(MathMinMax)
5038
5039 protected:
5040 bool DataEquals(HValue* other) override {
5041 return other->IsMathMinMax() &&
5042 HMathMinMax::cast(other)->operation_ == operation_;
5043 }
5044
5045 Range* InferRange(Zone* zone) override;
5046
5047 private:
HMathMinMax(HValue * context,HValue * left,HValue * right,Operation op)5048 HMathMinMax(HValue* context, HValue* left, HValue* right, Operation op)
5049 : HArithmeticBinaryOperation(context, left, right, Strength::WEAK),
5050 operation_(op) {}
5051
5052 Operation operation_;
5053 };
5054
5055
5056 class HBitwise final : public HBitwiseBinaryOperation {
5057 public:
5058 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5059 Token::Value op, HValue* left, HValue* right,
5060 Strength strength = Strength::WEAK);
5061
op()5062 Token::Value op() const { return op_; }
5063
IsCommutative()5064 bool IsCommutative() const override { return true; }
5065
5066 HValue* Canonicalize() override;
5067
5068 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5069
DECLARE_CONCRETE_INSTRUCTION(Bitwise)5070 DECLARE_CONCRETE_INSTRUCTION(Bitwise)
5071
5072 protected:
5073 bool DataEquals(HValue* other) override {
5074 return op() == HBitwise::cast(other)->op();
5075 }
5076
5077 Range* InferRange(Zone* zone) override;
5078
5079 private:
HBitwise(HValue * context,Token::Value op,HValue * left,HValue * right,Strength strength)5080 HBitwise(HValue* context, Token::Value op, HValue* left, HValue* right,
5081 Strength strength)
5082 : HBitwiseBinaryOperation(context, left, right, strength), op_(op) {
5083 DCHECK(op == Token::BIT_AND || op == Token::BIT_OR || op == Token::BIT_XOR);
5084 // BIT_AND with a smi-range positive value will always unset the
5085 // entire sign-extension of the smi-sign.
5086 if (op == Token::BIT_AND &&
5087 ((left->IsConstant() &&
5088 left->representation().IsSmi() &&
5089 HConstant::cast(left)->Integer32Value() >= 0) ||
5090 (right->IsConstant() &&
5091 right->representation().IsSmi() &&
5092 HConstant::cast(right)->Integer32Value() >= 0))) {
5093 SetFlag(kTruncatingToSmi);
5094 SetFlag(kTruncatingToInt32);
5095 // BIT_OR with a smi-range negative value will always set the entire
5096 // sign-extension of the smi-sign.
5097 } else if (op == Token::BIT_OR &&
5098 ((left->IsConstant() &&
5099 left->representation().IsSmi() &&
5100 HConstant::cast(left)->Integer32Value() < 0) ||
5101 (right->IsConstant() &&
5102 right->representation().IsSmi() &&
5103 HConstant::cast(right)->Integer32Value() < 0))) {
5104 SetFlag(kTruncatingToSmi);
5105 SetFlag(kTruncatingToInt32);
5106 }
5107 }
5108
5109 Token::Value op_;
5110 };
5111
5112
5113 class HShl final : public HBitwiseBinaryOperation {
5114 public:
5115 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5116 HValue* left, HValue* right,
5117 Strength strength = Strength::WEAK);
5118
5119 Range* InferRange(Zone* zone) override;
5120
UpdateRepresentation(Representation new_rep,HInferRepresentationPhase * h_infer,const char * reason)5121 void UpdateRepresentation(Representation new_rep,
5122 HInferRepresentationPhase* h_infer,
5123 const char* reason) override {
5124 if (new_rep.IsSmi() &&
5125 !(right()->IsInteger32Constant() &&
5126 right()->GetInteger32Constant() >= 0)) {
5127 new_rep = Representation::Integer32();
5128 }
5129 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5130 }
5131
DECLARE_CONCRETE_INSTRUCTION(Shl)5132 DECLARE_CONCRETE_INSTRUCTION(Shl)
5133
5134 protected:
5135 bool DataEquals(HValue* other) override { return true; }
5136
5137 private:
HShl(HValue * context,HValue * left,HValue * right,Strength strength)5138 HShl(HValue* context, HValue* left, HValue* right, Strength strength)
5139 : HBitwiseBinaryOperation(context, left, right, strength) {}
5140 };
5141
5142
5143 class HShr final : public HBitwiseBinaryOperation {
5144 public:
5145 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5146 HValue* left, HValue* right,
5147 Strength strength = Strength::WEAK);
5148
TryDecompose(DecompositionResult * decomposition)5149 bool TryDecompose(DecompositionResult* decomposition) override {
5150 if (right()->IsInteger32Constant()) {
5151 if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) {
5152 // This is intended to look for HAdd and HSub, to handle compounds
5153 // like ((base + offset) >> scale) with one single decomposition.
5154 left()->TryDecompose(decomposition);
5155 return true;
5156 }
5157 }
5158 return false;
5159 }
5160
5161 Range* InferRange(Zone* zone) override;
5162
UpdateRepresentation(Representation new_rep,HInferRepresentationPhase * h_infer,const char * reason)5163 void UpdateRepresentation(Representation new_rep,
5164 HInferRepresentationPhase* h_infer,
5165 const char* reason) override {
5166 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5167 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5168 }
5169
DECLARE_CONCRETE_INSTRUCTION(Shr)5170 DECLARE_CONCRETE_INSTRUCTION(Shr)
5171
5172 protected:
5173 bool DataEquals(HValue* other) override { return true; }
5174
5175 private:
HShr(HValue * context,HValue * left,HValue * right,Strength strength)5176 HShr(HValue* context, HValue* left, HValue* right, Strength strength)
5177 : HBitwiseBinaryOperation(context, left, right, strength) {}
5178 };
5179
5180
5181 class HSar final : public HBitwiseBinaryOperation {
5182 public:
5183 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5184 HValue* left, HValue* right,
5185 Strength strength = Strength::WEAK);
5186
TryDecompose(DecompositionResult * decomposition)5187 bool TryDecompose(DecompositionResult* decomposition) override {
5188 if (right()->IsInteger32Constant()) {
5189 if (decomposition->Apply(left(), 0, right()->GetInteger32Constant())) {
5190 // This is intended to look for HAdd and HSub, to handle compounds
5191 // like ((base + offset) >> scale) with one single decomposition.
5192 left()->TryDecompose(decomposition);
5193 return true;
5194 }
5195 }
5196 return false;
5197 }
5198
5199 Range* InferRange(Zone* zone) override;
5200
UpdateRepresentation(Representation new_rep,HInferRepresentationPhase * h_infer,const char * reason)5201 void UpdateRepresentation(Representation new_rep,
5202 HInferRepresentationPhase* h_infer,
5203 const char* reason) override {
5204 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5205 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5206 }
5207
DECLARE_CONCRETE_INSTRUCTION(Sar)5208 DECLARE_CONCRETE_INSTRUCTION(Sar)
5209
5210 protected:
5211 bool DataEquals(HValue* other) override { return true; }
5212
5213 private:
HSar(HValue * context,HValue * left,HValue * right,Strength strength)5214 HSar(HValue* context, HValue* left, HValue* right, Strength strength)
5215 : HBitwiseBinaryOperation(context, left, right, strength) {}
5216 };
5217
5218
5219 class HRor final : public HBitwiseBinaryOperation {
5220 public:
5221 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
5222 HValue* left, HValue* right,
5223 Strength strength = Strength::WEAK) {
5224 return new (zone) HRor(context, left, right, strength);
5225 }
5226
UpdateRepresentation(Representation new_rep,HInferRepresentationPhase * h_infer,const char * reason)5227 void UpdateRepresentation(Representation new_rep,
5228 HInferRepresentationPhase* h_infer,
5229 const char* reason) override {
5230 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
5231 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
5232 }
5233
DECLARE_CONCRETE_INSTRUCTION(Ror)5234 DECLARE_CONCRETE_INSTRUCTION(Ror)
5235
5236 protected:
5237 bool DataEquals(HValue* other) override { return true; }
5238
5239 private:
HRor(HValue * context,HValue * left,HValue * right,Strength strength)5240 HRor(HValue* context, HValue* left, HValue* right, Strength strength)
5241 : HBitwiseBinaryOperation(context, left, right, strength) {
5242 ChangeRepresentation(Representation::Integer32());
5243 }
5244 };
5245
5246
5247 class HOsrEntry final : public HTemplateInstruction<0> {
5248 public:
5249 DECLARE_INSTRUCTION_FACTORY_P1(HOsrEntry, BailoutId);
5250
ast_id()5251 BailoutId ast_id() const { return ast_id_; }
5252
RequiredInputRepresentation(int index)5253 Representation RequiredInputRepresentation(int index) override {
5254 return Representation::None();
5255 }
5256
DECLARE_CONCRETE_INSTRUCTION(OsrEntry)5257 DECLARE_CONCRETE_INSTRUCTION(OsrEntry)
5258
5259 private:
5260 explicit HOsrEntry(BailoutId ast_id) : ast_id_(ast_id) {
5261 SetChangesFlag(kOsrEntries);
5262 SetChangesFlag(kNewSpacePromotion);
5263 }
5264
5265 BailoutId ast_id_;
5266 };
5267
5268
5269 class HParameter final : public HTemplateInstruction<0> {
5270 public:
5271 enum ParameterKind {
5272 STACK_PARAMETER,
5273 REGISTER_PARAMETER
5274 };
5275
5276 DECLARE_INSTRUCTION_FACTORY_P1(HParameter, unsigned);
5277 DECLARE_INSTRUCTION_FACTORY_P2(HParameter, unsigned, ParameterKind);
5278 DECLARE_INSTRUCTION_FACTORY_P3(HParameter, unsigned, ParameterKind,
5279 Representation);
5280
index()5281 unsigned index() const { return index_; }
kind()5282 ParameterKind kind() const { return kind_; }
5283
5284 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5285
RequiredInputRepresentation(int index)5286 Representation RequiredInputRepresentation(int index) override {
5287 return Representation::None();
5288 }
5289
KnownOptimalRepresentation()5290 Representation KnownOptimalRepresentation() override {
5291 // If a parameter is an input to a phi, that phi should not
5292 // choose any more optimistic representation than Tagged.
5293 return Representation::Tagged();
5294 }
5295
DECLARE_CONCRETE_INSTRUCTION(Parameter)5296 DECLARE_CONCRETE_INSTRUCTION(Parameter)
5297
5298 private:
5299 explicit HParameter(unsigned index,
5300 ParameterKind kind = STACK_PARAMETER)
5301 : index_(index),
5302 kind_(kind) {
5303 set_representation(Representation::Tagged());
5304 }
5305
HParameter(unsigned index,ParameterKind kind,Representation r)5306 explicit HParameter(unsigned index,
5307 ParameterKind kind,
5308 Representation r)
5309 : index_(index),
5310 kind_(kind) {
5311 set_representation(r);
5312 }
5313
5314 unsigned index_;
5315 ParameterKind kind_;
5316 };
5317
5318
5319 class HCallStub final : public HUnaryCall {
5320 public:
5321 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallStub, CodeStub::Major, int);
major_key()5322 CodeStub::Major major_key() { return major_key_; }
5323
context()5324 HValue* context() { return value(); }
5325
5326 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5327
DECLARE_CONCRETE_INSTRUCTION(CallStub)5328 DECLARE_CONCRETE_INSTRUCTION(CallStub)
5329
5330 private:
5331 HCallStub(HValue* context, CodeStub::Major major_key, int argument_count)
5332 : HUnaryCall(context, argument_count),
5333 major_key_(major_key) {
5334 }
5335
5336 CodeStub::Major major_key_;
5337 };
5338
5339
5340 class HUnknownOSRValue final : public HTemplateInstruction<0> {
5341 public:
5342 DECLARE_INSTRUCTION_FACTORY_P2(HUnknownOSRValue, HEnvironment*, int);
5343
5344 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5345
RequiredInputRepresentation(int index)5346 Representation RequiredInputRepresentation(int index) override {
5347 return Representation::None();
5348 }
5349
set_incoming_value(HPhi * value)5350 void set_incoming_value(HPhi* value) { incoming_value_ = value; }
incoming_value()5351 HPhi* incoming_value() { return incoming_value_; }
environment()5352 HEnvironment *environment() { return environment_; }
index()5353 int index() { return index_; }
5354
KnownOptimalRepresentation()5355 Representation KnownOptimalRepresentation() override {
5356 if (incoming_value_ == NULL) return Representation::None();
5357 return incoming_value_->KnownOptimalRepresentation();
5358 }
5359
DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue)5360 DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue)
5361
5362 private:
5363 HUnknownOSRValue(HEnvironment* environment, int index)
5364 : environment_(environment),
5365 index_(index),
5366 incoming_value_(NULL) {
5367 set_representation(Representation::Tagged());
5368 }
5369
5370 HEnvironment* environment_;
5371 int index_;
5372 HPhi* incoming_value_;
5373 };
5374
5375
5376 class HLoadGlobalGeneric final : public HTemplateInstruction<2> {
5377 public:
5378 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HLoadGlobalGeneric, HValue*,
5379 Handle<String>, TypeofMode);
5380
context()5381 HValue* context() { return OperandAt(0); }
global_object()5382 HValue* global_object() { return OperandAt(1); }
name()5383 Handle<String> name() const { return name_; }
typeof_mode()5384 TypeofMode typeof_mode() const { return typeof_mode_; }
slot()5385 FeedbackVectorSlot slot() const { return slot_; }
feedback_vector()5386 Handle<TypeFeedbackVector> feedback_vector() const {
5387 return feedback_vector_;
5388 }
HasVectorAndSlot()5389 bool HasVectorAndSlot() const { return true; }
SetVectorAndSlot(Handle<TypeFeedbackVector> vector,FeedbackVectorSlot slot)5390 void SetVectorAndSlot(Handle<TypeFeedbackVector> vector,
5391 FeedbackVectorSlot slot) {
5392 feedback_vector_ = vector;
5393 slot_ = slot;
5394 }
5395
5396 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5397
RequiredInputRepresentation(int index)5398 Representation RequiredInputRepresentation(int index) override {
5399 return Representation::Tagged();
5400 }
5401
DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric)5402 DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric)
5403
5404 private:
5405 HLoadGlobalGeneric(HValue* context, HValue* global_object,
5406 Handle<String> name, TypeofMode typeof_mode)
5407 : name_(name), typeof_mode_(typeof_mode) {
5408 SetOperandAt(0, context);
5409 SetOperandAt(1, global_object);
5410 set_representation(Representation::Tagged());
5411 SetAllSideEffects();
5412 }
5413
5414 Handle<String> name_;
5415 TypeofMode typeof_mode_;
5416 Handle<TypeFeedbackVector> feedback_vector_;
5417 FeedbackVectorSlot slot_;
5418 };
5419
5420
5421 class HAllocate final : public HTemplateInstruction<2> {
5422 public:
CompatibleInstanceTypes(InstanceType type1,InstanceType type2)5423 static bool CompatibleInstanceTypes(InstanceType type1,
5424 InstanceType type2) {
5425 return ComputeFlags(TENURED, type1) == ComputeFlags(TENURED, type2) &&
5426 ComputeFlags(NOT_TENURED, type1) == ComputeFlags(NOT_TENURED, type2);
5427 }
5428
5429 static HAllocate* New(
5430 Isolate* isolate, Zone* zone, HValue* context, HValue* size, HType type,
5431 PretenureFlag pretenure_flag, InstanceType instance_type,
5432 Handle<AllocationSite> allocation_site = Handle<AllocationSite>::null()) {
5433 return new(zone) HAllocate(context, size, type, pretenure_flag,
5434 instance_type, allocation_site);
5435 }
5436
5437 // Maximum instance size for which allocations will be inlined.
5438 static const int kMaxInlineSize = 64 * kPointerSize;
5439
context()5440 HValue* context() const { return OperandAt(0); }
size()5441 HValue* size() const { return OperandAt(1); }
5442
has_size_upper_bound()5443 bool has_size_upper_bound() { return size_upper_bound_ != NULL; }
size_upper_bound()5444 HConstant* size_upper_bound() { return size_upper_bound_; }
set_size_upper_bound(HConstant * value)5445 void set_size_upper_bound(HConstant* value) {
5446 DCHECK(size_upper_bound_ == NULL);
5447 size_upper_bound_ = value;
5448 }
5449
RequiredInputRepresentation(int index)5450 Representation RequiredInputRepresentation(int index) override {
5451 if (index == 0) {
5452 return Representation::Tagged();
5453 } else {
5454 return Representation::Integer32();
5455 }
5456 }
5457
GetMonomorphicJSObjectMap()5458 Handle<Map> GetMonomorphicJSObjectMap() override {
5459 return known_initial_map_;
5460 }
5461
set_known_initial_map(Handle<Map> known_initial_map)5462 void set_known_initial_map(Handle<Map> known_initial_map) {
5463 known_initial_map_ = known_initial_map;
5464 }
5465
IsNewSpaceAllocation()5466 bool IsNewSpaceAllocation() const {
5467 return (flags_ & ALLOCATE_IN_NEW_SPACE) != 0;
5468 }
5469
IsOldSpaceAllocation()5470 bool IsOldSpaceAllocation() const {
5471 return (flags_ & ALLOCATE_IN_OLD_SPACE) != 0;
5472 }
5473
MustAllocateDoubleAligned()5474 bool MustAllocateDoubleAligned() const {
5475 return (flags_ & ALLOCATE_DOUBLE_ALIGNED) != 0;
5476 }
5477
MustPrefillWithFiller()5478 bool MustPrefillWithFiller() const {
5479 return (flags_ & PREFILL_WITH_FILLER) != 0;
5480 }
5481
MakePrefillWithFiller()5482 void MakePrefillWithFiller() {
5483 flags_ = static_cast<HAllocate::Flags>(flags_ | PREFILL_WITH_FILLER);
5484 }
5485
MustClearNextMapWord()5486 bool MustClearNextMapWord() const {
5487 return (flags_ & CLEAR_NEXT_MAP_WORD) != 0;
5488 }
5489
MakeDoubleAligned()5490 void MakeDoubleAligned() {
5491 flags_ = static_cast<HAllocate::Flags>(flags_ | ALLOCATE_DOUBLE_ALIGNED);
5492 }
5493
5494 bool HandleSideEffectDominator(GVNFlag side_effect,
5495 HValue* dominator) override;
5496
5497 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5498
5499 DECLARE_CONCRETE_INSTRUCTION(Allocate)
5500
5501 private:
5502 enum Flags {
5503 ALLOCATE_IN_NEW_SPACE = 1 << 0,
5504 ALLOCATE_IN_OLD_SPACE = 1 << 2,
5505 ALLOCATE_DOUBLE_ALIGNED = 1 << 3,
5506 PREFILL_WITH_FILLER = 1 << 4,
5507 CLEAR_NEXT_MAP_WORD = 1 << 5
5508 };
5509
5510 HAllocate(HValue* context,
5511 HValue* size,
5512 HType type,
5513 PretenureFlag pretenure_flag,
5514 InstanceType instance_type,
5515 Handle<AllocationSite> allocation_site =
5516 Handle<AllocationSite>::null())
5517 : HTemplateInstruction<2>(type),
5518 flags_(ComputeFlags(pretenure_flag, instance_type)),
5519 dominating_allocate_(NULL),
5520 filler_free_space_size_(NULL),
5521 size_upper_bound_(NULL) {
5522 SetOperandAt(0, context);
5523 UpdateSize(size);
5524 set_representation(Representation::Tagged());
5525 SetFlag(kTrackSideEffectDominators);
5526 SetChangesFlag(kNewSpacePromotion);
5527 SetDependsOnFlag(kNewSpacePromotion);
5528
5529 if (FLAG_trace_pretenuring) {
5530 PrintF("HAllocate with AllocationSite %p %s\n",
5531 allocation_site.is_null()
5532 ? static_cast<void*>(NULL)
5533 : static_cast<void*>(*allocation_site),
5534 pretenure_flag == TENURED ? "tenured" : "not tenured");
5535 }
5536 }
5537
ComputeFlags(PretenureFlag pretenure_flag,InstanceType instance_type)5538 static Flags ComputeFlags(PretenureFlag pretenure_flag,
5539 InstanceType instance_type) {
5540 Flags flags = pretenure_flag == TENURED ? ALLOCATE_IN_OLD_SPACE
5541 : ALLOCATE_IN_NEW_SPACE;
5542 if (instance_type == FIXED_DOUBLE_ARRAY_TYPE) {
5543 flags = static_cast<Flags>(flags | ALLOCATE_DOUBLE_ALIGNED);
5544 }
5545 // We have to fill the allocated object with one word fillers if we do
5546 // not use allocation folding since some allocations may depend on each
5547 // other, i.e., have a pointer to each other. A GC in between these
5548 // allocations may leave such objects behind in a not completely initialized
5549 // state.
5550 if (!FLAG_use_gvn || !FLAG_use_allocation_folding) {
5551 flags = static_cast<Flags>(flags | PREFILL_WITH_FILLER);
5552 }
5553 if (pretenure_flag == NOT_TENURED &&
5554 AllocationSite::CanTrack(instance_type)) {
5555 flags = static_cast<Flags>(flags | CLEAR_NEXT_MAP_WORD);
5556 }
5557 return flags;
5558 }
5559
UpdateClearNextMapWord(bool clear_next_map_word)5560 void UpdateClearNextMapWord(bool clear_next_map_word) {
5561 flags_ = static_cast<Flags>(clear_next_map_word
5562 ? flags_ | CLEAR_NEXT_MAP_WORD
5563 : flags_ & ~CLEAR_NEXT_MAP_WORD);
5564 }
5565
UpdateSize(HValue * size)5566 void UpdateSize(HValue* size) {
5567 SetOperandAt(1, size);
5568 if (size->IsInteger32Constant()) {
5569 size_upper_bound_ = HConstant::cast(size);
5570 } else {
5571 size_upper_bound_ = NULL;
5572 }
5573 }
5574
5575 HAllocate* GetFoldableDominator(HAllocate* dominator);
5576
5577 void UpdateFreeSpaceFiller(int32_t filler_size);
5578
5579 void CreateFreeSpaceFiller(int32_t filler_size);
5580
IsFoldable(HAllocate * allocate)5581 bool IsFoldable(HAllocate* allocate) {
5582 return (IsNewSpaceAllocation() && allocate->IsNewSpaceAllocation()) ||
5583 (IsOldSpaceAllocation() && allocate->IsOldSpaceAllocation());
5584 }
5585
5586 void ClearNextMapWord(int offset);
5587
5588 Flags flags_;
5589 Handle<Map> known_initial_map_;
5590 HAllocate* dominating_allocate_;
5591 HStoreNamedField* filler_free_space_size_;
5592 HConstant* size_upper_bound_;
5593 };
5594
5595
5596 class HStoreCodeEntry final : public HTemplateInstruction<2> {
5597 public:
New(Isolate * isolate,Zone * zone,HValue * context,HValue * function,HValue * code)5598 static HStoreCodeEntry* New(Isolate* isolate, Zone* zone, HValue* context,
5599 HValue* function, HValue* code) {
5600 return new(zone) HStoreCodeEntry(function, code);
5601 }
5602
RequiredInputRepresentation(int index)5603 Representation RequiredInputRepresentation(int index) override {
5604 return Representation::Tagged();
5605 }
5606
function()5607 HValue* function() { return OperandAt(0); }
code_object()5608 HValue* code_object() { return OperandAt(1); }
5609
DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry)5610 DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry)
5611
5612 private:
5613 HStoreCodeEntry(HValue* function, HValue* code) {
5614 SetOperandAt(0, function);
5615 SetOperandAt(1, code);
5616 }
5617 };
5618
5619
5620 class HInnerAllocatedObject final : public HTemplateInstruction<2> {
5621 public:
New(Isolate * isolate,Zone * zone,HValue * context,HValue * value,HValue * offset,HType type)5622 static HInnerAllocatedObject* New(Isolate* isolate, Zone* zone,
5623 HValue* context, HValue* value,
5624 HValue* offset, HType type) {
5625 return new(zone) HInnerAllocatedObject(value, offset, type);
5626 }
5627
base_object()5628 HValue* base_object() const { return OperandAt(0); }
offset()5629 HValue* offset() const { return OperandAt(1); }
5630
RequiredInputRepresentation(int index)5631 Representation RequiredInputRepresentation(int index) override {
5632 return index == 0 ? Representation::Tagged() : Representation::Integer32();
5633 }
5634
5635 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5636
DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject)5637 DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject)
5638
5639 private:
5640 HInnerAllocatedObject(HValue* value,
5641 HValue* offset,
5642 HType type) : HTemplateInstruction<2>(type) {
5643 DCHECK(value->IsAllocate());
5644 DCHECK(type.IsHeapObject());
5645 SetOperandAt(0, value);
5646 SetOperandAt(1, offset);
5647 set_representation(Representation::Tagged());
5648 }
5649 };
5650
5651
StoringValueNeedsWriteBarrier(HValue * value)5652 inline bool StoringValueNeedsWriteBarrier(HValue* value) {
5653 return !value->type().IsSmi()
5654 && !value->type().IsNull()
5655 && !value->type().IsBoolean()
5656 && !value->type().IsUndefined()
5657 && !(value->IsConstant() && HConstant::cast(value)->ImmortalImmovable());
5658 }
5659
5660
ReceiverObjectNeedsWriteBarrier(HValue * object,HValue * value,HValue * dominator)5661 inline bool ReceiverObjectNeedsWriteBarrier(HValue* object,
5662 HValue* value,
5663 HValue* dominator) {
5664 while (object->IsInnerAllocatedObject()) {
5665 object = HInnerAllocatedObject::cast(object)->base_object();
5666 }
5667 if (object->IsConstant() &&
5668 HConstant::cast(object)->HasExternalReferenceValue()) {
5669 // Stores to external references require no write barriers
5670 return false;
5671 }
5672 // We definitely need a write barrier unless the object is the allocation
5673 // dominator.
5674 if (object == dominator && object->IsAllocate()) {
5675 // Stores to new space allocations require no write barriers.
5676 if (HAllocate::cast(object)->IsNewSpaceAllocation()) {
5677 return false;
5678 }
5679 // Stores to old space allocations require no write barriers if the value is
5680 // a constant provably not in new space.
5681 if (value->IsConstant() && HConstant::cast(value)->NotInNewSpace()) {
5682 return false;
5683 }
5684 }
5685 return true;
5686 }
5687
5688
PointersToHereCheckForObject(HValue * object,HValue * dominator)5689 inline PointersToHereCheck PointersToHereCheckForObject(HValue* object,
5690 HValue* dominator) {
5691 while (object->IsInnerAllocatedObject()) {
5692 object = HInnerAllocatedObject::cast(object)->base_object();
5693 }
5694 if (object == dominator &&
5695 object->IsAllocate() &&
5696 HAllocate::cast(object)->IsNewSpaceAllocation()) {
5697 return kPointersToHereAreAlwaysInteresting;
5698 }
5699 return kPointersToHereMaybeInteresting;
5700 }
5701
5702
5703 class HLoadContextSlot final : public HUnaryOperation {
5704 public:
5705 enum Mode {
5706 // Perform a normal load of the context slot without checking its value.
5707 kNoCheck,
5708 // Load and check the value of the context slot. Deoptimize if it's the
5709 // hole value. This is used for checking for loading of uninitialized
5710 // harmony bindings where we deoptimize into full-codegen generated code
5711 // which will subsequently throw a reference error.
5712 kCheckDeoptimize,
5713 // Load and check the value of the context slot. Return undefined if it's
5714 // the hole value. This is used for non-harmony const assignments
5715 kCheckReturnUndefined
5716 };
5717
HLoadContextSlot(HValue * context,int slot_index,Mode mode)5718 HLoadContextSlot(HValue* context, int slot_index, Mode mode)
5719 : HUnaryOperation(context), slot_index_(slot_index), mode_(mode) {
5720 set_representation(Representation::Tagged());
5721 SetFlag(kUseGVN);
5722 SetDependsOnFlag(kContextSlots);
5723 }
5724
slot_index()5725 int slot_index() const { return slot_index_; }
mode()5726 Mode mode() const { return mode_; }
5727
DeoptimizesOnHole()5728 bool DeoptimizesOnHole() {
5729 return mode_ == kCheckDeoptimize;
5730 }
5731
RequiresHoleCheck()5732 bool RequiresHoleCheck() const {
5733 return mode_ != kNoCheck;
5734 }
5735
RequiredInputRepresentation(int index)5736 Representation RequiredInputRepresentation(int index) override {
5737 return Representation::Tagged();
5738 }
5739
5740 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5741
DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot)5742 DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot)
5743
5744 protected:
5745 bool DataEquals(HValue* other) override {
5746 HLoadContextSlot* b = HLoadContextSlot::cast(other);
5747 return (slot_index() == b->slot_index());
5748 }
5749
5750 private:
IsDeletable()5751 bool IsDeletable() const override { return !RequiresHoleCheck(); }
5752
5753 int slot_index_;
5754 Mode mode_;
5755 };
5756
5757
5758 class HStoreContextSlot final : public HTemplateInstruction<2> {
5759 public:
5760 enum Mode {
5761 // Perform a normal store to the context slot without checking its previous
5762 // value.
5763 kNoCheck,
5764 // Check the previous value of the context slot and deoptimize if it's the
5765 // hole value. This is used for checking for assignments to uninitialized
5766 // harmony bindings where we deoptimize into full-codegen generated code
5767 // which will subsequently throw a reference error.
5768 kCheckDeoptimize,
5769 // Check the previous value and ignore assignment if it isn't a hole value
5770 kCheckIgnoreAssignment
5771 };
5772
5773 DECLARE_INSTRUCTION_FACTORY_P4(HStoreContextSlot, HValue*, int,
5774 Mode, HValue*);
5775
context()5776 HValue* context() const { return OperandAt(0); }
value()5777 HValue* value() const { return OperandAt(1); }
slot_index()5778 int slot_index() const { return slot_index_; }
mode()5779 Mode mode() const { return mode_; }
5780
NeedsWriteBarrier()5781 bool NeedsWriteBarrier() {
5782 return StoringValueNeedsWriteBarrier(value());
5783 }
5784
DeoptimizesOnHole()5785 bool DeoptimizesOnHole() {
5786 return mode_ == kCheckDeoptimize;
5787 }
5788
RequiresHoleCheck()5789 bool RequiresHoleCheck() {
5790 return mode_ != kNoCheck;
5791 }
5792
RequiredInputRepresentation(int index)5793 Representation RequiredInputRepresentation(int index) override {
5794 return Representation::Tagged();
5795 }
5796
5797 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5798
DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot)5799 DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot)
5800
5801 private:
5802 HStoreContextSlot(HValue* context, int slot_index, Mode mode, HValue* value)
5803 : slot_index_(slot_index), mode_(mode) {
5804 SetOperandAt(0, context);
5805 SetOperandAt(1, value);
5806 SetChangesFlag(kContextSlots);
5807 }
5808
5809 int slot_index_;
5810 Mode mode_;
5811 };
5812
5813
5814 // Represents an access to a portion of an object, such as the map pointer,
5815 // array elements pointer, etc, but not accesses to array elements themselves.
5816 class HObjectAccess final {
5817 public:
IsInobject()5818 inline bool IsInobject() const {
5819 return portion() != kBackingStore && portion() != kExternalMemory;
5820 }
5821
IsExternalMemory()5822 inline bool IsExternalMemory() const {
5823 return portion() == kExternalMemory;
5824 }
5825
IsStringLength()5826 inline bool IsStringLength() const {
5827 return portion() == kStringLengths;
5828 }
5829
IsMap()5830 inline bool IsMap() const {
5831 return portion() == kMaps;
5832 }
5833
offset()5834 inline int offset() const {
5835 return OffsetField::decode(value_);
5836 }
5837
representation()5838 inline Representation representation() const {
5839 return Representation::FromKind(RepresentationField::decode(value_));
5840 }
5841
name()5842 inline Handle<Name> name() const { return name_; }
5843
immutable()5844 inline bool immutable() const {
5845 return ImmutableField::decode(value_);
5846 }
5847
5848 // Returns true if access is being made to an in-object property that
5849 // was already added to the object.
existing_inobject_property()5850 inline bool existing_inobject_property() const {
5851 return ExistingInobjectPropertyField::decode(value_);
5852 }
5853
WithRepresentation(Representation representation)5854 inline HObjectAccess WithRepresentation(Representation representation) {
5855 return HObjectAccess(portion(), offset(), representation, name(),
5856 immutable(), existing_inobject_property());
5857 }
5858
ForHeapNumberValue()5859 static HObjectAccess ForHeapNumberValue() {
5860 return HObjectAccess(
5861 kDouble, HeapNumber::kValueOffset, Representation::Double());
5862 }
5863
ForHeapNumberValueLowestBits()5864 static HObjectAccess ForHeapNumberValueLowestBits() {
5865 return HObjectAccess(kDouble,
5866 HeapNumber::kValueOffset,
5867 Representation::Integer32());
5868 }
5869
ForHeapNumberValueHighestBits()5870 static HObjectAccess ForHeapNumberValueHighestBits() {
5871 return HObjectAccess(kDouble,
5872 HeapNumber::kValueOffset + kIntSize,
5873 Representation::Integer32());
5874 }
5875
5876 static HObjectAccess ForOddballToNumber(
5877 Representation representation = Representation::Tagged()) {
5878 return HObjectAccess(kInobject, Oddball::kToNumberOffset, representation);
5879 }
5880
ForOddballTypeOf()5881 static HObjectAccess ForOddballTypeOf() {
5882 return HObjectAccess(kInobject, Oddball::kTypeOfOffset,
5883 Representation::HeapObject());
5884 }
5885
ForElementsPointer()5886 static HObjectAccess ForElementsPointer() {
5887 return HObjectAccess(kElementsPointer, JSObject::kElementsOffset);
5888 }
5889
ForLiteralsPointer()5890 static HObjectAccess ForLiteralsPointer() {
5891 return HObjectAccess(kInobject, JSFunction::kLiteralsOffset);
5892 }
5893
ForNextFunctionLinkPointer()5894 static HObjectAccess ForNextFunctionLinkPointer() {
5895 return HObjectAccess(kInobject, JSFunction::kNextFunctionLinkOffset);
5896 }
5897
ForArrayLength(ElementsKind elements_kind)5898 static HObjectAccess ForArrayLength(ElementsKind elements_kind) {
5899 return HObjectAccess(
5900 kArrayLengths,
5901 JSArray::kLengthOffset,
5902 IsFastElementsKind(elements_kind)
5903 ? Representation::Smi() : Representation::Tagged());
5904 }
5905
5906 static HObjectAccess ForAllocationSiteOffset(int offset);
5907
ForAllocationSiteList()5908 static HObjectAccess ForAllocationSiteList() {
5909 return HObjectAccess(kExternalMemory, 0, Representation::Tagged(),
5910 Handle<Name>::null(), false, false);
5911 }
5912
ForFixedArrayLength()5913 static HObjectAccess ForFixedArrayLength() {
5914 return HObjectAccess(
5915 kArrayLengths,
5916 FixedArray::kLengthOffset,
5917 Representation::Smi());
5918 }
5919
ForFixedTypedArrayBaseBasePointer()5920 static HObjectAccess ForFixedTypedArrayBaseBasePointer() {
5921 return HObjectAccess(kInobject, FixedTypedArrayBase::kBasePointerOffset,
5922 Representation::Tagged());
5923 }
5924
ForFixedTypedArrayBaseExternalPointer()5925 static HObjectAccess ForFixedTypedArrayBaseExternalPointer() {
5926 return HObjectAccess::ForObservableJSObjectOffset(
5927 FixedTypedArrayBase::kExternalPointerOffset,
5928 Representation::External());
5929 }
5930
ForStringHashField()5931 static HObjectAccess ForStringHashField() {
5932 return HObjectAccess(kInobject,
5933 String::kHashFieldOffset,
5934 Representation::Integer32());
5935 }
5936
ForStringLength()5937 static HObjectAccess ForStringLength() {
5938 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
5939 return HObjectAccess(
5940 kStringLengths,
5941 String::kLengthOffset,
5942 Representation::Smi());
5943 }
5944
ForConsStringFirst()5945 static HObjectAccess ForConsStringFirst() {
5946 return HObjectAccess(kInobject, ConsString::kFirstOffset);
5947 }
5948
ForConsStringSecond()5949 static HObjectAccess ForConsStringSecond() {
5950 return HObjectAccess(kInobject, ConsString::kSecondOffset);
5951 }
5952
ForPropertiesPointer()5953 static HObjectAccess ForPropertiesPointer() {
5954 return HObjectAccess(kInobject, JSObject::kPropertiesOffset);
5955 }
5956
ForPrototypeOrInitialMap()5957 static HObjectAccess ForPrototypeOrInitialMap() {
5958 return HObjectAccess(kInobject, JSFunction::kPrototypeOrInitialMapOffset);
5959 }
5960
ForSharedFunctionInfoPointer()5961 static HObjectAccess ForSharedFunctionInfoPointer() {
5962 return HObjectAccess(kInobject, JSFunction::kSharedFunctionInfoOffset);
5963 }
5964
ForCodeEntryPointer()5965 static HObjectAccess ForCodeEntryPointer() {
5966 return HObjectAccess(kInobject, JSFunction::kCodeEntryOffset);
5967 }
5968
ForCodeOffset()5969 static HObjectAccess ForCodeOffset() {
5970 return HObjectAccess(kInobject, SharedFunctionInfo::kCodeOffset);
5971 }
5972
ForOptimizedCodeMap()5973 static HObjectAccess ForOptimizedCodeMap() {
5974 return HObjectAccess(kInobject,
5975 SharedFunctionInfo::kOptimizedCodeMapOffset);
5976 }
5977
ForOptimizedCodeMapSharedCode()5978 static HObjectAccess ForOptimizedCodeMapSharedCode() {
5979 return HObjectAccess(kInobject, FixedArray::OffsetOfElementAt(
5980 SharedFunctionInfo::kSharedCodeIndex));
5981 }
5982
ForFunctionContextPointer()5983 static HObjectAccess ForFunctionContextPointer() {
5984 return HObjectAccess(kInobject, JSFunction::kContextOffset);
5985 }
5986
ForMap()5987 static HObjectAccess ForMap() {
5988 return HObjectAccess(kMaps, JSObject::kMapOffset);
5989 }
5990
ForPrototype()5991 static HObjectAccess ForPrototype() {
5992 return HObjectAccess(kMaps, Map::kPrototypeOffset);
5993 }
5994
ForMapAsInteger32()5995 static HObjectAccess ForMapAsInteger32() {
5996 return HObjectAccess(kMaps, JSObject::kMapOffset,
5997 Representation::Integer32());
5998 }
5999
ForMapInObjectPropertiesOrConstructorFunctionIndex()6000 static HObjectAccess ForMapInObjectPropertiesOrConstructorFunctionIndex() {
6001 return HObjectAccess(
6002 kInobject, Map::kInObjectPropertiesOrConstructorFunctionIndexOffset,
6003 Representation::UInteger8());
6004 }
6005
ForMapInstanceType()6006 static HObjectAccess ForMapInstanceType() {
6007 return HObjectAccess(kInobject,
6008 Map::kInstanceTypeOffset,
6009 Representation::UInteger8());
6010 }
6011
ForMapInstanceSize()6012 static HObjectAccess ForMapInstanceSize() {
6013 return HObjectAccess(kInobject,
6014 Map::kInstanceSizeOffset,
6015 Representation::UInteger8());
6016 }
6017
ForMapBitField()6018 static HObjectAccess ForMapBitField() {
6019 return HObjectAccess(kInobject,
6020 Map::kBitFieldOffset,
6021 Representation::UInteger8());
6022 }
6023
ForMapBitField2()6024 static HObjectAccess ForMapBitField2() {
6025 return HObjectAccess(kInobject,
6026 Map::kBitField2Offset,
6027 Representation::UInteger8());
6028 }
6029
ForNameHashField()6030 static HObjectAccess ForNameHashField() {
6031 return HObjectAccess(kInobject,
6032 Name::kHashFieldOffset,
6033 Representation::Integer32());
6034 }
6035
ForMapInstanceTypeAndBitField()6036 static HObjectAccess ForMapInstanceTypeAndBitField() {
6037 STATIC_ASSERT((Map::kInstanceTypeAndBitFieldOffset & 1) == 0);
6038 // Ensure the two fields share one 16-bit word, endian-independent.
6039 STATIC_ASSERT((Map::kBitFieldOffset & ~1) ==
6040 (Map::kInstanceTypeOffset & ~1));
6041 return HObjectAccess(kInobject,
6042 Map::kInstanceTypeAndBitFieldOffset,
6043 Representation::UInteger16());
6044 }
6045
ForPropertyCellValue()6046 static HObjectAccess ForPropertyCellValue() {
6047 return HObjectAccess(kInobject, PropertyCell::kValueOffset);
6048 }
6049
ForPropertyCellDetails()6050 static HObjectAccess ForPropertyCellDetails() {
6051 return HObjectAccess(kInobject, PropertyCell::kDetailsOffset,
6052 Representation::Smi());
6053 }
6054
ForCellValue()6055 static HObjectAccess ForCellValue() {
6056 return HObjectAccess(kInobject, Cell::kValueOffset);
6057 }
6058
ForWeakCellValue()6059 static HObjectAccess ForWeakCellValue() {
6060 return HObjectAccess(kInobject, WeakCell::kValueOffset);
6061 }
6062
ForWeakCellNext()6063 static HObjectAccess ForWeakCellNext() {
6064 return HObjectAccess(kInobject, WeakCell::kNextOffset);
6065 }
6066
ForAllocationMementoSite()6067 static HObjectAccess ForAllocationMementoSite() {
6068 return HObjectAccess(kInobject, AllocationMemento::kAllocationSiteOffset);
6069 }
6070
ForCounter()6071 static HObjectAccess ForCounter() {
6072 return HObjectAccess(kExternalMemory, 0, Representation::Integer32(),
6073 Handle<Name>::null(), false, false);
6074 }
6075
ForExternalUInteger8()6076 static HObjectAccess ForExternalUInteger8() {
6077 return HObjectAccess(kExternalMemory, 0, Representation::UInteger8(),
6078 Handle<Name>::null(), false, false);
6079 }
6080
6081 // Create an access to an offset in a fixed array header.
6082 static HObjectAccess ForFixedArrayHeader(int offset);
6083
6084 // Create an access to an in-object property in a JSObject.
6085 // This kind of access must be used when the object |map| is known and
6086 // in-object properties are being accessed. Accesses of the in-object
6087 // properties can have different semantics depending on whether corresponding
6088 // property was added to the map or not.
6089 static HObjectAccess ForMapAndOffset(Handle<Map> map, int offset,
6090 Representation representation = Representation::Tagged());
6091
6092 // Create an access to an in-object property in a JSObject.
6093 // This kind of access can be used for accessing object header fields or
6094 // in-object properties if the map of the object is not known.
6095 static HObjectAccess ForObservableJSObjectOffset(int offset,
6096 Representation representation = Representation::Tagged()) {
6097 return ForMapAndOffset(Handle<Map>::null(), offset, representation);
6098 }
6099
6100 // Create an access to an in-object property in a JSArray.
6101 static HObjectAccess ForJSArrayOffset(int offset);
6102
6103 static HObjectAccess ForContextSlot(int index);
6104
6105 static HObjectAccess ForScriptContext(int index);
6106
6107 // Create an access to the backing store of an object.
6108 static HObjectAccess ForBackingStoreOffset(int offset,
6109 Representation representation = Representation::Tagged());
6110
6111 // Create an access to a resolved field (in-object or backing store).
6112 static HObjectAccess ForField(Handle<Map> map, int index,
6113 Representation representation,
6114 Handle<Name> name);
6115
ForJSTypedArrayLength()6116 static HObjectAccess ForJSTypedArrayLength() {
6117 return HObjectAccess::ForObservableJSObjectOffset(
6118 JSTypedArray::kLengthOffset);
6119 }
6120
ForJSArrayBufferBackingStore()6121 static HObjectAccess ForJSArrayBufferBackingStore() {
6122 return HObjectAccess::ForObservableJSObjectOffset(
6123 JSArrayBuffer::kBackingStoreOffset, Representation::External());
6124 }
6125
ForJSArrayBufferByteLength()6126 static HObjectAccess ForJSArrayBufferByteLength() {
6127 return HObjectAccess::ForObservableJSObjectOffset(
6128 JSArrayBuffer::kByteLengthOffset, Representation::Tagged());
6129 }
6130
ForJSArrayBufferBitField()6131 static HObjectAccess ForJSArrayBufferBitField() {
6132 return HObjectAccess::ForObservableJSObjectOffset(
6133 JSArrayBuffer::kBitFieldOffset, Representation::Integer32());
6134 }
6135
ForJSArrayBufferBitFieldSlot()6136 static HObjectAccess ForJSArrayBufferBitFieldSlot() {
6137 return HObjectAccess::ForObservableJSObjectOffset(
6138 JSArrayBuffer::kBitFieldSlot, Representation::Smi());
6139 }
6140
ForJSArrayBufferViewBuffer()6141 static HObjectAccess ForJSArrayBufferViewBuffer() {
6142 return HObjectAccess::ForObservableJSObjectOffset(
6143 JSArrayBufferView::kBufferOffset);
6144 }
6145
ForJSArrayBufferViewByteOffset()6146 static HObjectAccess ForJSArrayBufferViewByteOffset() {
6147 return HObjectAccess::ForObservableJSObjectOffset(
6148 JSArrayBufferView::kByteOffsetOffset);
6149 }
6150
ForJSArrayBufferViewByteLength()6151 static HObjectAccess ForJSArrayBufferViewByteLength() {
6152 return HObjectAccess::ForObservableJSObjectOffset(
6153 JSArrayBufferView::kByteLengthOffset);
6154 }
6155
ForJSGlobalObjectNativeContext()6156 static HObjectAccess ForJSGlobalObjectNativeContext() {
6157 return HObjectAccess(kInobject, JSGlobalObject::kNativeContextOffset);
6158 }
6159
ForJSRegExpFlags()6160 static HObjectAccess ForJSRegExpFlags() {
6161 return HObjectAccess(kInobject, JSRegExp::kFlagsOffset);
6162 }
6163
ForJSRegExpSource()6164 static HObjectAccess ForJSRegExpSource() {
6165 return HObjectAccess(kInobject, JSRegExp::kSourceOffset);
6166 }
6167
ForJSCollectionTable()6168 static HObjectAccess ForJSCollectionTable() {
6169 return HObjectAccess::ForObservableJSObjectOffset(
6170 JSCollection::kTableOffset);
6171 }
6172
6173 template <typename CollectionType>
ForOrderedHashTableNumberOfBuckets()6174 static HObjectAccess ForOrderedHashTableNumberOfBuckets() {
6175 return HObjectAccess(kInobject, CollectionType::kNumberOfBucketsOffset,
6176 Representation::Smi());
6177 }
6178
6179 template <typename CollectionType>
ForOrderedHashTableNumberOfElements()6180 static HObjectAccess ForOrderedHashTableNumberOfElements() {
6181 return HObjectAccess(kInobject, CollectionType::kNumberOfElementsOffset,
6182 Representation::Smi());
6183 }
6184
6185 template <typename CollectionType>
ForOrderedHashTableNumberOfDeletedElements()6186 static HObjectAccess ForOrderedHashTableNumberOfDeletedElements() {
6187 return HObjectAccess(kInobject,
6188 CollectionType::kNumberOfDeletedElementsOffset,
6189 Representation::Smi());
6190 }
6191
6192 template <typename CollectionType>
ForOrderedHashTableNextTable()6193 static HObjectAccess ForOrderedHashTableNextTable() {
6194 return HObjectAccess(kInobject, CollectionType::kNextTableOffset);
6195 }
6196
6197 template <typename CollectionType>
ForOrderedHashTableBucket(int bucket)6198 static HObjectAccess ForOrderedHashTableBucket(int bucket) {
6199 return HObjectAccess(kInobject, CollectionType::kHashTableStartOffset +
6200 (bucket * kPointerSize),
6201 Representation::Smi());
6202 }
6203
6204 // Access into the data table of an OrderedHashTable with a
6205 // known-at-compile-time bucket count.
6206 template <typename CollectionType, int kBucketCount>
ForOrderedHashTableDataTableIndex(int index)6207 static HObjectAccess ForOrderedHashTableDataTableIndex(int index) {
6208 return HObjectAccess(kInobject, CollectionType::kHashTableStartOffset +
6209 (kBucketCount * kPointerSize) +
6210 (index * kPointerSize));
6211 }
6212
Equals(HObjectAccess that)6213 inline bool Equals(HObjectAccess that) const {
6214 return value_ == that.value_; // portion and offset must match
6215 }
6216
6217 protected:
6218 void SetGVNFlags(HValue *instr, PropertyAccessType access_type);
6219
6220 private:
6221 // internal use only; different parts of an object or array
6222 enum Portion {
6223 kMaps, // map of an object
6224 kArrayLengths, // the length of an array
6225 kStringLengths, // the length of a string
6226 kElementsPointer, // elements pointer
6227 kBackingStore, // some field in the backing store
6228 kDouble, // some double field
6229 kInobject, // some other in-object field
6230 kExternalMemory // some field in external memory
6231 };
6232
HObjectAccess()6233 HObjectAccess() : value_(0) {}
6234
6235 HObjectAccess(Portion portion, int offset,
6236 Representation representation = Representation::Tagged(),
6237 Handle<Name> name = Handle<Name>::null(),
6238 bool immutable = false, bool existing_inobject_property = true)
6239 : value_(PortionField::encode(portion) |
6240 RepresentationField::encode(representation.kind()) |
6241 ImmutableField::encode(immutable ? 1 : 0) |
6242 ExistingInobjectPropertyField::encode(
6243 existing_inobject_property ? 1 : 0) |
6244 OffsetField::encode(offset)),
6245 name_(name) {
6246 // assert that the fields decode correctly
6247 DCHECK(this->offset() == offset);
6248 DCHECK(this->portion() == portion);
6249 DCHECK(this->immutable() == immutable);
6250 DCHECK(this->existing_inobject_property() == existing_inobject_property);
6251 DCHECK(RepresentationField::decode(value_) == representation.kind());
6252 DCHECK(!this->existing_inobject_property() || IsInobject());
6253 }
6254
6255 class PortionField : public BitField<Portion, 0, 3> {};
6256 class RepresentationField : public BitField<Representation::Kind, 3, 4> {};
6257 class ImmutableField : public BitField<bool, 7, 1> {};
6258 class ExistingInobjectPropertyField : public BitField<bool, 8, 1> {};
6259 class OffsetField : public BitField<int, 9, 23> {};
6260
6261 uint32_t value_; // encodes portion, representation, immutable, and offset
6262 Handle<Name> name_;
6263
6264 friend class HLoadNamedField;
6265 friend class HStoreNamedField;
6266 friend class SideEffectsTracker;
6267 friend std::ostream& operator<<(std::ostream& os,
6268 const HObjectAccess& access);
6269
portion()6270 inline Portion portion() const {
6271 return PortionField::decode(value_);
6272 }
6273 };
6274
6275
6276 std::ostream& operator<<(std::ostream& os, const HObjectAccess& access);
6277
6278
6279 class HLoadNamedField final : public HTemplateInstruction<2> {
6280 public:
6281 DECLARE_INSTRUCTION_FACTORY_P3(HLoadNamedField, HValue*,
6282 HValue*, HObjectAccess);
6283 DECLARE_INSTRUCTION_FACTORY_P5(HLoadNamedField, HValue*, HValue*,
6284 HObjectAccess, const UniqueSet<Map>*, HType);
6285
object()6286 HValue* object() const { return OperandAt(0); }
dependency()6287 HValue* dependency() const {
6288 DCHECK(HasDependency());
6289 return OperandAt(1);
6290 }
HasDependency()6291 bool HasDependency() const { return OperandAt(0) != OperandAt(1); }
access()6292 HObjectAccess access() const { return access_; }
field_representation()6293 Representation field_representation() const {
6294 return access_.representation();
6295 }
6296
maps()6297 const UniqueSet<Map>* maps() const { return maps_; }
6298
HasEscapingOperandAt(int index)6299 bool HasEscapingOperandAt(int index) override { return false; }
HasOutOfBoundsAccess(int size)6300