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