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