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