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