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