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