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