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