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<TypeFeedbackVector>);
1948
context()1949 HValue* context() { return OperandAt(0); }
pairs()1950 Handle<FixedArray> pairs() const { return pairs_; }
flags()1951 int flags() const { return flags_; }
feedback_vector()1952 Handle<TypeFeedbackVector> feedback_vector() const {
1953 return feedback_vector_;
1954 }
1955
DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals)1956 DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals)
1957
1958 Representation RequiredInputRepresentation(int index) override {
1959 return Representation::Tagged();
1960 }
1961
1962 private:
HDeclareGlobals(HValue * context,Handle<FixedArray> pairs,int flags,Handle<TypeFeedbackVector> feedback_vector)1963 HDeclareGlobals(HValue* context, Handle<FixedArray> pairs, int flags,
1964 Handle<TypeFeedbackVector> feedback_vector)
1965 : HUnaryOperation(context),
1966 pairs_(pairs),
1967 feedback_vector_(feedback_vector),
1968 flags_(flags) {
1969 set_representation(Representation::Tagged());
1970 SetAllSideEffects();
1971 }
1972
1973 Handle<FixedArray> pairs_;
1974 Handle<TypeFeedbackVector> feedback_vector_;
1975 int flags_;
1976 };
1977
1978
1979 template <int V>
1980 class HCall : public HTemplateInstruction<V> {
1981 public:
1982 // The argument count includes the receiver.
argument_count_(argument_count)1983 explicit HCall<V>(int argument_count) : argument_count_(argument_count) {
1984 this->set_representation(Representation::Tagged());
1985 this->SetAllSideEffects();
1986 }
1987
argument_count()1988 virtual int argument_count() const {
1989 return argument_count_;
1990 }
1991
argument_delta()1992 int argument_delta() const override { return -argument_count(); }
1993
1994 private:
1995 int argument_count_;
1996 };
1997
1998
1999 class HUnaryCall : public HCall<1> {
2000 public:
HUnaryCall(HValue * value,int argument_count)2001 HUnaryCall(HValue* value, int argument_count)
2002 : HCall<1>(argument_count) {
2003 SetOperandAt(0, value);
2004 }
2005
RequiredInputRepresentation(int index)2006 Representation RequiredInputRepresentation(int index) final {
2007 return Representation::Tagged();
2008 }
2009
2010 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2011
value()2012 HValue* value() const { return OperandAt(0); }
2013 };
2014
2015
2016 class HBinaryCall : public HCall<2> {
2017 public:
HBinaryCall(HValue * first,HValue * second,int argument_count)2018 HBinaryCall(HValue* first, HValue* second, int argument_count)
2019 : HCall<2>(argument_count) {
2020 SetOperandAt(0, first);
2021 SetOperandAt(1, second);
2022 }
2023
2024 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2025
RequiredInputRepresentation(int index)2026 Representation RequiredInputRepresentation(int index) final {
2027 return Representation::Tagged();
2028 }
2029
first()2030 HValue* first() const { return OperandAt(0); }
second()2031 HValue* second() const { return OperandAt(1); }
2032 };
2033
2034
2035 class HCallWithDescriptor final : public HInstruction {
2036 public:
2037 static HCallWithDescriptor* New(
2038 Isolate* isolate, Zone* zone, HValue* context, HValue* target,
2039 int argument_count, CallInterfaceDescriptor descriptor,
2040 const Vector<HValue*>& operands,
2041 TailCallMode syntactic_tail_call_mode = TailCallMode::kDisallow,
2042 TailCallMode tail_call_mode = TailCallMode::kDisallow) {
2043 HCallWithDescriptor* res = new (zone) HCallWithDescriptor(
2044 Code::STUB, context, target, argument_count, descriptor, operands,
2045 syntactic_tail_call_mode, tail_call_mode, zone);
2046 return res;
2047 }
2048
2049 static HCallWithDescriptor* New(
2050 Isolate* isolate, Zone* zone, HValue* context, Code::Kind kind,
2051 HValue* target, int argument_count, CallInterfaceDescriptor descriptor,
2052 const Vector<HValue*>& operands,
2053 TailCallMode syntactic_tail_call_mode = TailCallMode::kDisallow,
2054 TailCallMode tail_call_mode = TailCallMode::kDisallow) {
2055 HCallWithDescriptor* res = new (zone) HCallWithDescriptor(
2056 kind, context, target, argument_count, descriptor, operands,
2057 syntactic_tail_call_mode, tail_call_mode, zone);
2058 return res;
2059 }
2060
OperandCount()2061 int OperandCount() const final { return values_.length(); }
OperandAt(int index)2062 HValue* OperandAt(int index) const final { return values_[index]; }
2063
RequiredInputRepresentation(int index)2064 Representation RequiredInputRepresentation(int index) final {
2065 if (index == 0 || index == 1) {
2066 // Target + context
2067 return Representation::Tagged();
2068 } else {
2069 int par_index = index - 2;
2070 DCHECK(par_index < GetParameterCount());
2071 return RepresentationFromMachineType(
2072 descriptor_.GetParameterType(par_index));
2073 }
2074 }
2075
DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor)2076 DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor)
2077
2078 // Defines whether this instruction corresponds to a JS call at tail position.
2079 TailCallMode syntactic_tail_call_mode() const {
2080 return SyntacticTailCallModeField::decode(bit_field_);
2081 }
2082
2083 // Defines whether this call should be generated as a tail call.
tail_call_mode()2084 TailCallMode tail_call_mode() const {
2085 return TailCallModeField::decode(bit_field_);
2086 }
IsTailCall()2087 bool IsTailCall() const { return tail_call_mode() == TailCallMode::kAllow; }
2088
kind()2089 Code::Kind kind() const { return KindField::decode(bit_field_); }
2090
argument_count()2091 virtual int argument_count() const {
2092 return argument_count_;
2093 }
2094
argument_delta()2095 int argument_delta() const override { return -argument_count_; }
2096
descriptor()2097 CallInterfaceDescriptor descriptor() const { return descriptor_; }
2098
target()2099 HValue* target() { return OperandAt(0); }
context()2100 HValue* context() { return OperandAt(1); }
parameter(int index)2101 HValue* parameter(int index) {
2102 DCHECK_LT(index, GetParameterCount());
2103 return OperandAt(index + 2);
2104 }
2105
2106 HValue* Canonicalize() override;
2107
2108 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2109
2110 private:
2111 // 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)2112 HCallWithDescriptor(Code::Kind kind, HValue* context, HValue* target,
2113 int argument_count, CallInterfaceDescriptor descriptor,
2114 const Vector<HValue*>& operands,
2115 TailCallMode syntactic_tail_call_mode,
2116 TailCallMode tail_call_mode, Zone* zone)
2117 : descriptor_(descriptor),
2118 values_(GetParameterCount() + 2, zone), // +2 for context and target.
2119 argument_count_(argument_count),
2120 bit_field_(
2121 TailCallModeField::encode(tail_call_mode) |
2122 SyntacticTailCallModeField::encode(syntactic_tail_call_mode) |
2123 KindField::encode(kind)) {
2124 DCHECK_EQ(operands.length(), GetParameterCount());
2125 // We can only tail call without any stack arguments.
2126 DCHECK(tail_call_mode != TailCallMode::kAllow || argument_count == 0);
2127 AddOperand(target, zone);
2128 AddOperand(context, zone);
2129 for (int i = 0; i < operands.length(); i++) {
2130 AddOperand(operands[i], zone);
2131 }
2132 this->set_representation(Representation::Tagged());
2133 this->SetAllSideEffects();
2134 }
2135
AddOperand(HValue * v,Zone * zone)2136 void AddOperand(HValue* v, Zone* zone) {
2137 values_.Add(NULL, zone);
2138 SetOperandAt(values_.length() - 1, v);
2139 }
2140
GetParameterCount()2141 int GetParameterCount() const { return descriptor_.GetParameterCount(); }
2142
InternalSetOperandAt(int index,HValue * value)2143 void InternalSetOperandAt(int index, HValue* value) final {
2144 values_[index] = value;
2145 }
2146
2147 CallInterfaceDescriptor descriptor_;
2148 ZoneList<HValue*> values_;
2149 int argument_count_;
2150 class TailCallModeField : public BitField<TailCallMode, 0, 1> {};
2151 class SyntacticTailCallModeField
2152 : public BitField<TailCallMode, TailCallModeField::kNext, 1> {};
2153 class KindField
2154 : public BitField<Code::Kind, SyntacticTailCallModeField::kNext, 5> {};
2155 uint32_t bit_field_;
2156 };
2157
2158
2159 class HInvokeFunction final : public HBinaryCall {
2160 public:
2161 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(HInvokeFunction, HValue*,
2162 Handle<JSFunction>, int,
2163 TailCallMode, TailCallMode);
2164
context()2165 HValue* context() { return first(); }
function()2166 HValue* function() { return second(); }
known_function()2167 Handle<JSFunction> known_function() { return known_function_; }
formal_parameter_count()2168 int formal_parameter_count() const { return formal_parameter_count_; }
2169
HasStackCheck()2170 bool HasStackCheck() final { return HasStackCheckField::decode(bit_field_); }
2171
2172 // Defines whether this instruction corresponds to a JS call at tail position.
syntactic_tail_call_mode()2173 TailCallMode syntactic_tail_call_mode() const {
2174 return SyntacticTailCallModeField::decode(bit_field_);
2175 }
2176
2177 // Defines whether this call should be generated as a tail call.
tail_call_mode()2178 TailCallMode tail_call_mode() const {
2179 return TailCallModeField::decode(bit_field_);
2180 }
2181
2182 DECLARE_CONCRETE_INSTRUCTION(InvokeFunction)
2183
2184 std::ostream& PrintTo(std::ostream& os) const override; // NOLINT
2185 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2186
2187 private:
set_has_stack_check(bool has_stack_check)2188 void set_has_stack_check(bool has_stack_check) {
2189 bit_field_ = HasStackCheckField::update(bit_field_, has_stack_check);
2190 }
2191
HInvokeFunction(HValue * context,HValue * function,Handle<JSFunction> known_function,int argument_count,TailCallMode syntactic_tail_call_mode,TailCallMode tail_call_mode)2192 HInvokeFunction(HValue* context, HValue* function,
2193 Handle<JSFunction> known_function, int argument_count,
2194 TailCallMode syntactic_tail_call_mode,
2195 TailCallMode tail_call_mode)
2196 : HBinaryCall(context, function, argument_count),
2197 known_function_(known_function),
2198 bit_field_(
2199 TailCallModeField::encode(tail_call_mode) |
2200 SyntacticTailCallModeField::encode(syntactic_tail_call_mode)) {
2201 DCHECK(tail_call_mode != TailCallMode::kAllow ||
2202 syntactic_tail_call_mode == TailCallMode::kAllow);
2203 formal_parameter_count_ =
2204 known_function.is_null()
2205 ? 0
2206 : known_function->shared()->internal_formal_parameter_count();
2207 set_has_stack_check(
2208 !known_function.is_null() &&
2209 (known_function->code()->kind() == Code::FUNCTION ||
2210 known_function->code()->kind() == Code::OPTIMIZED_FUNCTION));
2211 }
2212
2213 Handle<JSFunction> known_function_;
2214 int formal_parameter_count_;
2215
2216 class HasStackCheckField : public BitField<bool, 0, 1> {};
2217 class TailCallModeField
2218 : public BitField<TailCallMode, HasStackCheckField::kNext, 1> {};
2219 class SyntacticTailCallModeField
2220 : public BitField<TailCallMode, TailCallModeField::kNext, 1> {};
2221 uint32_t bit_field_;
2222 };
2223
2224
2225 class HCallNewArray final : public HBinaryCall {
2226 public:
2227 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HCallNewArray, HValue*, int,
2228 ElementsKind,
2229 Handle<AllocationSite>);
2230
context()2231 HValue* context() { return first(); }
constructor()2232 HValue* constructor() { return second(); }
2233
2234 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2235
elements_kind()2236 ElementsKind elements_kind() const { return elements_kind_; }
site()2237 Handle<AllocationSite> site() const { return site_; }
2238
DECLARE_CONCRETE_INSTRUCTION(CallNewArray)2239 DECLARE_CONCRETE_INSTRUCTION(CallNewArray)
2240
2241 private:
2242 HCallNewArray(HValue* context, HValue* constructor, int argument_count,
2243 ElementsKind elements_kind, Handle<AllocationSite> site)
2244 : HBinaryCall(context, constructor, argument_count),
2245 elements_kind_(elements_kind),
2246 site_(site) {}
2247
2248 ElementsKind elements_kind_;
2249 Handle<AllocationSite> site_;
2250 };
2251
2252
2253 class HCallRuntime final : public HCall<1> {
2254 public:
2255 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HCallRuntime,
2256 const Runtime::Function*, int);
2257
2258 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2259
context()2260 HValue* context() { return OperandAt(0); }
function()2261 const Runtime::Function* function() const { return c_function_; }
save_doubles()2262 SaveFPRegsMode save_doubles() const { return save_doubles_; }
set_save_doubles(SaveFPRegsMode save_doubles)2263 void set_save_doubles(SaveFPRegsMode save_doubles) {
2264 save_doubles_ = save_doubles;
2265 }
2266
RequiredInputRepresentation(int index)2267 Representation RequiredInputRepresentation(int index) override {
2268 return Representation::Tagged();
2269 }
2270
DECLARE_CONCRETE_INSTRUCTION(CallRuntime)2271 DECLARE_CONCRETE_INSTRUCTION(CallRuntime)
2272
2273 private:
2274 HCallRuntime(HValue* context, const Runtime::Function* c_function,
2275 int argument_count)
2276 : HCall<1>(argument_count),
2277 c_function_(c_function),
2278 save_doubles_(kDontSaveFPRegs) {
2279 SetOperandAt(0, context);
2280 }
2281
2282 const Runtime::Function* c_function_;
2283 SaveFPRegsMode save_doubles_;
2284 };
2285
2286
2287 class HUnaryMathOperation final : public HTemplateInstruction<2> {
2288 public:
2289 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
2290 HValue* value, BuiltinFunctionId op);
2291
context()2292 HValue* context() const { return OperandAt(0); }
value()2293 HValue* value() const { return OperandAt(1); }
2294
2295 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2296
RequiredInputRepresentation(int index)2297 Representation RequiredInputRepresentation(int index) override {
2298 if (index == 0) {
2299 return Representation::Tagged();
2300 } else {
2301 switch (op_) {
2302 case kMathCos:
2303 case kMathFloor:
2304 case kMathRound:
2305 case kMathFround:
2306 case kMathSin:
2307 case kMathSqrt:
2308 case kMathPowHalf:
2309 case kMathLog:
2310 case kMathExp:
2311 return Representation::Double();
2312 case kMathAbs:
2313 return representation();
2314 case kMathClz32:
2315 return Representation::Integer32();
2316 default:
2317 UNREACHABLE();
2318 return Representation::None();
2319 }
2320 }
2321 }
2322
2323 Range* InferRange(Zone* zone) override;
2324
2325 HValue* Canonicalize() override;
2326 Representation RepresentationFromUses() override;
2327 Representation RepresentationFromInputs() override;
2328
op()2329 BuiltinFunctionId op() const { return op_; }
2330 const char* OpName() const;
2331
DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation)2332 DECLARE_CONCRETE_INSTRUCTION(UnaryMathOperation)
2333
2334 protected:
2335 bool DataEquals(HValue* other) override {
2336 HUnaryMathOperation* b = HUnaryMathOperation::cast(other);
2337 return op_ == b->op();
2338 }
2339
2340 private:
2341 // Indicates if we support a double (and int32) output for Math.floor and
2342 // Math.round.
SupportsFlexibleFloorAndRound()2343 bool SupportsFlexibleFloorAndRound() const {
2344 #if V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_PPC
2345 return true;
2346 #elif V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64
2347 return CpuFeatures::IsSupported(SSE4_1);
2348 #else
2349 return false;
2350 #endif
2351 }
HUnaryMathOperation(HValue * context,HValue * value,BuiltinFunctionId op)2352 HUnaryMathOperation(HValue* context, HValue* value, BuiltinFunctionId op)
2353 : HTemplateInstruction<2>(HType::TaggedNumber()), op_(op) {
2354 SetOperandAt(0, context);
2355 SetOperandAt(1, value);
2356 switch (op) {
2357 case kMathFloor:
2358 case kMathRound:
2359 if (SupportsFlexibleFloorAndRound()) {
2360 SetFlag(kFlexibleRepresentation);
2361 } else {
2362 set_representation(Representation::Integer32());
2363 }
2364 break;
2365 case kMathClz32:
2366 set_representation(Representation::Integer32());
2367 break;
2368 case kMathAbs:
2369 // Not setting representation here: it is None intentionally.
2370 SetFlag(kFlexibleRepresentation);
2371 // TODO(svenpanne) This flag is actually only needed if representation()
2372 // is tagged, and not when it is an unboxed double or unboxed integer.
2373 SetChangesFlag(kNewSpacePromotion);
2374 break;
2375 case kMathCos:
2376 case kMathFround:
2377 case kMathLog:
2378 case kMathExp:
2379 case kMathSin:
2380 case kMathSqrt:
2381 case kMathPowHalf:
2382 set_representation(Representation::Double());
2383 break;
2384 default:
2385 UNREACHABLE();
2386 }
2387 SetFlag(kUseGVN);
2388 SetFlag(kTruncatingToNumber);
2389 }
2390
IsDeletable()2391 bool IsDeletable() const override {
2392 // TODO(crankshaft): This should be true, however the semantics of this
2393 // instruction also include the ToNumber conversion that is mentioned in the
2394 // spec, which is of course observable.
2395 return false;
2396 }
2397
2398 HValue* SimplifiedDividendForMathFloorOfDiv(HDiv* hdiv);
2399 HValue* SimplifiedDivisorForMathFloorOfDiv(HDiv* hdiv);
2400
2401 BuiltinFunctionId op_;
2402 };
2403
2404
2405 class HLoadRoot final : public HTemplateInstruction<0> {
2406 public:
2407 DECLARE_INSTRUCTION_FACTORY_P1(HLoadRoot, Heap::RootListIndex);
2408 DECLARE_INSTRUCTION_FACTORY_P2(HLoadRoot, Heap::RootListIndex, HType);
2409
RequiredInputRepresentation(int index)2410 Representation RequiredInputRepresentation(int index) override {
2411 return Representation::None();
2412 }
2413
index()2414 Heap::RootListIndex index() const { return index_; }
2415
DECLARE_CONCRETE_INSTRUCTION(LoadRoot)2416 DECLARE_CONCRETE_INSTRUCTION(LoadRoot)
2417
2418 protected:
2419 bool DataEquals(HValue* other) override {
2420 HLoadRoot* b = HLoadRoot::cast(other);
2421 return index_ == b->index_;
2422 }
2423
2424 private:
2425 explicit HLoadRoot(Heap::RootListIndex index, HType type = HType::Tagged())
2426 : HTemplateInstruction<0>(type), index_(index) {
2427 SetFlag(kUseGVN);
2428 // TODO(bmeurer): We'll need kDependsOnRoots once we add the
2429 // corresponding HStoreRoot instruction.
2430 SetDependsOnFlag(kCalls);
2431 set_representation(Representation::Tagged());
2432 }
2433
IsDeletable()2434 bool IsDeletable() const override { return true; }
2435
2436 const Heap::RootListIndex index_;
2437 };
2438
2439
2440 class HCheckMaps final : public HTemplateInstruction<2> {
2441 public:
2442 static HCheckMaps* New(Isolate* isolate, Zone* zone, HValue* context,
2443 HValue* value, Handle<Map> map,
2444 HValue* typecheck = NULL) {
2445 return new(zone) HCheckMaps(value, new(zone) UniqueSet<Map>(
2446 Unique<Map>::CreateImmovable(map), zone), typecheck);
2447 }
2448 static HCheckMaps* New(Isolate* isolate, Zone* zone, HValue* context,
2449 HValue* value, SmallMapList* map_list,
2450 HValue* typecheck = NULL) {
2451 UniqueSet<Map>* maps = new(zone) UniqueSet<Map>(map_list->length(), zone);
2452 for (int i = 0; i < map_list->length(); ++i) {
2453 maps->Add(Unique<Map>::CreateImmovable(map_list->at(i)), zone);
2454 }
2455 return new(zone) HCheckMaps(value, maps, typecheck);
2456 }
2457
IsStabilityCheck()2458 bool IsStabilityCheck() const {
2459 return IsStabilityCheckField::decode(bit_field_);
2460 }
MarkAsStabilityCheck()2461 void MarkAsStabilityCheck() {
2462 bit_field_ = MapsAreStableField::encode(true) |
2463 HasMigrationTargetField::encode(false) |
2464 IsStabilityCheckField::encode(true);
2465 ClearChangesFlag(kNewSpacePromotion);
2466 ClearDependsOnFlag(kElementsKind);
2467 ClearDependsOnFlag(kMaps);
2468 }
2469
HasEscapingOperandAt(int index)2470 bool HasEscapingOperandAt(int index) override { return false; }
RequiredInputRepresentation(int index)2471 Representation RequiredInputRepresentation(int index) override {
2472 return Representation::Tagged();
2473 }
2474
CalculateInferredType()2475 HType CalculateInferredType() override {
2476 if (value()->type().IsHeapObject()) return value()->type();
2477 return HType::HeapObject();
2478 }
2479
2480 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2481
value()2482 HValue* value() const { return OperandAt(0); }
typecheck()2483 HValue* typecheck() const { return OperandAt(1); }
2484
maps()2485 const UniqueSet<Map>* maps() const { return maps_; }
set_maps(const UniqueSet<Map> * maps)2486 void set_maps(const UniqueSet<Map>* maps) { maps_ = maps; }
2487
maps_are_stable()2488 bool maps_are_stable() const {
2489 return MapsAreStableField::decode(bit_field_);
2490 }
2491
HasMigrationTarget()2492 bool HasMigrationTarget() const {
2493 return HasMigrationTargetField::decode(bit_field_);
2494 }
2495
2496 HValue* Canonicalize() override;
2497
CreateAndInsertAfter(Zone * zone,HValue * value,Unique<Map> map,bool map_is_stable,HInstruction * instr)2498 static HCheckMaps* CreateAndInsertAfter(Zone* zone,
2499 HValue* value,
2500 Unique<Map> map,
2501 bool map_is_stable,
2502 HInstruction* instr) {
2503 return instr->Append(new(zone) HCheckMaps(
2504 value, new(zone) UniqueSet<Map>(map, zone), map_is_stable));
2505 }
2506
CreateAndInsertBefore(Zone * zone,HValue * value,const UniqueSet<Map> * maps,bool maps_are_stable,HInstruction * instr)2507 static HCheckMaps* CreateAndInsertBefore(Zone* zone,
2508 HValue* value,
2509 const UniqueSet<Map>* maps,
2510 bool maps_are_stable,
2511 HInstruction* instr) {
2512 return instr->Prepend(new(zone) HCheckMaps(value, maps, maps_are_stable));
2513 }
2514
DECLARE_CONCRETE_INSTRUCTION(CheckMaps)2515 DECLARE_CONCRETE_INSTRUCTION(CheckMaps)
2516
2517 protected:
2518 bool DataEquals(HValue* other) override {
2519 return this->maps()->Equals(HCheckMaps::cast(other)->maps());
2520 }
2521
RedefinedOperandIndex()2522 int RedefinedOperandIndex() override { return 0; }
2523
2524 private:
HCheckMaps(HValue * value,const UniqueSet<Map> * maps,bool maps_are_stable)2525 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, bool maps_are_stable)
2526 : HTemplateInstruction<2>(HType::HeapObject()),
2527 maps_(maps),
2528 bit_field_(HasMigrationTargetField::encode(false) |
2529 IsStabilityCheckField::encode(false) |
2530 MapsAreStableField::encode(maps_are_stable)) {
2531 DCHECK_NE(0, maps->size());
2532 SetOperandAt(0, value);
2533 // Use the object value for the dependency.
2534 SetOperandAt(1, value);
2535 set_representation(Representation::Tagged());
2536 SetFlag(kUseGVN);
2537 SetDependsOnFlag(kMaps);
2538 SetDependsOnFlag(kElementsKind);
2539 }
2540
HCheckMaps(HValue * value,const UniqueSet<Map> * maps,HValue * typecheck)2541 HCheckMaps(HValue* value, const UniqueSet<Map>* maps, HValue* typecheck)
2542 : HTemplateInstruction<2>(HType::HeapObject()),
2543 maps_(maps),
2544 bit_field_(HasMigrationTargetField::encode(false) |
2545 IsStabilityCheckField::encode(false) |
2546 MapsAreStableField::encode(true)) {
2547 DCHECK_NE(0, maps->size());
2548 SetOperandAt(0, value);
2549 // Use the object value for the dependency if NULL is passed.
2550 SetOperandAt(1, typecheck ? typecheck : value);
2551 set_representation(Representation::Tagged());
2552 SetFlag(kUseGVN);
2553 SetDependsOnFlag(kMaps);
2554 SetDependsOnFlag(kElementsKind);
2555 for (int i = 0; i < maps->size(); ++i) {
2556 Handle<Map> map = maps->at(i).handle();
2557 if (map->is_migration_target()) {
2558 bit_field_ = HasMigrationTargetField::update(bit_field_, true);
2559 }
2560 if (!map->is_stable()) {
2561 bit_field_ = MapsAreStableField::update(bit_field_, false);
2562 }
2563 }
2564 if (HasMigrationTarget()) SetChangesFlag(kNewSpacePromotion);
2565 }
2566
2567 class HasMigrationTargetField : public BitField<bool, 0, 1> {};
2568 class IsStabilityCheckField : public BitField<bool, 1, 1> {};
2569 class MapsAreStableField : public BitField<bool, 2, 1> {};
2570
2571 const UniqueSet<Map>* maps_;
2572 uint32_t bit_field_;
2573 };
2574
2575
2576 class HCheckValue final : public HUnaryOperation {
2577 public:
New(Isolate * isolate,Zone * zone,HValue * context,HValue * value,Handle<JSFunction> func)2578 static HCheckValue* New(Isolate* isolate, Zone* zone, HValue* context,
2579 HValue* value, Handle<JSFunction> func) {
2580 bool in_new_space = isolate->heap()->InNewSpace(*func);
2581 // NOTE: We create an uninitialized Unique and initialize it later.
2582 // This is because a JSFunction can move due to GC during graph creation.
2583 Unique<JSFunction> target = Unique<JSFunction>::CreateUninitialized(func);
2584 HCheckValue* check = new(zone) HCheckValue(value, target, in_new_space);
2585 return check;
2586 }
New(Isolate * isolate,Zone * zone,HValue * context,HValue * value,Unique<HeapObject> target,bool object_in_new_space)2587 static HCheckValue* New(Isolate* isolate, Zone* zone, HValue* context,
2588 HValue* value, Unique<HeapObject> target,
2589 bool object_in_new_space) {
2590 return new(zone) HCheckValue(value, target, object_in_new_space);
2591 }
2592
FinalizeUniqueness()2593 void FinalizeUniqueness() override {
2594 object_ = Unique<HeapObject>(object_.handle());
2595 }
2596
RequiredInputRepresentation(int index)2597 Representation RequiredInputRepresentation(int index) override {
2598 return Representation::Tagged();
2599 }
2600 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2601
2602 HValue* Canonicalize() override;
2603
2604 #ifdef DEBUG
2605 void Verify() override;
2606 #endif
2607
object()2608 Unique<HeapObject> object() const { return object_; }
object_in_new_space()2609 bool object_in_new_space() const { return object_in_new_space_; }
2610
DECLARE_CONCRETE_INSTRUCTION(CheckValue)2611 DECLARE_CONCRETE_INSTRUCTION(CheckValue)
2612
2613 protected:
2614 bool DataEquals(HValue* other) override {
2615 HCheckValue* b = HCheckValue::cast(other);
2616 return object_ == b->object_;
2617 }
2618
2619 private:
HCheckValue(HValue * value,Unique<HeapObject> object,bool object_in_new_space)2620 HCheckValue(HValue* value, Unique<HeapObject> object,
2621 bool object_in_new_space)
2622 : HUnaryOperation(value, value->type()),
2623 object_(object),
2624 object_in_new_space_(object_in_new_space) {
2625 set_representation(Representation::Tagged());
2626 SetFlag(kUseGVN);
2627 }
2628
2629 Unique<HeapObject> object_;
2630 bool object_in_new_space_;
2631 };
2632
2633
2634 class HCheckInstanceType final : public HUnaryOperation {
2635 public:
2636 enum Check {
2637 IS_JS_RECEIVER,
2638 IS_JS_ARRAY,
2639 IS_JS_FUNCTION,
2640 IS_JS_DATE,
2641 IS_STRING,
2642 IS_INTERNALIZED_STRING,
2643 LAST_INTERVAL_CHECK = IS_JS_DATE
2644 };
2645
2646 DECLARE_INSTRUCTION_FACTORY_P2(HCheckInstanceType, HValue*, Check);
2647
2648 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2649
RequiredInputRepresentation(int index)2650 Representation RequiredInputRepresentation(int index) override {
2651 return Representation::Tagged();
2652 }
2653
CalculateInferredType()2654 HType CalculateInferredType() override {
2655 switch (check_) {
2656 case IS_JS_RECEIVER: return HType::JSReceiver();
2657 case IS_JS_ARRAY: return HType::JSArray();
2658 case IS_JS_FUNCTION:
2659 return HType::JSObject();
2660 case IS_JS_DATE: return HType::JSObject();
2661 case IS_STRING: return HType::String();
2662 case IS_INTERNALIZED_STRING: return HType::String();
2663 }
2664 UNREACHABLE();
2665 return HType::Tagged();
2666 }
2667
2668 HValue* Canonicalize() override;
2669
is_interval_check()2670 bool is_interval_check() const { return check_ <= LAST_INTERVAL_CHECK; }
2671 void GetCheckInterval(InstanceType* first, InstanceType* last);
2672 void GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag);
2673
check()2674 Check check() const { return check_; }
2675
DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType)2676 DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType)
2677
2678 protected:
2679 // TODO(ager): It could be nice to allow the ommision of instance
2680 // type checks if we have already performed an instance type check
2681 // with a larger range.
2682 bool DataEquals(HValue* other) override {
2683 HCheckInstanceType* b = HCheckInstanceType::cast(other);
2684 return check_ == b->check_;
2685 }
2686
RedefinedOperandIndex()2687 int RedefinedOperandIndex() override { return 0; }
2688
2689 private:
2690 const char* GetCheckName() const;
2691
HCheckInstanceType(HValue * value,Check check)2692 HCheckInstanceType(HValue* value, Check check)
2693 : HUnaryOperation(value, HType::HeapObject()), check_(check) {
2694 set_representation(Representation::Tagged());
2695 SetFlag(kUseGVN);
2696 }
2697
2698 const Check check_;
2699 };
2700
2701
2702 class HCheckSmi final : public HUnaryOperation {
2703 public:
2704 DECLARE_INSTRUCTION_FACTORY_P1(HCheckSmi, HValue*);
2705
RequiredInputRepresentation(int index)2706 Representation RequiredInputRepresentation(int index) override {
2707 return Representation::Tagged();
2708 }
2709
Canonicalize()2710 HValue* Canonicalize() override {
2711 HType value_type = value()->type();
2712 if (value_type.IsSmi()) {
2713 return NULL;
2714 }
2715 return this;
2716 }
2717
DECLARE_CONCRETE_INSTRUCTION(CheckSmi)2718 DECLARE_CONCRETE_INSTRUCTION(CheckSmi)
2719
2720 protected:
2721 bool DataEquals(HValue* other) override { return true; }
2722
2723 private:
HCheckSmi(HValue * value)2724 explicit HCheckSmi(HValue* value) : HUnaryOperation(value, HType::Smi()) {
2725 set_representation(Representation::Smi());
2726 SetFlag(kUseGVN);
2727 }
2728 };
2729
2730
2731 class HCheckArrayBufferNotNeutered final : public HUnaryOperation {
2732 public:
2733 DECLARE_INSTRUCTION_FACTORY_P1(HCheckArrayBufferNotNeutered, HValue*);
2734
HasEscapingOperandAt(int index)2735 bool HasEscapingOperandAt(int index) override { return false; }
RequiredInputRepresentation(int index)2736 Representation RequiredInputRepresentation(int index) override {
2737 return Representation::Tagged();
2738 }
2739
CalculateInferredType()2740 HType CalculateInferredType() override {
2741 if (value()->type().IsHeapObject()) return value()->type();
2742 return HType::HeapObject();
2743 }
2744
DECLARE_CONCRETE_INSTRUCTION(CheckArrayBufferNotNeutered)2745 DECLARE_CONCRETE_INSTRUCTION(CheckArrayBufferNotNeutered)
2746
2747 protected:
2748 bool DataEquals(HValue* other) override { return true; }
RedefinedOperandIndex()2749 int RedefinedOperandIndex() override { return 0; }
2750
2751 private:
HCheckArrayBufferNotNeutered(HValue * value)2752 explicit HCheckArrayBufferNotNeutered(HValue* value)
2753 : HUnaryOperation(value) {
2754 set_representation(Representation::Tagged());
2755 SetFlag(kUseGVN);
2756 SetDependsOnFlag(kCalls);
2757 }
2758 };
2759
2760
2761 class HCheckHeapObject final : public HUnaryOperation {
2762 public:
2763 DECLARE_INSTRUCTION_FACTORY_P1(HCheckHeapObject, HValue*);
2764
HasEscapingOperandAt(int index)2765 bool HasEscapingOperandAt(int index) override { return false; }
RequiredInputRepresentation(int index)2766 Representation RequiredInputRepresentation(int index) override {
2767 return Representation::Tagged();
2768 }
2769
CalculateInferredType()2770 HType CalculateInferredType() override {
2771 if (value()->type().IsHeapObject()) return value()->type();
2772 return HType::HeapObject();
2773 }
2774
2775 #ifdef DEBUG
2776 void Verify() override;
2777 #endif
2778
Canonicalize()2779 HValue* Canonicalize() override {
2780 return value()->type().IsHeapObject() ? NULL : this;
2781 }
2782
DECLARE_CONCRETE_INSTRUCTION(CheckHeapObject)2783 DECLARE_CONCRETE_INSTRUCTION(CheckHeapObject)
2784
2785 protected:
2786 bool DataEquals(HValue* other) override { return true; }
2787
2788 private:
HCheckHeapObject(HValue * value)2789 explicit HCheckHeapObject(HValue* value) : HUnaryOperation(value) {
2790 set_representation(Representation::Tagged());
2791 SetFlag(kUseGVN);
2792 }
2793 };
2794
2795
2796 class HPhi final : public HValue {
2797 public:
HPhi(int merged_index,Zone * zone)2798 HPhi(int merged_index, Zone* zone)
2799 : inputs_(2, zone), merged_index_(merged_index) {
2800 DCHECK(merged_index >= 0 || merged_index == kInvalidMergedIndex);
2801 SetFlag(kFlexibleRepresentation);
2802 }
2803
2804 Representation RepresentationFromInputs() override;
2805
2806 Range* InferRange(Zone* zone) override;
2807 void InferRepresentation(HInferRepresentationPhase* h_infer) override;
RequiredInputRepresentation(int index)2808 Representation RequiredInputRepresentation(int index) override {
2809 return representation();
2810 }
KnownOptimalRepresentation()2811 Representation KnownOptimalRepresentation() override {
2812 return representation();
2813 }
2814 HType CalculateInferredType() override;
OperandCount()2815 int OperandCount() const override { return inputs_.length(); }
OperandAt(int index)2816 HValue* OperandAt(int index) const override { return inputs_[index]; }
2817 HValue* GetRedundantReplacement();
2818 void AddInput(HValue* value);
2819 bool HasRealUses();
2820
IsReceiver()2821 bool IsReceiver() const { return merged_index_ == 0; }
HasMergedIndex()2822 bool HasMergedIndex() const { return merged_index_ != kInvalidMergedIndex; }
2823
2824 SourcePosition position() const override;
2825
merged_index()2826 int merged_index() const { return merged_index_; }
2827
2828 std::ostream& PrintTo(std::ostream& os) const override; // NOLINT
2829
2830 #ifdef DEBUG
2831 void Verify() override;
2832 #endif
2833
2834 void InitRealUses(int id);
2835 void AddNonPhiUsesFrom(HPhi* other);
2836
representation_from_indirect_uses()2837 Representation representation_from_indirect_uses() const {
2838 return representation_from_indirect_uses_;
2839 }
2840
has_type_feedback_from_uses()2841 bool has_type_feedback_from_uses() const {
2842 return has_type_feedback_from_uses_;
2843 }
2844
phi_id()2845 int phi_id() { return phi_id_; }
2846
cast(HValue * value)2847 static HPhi* cast(HValue* value) {
2848 DCHECK(value->IsPhi());
2849 return reinterpret_cast<HPhi*>(value);
2850 }
opcode()2851 Opcode opcode() const override { return HValue::kPhi; }
2852
2853 void SimplifyConstantInputs();
2854
2855 // Marker value representing an invalid merge index.
2856 static const int kInvalidMergedIndex = -1;
2857
2858 protected:
2859 void DeleteFromGraph() override;
InternalSetOperandAt(int index,HValue * value)2860 void InternalSetOperandAt(int index, HValue* value) override {
2861 inputs_[index] = value;
2862 }
2863
2864 private:
representation_from_non_phi_uses()2865 Representation representation_from_non_phi_uses() const {
2866 return representation_from_non_phi_uses_;
2867 }
2868
2869 ZoneList<HValue*> inputs_;
2870 int merged_index_ = 0;
2871
2872 int phi_id_ = -1;
2873
2874 Representation representation_from_indirect_uses_ = Representation::None();
2875 Representation representation_from_non_phi_uses_ = Representation::None();
2876 bool has_type_feedback_from_uses_ = false;
2877
IsDeletable()2878 bool IsDeletable() const override { return !IsReceiver(); }
2879 };
2880
2881
2882 // Common base class for HArgumentsObject and HCapturedObject.
2883 class HDematerializedObject : public HInstruction {
2884 public:
HDematerializedObject(int count,Zone * zone)2885 HDematerializedObject(int count, Zone* zone) : values_(count, zone) {}
2886
OperandCount()2887 int OperandCount() const final { return values_.length(); }
OperandAt(int index)2888 HValue* OperandAt(int index) const final { return values_[index]; }
2889
HasEscapingOperandAt(int index)2890 bool HasEscapingOperandAt(int index) final { return false; }
RequiredInputRepresentation(int index)2891 Representation RequiredInputRepresentation(int index) final {
2892 return Representation::None();
2893 }
2894
2895 protected:
InternalSetOperandAt(int index,HValue * value)2896 void InternalSetOperandAt(int index, HValue* value) final {
2897 values_[index] = value;
2898 }
2899
2900 // List of values tracked by this marker.
2901 ZoneList<HValue*> values_;
2902 };
2903
2904
2905 class HArgumentsObject final : public HDematerializedObject {
2906 public:
New(Isolate * isolate,Zone * zone,HValue * context,int count)2907 static HArgumentsObject* New(Isolate* isolate, Zone* zone, HValue* context,
2908 int count) {
2909 return new(zone) HArgumentsObject(count, zone);
2910 }
2911
2912 // The values contain a list of all elements in the arguments object
2913 // including the receiver object, which is skipped when materializing.
arguments_values()2914 const ZoneList<HValue*>* arguments_values() const { return &values_; }
arguments_count()2915 int arguments_count() const { return values_.length(); }
2916
AddArgument(HValue * argument,Zone * zone)2917 void AddArgument(HValue* argument, Zone* zone) {
2918 values_.Add(NULL, zone); // Resize list.
2919 SetOperandAt(values_.length() - 1, argument);
2920 }
2921
DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject)2922 DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject)
2923
2924 private:
2925 HArgumentsObject(int count, Zone* zone)
2926 : HDematerializedObject(count, zone) {
2927 set_representation(Representation::Tagged());
2928 SetFlag(kIsArguments);
2929 }
2930 };
2931
2932
2933 class HCapturedObject final : public HDematerializedObject {
2934 public:
HCapturedObject(int length,int id,Zone * zone)2935 HCapturedObject(int length, int id, Zone* zone)
2936 : HDematerializedObject(length, zone), capture_id_(id) {
2937 set_representation(Representation::Tagged());
2938 values_.AddBlock(NULL, length, zone); // Resize list.
2939 }
2940
2941 // The values contain a list of all in-object properties inside the
2942 // captured object and is index by field index. Properties in the
2943 // properties or elements backing store are not tracked here.
values()2944 const ZoneList<HValue*>* values() const { return &values_; }
length()2945 int length() const { return values_.length(); }
capture_id()2946 int capture_id() const { return capture_id_; }
2947
2948 // Shortcut for the map value of this captured object.
map_value()2949 HValue* map_value() const { return values()->first(); }
2950
ReuseSideEffectsFromStore(HInstruction * store)2951 void ReuseSideEffectsFromStore(HInstruction* store) {
2952 DCHECK(store->HasObservableSideEffects());
2953 DCHECK(store->IsStoreNamedField());
2954 changes_flags_.Add(store->ChangesFlags());
2955 }
2956
2957 // Replay effects of this instruction on the given environment.
2958 void ReplayEnvironment(HEnvironment* env);
2959
2960 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
2961
DECLARE_CONCRETE_INSTRUCTION(CapturedObject)2962 DECLARE_CONCRETE_INSTRUCTION(CapturedObject)
2963
2964 private:
2965 int capture_id_;
2966
2967 // Note that we cannot DCE captured objects as they are used to replay
2968 // the environment. This method is here as an explicit reminder.
2969 // TODO(mstarzinger): Turn HSimulates into full snapshots maybe?
2970 bool IsDeletable() const final { return false; }
2971 };
2972
2973
2974 class HConstant final : public HTemplateInstruction<0> {
2975 public:
2976 enum Special { kHoleNaN };
2977
2978 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Special);
2979 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, int32_t);
2980 DECLARE_INSTRUCTION_FACTORY_P2(HConstant, int32_t, Representation);
2981 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, double);
2982 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, Handle<Object>);
2983 DECLARE_INSTRUCTION_FACTORY_P1(HConstant, ExternalReference);
2984
CreateAndInsertAfter(Isolate * isolate,Zone * zone,HValue * context,int32_t value,Representation representation,HInstruction * instruction)2985 static HConstant* CreateAndInsertAfter(Isolate* isolate, Zone* zone,
2986 HValue* context, int32_t value,
2987 Representation representation,
2988 HInstruction* instruction) {
2989 return instruction->Append(
2990 HConstant::New(isolate, zone, context, value, representation));
2991 }
2992
GetMonomorphicJSObjectMap()2993 Handle<Map> GetMonomorphicJSObjectMap() override {
2994 Handle<Object> object = object_.handle();
2995 if (!object.is_null() && object->IsHeapObject()) {
2996 return v8::internal::handle(HeapObject::cast(*object)->map());
2997 }
2998 return Handle<Map>();
2999 }
3000
CreateAndInsertBefore(Isolate * isolate,Zone * zone,HValue * context,int32_t value,Representation representation,HInstruction * instruction)3001 static HConstant* CreateAndInsertBefore(Isolate* isolate, Zone* zone,
3002 HValue* context, int32_t value,
3003 Representation representation,
3004 HInstruction* instruction) {
3005 return instruction->Prepend(
3006 HConstant::New(isolate, zone, context, value, representation));
3007 }
3008
CreateAndInsertBefore(Zone * zone,Unique<Map> map,bool map_is_stable,HInstruction * instruction)3009 static HConstant* CreateAndInsertBefore(Zone* zone,
3010 Unique<Map> map,
3011 bool map_is_stable,
3012 HInstruction* instruction) {
3013 return instruction->Prepend(new(zone) HConstant(
3014 map, Unique<Map>(Handle<Map>::null()), map_is_stable,
3015 Representation::Tagged(), HType::HeapObject(), true,
3016 false, false, MAP_TYPE));
3017 }
3018
CreateAndInsertAfter(Zone * zone,Unique<Map> map,bool map_is_stable,HInstruction * instruction)3019 static HConstant* CreateAndInsertAfter(Zone* zone,
3020 Unique<Map> map,
3021 bool map_is_stable,
3022 HInstruction* instruction) {
3023 return instruction->Append(new(zone) HConstant(
3024 map, Unique<Map>(Handle<Map>::null()), map_is_stable,
3025 Representation::Tagged(), HType::HeapObject(), true,
3026 false, false, MAP_TYPE));
3027 }
3028
handle(Isolate * isolate)3029 Handle<Object> handle(Isolate* isolate) {
3030 if (object_.handle().is_null()) {
3031 // Default arguments to is_not_in_new_space depend on this heap number
3032 // to be tenured so that it's guaranteed not to be located in new space.
3033 object_ = Unique<Object>::CreateUninitialized(
3034 isolate->factory()->NewNumber(double_value_, TENURED));
3035 }
3036 AllowDeferredHandleDereference smi_check;
3037 DCHECK(HasInteger32Value() || !object_.handle()->IsSmi());
3038 return object_.handle();
3039 }
3040
IsSpecialDouble()3041 bool IsSpecialDouble() const {
3042 return HasDoubleValue() &&
3043 (bit_cast<int64_t>(double_value_) == bit_cast<int64_t>(-0.0) ||
3044 std::isnan(double_value_));
3045 }
3046
NotInNewSpace()3047 bool NotInNewSpace() const {
3048 return IsNotInNewSpaceField::decode(bit_field_);
3049 }
3050
3051 bool ImmortalImmovable() const;
3052
IsCell()3053 bool IsCell() const {
3054 InstanceType instance_type = GetInstanceType();
3055 return instance_type == CELL_TYPE;
3056 }
3057
RequiredInputRepresentation(int index)3058 Representation RequiredInputRepresentation(int index) override {
3059 return Representation::None();
3060 }
3061
KnownOptimalRepresentation()3062 Representation KnownOptimalRepresentation() override {
3063 if (HasSmiValue() && SmiValuesAre31Bits()) return Representation::Smi();
3064 if (HasInteger32Value()) return Representation::Integer32();
3065 if (HasNumberValue()) return Representation::Double();
3066 if (HasExternalReferenceValue()) return Representation::External();
3067 return Representation::Tagged();
3068 }
3069
3070 bool EmitAtUses() override;
3071 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
3072 HConstant* CopyToRepresentation(Representation r, Zone* zone) const;
3073 Maybe<HConstant*> CopyToTruncatedInt32(Zone* zone);
3074 Maybe<HConstant*> CopyToTruncatedNumber(Isolate* isolate, Zone* zone);
HasInteger32Value()3075 bool HasInteger32Value() const {
3076 return HasInt32ValueField::decode(bit_field_);
3077 }
Integer32Value()3078 int32_t Integer32Value() const {
3079 DCHECK(HasInteger32Value());
3080 return int32_value_;
3081 }
HasSmiValue()3082 bool HasSmiValue() const { return HasSmiValueField::decode(bit_field_); }
HasDoubleValue()3083 bool HasDoubleValue() const {
3084 return HasDoubleValueField::decode(bit_field_);
3085 }
DoubleValue()3086 double DoubleValue() const {
3087 DCHECK(HasDoubleValue());
3088 return double_value_;
3089 }
DoubleValueAsBits()3090 uint64_t DoubleValueAsBits() const {
3091 uint64_t bits;
3092 DCHECK(HasDoubleValue());
3093 STATIC_ASSERT(sizeof(bits) == sizeof(double_value_));
3094 std::memcpy(&bits, &double_value_, sizeof(bits));
3095 return bits;
3096 }
IsTheHole()3097 bool IsTheHole() const {
3098 if (HasDoubleValue() && DoubleValueAsBits() == kHoleNanInt64) {
3099 return true;
3100 }
3101 return object_.IsInitialized() &&
3102 object_.IsKnownGlobal(isolate()->heap()->the_hole_value());
3103 }
HasNumberValue()3104 bool HasNumberValue() const { return HasDoubleValue(); }
NumberValueAsInteger32()3105 int32_t NumberValueAsInteger32() const {
3106 DCHECK(HasNumberValue());
3107 // Irrespective of whether a numeric HConstant can be safely
3108 // represented as an int32, we store the (in some cases lossy)
3109 // representation of the number in int32_value_.
3110 return int32_value_;
3111 }
HasStringValue()3112 bool HasStringValue() const {
3113 if (HasNumberValue()) return false;
3114 DCHECK(!object_.handle().is_null());
3115 return GetInstanceType() < FIRST_NONSTRING_TYPE;
3116 }
StringValue()3117 Handle<String> StringValue() const {
3118 DCHECK(HasStringValue());
3119 return Handle<String>::cast(object_.handle());
3120 }
HasInternalizedStringValue()3121 bool HasInternalizedStringValue() const {
3122 return HasStringValue() && StringShape(GetInstanceType()).IsInternalized();
3123 }
3124
HasExternalReferenceValue()3125 bool HasExternalReferenceValue() const {
3126 return HasExternalReferenceValueField::decode(bit_field_);
3127 }
ExternalReferenceValue()3128 ExternalReference ExternalReferenceValue() const {
3129 return external_reference_value_;
3130 }
3131
HasBooleanValue()3132 bool HasBooleanValue() const { return type_.IsBoolean(); }
BooleanValue()3133 bool BooleanValue() const { return BooleanValueField::decode(bit_field_); }
IsCallable()3134 bool IsCallable() const { return IsCallableField::decode(bit_field_); }
IsUndetectable()3135 bool IsUndetectable() const {
3136 return IsUndetectableField::decode(bit_field_);
3137 }
GetInstanceType()3138 InstanceType GetInstanceType() const {
3139 return InstanceTypeField::decode(bit_field_);
3140 }
3141
HasMapValue()3142 bool HasMapValue() const { return GetInstanceType() == MAP_TYPE; }
MapValue()3143 Unique<Map> MapValue() const {
3144 DCHECK(HasMapValue());
3145 return Unique<Map>::cast(GetUnique());
3146 }
HasStableMapValue()3147 bool HasStableMapValue() const {
3148 DCHECK(HasMapValue() || !HasStableMapValueField::decode(bit_field_));
3149 return HasStableMapValueField::decode(bit_field_);
3150 }
3151
HasObjectMap()3152 bool HasObjectMap() const { return !object_map_.IsNull(); }
ObjectMap()3153 Unique<Map> ObjectMap() const {
3154 DCHECK(HasObjectMap());
3155 return object_map_;
3156 }
3157
Hashcode()3158 intptr_t Hashcode() override {
3159 if (HasInteger32Value()) {
3160 return static_cast<intptr_t>(int32_value_);
3161 } else if (HasDoubleValue()) {
3162 uint64_t bits = DoubleValueAsBits();
3163 if (sizeof(bits) > sizeof(intptr_t)) {
3164 bits ^= (bits >> 32);
3165 }
3166 return static_cast<intptr_t>(bits);
3167 } else if (HasExternalReferenceValue()) {
3168 return reinterpret_cast<intptr_t>(external_reference_value_.address());
3169 } else {
3170 DCHECK(!object_.handle().is_null());
3171 return object_.Hashcode();
3172 }
3173 }
3174
FinalizeUniqueness()3175 void FinalizeUniqueness() override {
3176 if (!HasDoubleValue() && !HasExternalReferenceValue()) {
3177 DCHECK(!object_.handle().is_null());
3178 object_ = Unique<Object>(object_.handle());
3179 }
3180 }
3181
GetUnique()3182 Unique<Object> GetUnique() const {
3183 return object_;
3184 }
3185
EqualsUnique(Unique<Object> other)3186 bool EqualsUnique(Unique<Object> other) const {
3187 return object_.IsInitialized() && object_ == other;
3188 }
3189
DataEquals(HValue * other)3190 bool DataEquals(HValue* other) override {
3191 HConstant* other_constant = HConstant::cast(other);
3192 if (HasInteger32Value()) {
3193 return other_constant->HasInteger32Value() &&
3194 int32_value_ == other_constant->int32_value_;
3195 } else if (HasDoubleValue()) {
3196 return other_constant->HasDoubleValue() &&
3197 std::memcmp(&double_value_, &other_constant->double_value_,
3198 sizeof(double_value_)) == 0;
3199 } else if (HasExternalReferenceValue()) {
3200 return other_constant->HasExternalReferenceValue() &&
3201 external_reference_value_ ==
3202 other_constant->external_reference_value_;
3203 } else {
3204 if (other_constant->HasInteger32Value() ||
3205 other_constant->HasDoubleValue() ||
3206 other_constant->HasExternalReferenceValue()) {
3207 return false;
3208 }
3209 DCHECK(!object_.handle().is_null());
3210 return other_constant->object_ == object_;
3211 }
3212 }
3213
3214 #ifdef DEBUG
Verify()3215 void Verify() override {}
3216 #endif
3217
3218 DECLARE_CONCRETE_INSTRUCTION(Constant)
3219
3220 protected:
3221 Range* InferRange(Zone* zone) override;
3222
3223 private:
3224 friend class HGraph;
3225 explicit HConstant(Special special);
3226 explicit HConstant(Handle<Object> handle,
3227 Representation r = Representation::None());
3228 HConstant(int32_t value,
3229 Representation r = Representation::None(),
3230 bool is_not_in_new_space = true,
3231 Unique<Object> optional = Unique<Object>(Handle<Object>::null()));
3232 HConstant(double value,
3233 Representation r = Representation::None(),
3234 bool is_not_in_new_space = true,
3235 Unique<Object> optional = Unique<Object>(Handle<Object>::null()));
3236 HConstant(Unique<Object> object,
3237 Unique<Map> object_map,
3238 bool has_stable_map_value,
3239 Representation r,
3240 HType type,
3241 bool is_not_in_new_space,
3242 bool boolean_value,
3243 bool is_undetectable,
3244 InstanceType instance_type);
3245
3246 explicit HConstant(ExternalReference reference);
3247
3248 void Initialize(Representation r);
3249
IsDeletable()3250 bool IsDeletable() const override { return true; }
3251
3252 // If object_ is a map, this indicates whether the map is stable.
3253 class HasStableMapValueField : public BitField<bool, 0, 1> {};
3254
3255 // We store the HConstant in the most specific form safely possible.
3256 // These flags tell us if the respective member fields hold valid, safe
3257 // representations of the constant. More specific flags imply more general
3258 // flags, but not the converse (i.e. smi => int32 => double).
3259 class HasSmiValueField : public BitField<bool, 1, 1> {};
3260 class HasInt32ValueField : public BitField<bool, 2, 1> {};
3261 class HasDoubleValueField : public BitField<bool, 3, 1> {};
3262
3263 class HasExternalReferenceValueField : public BitField<bool, 4, 1> {};
3264 class IsNotInNewSpaceField : public BitField<bool, 5, 1> {};
3265 class BooleanValueField : public BitField<bool, 6, 1> {};
3266 class IsUndetectableField : public BitField<bool, 7, 1> {};
3267 class IsCallableField : public BitField<bool, 8, 1> {};
3268
3269 static const InstanceType kUnknownInstanceType = FILLER_TYPE;
3270 class InstanceTypeField : public BitField<InstanceType, 16, 8> {};
3271
3272 // If this is a numerical constant, object_ either points to the
3273 // HeapObject the constant originated from or is null. If the
3274 // constant is non-numeric, object_ always points to a valid
3275 // constant HeapObject.
3276 Unique<Object> object_;
3277
3278 // If object_ is a heap object, this points to the stable map of the object.
3279 Unique<Map> object_map_;
3280
3281 uint32_t bit_field_;
3282
3283 int32_t int32_value_;
3284 double double_value_;
3285 ExternalReference external_reference_value_;
3286 };
3287
3288
3289 class HBinaryOperation : public HTemplateInstruction<3> {
3290 public:
3291 HBinaryOperation(HValue* context, HValue* left, HValue* right,
3292 HType type = HType::Tagged())
3293 : HTemplateInstruction<3>(type),
3294 observed_output_representation_(Representation::None()) {
3295 DCHECK(left != NULL && right != NULL);
3296 SetOperandAt(0, context);
3297 SetOperandAt(1, left);
3298 SetOperandAt(2, right);
3299 observed_input_representation_[0] = Representation::None();
3300 observed_input_representation_[1] = Representation::None();
3301 }
3302
context()3303 HValue* context() const { return OperandAt(0); }
left()3304 HValue* left() const { return OperandAt(1); }
right()3305 HValue* right() const { return OperandAt(2); }
3306
3307 // True if switching left and right operands likely generates better code.
AreOperandsBetterSwitched()3308 bool AreOperandsBetterSwitched() {
3309 if (!IsCommutative()) return false;
3310
3311 // Constant operands are better off on the right, they can be inlined in
3312 // many situations on most platforms.
3313 if (left()->IsConstant()) return true;
3314 if (right()->IsConstant()) return false;
3315
3316 // Otherwise, if there is only one use of the right operand, it would be
3317 // better off on the left for platforms that only have 2-arg arithmetic
3318 // ops (e.g ia32, x64) that clobber the left operand.
3319 return right()->HasOneUse();
3320 }
3321
BetterLeftOperand()3322 HValue* BetterLeftOperand() {
3323 return AreOperandsBetterSwitched() ? right() : left();
3324 }
3325
BetterRightOperand()3326 HValue* BetterRightOperand() {
3327 return AreOperandsBetterSwitched() ? left() : right();
3328 }
3329
set_observed_input_representation(int index,Representation rep)3330 void set_observed_input_representation(int index, Representation rep) {
3331 DCHECK(index >= 1 && index <= 2);
3332 observed_input_representation_[index - 1] = rep;
3333 }
3334
initialize_output_representation(Representation observed)3335 virtual void initialize_output_representation(Representation observed) {
3336 observed_output_representation_ = observed;
3337 }
3338
observed_input_representation(int index)3339 Representation observed_input_representation(int index) override {
3340 if (index == 0) return Representation::Tagged();
3341 return observed_input_representation_[index - 1];
3342 }
3343
UpdateRepresentation(Representation new_rep,HInferRepresentationPhase * h_infer,const char * reason)3344 void UpdateRepresentation(Representation new_rep,
3345 HInferRepresentationPhase* h_infer,
3346 const char* reason) override {
3347 Representation rep = !FLAG_smi_binop && new_rep.IsSmi()
3348 ? Representation::Integer32() : new_rep;
3349 HValue::UpdateRepresentation(rep, h_infer, reason);
3350 }
3351
3352 void InferRepresentation(HInferRepresentationPhase* h_infer) override;
3353 Representation RepresentationFromInputs() override;
3354 Representation RepresentationFromOutput();
3355 void AssumeRepresentation(Representation r) override;
3356
IsCommutative()3357 virtual bool IsCommutative() const { return false; }
3358
3359 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
3360
RequiredInputRepresentation(int index)3361 Representation RequiredInputRepresentation(int index) override {
3362 if (index == 0) return Representation::Tagged();
3363 return representation();
3364 }
3365
RightIsPowerOf2()3366 bool RightIsPowerOf2() {
3367 if (!right()->IsInteger32Constant()) return false;
3368 int32_t value = right()->GetInteger32Constant();
3369 if (value < 0) {
3370 return base::bits::IsPowerOfTwo32(static_cast<uint32_t>(-value));
3371 }
3372 return base::bits::IsPowerOfTwo32(static_cast<uint32_t>(value));
3373 }
3374
3375 DECLARE_ABSTRACT_INSTRUCTION(BinaryOperation)
3376
3377 private:
3378 bool IgnoreObservedOutputRepresentation(Representation current_rep);
3379
3380 Representation observed_input_representation_[2];
3381 Representation observed_output_representation_;
3382 };
3383
3384
3385 class HWrapReceiver final : public HTemplateInstruction<2> {
3386 public:
3387 DECLARE_INSTRUCTION_FACTORY_P2(HWrapReceiver, HValue*, HValue*);
3388
DataEquals(HValue * other)3389 bool DataEquals(HValue* other) override { return true; }
3390
RequiredInputRepresentation(int index)3391 Representation RequiredInputRepresentation(int index) override {
3392 return Representation::Tagged();
3393 }
3394
receiver()3395 HValue* receiver() const { return OperandAt(0); }
function()3396 HValue* function() const { return OperandAt(1); }
3397
3398 HValue* Canonicalize() override;
3399
3400 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
known_function()3401 bool known_function() const { return known_function_; }
3402
DECLARE_CONCRETE_INSTRUCTION(WrapReceiver)3403 DECLARE_CONCRETE_INSTRUCTION(WrapReceiver)
3404
3405 private:
3406 HWrapReceiver(HValue* receiver, HValue* function) {
3407 known_function_ = function->IsConstant() &&
3408 HConstant::cast(function)->handle(function->isolate())->IsJSFunction();
3409 set_representation(Representation::Tagged());
3410 SetOperandAt(0, receiver);
3411 SetOperandAt(1, function);
3412 SetFlag(kUseGVN);
3413 }
3414
3415 bool known_function_;
3416 };
3417
3418
3419 class HApplyArguments final : public HTemplateInstruction<4> {
3420 public:
3421 DECLARE_INSTRUCTION_FACTORY_P5(HApplyArguments, HValue*, HValue*, HValue*,
3422 HValue*, TailCallMode);
3423
RequiredInputRepresentation(int index)3424 Representation RequiredInputRepresentation(int index) override {
3425 // The length is untagged, all other inputs are tagged.
3426 return (index == 2)
3427 ? Representation::Integer32()
3428 : Representation::Tagged();
3429 }
3430
function()3431 HValue* function() { return OperandAt(0); }
receiver()3432 HValue* receiver() { return OperandAt(1); }
length()3433 HValue* length() { return OperandAt(2); }
elements()3434 HValue* elements() { return OperandAt(3); }
3435
tail_call_mode()3436 TailCallMode tail_call_mode() const {
3437 return TailCallModeField::decode(bit_field_);
3438 }
3439
DECLARE_CONCRETE_INSTRUCTION(ApplyArguments)3440 DECLARE_CONCRETE_INSTRUCTION(ApplyArguments)
3441
3442 private:
3443 HApplyArguments(HValue* function, HValue* receiver, HValue* length,
3444 HValue* elements, TailCallMode tail_call_mode)
3445 : bit_field_(TailCallModeField::encode(tail_call_mode)) {
3446 set_representation(Representation::Tagged());
3447 SetOperandAt(0, function);
3448 SetOperandAt(1, receiver);
3449 SetOperandAt(2, length);
3450 SetOperandAt(3, elements);
3451 SetAllSideEffects();
3452 }
3453
3454 class TailCallModeField : public BitField<TailCallMode, 0, 1> {};
3455 uint32_t bit_field_;
3456 };
3457
3458
3459 class HArgumentsElements final : public HTemplateInstruction<0> {
3460 public:
3461 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsElements, bool);
3462 DECLARE_INSTRUCTION_FACTORY_P2(HArgumentsElements, bool, bool);
3463
DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements)3464 DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements)
3465
3466 Representation RequiredInputRepresentation(int index) override {
3467 return Representation::None();
3468 }
3469
from_inlined()3470 bool from_inlined() const { return from_inlined_; }
arguments_adaptor()3471 bool arguments_adaptor() const { return arguments_adaptor_; }
3472
3473 protected:
DataEquals(HValue * other)3474 bool DataEquals(HValue* other) override { return true; }
3475
3476 private:
3477 explicit HArgumentsElements(bool from_inlined, bool arguments_adaptor = true)
from_inlined_(from_inlined)3478 : from_inlined_(from_inlined), arguments_adaptor_(arguments_adaptor) {
3479 // The value produced by this instruction is a pointer into the stack
3480 // that looks as if it was a smi because of alignment.
3481 set_representation(Representation::Tagged());
3482 SetFlag(kUseGVN);
3483 }
3484
IsDeletable()3485 bool IsDeletable() const override { return true; }
3486
3487 bool from_inlined_;
3488 bool arguments_adaptor_;
3489 };
3490
3491
3492 class HArgumentsLength final : public HUnaryOperation {
3493 public:
3494 DECLARE_INSTRUCTION_FACTORY_P1(HArgumentsLength, HValue*);
3495
RequiredInputRepresentation(int index)3496 Representation RequiredInputRepresentation(int index) override {
3497 return Representation::Tagged();
3498 }
3499
DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength)3500 DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength)
3501
3502 protected:
3503 bool DataEquals(HValue* other) override { return true; }
3504
3505 private:
HArgumentsLength(HValue * value)3506 explicit HArgumentsLength(HValue* value) : HUnaryOperation(value) {
3507 set_representation(Representation::Integer32());
3508 SetFlag(kUseGVN);
3509 }
3510
IsDeletable()3511 bool IsDeletable() const override { return true; }
3512 };
3513
3514
3515 class HAccessArgumentsAt final : public HTemplateInstruction<3> {
3516 public:
3517 DECLARE_INSTRUCTION_FACTORY_P3(HAccessArgumentsAt, HValue*, HValue*, HValue*);
3518
3519 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
3520
RequiredInputRepresentation(int index)3521 Representation RequiredInputRepresentation(int index) override {
3522 // The arguments elements is considered tagged.
3523 return index == 0
3524 ? Representation::Tagged()
3525 : Representation::Integer32();
3526 }
3527
arguments()3528 HValue* arguments() const { return OperandAt(0); }
length()3529 HValue* length() const { return OperandAt(1); }
index()3530 HValue* index() const { return OperandAt(2); }
3531
DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt)3532 DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt)
3533
3534 private:
3535 HAccessArgumentsAt(HValue* arguments, HValue* length, HValue* index) {
3536 set_representation(Representation::Tagged());
3537 SetFlag(kUseGVN);
3538 SetOperandAt(0, arguments);
3539 SetOperandAt(1, length);
3540 SetOperandAt(2, index);
3541 }
3542
DataEquals(HValue * other)3543 bool DataEquals(HValue* other) override { return true; }
3544 };
3545
3546
3547 class HBoundsCheck final : public HTemplateInstruction<2> {
3548 public:
3549 DECLARE_INSTRUCTION_FACTORY_P2(HBoundsCheck, HValue*, HValue*);
3550
skip_check()3551 bool skip_check() const { return skip_check_; }
set_skip_check()3552 void set_skip_check() { skip_check_ = true; }
3553
base()3554 HValue* base() const { return base_; }
offset()3555 int offset() const { return offset_; }
scale()3556 int scale() const { return scale_; }
3557
RequiredInputRepresentation(int index)3558 Representation RequiredInputRepresentation(int index) override {
3559 return representation();
3560 }
3561
3562 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
3563 void InferRepresentation(HInferRepresentationPhase* h_infer) override;
3564
index()3565 HValue* index() const { return OperandAt(0); }
length()3566 HValue* length() const { return OperandAt(1); }
allow_equality()3567 bool allow_equality() const { return allow_equality_; }
set_allow_equality(bool v)3568 void set_allow_equality(bool v) { allow_equality_ = v; }
3569
RedefinedOperandIndex()3570 int RedefinedOperandIndex() override { return 0; }
IsPurelyInformativeDefinition()3571 bool IsPurelyInformativeDefinition() override { return skip_check(); }
3572
3573 DECLARE_CONCRETE_INSTRUCTION(BoundsCheck)
3574
3575 protected:
3576 Range* InferRange(Zone* zone) override;
3577
DataEquals(HValue * other)3578 bool DataEquals(HValue* other) override { return true; }
3579 bool skip_check_;
3580 HValue* base_;
3581 int offset_;
3582 int scale_;
3583 bool allow_equality_;
3584
3585 private:
3586 // Normally HBoundsCheck should be created using the
3587 // HGraphBuilder::AddBoundsCheck() helper.
3588 // However when building stubs, where we know that the arguments are Int32,
3589 // it makes sense to invoke this constructor directly.
HBoundsCheck(HValue * index,HValue * length)3590 HBoundsCheck(HValue* index, HValue* length)
3591 : skip_check_(false),
3592 base_(NULL), offset_(0), scale_(0),
3593 allow_equality_(false) {
3594 SetOperandAt(0, index);
3595 SetOperandAt(1, length);
3596 SetFlag(kFlexibleRepresentation);
3597 SetFlag(kUseGVN);
3598 }
3599
IsDeletable()3600 bool IsDeletable() const override { return skip_check() && !FLAG_debug_code; }
3601 };
3602
3603
3604 class HBitwiseBinaryOperation : public HBinaryOperation {
3605 public:
3606 HBitwiseBinaryOperation(HValue* context, HValue* left, HValue* right,
3607 HType type = HType::TaggedNumber())
HBinaryOperation(context,left,right,type)3608 : HBinaryOperation(context, left, right, type) {
3609 SetFlag(kFlexibleRepresentation);
3610 SetFlag(kTruncatingToInt32);
3611 SetFlag(kTruncatingToNumber);
3612 SetAllSideEffects();
3613 }
3614
RepresentationChanged(Representation to)3615 void RepresentationChanged(Representation to) override {
3616 if (to.IsTagged() &&
3617 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
3618 SetAllSideEffects();
3619 ClearFlag(kUseGVN);
3620 } else {
3621 ClearAllSideEffects();
3622 SetFlag(kUseGVN);
3623 }
3624 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
3625 }
3626
UpdateRepresentation(Representation new_rep,HInferRepresentationPhase * h_infer,const char * reason)3627 void UpdateRepresentation(Representation new_rep,
3628 HInferRepresentationPhase* h_infer,
3629 const char* reason) override {
3630 // We only generate either int32 or generic tagged bitwise operations.
3631 if (new_rep.IsDouble()) new_rep = Representation::Integer32();
3632 HBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
3633 }
3634
observed_input_representation(int index)3635 Representation observed_input_representation(int index) override {
3636 Representation r = HBinaryOperation::observed_input_representation(index);
3637 if (r.IsDouble()) return Representation::Integer32();
3638 return r;
3639 }
3640
initialize_output_representation(Representation observed)3641 void initialize_output_representation(Representation observed) override {
3642 if (observed.IsDouble()) observed = Representation::Integer32();
3643 HBinaryOperation::initialize_output_representation(observed);
3644 }
3645
DECLARE_ABSTRACT_INSTRUCTION(BitwiseBinaryOperation)3646 DECLARE_ABSTRACT_INSTRUCTION(BitwiseBinaryOperation)
3647
3648 private:
3649 bool IsDeletable() const override { return true; }
3650 };
3651
3652
3653 class HMathFloorOfDiv final : public HBinaryOperation {
3654 public:
3655 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HMathFloorOfDiv,
3656 HValue*,
3657 HValue*);
3658
DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv)3659 DECLARE_CONCRETE_INSTRUCTION(MathFloorOfDiv)
3660
3661 protected:
3662 bool DataEquals(HValue* other) override { return true; }
3663
3664 private:
HMathFloorOfDiv(HValue * context,HValue * left,HValue * right)3665 HMathFloorOfDiv(HValue* context, HValue* left, HValue* right)
3666 : HBinaryOperation(context, left, right) {
3667 set_representation(Representation::Integer32());
3668 SetFlag(kUseGVN);
3669 SetFlag(kCanOverflow);
3670 SetFlag(kCanBeDivByZero);
3671 SetFlag(kLeftCanBeMinInt);
3672 SetFlag(kLeftCanBeNegative);
3673 SetFlag(kLeftCanBePositive);
3674 SetFlag(kTruncatingToNumber);
3675 }
3676
3677 Range* InferRange(Zone* zone) override;
3678
IsDeletable()3679 bool IsDeletable() const override { return true; }
3680 };
3681
3682
3683 class HArithmeticBinaryOperation : public HBinaryOperation {
3684 public:
3685 HArithmeticBinaryOperation(HValue* context, HValue* left, HValue* right,
3686 HType type = HType::TaggedNumber())
HBinaryOperation(context,left,right,type)3687 : HBinaryOperation(context, left, right, type) {
3688 SetAllSideEffects();
3689 SetFlag(kFlexibleRepresentation);
3690 SetFlag(kTruncatingToNumber);
3691 }
3692
RepresentationChanged(Representation to)3693 void RepresentationChanged(Representation to) override {
3694 if (to.IsTagged() &&
3695 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved())) {
3696 SetAllSideEffects();
3697 ClearFlag(kUseGVN);
3698 } else {
3699 ClearAllSideEffects();
3700 SetFlag(kUseGVN);
3701 }
3702 if (to.IsTagged()) SetChangesFlag(kNewSpacePromotion);
3703 }
3704
DECLARE_ABSTRACT_INSTRUCTION(ArithmeticBinaryOperation)3705 DECLARE_ABSTRACT_INSTRUCTION(ArithmeticBinaryOperation)
3706
3707 private:
3708 bool IsDeletable() const override { return true; }
3709 };
3710
3711
3712 class HCompareGeneric final : public HBinaryOperation {
3713 public:
New(Isolate * isolate,Zone * zone,HValue * context,HValue * left,HValue * right,Token::Value token)3714 static HCompareGeneric* New(Isolate* isolate, Zone* zone, HValue* context,
3715 HValue* left, HValue* right, Token::Value token) {
3716 return new (zone) HCompareGeneric(context, left, right, token);
3717 }
3718
RequiredInputRepresentation(int index)3719 Representation RequiredInputRepresentation(int index) override {
3720 return index == 0
3721 ? Representation::Tagged()
3722 : representation();
3723 }
3724
token()3725 Token::Value token() const { return token_; }
3726 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
3727
DECLARE_CONCRETE_INSTRUCTION(CompareGeneric)3728 DECLARE_CONCRETE_INSTRUCTION(CompareGeneric)
3729
3730 private:
3731 HCompareGeneric(HValue* context, HValue* left, HValue* right,
3732 Token::Value token)
3733 : HBinaryOperation(context, left, right, HType::Boolean()),
3734 token_(token) {
3735 DCHECK(Token::IsCompareOp(token));
3736 set_representation(Representation::Tagged());
3737 SetAllSideEffects();
3738 }
3739
3740 Token::Value token_;
3741 };
3742
3743
3744 class HCompareNumericAndBranch : public HTemplateControlInstruction<2, 2> {
3745 public:
3746 static HCompareNumericAndBranch* New(Isolate* isolate, Zone* zone,
3747 HValue* context, HValue* left,
3748 HValue* right, Token::Value token,
3749 HBasicBlock* true_target = NULL,
3750 HBasicBlock* false_target = NULL) {
3751 return new (zone)
3752 HCompareNumericAndBranch(left, right, token, true_target, false_target);
3753 }
3754
left()3755 HValue* left() const { return OperandAt(0); }
right()3756 HValue* right() const { return OperandAt(1); }
token()3757 Token::Value token() const { return token_; }
3758
set_observed_input_representation(Representation left,Representation right)3759 void set_observed_input_representation(Representation left,
3760 Representation right) {
3761 observed_input_representation_[0] = left;
3762 observed_input_representation_[1] = right;
3763 }
3764
3765 void InferRepresentation(HInferRepresentationPhase* h_infer) override;
3766
RequiredInputRepresentation(int index)3767 Representation RequiredInputRepresentation(int index) override {
3768 return representation();
3769 }
observed_input_representation(int index)3770 Representation observed_input_representation(int index) override {
3771 return observed_input_representation_[index];
3772 }
3773
3774 bool KnownSuccessorBlock(HBasicBlock** block) override;
3775
3776 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
3777
DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch)3778 DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch)
3779
3780 private:
3781 HCompareNumericAndBranch(HValue* left, HValue* right, Token::Value token,
3782 HBasicBlock* true_target, HBasicBlock* false_target)
3783 : token_(token) {
3784 SetFlag(kFlexibleRepresentation);
3785 DCHECK(Token::IsCompareOp(token));
3786 SetOperandAt(0, left);
3787 SetOperandAt(1, right);
3788 SetSuccessorAt(0, true_target);
3789 SetSuccessorAt(1, false_target);
3790 }
3791
3792 Representation observed_input_representation_[2];
3793 Token::Value token_;
3794 };
3795
3796
3797 class HCompareHoleAndBranch final : public HUnaryControlInstruction {
3798 public:
3799 DECLARE_INSTRUCTION_FACTORY_P1(HCompareHoleAndBranch, HValue*);
3800 DECLARE_INSTRUCTION_FACTORY_P3(HCompareHoleAndBranch, HValue*,
3801 HBasicBlock*, HBasicBlock*);
3802
3803 void InferRepresentation(HInferRepresentationPhase* h_infer) override;
3804
RequiredInputRepresentation(int index)3805 Representation RequiredInputRepresentation(int index) override {
3806 return representation();
3807 }
3808
DECLARE_CONCRETE_INSTRUCTION(CompareHoleAndBranch)3809 DECLARE_CONCRETE_INSTRUCTION(CompareHoleAndBranch)
3810
3811 private:
3812 HCompareHoleAndBranch(HValue* value,
3813 HBasicBlock* true_target = NULL,
3814 HBasicBlock* false_target = NULL)
3815 : HUnaryControlInstruction(value, true_target, false_target) {
3816 SetFlag(kFlexibleRepresentation);
3817 }
3818 };
3819
3820
3821 class HCompareObjectEqAndBranch : public HTemplateControlInstruction<2, 2> {
3822 public:
3823 DECLARE_INSTRUCTION_FACTORY_P2(HCompareObjectEqAndBranch, HValue*, HValue*);
3824 DECLARE_INSTRUCTION_FACTORY_P4(HCompareObjectEqAndBranch, HValue*, HValue*,
3825 HBasicBlock*, HBasicBlock*);
3826
3827 bool KnownSuccessorBlock(HBasicBlock** block) override;
3828
3829 static const int kNoKnownSuccessorIndex = -1;
known_successor_index()3830 int known_successor_index() const { return known_successor_index_; }
set_known_successor_index(int known_successor_index)3831 void set_known_successor_index(int known_successor_index) {
3832 known_successor_index_ = known_successor_index;
3833 }
3834
left()3835 HValue* left() const { return OperandAt(0); }
right()3836 HValue* right() const { return OperandAt(1); }
3837
3838 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
3839
RequiredInputRepresentation(int index)3840 Representation RequiredInputRepresentation(int index) override {
3841 return Representation::Tagged();
3842 }
3843
observed_input_representation(int index)3844 Representation observed_input_representation(int index) override {
3845 return Representation::Tagged();
3846 }
3847
DECLARE_CONCRETE_INSTRUCTION(CompareObjectEqAndBranch)3848 DECLARE_CONCRETE_INSTRUCTION(CompareObjectEqAndBranch)
3849
3850 private:
3851 HCompareObjectEqAndBranch(HValue* left,
3852 HValue* right,
3853 HBasicBlock* true_target = NULL,
3854 HBasicBlock* false_target = NULL)
3855 : known_successor_index_(kNoKnownSuccessorIndex) {
3856 SetOperandAt(0, left);
3857 SetOperandAt(1, right);
3858 SetSuccessorAt(0, true_target);
3859 SetSuccessorAt(1, false_target);
3860 }
3861
3862 int known_successor_index_;
3863 };
3864
3865
3866 class HIsStringAndBranch final : public HUnaryControlInstruction {
3867 public:
3868 DECLARE_INSTRUCTION_FACTORY_P1(HIsStringAndBranch, HValue*);
3869 DECLARE_INSTRUCTION_FACTORY_P3(HIsStringAndBranch, HValue*,
3870 HBasicBlock*, HBasicBlock*);
3871
RequiredInputRepresentation(int index)3872 Representation RequiredInputRepresentation(int index) override {
3873 return Representation::Tagged();
3874 }
3875
3876 bool KnownSuccessorBlock(HBasicBlock** block) override;
3877
3878 static const int kNoKnownSuccessorIndex = -1;
known_successor_index()3879 int known_successor_index() const { return known_successor_index_; }
set_known_successor_index(int known_successor_index)3880 void set_known_successor_index(int known_successor_index) {
3881 known_successor_index_ = known_successor_index;
3882 }
3883
DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch)3884 DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch)
3885
3886 protected:
3887 int RedefinedOperandIndex() override { return 0; }
3888
3889 private:
3890 HIsStringAndBranch(HValue* value, HBasicBlock* true_target = NULL,
3891 HBasicBlock* false_target = NULL)
HUnaryControlInstruction(value,true_target,false_target)3892 : HUnaryControlInstruction(value, true_target, false_target),
3893 known_successor_index_(kNoKnownSuccessorIndex) {
3894 set_representation(Representation::Tagged());
3895 }
3896
3897 int known_successor_index_;
3898 };
3899
3900
3901 class HIsSmiAndBranch final : public HUnaryControlInstruction {
3902 public:
3903 DECLARE_INSTRUCTION_FACTORY_P1(HIsSmiAndBranch, HValue*);
3904 DECLARE_INSTRUCTION_FACTORY_P3(HIsSmiAndBranch, HValue*,
3905 HBasicBlock*, HBasicBlock*);
3906
DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch)3907 DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch)
3908
3909 Representation RequiredInputRepresentation(int index) override {
3910 return Representation::Tagged();
3911 }
3912
3913 protected:
DataEquals(HValue * other)3914 bool DataEquals(HValue* other) override { return true; }
RedefinedOperandIndex()3915 int RedefinedOperandIndex() override { return 0; }
3916
3917 private:
3918 HIsSmiAndBranch(HValue* value,
3919 HBasicBlock* true_target = NULL,
3920 HBasicBlock* false_target = NULL)
HUnaryControlInstruction(value,true_target,false_target)3921 : HUnaryControlInstruction(value, true_target, false_target) {
3922 set_representation(Representation::Tagged());
3923 }
3924 };
3925
3926
3927 class HIsUndetectableAndBranch final : public HUnaryControlInstruction {
3928 public:
3929 DECLARE_INSTRUCTION_FACTORY_P1(HIsUndetectableAndBranch, HValue*);
3930 DECLARE_INSTRUCTION_FACTORY_P3(HIsUndetectableAndBranch, HValue*,
3931 HBasicBlock*, HBasicBlock*);
3932
RequiredInputRepresentation(int index)3933 Representation RequiredInputRepresentation(int index) override {
3934 return Representation::Tagged();
3935 }
3936
3937 bool KnownSuccessorBlock(HBasicBlock** block) override;
3938
DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch)3939 DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch)
3940
3941 private:
3942 HIsUndetectableAndBranch(HValue* value,
3943 HBasicBlock* true_target = NULL,
3944 HBasicBlock* false_target = NULL)
3945 : HUnaryControlInstruction(value, true_target, false_target) {}
3946 };
3947
3948
3949 class HStringCompareAndBranch final : public HTemplateControlInstruction<2, 3> {
3950 public:
3951 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P3(HStringCompareAndBranch,
3952 HValue*,
3953 HValue*,
3954 Token::Value);
3955
context()3956 HValue* context() const { return OperandAt(0); }
left()3957 HValue* left() const { return OperandAt(1); }
right()3958 HValue* right() const { return OperandAt(2); }
token()3959 Token::Value token() const { return token_; }
3960
3961 std::ostream& PrintDataTo(std::ostream& os) const final; // NOLINT
3962
RequiredInputRepresentation(int index)3963 Representation RequiredInputRepresentation(int index) final {
3964 return Representation::Tagged();
3965 }
3966
DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch)3967 DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch)
3968
3969 private:
3970 HStringCompareAndBranch(HValue* context, HValue* left, HValue* right,
3971 Token::Value token)
3972 : token_(token) {
3973 DCHECK(Token::IsCompareOp(token));
3974 SetOperandAt(0, context);
3975 SetOperandAt(1, left);
3976 SetOperandAt(2, right);
3977 set_representation(Representation::Tagged());
3978 SetChangesFlag(kNewSpacePromotion);
3979 SetDependsOnFlag(kStringChars);
3980 SetDependsOnFlag(kStringLengths);
3981 }
3982
3983 Token::Value const token_;
3984 };
3985
3986
3987 class HHasInstanceTypeAndBranch final : public HUnaryControlInstruction {
3988 public:
3989 DECLARE_INSTRUCTION_FACTORY_P2(
3990 HHasInstanceTypeAndBranch, HValue*, InstanceType);
3991 DECLARE_INSTRUCTION_FACTORY_P3(
3992 HHasInstanceTypeAndBranch, HValue*, InstanceType, InstanceType);
3993
from()3994 InstanceType from() { return from_; }
to()3995 InstanceType to() { return to_; }
3996
3997 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
3998
RequiredInputRepresentation(int index)3999 Representation RequiredInputRepresentation(int index) override {
4000 return Representation::Tagged();
4001 }
4002
4003 bool KnownSuccessorBlock(HBasicBlock** block) override;
4004
DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch)4005 DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch)
4006
4007 private:
4008 HHasInstanceTypeAndBranch(HValue* value, InstanceType type)
4009 : HUnaryControlInstruction(value, NULL, NULL), from_(type), to_(type) { }
HHasInstanceTypeAndBranch(HValue * value,InstanceType from,InstanceType to)4010 HHasInstanceTypeAndBranch(HValue* value, InstanceType from, InstanceType to)
4011 : HUnaryControlInstruction(value, NULL, NULL), from_(from), to_(to) {
4012 DCHECK(to == LAST_TYPE); // Others not implemented yet in backend.
4013 }
4014
4015 InstanceType from_;
4016 InstanceType to_; // Inclusive range, not all combinations work.
4017 };
4018
4019 class HClassOfTestAndBranch final : public HUnaryControlInstruction {
4020 public:
4021 DECLARE_INSTRUCTION_FACTORY_P2(HClassOfTestAndBranch, HValue*,
4022 Handle<String>);
4023
DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch)4024 DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch)
4025
4026 Representation RequiredInputRepresentation(int index) override {
4027 return Representation::Tagged();
4028 }
4029
4030 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4031
class_name()4032 Handle<String> class_name() const { return class_name_; }
4033
4034 private:
HClassOfTestAndBranch(HValue * value,Handle<String> class_name)4035 HClassOfTestAndBranch(HValue* value, Handle<String> class_name)
4036 : HUnaryControlInstruction(value, NULL, NULL),
4037 class_name_(class_name) { }
4038
4039 Handle<String> class_name_;
4040 };
4041
4042
4043 class HTypeofIsAndBranch final : public HUnaryControlInstruction {
4044 public:
4045 DECLARE_INSTRUCTION_FACTORY_P2(HTypeofIsAndBranch, HValue*, Handle<String>);
4046
type_literal()4047 Handle<String> type_literal() const { return type_literal_.handle(); }
4048 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4049
DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch)4050 DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch)
4051
4052 Representation RequiredInputRepresentation(int index) override {
4053 return Representation::None();
4054 }
4055
4056 bool KnownSuccessorBlock(HBasicBlock** block) override;
4057
FinalizeUniqueness()4058 void FinalizeUniqueness() override {
4059 type_literal_ = Unique<String>(type_literal_.handle());
4060 }
4061
4062 private:
HTypeofIsAndBranch(HValue * value,Handle<String> type_literal)4063 HTypeofIsAndBranch(HValue* value, Handle<String> type_literal)
4064 : HUnaryControlInstruction(value, NULL, NULL),
4065 type_literal_(Unique<String>::CreateUninitialized(type_literal)) { }
4066
4067 Unique<String> type_literal_;
4068 };
4069
4070
4071 class HHasInPrototypeChainAndBranch final
4072 : public HTemplateControlInstruction<2, 2> {
4073 public:
4074 DECLARE_INSTRUCTION_FACTORY_P2(HHasInPrototypeChainAndBranch, HValue*,
4075 HValue*);
4076
object()4077 HValue* object() const { return OperandAt(0); }
prototype()4078 HValue* prototype() const { return OperandAt(1); }
4079
RequiredInputRepresentation(int index)4080 Representation RequiredInputRepresentation(int index) override {
4081 return Representation::Tagged();
4082 }
4083
ObjectNeedsSmiCheck()4084 bool ObjectNeedsSmiCheck() const {
4085 return !object()->type().IsHeapObject() &&
4086 !object()->representation().IsHeapObject();
4087 }
4088
DECLARE_CONCRETE_INSTRUCTION(HasInPrototypeChainAndBranch)4089 DECLARE_CONCRETE_INSTRUCTION(HasInPrototypeChainAndBranch)
4090
4091 private:
4092 HHasInPrototypeChainAndBranch(HValue* object, HValue* prototype) {
4093 SetOperandAt(0, object);
4094 SetOperandAt(1, prototype);
4095 SetDependsOnFlag(kCalls);
4096 }
4097 };
4098
4099
4100 class HPower final : public HTemplateInstruction<2> {
4101 public:
4102 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4103 HValue* left, HValue* right);
4104
left()4105 HValue* left() { return OperandAt(0); }
right()4106 HValue* right() const { return OperandAt(1); }
4107
RequiredInputRepresentation(int index)4108 Representation RequiredInputRepresentation(int index) override {
4109 return index == 0
4110 ? Representation::Double()
4111 : Representation::None();
4112 }
observed_input_representation(int index)4113 Representation observed_input_representation(int index) override {
4114 return RequiredInputRepresentation(index);
4115 }
4116
DECLARE_CONCRETE_INSTRUCTION(Power)4117 DECLARE_CONCRETE_INSTRUCTION(Power)
4118
4119 protected:
4120 bool DataEquals(HValue* other) override { return true; }
4121
4122 private:
HPower(HValue * left,HValue * right)4123 HPower(HValue* left, HValue* right) {
4124 SetOperandAt(0, left);
4125 SetOperandAt(1, right);
4126 set_representation(Representation::Double());
4127 SetFlag(kUseGVN);
4128 SetChangesFlag(kNewSpacePromotion);
4129 }
4130
IsDeletable()4131 bool IsDeletable() const override {
4132 return !right()->representation().IsTagged();
4133 }
4134 };
4135
4136
4137 enum ExternalAddType {
4138 AddOfExternalAndTagged,
4139 AddOfExternalAndInt32,
4140 NoExternalAdd
4141 };
4142
4143
4144 class HAdd final : public HArithmeticBinaryOperation {
4145 public:
4146 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4147 HValue* left, HValue* right);
4148 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4149 HValue* left, HValue* right,
4150 ExternalAddType external_add_type);
4151
4152 // Add is only commutative if two integer values are added and not if two
4153 // tagged values are added (because it might be a String concatenation).
4154 // We also do not commute (pointer + offset).
IsCommutative()4155 bool IsCommutative() const override {
4156 return !representation().IsTagged() && !representation().IsExternal();
4157 }
4158
4159 HValue* Canonicalize() override;
4160
RepresentationChanged(Representation to)4161 void RepresentationChanged(Representation to) override {
4162 if (to.IsTagged() &&
4163 (left()->ToNumberCanBeObserved() || right()->ToNumberCanBeObserved() ||
4164 left()->ToStringCanBeObserved() || right()->ToStringCanBeObserved())) {
4165 SetAllSideEffects();
4166 ClearFlag(kUseGVN);
4167 } else {
4168 ClearAllSideEffects();
4169 SetFlag(kUseGVN);
4170 }
4171 if (to.IsTagged()) {
4172 SetChangesFlag(kNewSpacePromotion);
4173 ClearFlag(kTruncatingToNumber);
4174 }
4175 if (!right()->type().IsTaggedNumber() &&
4176 !right()->representation().IsDouble() &&
4177 !right()->representation().IsSmiOrInteger32()) {
4178 ClearFlag(kTruncatingToNumber);
4179 }
4180 }
4181
4182 Representation RepresentationFromInputs() override;
4183
4184 Representation RequiredInputRepresentation(int index) override;
4185
IsConsistentExternalRepresentation()4186 bool IsConsistentExternalRepresentation() {
4187 return left()->representation().IsExternal() &&
4188 ((external_add_type_ == AddOfExternalAndInt32 &&
4189 right()->representation().IsInteger32()) ||
4190 (external_add_type_ == AddOfExternalAndTagged &&
4191 right()->representation().IsTagged()));
4192 }
4193
external_add_type()4194 ExternalAddType external_add_type() const { return external_add_type_; }
4195
DECLARE_CONCRETE_INSTRUCTION(Add)4196 DECLARE_CONCRETE_INSTRUCTION(Add)
4197
4198 protected:
4199 bool DataEquals(HValue* other) override { return true; }
4200
4201 Range* InferRange(Zone* zone) override;
4202
4203 private:
4204 HAdd(HValue* context, HValue* left, HValue* right,
4205 ExternalAddType external_add_type = NoExternalAdd)
HArithmeticBinaryOperation(context,left,right,HType::Tagged ())4206 : HArithmeticBinaryOperation(context, left, right, HType::Tagged()),
4207 external_add_type_(external_add_type) {
4208 SetFlag(kCanOverflow);
4209 switch (external_add_type_) {
4210 case AddOfExternalAndTagged:
4211 DCHECK(left->representation().IsExternal());
4212 DCHECK(right->representation().IsTagged());
4213 SetDependsOnFlag(kNewSpacePromotion);
4214 ClearFlag(HValue::kCanOverflow);
4215 SetFlag(kHasNoObservableSideEffects);
4216 break;
4217
4218 case NoExternalAdd:
4219 // This is a bit of a hack: The call to this constructor is generated
4220 // by a macro that also supports sub and mul, so it doesn't pass in
4221 // a value for external_add_type but uses the default.
4222 if (left->representation().IsExternal()) {
4223 external_add_type_ = AddOfExternalAndInt32;
4224 }
4225 break;
4226
4227 case AddOfExternalAndInt32:
4228 // See comment above.
4229 UNREACHABLE();
4230 break;
4231 }
4232 }
4233
4234 ExternalAddType external_add_type_;
4235 };
4236
4237
4238 class HSub final : public HArithmeticBinaryOperation {
4239 public:
4240 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4241 HValue* left, HValue* right);
4242
4243 HValue* Canonicalize() override;
4244
DECLARE_CONCRETE_INSTRUCTION(Sub)4245 DECLARE_CONCRETE_INSTRUCTION(Sub)
4246
4247 protected:
4248 bool DataEquals(HValue* other) override { return true; }
4249
4250 Range* InferRange(Zone* zone) override;
4251
4252 private:
HSub(HValue * context,HValue * left,HValue * right)4253 HSub(HValue* context, HValue* left, HValue* right)
4254 : HArithmeticBinaryOperation(context, left, right) {
4255 SetFlag(kCanOverflow);
4256 }
4257 };
4258
4259
4260 class HMul final : public HArithmeticBinaryOperation {
4261 public:
4262 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4263 HValue* left, HValue* right);
4264
NewImul(Isolate * isolate,Zone * zone,HValue * context,HValue * left,HValue * right)4265 static HInstruction* NewImul(Isolate* isolate, Zone* zone, HValue* context,
4266 HValue* left, HValue* right) {
4267 HInstruction* instr = HMul::New(isolate, zone, context, left, right);
4268 if (!instr->IsMul()) return instr;
4269 HMul* mul = HMul::cast(instr);
4270 // TODO(mstarzinger): Prevent bailout on minus zero for imul.
4271 mul->AssumeRepresentation(Representation::Integer32());
4272 mul->ClearFlag(HValue::kCanOverflow);
4273 return mul;
4274 }
4275
4276 HValue* Canonicalize() override;
4277
4278 // Only commutative if it is certain that not two objects are multiplicated.
IsCommutative()4279 bool IsCommutative() const override { return !representation().IsTagged(); }
4280
UpdateRepresentation(Representation new_rep,HInferRepresentationPhase * h_infer,const char * reason)4281 void UpdateRepresentation(Representation new_rep,
4282 HInferRepresentationPhase* h_infer,
4283 const char* reason) override {
4284 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4285 }
4286
4287 bool MulMinusOne();
4288
DECLARE_CONCRETE_INSTRUCTION(Mul)4289 DECLARE_CONCRETE_INSTRUCTION(Mul)
4290
4291 protected:
4292 bool DataEquals(HValue* other) override { return true; }
4293
4294 Range* InferRange(Zone* zone) override;
4295
4296 private:
HMul(HValue * context,HValue * left,HValue * right)4297 HMul(HValue* context, HValue* left, HValue* right)
4298 : HArithmeticBinaryOperation(context, left, right) {
4299 SetFlag(kCanOverflow);
4300 }
4301 };
4302
4303
4304 class HMod final : public HArithmeticBinaryOperation {
4305 public:
4306 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4307 HValue* left, HValue* right);
4308
4309 HValue* Canonicalize() override;
4310
UpdateRepresentation(Representation new_rep,HInferRepresentationPhase * h_infer,const char * reason)4311 void UpdateRepresentation(Representation new_rep,
4312 HInferRepresentationPhase* h_infer,
4313 const char* reason) override {
4314 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
4315 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4316 }
4317
DECLARE_CONCRETE_INSTRUCTION(Mod)4318 DECLARE_CONCRETE_INSTRUCTION(Mod)
4319
4320 protected:
4321 bool DataEquals(HValue* other) override { return true; }
4322
4323 Range* InferRange(Zone* zone) override;
4324
4325 private:
HMod(HValue * context,HValue * left,HValue * right)4326 HMod(HValue* context, HValue* left, HValue* right)
4327 : HArithmeticBinaryOperation(context, left, right) {
4328 SetFlag(kCanBeDivByZero);
4329 SetFlag(kCanOverflow);
4330 SetFlag(kLeftCanBeNegative);
4331 }
4332 };
4333
4334
4335 class HDiv final : public HArithmeticBinaryOperation {
4336 public:
4337 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4338 HValue* left, HValue* right);
4339
4340 HValue* Canonicalize() override;
4341
UpdateRepresentation(Representation new_rep,HInferRepresentationPhase * h_infer,const char * reason)4342 void UpdateRepresentation(Representation new_rep,
4343 HInferRepresentationPhase* h_infer,
4344 const char* reason) override {
4345 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
4346 HArithmeticBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4347 }
4348
DECLARE_CONCRETE_INSTRUCTION(Div)4349 DECLARE_CONCRETE_INSTRUCTION(Div)
4350
4351 protected:
4352 bool DataEquals(HValue* other) override { return true; }
4353
4354 Range* InferRange(Zone* zone) override;
4355
4356 private:
HDiv(HValue * context,HValue * left,HValue * right)4357 HDiv(HValue* context, HValue* left, HValue* right)
4358 : HArithmeticBinaryOperation(context, left, right) {
4359 SetFlag(kCanBeDivByZero);
4360 SetFlag(kCanOverflow);
4361 }
4362 };
4363
4364
4365 class HMathMinMax final : public HArithmeticBinaryOperation {
4366 public:
4367 enum Operation { kMathMin, kMathMax };
4368
4369 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4370 HValue* left, HValue* right, Operation op);
4371
observed_input_representation(int index)4372 Representation observed_input_representation(int index) override {
4373 return RequiredInputRepresentation(index);
4374 }
4375
4376 void InferRepresentation(HInferRepresentationPhase* h_infer) override;
4377
RepresentationFromInputs()4378 Representation RepresentationFromInputs() override {
4379 Representation left_rep = left()->representation();
4380 Representation right_rep = right()->representation();
4381 Representation result = Representation::Smi();
4382 result = result.generalize(left_rep);
4383 result = result.generalize(right_rep);
4384 if (result.IsTagged()) return Representation::Double();
4385 return result;
4386 }
4387
IsCommutative()4388 bool IsCommutative() const override { return true; }
4389
operation()4390 Operation operation() { return operation_; }
4391
DECLARE_CONCRETE_INSTRUCTION(MathMinMax)4392 DECLARE_CONCRETE_INSTRUCTION(MathMinMax)
4393
4394 protected:
4395 bool DataEquals(HValue* other) override {
4396 return other->IsMathMinMax() &&
4397 HMathMinMax::cast(other)->operation_ == operation_;
4398 }
4399
4400 Range* InferRange(Zone* zone) override;
4401
4402 private:
HMathMinMax(HValue * context,HValue * left,HValue * right,Operation op)4403 HMathMinMax(HValue* context, HValue* left, HValue* right, Operation op)
4404 : HArithmeticBinaryOperation(context, left, right), operation_(op) {}
4405
4406 Operation operation_;
4407 };
4408
4409
4410 class HBitwise final : public HBitwiseBinaryOperation {
4411 public:
4412 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4413 Token::Value op, HValue* left, HValue* right);
4414
op()4415 Token::Value op() const { return op_; }
4416
IsCommutative()4417 bool IsCommutative() const override { return true; }
4418
4419 HValue* Canonicalize() override;
4420
4421 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4422
DECLARE_CONCRETE_INSTRUCTION(Bitwise)4423 DECLARE_CONCRETE_INSTRUCTION(Bitwise)
4424
4425 protected:
4426 bool DataEquals(HValue* other) override {
4427 return op() == HBitwise::cast(other)->op();
4428 }
4429
4430 Range* InferRange(Zone* zone) override;
4431
4432 private:
HBitwise(HValue * context,Token::Value op,HValue * left,HValue * right)4433 HBitwise(HValue* context, Token::Value op, HValue* left, HValue* right)
4434 : HBitwiseBinaryOperation(context, left, right), op_(op) {
4435 DCHECK(op == Token::BIT_AND || op == Token::BIT_OR || op == Token::BIT_XOR);
4436 // BIT_AND with a smi-range positive value will always unset the
4437 // entire sign-extension of the smi-sign.
4438 if (op == Token::BIT_AND &&
4439 ((left->IsConstant() &&
4440 left->representation().IsSmi() &&
4441 HConstant::cast(left)->Integer32Value() >= 0) ||
4442 (right->IsConstant() &&
4443 right->representation().IsSmi() &&
4444 HConstant::cast(right)->Integer32Value() >= 0))) {
4445 SetFlag(kTruncatingToSmi);
4446 SetFlag(kTruncatingToInt32);
4447 // BIT_OR with a smi-range negative value will always set the entire
4448 // sign-extension of the smi-sign.
4449 } else if (op == Token::BIT_OR &&
4450 ((left->IsConstant() &&
4451 left->representation().IsSmi() &&
4452 HConstant::cast(left)->Integer32Value() < 0) ||
4453 (right->IsConstant() &&
4454 right->representation().IsSmi() &&
4455 HConstant::cast(right)->Integer32Value() < 0))) {
4456 SetFlag(kTruncatingToSmi);
4457 SetFlag(kTruncatingToInt32);
4458 }
4459 }
4460
4461 Token::Value op_;
4462 };
4463
4464
4465 class HShl final : public HBitwiseBinaryOperation {
4466 public:
4467 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4468 HValue* left, HValue* right);
4469
4470 Range* InferRange(Zone* zone) override;
4471
UpdateRepresentation(Representation new_rep,HInferRepresentationPhase * h_infer,const char * reason)4472 void UpdateRepresentation(Representation new_rep,
4473 HInferRepresentationPhase* h_infer,
4474 const char* reason) override {
4475 if (new_rep.IsSmi() &&
4476 !(right()->IsInteger32Constant() &&
4477 right()->GetInteger32Constant() >= 0)) {
4478 new_rep = Representation::Integer32();
4479 }
4480 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4481 }
4482
DECLARE_CONCRETE_INSTRUCTION(Shl)4483 DECLARE_CONCRETE_INSTRUCTION(Shl)
4484
4485 protected:
4486 bool DataEquals(HValue* other) override { return true; }
4487
4488 private:
HShl(HValue * context,HValue * left,HValue * right)4489 HShl(HValue* context, HValue* left, HValue* right)
4490 : HBitwiseBinaryOperation(context, left, right) {}
4491 };
4492
4493
4494 class HShr final : public HBitwiseBinaryOperation {
4495 public:
4496 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4497 HValue* left, HValue* right);
4498
4499 Range* InferRange(Zone* zone) override;
4500
UpdateRepresentation(Representation new_rep,HInferRepresentationPhase * h_infer,const char * reason)4501 void UpdateRepresentation(Representation new_rep,
4502 HInferRepresentationPhase* h_infer,
4503 const char* reason) override {
4504 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
4505 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4506 }
4507
DECLARE_CONCRETE_INSTRUCTION(Shr)4508 DECLARE_CONCRETE_INSTRUCTION(Shr)
4509
4510 protected:
4511 bool DataEquals(HValue* other) override { return true; }
4512
4513 private:
HShr(HValue * context,HValue * left,HValue * right)4514 HShr(HValue* context, HValue* left, HValue* right)
4515 : HBitwiseBinaryOperation(context, left, right) {}
4516 };
4517
4518
4519 class HSar final : public HBitwiseBinaryOperation {
4520 public:
4521 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4522 HValue* left, HValue* right);
4523
4524 Range* InferRange(Zone* zone) override;
4525
UpdateRepresentation(Representation new_rep,HInferRepresentationPhase * h_infer,const char * reason)4526 void UpdateRepresentation(Representation new_rep,
4527 HInferRepresentationPhase* h_infer,
4528 const char* reason) override {
4529 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
4530 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4531 }
4532
DECLARE_CONCRETE_INSTRUCTION(Sar)4533 DECLARE_CONCRETE_INSTRUCTION(Sar)
4534
4535 protected:
4536 bool DataEquals(HValue* other) override { return true; }
4537
4538 private:
HSar(HValue * context,HValue * left,HValue * right)4539 HSar(HValue* context, HValue* left, HValue* right)
4540 : HBitwiseBinaryOperation(context, left, right) {}
4541 };
4542
4543
4544 class HRor final : public HBitwiseBinaryOperation {
4545 public:
New(Isolate * isolate,Zone * zone,HValue * context,HValue * left,HValue * right)4546 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
4547 HValue* left, HValue* right) {
4548 return new (zone) HRor(context, left, right);
4549 }
4550
UpdateRepresentation(Representation new_rep,HInferRepresentationPhase * h_infer,const char * reason)4551 void UpdateRepresentation(Representation new_rep,
4552 HInferRepresentationPhase* h_infer,
4553 const char* reason) override {
4554 if (new_rep.IsSmi()) new_rep = Representation::Integer32();
4555 HBitwiseBinaryOperation::UpdateRepresentation(new_rep, h_infer, reason);
4556 }
4557
DECLARE_CONCRETE_INSTRUCTION(Ror)4558 DECLARE_CONCRETE_INSTRUCTION(Ror)
4559
4560 protected:
4561 bool DataEquals(HValue* other) override { return true; }
4562
4563 private:
HRor(HValue * context,HValue * left,HValue * right)4564 HRor(HValue* context, HValue* left, HValue* right)
4565 : HBitwiseBinaryOperation(context, left, right) {
4566 ChangeRepresentation(Representation::Integer32());
4567 }
4568 };
4569
4570
4571 class HOsrEntry final : public HTemplateInstruction<0> {
4572 public:
4573 DECLARE_INSTRUCTION_FACTORY_P1(HOsrEntry, BailoutId);
4574
ast_id()4575 BailoutId ast_id() const { return ast_id_; }
4576
RequiredInputRepresentation(int index)4577 Representation RequiredInputRepresentation(int index) override {
4578 return Representation::None();
4579 }
4580
DECLARE_CONCRETE_INSTRUCTION(OsrEntry)4581 DECLARE_CONCRETE_INSTRUCTION(OsrEntry)
4582
4583 private:
4584 explicit HOsrEntry(BailoutId ast_id) : ast_id_(ast_id) {
4585 SetChangesFlag(kOsrEntries);
4586 SetChangesFlag(kNewSpacePromotion);
4587 }
4588
4589 BailoutId ast_id_;
4590 };
4591
4592
4593 class HParameter final : public HTemplateInstruction<0> {
4594 public:
4595 enum ParameterKind {
4596 STACK_PARAMETER,
4597 REGISTER_PARAMETER
4598 };
4599
4600 DECLARE_INSTRUCTION_FACTORY_P1(HParameter, unsigned);
4601 DECLARE_INSTRUCTION_FACTORY_P2(HParameter, unsigned, ParameterKind);
4602 DECLARE_INSTRUCTION_FACTORY_P3(HParameter, unsigned, ParameterKind,
4603 Representation);
4604
index()4605 unsigned index() const { return index_; }
kind()4606 ParameterKind kind() const { return kind_; }
4607
4608 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4609
RequiredInputRepresentation(int index)4610 Representation RequiredInputRepresentation(int index) override {
4611 return Representation::None();
4612 }
4613
KnownOptimalRepresentation()4614 Representation KnownOptimalRepresentation() override {
4615 // If a parameter is an input to a phi, that phi should not
4616 // choose any more optimistic representation than Tagged.
4617 return Representation::Tagged();
4618 }
4619
DECLARE_CONCRETE_INSTRUCTION(Parameter)4620 DECLARE_CONCRETE_INSTRUCTION(Parameter)
4621
4622 private:
4623 explicit HParameter(unsigned index,
4624 ParameterKind kind = STACK_PARAMETER)
4625 : index_(index),
4626 kind_(kind) {
4627 set_representation(Representation::Tagged());
4628 }
4629
HParameter(unsigned index,ParameterKind kind,Representation r)4630 explicit HParameter(unsigned index,
4631 ParameterKind kind,
4632 Representation r)
4633 : index_(index),
4634 kind_(kind) {
4635 set_representation(r);
4636 }
4637
4638 unsigned index_;
4639 ParameterKind kind_;
4640 };
4641
4642
4643 class HUnknownOSRValue final : public HTemplateInstruction<0> {
4644 public:
4645 DECLARE_INSTRUCTION_FACTORY_P2(HUnknownOSRValue, HEnvironment*, int);
4646
4647 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4648
RequiredInputRepresentation(int index)4649 Representation RequiredInputRepresentation(int index) override {
4650 return Representation::None();
4651 }
4652
set_incoming_value(HPhi * value)4653 void set_incoming_value(HPhi* value) { incoming_value_ = value; }
incoming_value()4654 HPhi* incoming_value() { return incoming_value_; }
environment()4655 HEnvironment *environment() { return environment_; }
index()4656 int index() { return index_; }
4657
KnownOptimalRepresentation()4658 Representation KnownOptimalRepresentation() override {
4659 if (incoming_value_ == NULL) return Representation::None();
4660 return incoming_value_->KnownOptimalRepresentation();
4661 }
4662
DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue)4663 DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue)
4664
4665 private:
4666 HUnknownOSRValue(HEnvironment* environment, int index)
4667 : environment_(environment),
4668 index_(index),
4669 incoming_value_(NULL) {
4670 set_representation(Representation::Tagged());
4671 }
4672
4673 HEnvironment* environment_;
4674 int index_;
4675 HPhi* incoming_value_;
4676 };
4677
4678 class HAllocate final : public HTemplateInstruction<3> {
4679 public:
CompatibleInstanceTypes(InstanceType type1,InstanceType type2)4680 static bool CompatibleInstanceTypes(InstanceType type1,
4681 InstanceType type2) {
4682 return ComputeFlags(TENURED, type1) == ComputeFlags(TENURED, type2) &&
4683 ComputeFlags(NOT_TENURED, type1) == ComputeFlags(NOT_TENURED, type2);
4684 }
4685
4686 static HAllocate* New(
4687 Isolate* isolate, Zone* zone, HValue* context, HValue* size, HType type,
4688 PretenureFlag pretenure_flag, InstanceType instance_type,
4689 HValue* dominator,
4690 Handle<AllocationSite> allocation_site = Handle<AllocationSite>::null()) {
4691 return new (zone) HAllocate(context, size, type, pretenure_flag,
4692 instance_type, dominator, allocation_site);
4693 }
4694
4695 // Maximum instance size for which allocations will be inlined.
4696 static const int kMaxInlineSize = 64 * kPointerSize;
4697
context()4698 HValue* context() const { return OperandAt(0); }
size()4699 HValue* size() const { return OperandAt(1); }
allocation_folding_dominator()4700 HValue* allocation_folding_dominator() const { return OperandAt(2); }
4701
RequiredInputRepresentation(int index)4702 Representation RequiredInputRepresentation(int index) override {
4703 if (index == 0) {
4704 return Representation::Tagged();
4705 } else {
4706 return Representation::Integer32();
4707 }
4708 }
4709
GetMonomorphicJSObjectMap()4710 Handle<Map> GetMonomorphicJSObjectMap() override {
4711 return known_initial_map_;
4712 }
4713
set_known_initial_map(Handle<Map> known_initial_map)4714 void set_known_initial_map(Handle<Map> known_initial_map) {
4715 known_initial_map_ = known_initial_map;
4716 }
4717
IsNewSpaceAllocation()4718 bool IsNewSpaceAllocation() const {
4719 return (flags_ & ALLOCATE_IN_NEW_SPACE) != 0;
4720 }
4721
IsOldSpaceAllocation()4722 bool IsOldSpaceAllocation() const {
4723 return (flags_ & ALLOCATE_IN_OLD_SPACE) != 0;
4724 }
4725
MustAllocateDoubleAligned()4726 bool MustAllocateDoubleAligned() const {
4727 return (flags_ & ALLOCATE_DOUBLE_ALIGNED) != 0;
4728 }
4729
MustPrefillWithFiller()4730 bool MustPrefillWithFiller() const {
4731 return (flags_ & PREFILL_WITH_FILLER) != 0;
4732 }
4733
MakePrefillWithFiller()4734 void MakePrefillWithFiller() {
4735 flags_ = static_cast<HAllocate::Flags>(flags_ | PREFILL_WITH_FILLER);
4736 }
4737
MakeDoubleAligned()4738 void MakeDoubleAligned() {
4739 flags_ = static_cast<HAllocate::Flags>(flags_ | ALLOCATE_DOUBLE_ALIGNED);
4740 }
4741
MakeAllocationFoldingDominator()4742 void MakeAllocationFoldingDominator() {
4743 flags_ =
4744 static_cast<HAllocate::Flags>(flags_ | ALLOCATION_FOLDING_DOMINATOR);
4745 }
4746
IsAllocationFoldingDominator()4747 bool IsAllocationFoldingDominator() const {
4748 return (flags_ & ALLOCATION_FOLDING_DOMINATOR) != 0;
4749 }
4750
MakeFoldedAllocation(HAllocate * dominator)4751 void MakeFoldedAllocation(HAllocate* dominator) {
4752 flags_ = static_cast<HAllocate::Flags>(flags_ | ALLOCATION_FOLDED);
4753 ClearFlag(kTrackSideEffectDominators);
4754 ClearChangesFlag(kNewSpacePromotion);
4755 SetOperandAt(2, dominator);
4756 }
4757
IsAllocationFolded()4758 bool IsAllocationFolded() const { return (flags_ & ALLOCATION_FOLDED) != 0; }
4759
4760 bool HandleSideEffectDominator(GVNFlag side_effect,
4761 HValue* dominator) override;
4762
4763 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4764
4765 DECLARE_CONCRETE_INSTRUCTION(Allocate)
4766
4767 private:
4768 enum Flags {
4769 ALLOCATE_IN_NEW_SPACE = 1 << 0,
4770 ALLOCATE_IN_OLD_SPACE = 1 << 2,
4771 ALLOCATE_DOUBLE_ALIGNED = 1 << 3,
4772 PREFILL_WITH_FILLER = 1 << 4,
4773 ALLOCATION_FOLDING_DOMINATOR = 1 << 5,
4774 ALLOCATION_FOLDED = 1 << 6
4775 };
4776
4777 HAllocate(
4778 HValue* context, HValue* size, HType type, PretenureFlag pretenure_flag,
4779 InstanceType instance_type, HValue* dominator,
4780 Handle<AllocationSite> allocation_site = Handle<AllocationSite>::null())
4781 : HTemplateInstruction<3>(type),
4782 flags_(ComputeFlags(pretenure_flag, instance_type)) {
4783 SetOperandAt(0, context);
4784 UpdateSize(size);
4785 SetOperandAt(2, dominator);
4786 set_representation(Representation::Tagged());
4787 SetFlag(kTrackSideEffectDominators);
4788 SetChangesFlag(kNewSpacePromotion);
4789 SetDependsOnFlag(kNewSpacePromotion);
4790
4791 if (FLAG_trace_pretenuring) {
4792 PrintF("HAllocate with AllocationSite %p %s\n",
4793 allocation_site.is_null()
4794 ? static_cast<void*>(NULL)
4795 : static_cast<void*>(*allocation_site),
4796 pretenure_flag == TENURED ? "tenured" : "not tenured");
4797 }
4798 }
4799
ComputeFlags(PretenureFlag pretenure_flag,InstanceType instance_type)4800 static Flags ComputeFlags(PretenureFlag pretenure_flag,
4801 InstanceType instance_type) {
4802 Flags flags = pretenure_flag == TENURED ? ALLOCATE_IN_OLD_SPACE
4803 : ALLOCATE_IN_NEW_SPACE;
4804 if (instance_type == FIXED_DOUBLE_ARRAY_TYPE) {
4805 flags = static_cast<Flags>(flags | ALLOCATE_DOUBLE_ALIGNED);
4806 }
4807 // We have to fill the allocated object with one word fillers if we do
4808 // not use allocation folding since some allocations may depend on each
4809 // other, i.e., have a pointer to each other. A GC in between these
4810 // allocations may leave such objects behind in a not completely initialized
4811 // state.
4812 if (!FLAG_use_gvn || !FLAG_use_allocation_folding) {
4813 flags = static_cast<Flags>(flags | PREFILL_WITH_FILLER);
4814 }
4815 return flags;
4816 }
4817
UpdateSize(HValue * size)4818 void UpdateSize(HValue* size) {
4819 SetOperandAt(1, size);
4820 }
4821
IsFoldable(HAllocate * allocate)4822 bool IsFoldable(HAllocate* allocate) {
4823 return (IsNewSpaceAllocation() && allocate->IsNewSpaceAllocation()) ||
4824 (IsOldSpaceAllocation() && allocate->IsOldSpaceAllocation());
4825 }
4826
4827 Flags flags_;
4828 Handle<Map> known_initial_map_;
4829 };
4830
4831
4832 class HStoreCodeEntry final : public HTemplateInstruction<2> {
4833 public:
New(Isolate * isolate,Zone * zone,HValue * context,HValue * function,HValue * code)4834 static HStoreCodeEntry* New(Isolate* isolate, Zone* zone, HValue* context,
4835 HValue* function, HValue* code) {
4836 return new(zone) HStoreCodeEntry(function, code);
4837 }
4838
RequiredInputRepresentation(int index)4839 Representation RequiredInputRepresentation(int index) override {
4840 return Representation::Tagged();
4841 }
4842
function()4843 HValue* function() { return OperandAt(0); }
code_object()4844 HValue* code_object() { return OperandAt(1); }
4845
DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry)4846 DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry)
4847
4848 private:
4849 HStoreCodeEntry(HValue* function, HValue* code) {
4850 SetOperandAt(0, function);
4851 SetOperandAt(1, code);
4852 }
4853 };
4854
4855
4856 class HInnerAllocatedObject final : public HTemplateInstruction<2> {
4857 public:
New(Isolate * isolate,Zone * zone,HValue * context,HValue * value,HValue * offset,HType type)4858 static HInnerAllocatedObject* New(Isolate* isolate, Zone* zone,
4859 HValue* context, HValue* value,
4860 HValue* offset, HType type) {
4861 return new(zone) HInnerAllocatedObject(value, offset, type);
4862 }
4863
base_object()4864 HValue* base_object() const { return OperandAt(0); }
offset()4865 HValue* offset() const { return OperandAt(1); }
4866
RequiredInputRepresentation(int index)4867 Representation RequiredInputRepresentation(int index) override {
4868 return index == 0 ? Representation::Tagged() : Representation::Integer32();
4869 }
4870
4871 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4872
DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject)4873 DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject)
4874
4875 private:
4876 HInnerAllocatedObject(HValue* value,
4877 HValue* offset,
4878 HType type) : HTemplateInstruction<2>(type) {
4879 DCHECK(value->IsAllocate());
4880 DCHECK(type.IsHeapObject());
4881 SetOperandAt(0, value);
4882 SetOperandAt(1, offset);
4883 set_representation(Representation::Tagged());
4884 }
4885 };
4886
4887
StoringValueNeedsWriteBarrier(HValue * value)4888 inline bool StoringValueNeedsWriteBarrier(HValue* value) {
4889 return !value->type().IsSmi()
4890 && !value->type().IsNull()
4891 && !value->type().IsBoolean()
4892 && !value->type().IsUndefined()
4893 && !(value->IsConstant() && HConstant::cast(value)->ImmortalImmovable());
4894 }
4895
4896
ReceiverObjectNeedsWriteBarrier(HValue * object,HValue * value,HValue * dominator)4897 inline bool ReceiverObjectNeedsWriteBarrier(HValue* object,
4898 HValue* value,
4899 HValue* dominator) {
4900 // There may be multiple inner allocates dominated by one allocate.
4901 while (object->IsInnerAllocatedObject()) {
4902 object = HInnerAllocatedObject::cast(object)->base_object();
4903 }
4904
4905 if (object->IsAllocate()) {
4906 HAllocate* allocate = HAllocate::cast(object);
4907 if (allocate->IsAllocationFolded()) {
4908 HValue* dominator = allocate->allocation_folding_dominator();
4909 // There is no guarantee that all allocations are folded together because
4910 // GVN performs a fixpoint.
4911 if (HAllocate::cast(dominator)->IsAllocationFoldingDominator()) {
4912 object = dominator;
4913 }
4914 }
4915 }
4916
4917 if (object->IsConstant() &&
4918 HConstant::cast(object)->HasExternalReferenceValue()) {
4919 // Stores to external references require no write barriers
4920 return false;
4921 }
4922 // We definitely need a write barrier unless the object is the allocation
4923 // dominator.
4924 if (object == dominator && object->IsAllocate()) {
4925 // Stores to new space allocations require no write barriers.
4926 if (HAllocate::cast(object)->IsNewSpaceAllocation()) {
4927 return false;
4928 }
4929 }
4930 return true;
4931 }
4932
4933
PointersToHereCheckForObject(HValue * object,HValue * dominator)4934 inline PointersToHereCheck PointersToHereCheckForObject(HValue* object,
4935 HValue* dominator) {
4936 while (object->IsInnerAllocatedObject()) {
4937 object = HInnerAllocatedObject::cast(object)->base_object();
4938 }
4939 if (object == dominator &&
4940 object->IsAllocate() &&
4941 HAllocate::cast(object)->IsNewSpaceAllocation()) {
4942 return kPointersToHereAreAlwaysInteresting;
4943 }
4944 return kPointersToHereMaybeInteresting;
4945 }
4946
4947
4948 class HLoadContextSlot final : public HUnaryOperation {
4949 public:
4950 enum Mode {
4951 // Perform a normal load of the context slot without checking its value.
4952 kNoCheck,
4953 // Load and check the value of the context slot. Deoptimize if it's the
4954 // hole value. This is used for checking for loading of uninitialized
4955 // harmony bindings where we deoptimize into full-codegen generated code
4956 // which will subsequently throw a reference error.
4957 kCheckDeoptimize
4958 };
4959
HLoadContextSlot(HValue * context,int slot_index,Mode mode)4960 HLoadContextSlot(HValue* context, int slot_index, Mode mode)
4961 : HUnaryOperation(context), slot_index_(slot_index), mode_(mode) {
4962 set_representation(Representation::Tagged());
4963 SetFlag(kUseGVN);
4964 SetDependsOnFlag(kContextSlots);
4965 }
4966
slot_index()4967 int slot_index() const { return slot_index_; }
mode()4968 Mode mode() const { return mode_; }
4969
DeoptimizesOnHole()4970 bool DeoptimizesOnHole() {
4971 return mode_ == kCheckDeoptimize;
4972 }
4973
RequiresHoleCheck()4974 bool RequiresHoleCheck() const {
4975 return mode_ != kNoCheck;
4976 }
4977
RequiredInputRepresentation(int index)4978 Representation RequiredInputRepresentation(int index) override {
4979 return Representation::Tagged();
4980 }
4981
4982 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
4983
DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot)4984 DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot)
4985
4986 protected:
4987 bool DataEquals(HValue* other) override {
4988 HLoadContextSlot* b = HLoadContextSlot::cast(other);
4989 return (slot_index() == b->slot_index());
4990 }
4991
4992 private:
IsDeletable()4993 bool IsDeletable() const override { return !RequiresHoleCheck(); }
4994
4995 int slot_index_;
4996 Mode mode_;
4997 };
4998
4999
5000 class HStoreContextSlot final : public HTemplateInstruction<2> {
5001 public:
5002 enum Mode {
5003 // Perform a normal store to the context slot without checking its previous
5004 // value.
5005 kNoCheck,
5006 // Check the previous value of the context slot and deoptimize if it's the
5007 // hole value. This is used for checking for assignments to uninitialized
5008 // harmony bindings where we deoptimize into full-codegen generated code
5009 // which will subsequently throw a reference error.
5010 kCheckDeoptimize
5011 };
5012
5013 DECLARE_INSTRUCTION_FACTORY_P4(HStoreContextSlot, HValue*, int,
5014 Mode, HValue*);
5015
context()5016 HValue* context() const { return OperandAt(0); }
value()5017 HValue* value() const { return OperandAt(1); }
slot_index()5018 int slot_index() const { return slot_index_; }
mode()5019 Mode mode() const { return mode_; }
5020
NeedsWriteBarrier()5021 bool NeedsWriteBarrier() {
5022 return StoringValueNeedsWriteBarrier(value());
5023 }
5024
DeoptimizesOnHole()5025 bool DeoptimizesOnHole() {
5026 return mode_ == kCheckDeoptimize;
5027 }
5028
RequiresHoleCheck()5029 bool RequiresHoleCheck() {
5030 return mode_ != kNoCheck;
5031 }
5032
RequiredInputRepresentation(int index)5033 Representation RequiredInputRepresentation(int index) override {
5034 return Representation::Tagged();
5035 }
5036
5037 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5038
DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot)5039 DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot)
5040
5041 private:
5042 HStoreContextSlot(HValue* context, int slot_index, Mode mode, HValue* value)
5043 : slot_index_(slot_index), mode_(mode) {
5044 SetOperandAt(0, context);
5045 SetOperandAt(1, value);
5046 SetChangesFlag(kContextSlots);
5047 }
5048
5049 int slot_index_;
5050 Mode mode_;
5051 };
5052
5053
5054 // Represents an access to a portion of an object, such as the map pointer,
5055 // array elements pointer, etc, but not accesses to array elements themselves.
5056 class HObjectAccess final {
5057 public:
IsInobject()5058 inline bool IsInobject() const {
5059 return portion() != kBackingStore && portion() != kExternalMemory;
5060 }
5061
IsExternalMemory()5062 inline bool IsExternalMemory() const {
5063 return portion() == kExternalMemory;
5064 }
5065
IsStringLength()5066 inline bool IsStringLength() const {
5067 return portion() == kStringLengths;
5068 }
5069
IsMap()5070 inline bool IsMap() const {
5071 return portion() == kMaps;
5072 }
5073
offset()5074 inline int offset() const {
5075 return OffsetField::decode(value_);
5076 }
5077
representation()5078 inline Representation representation() const {
5079 return Representation::FromKind(RepresentationField::decode(value_));
5080 }
5081
name()5082 inline Handle<Name> name() const { return name_; }
5083
immutable()5084 inline bool immutable() const {
5085 return ImmutableField::decode(value_);
5086 }
5087
5088 // Returns true if access is being made to an in-object property that
5089 // was already added to the object.
existing_inobject_property()5090 inline bool existing_inobject_property() const {
5091 return ExistingInobjectPropertyField::decode(value_);
5092 }
5093
WithRepresentation(Representation representation)5094 inline HObjectAccess WithRepresentation(Representation representation) {
5095 return HObjectAccess(portion(), offset(), representation, name(),
5096 immutable(), existing_inobject_property());
5097 }
5098
ForHeapNumberValue()5099 static HObjectAccess ForHeapNumberValue() {
5100 return HObjectAccess(
5101 kDouble, HeapNumber::kValueOffset, Representation::Double());
5102 }
5103
ForHeapNumberValueLowestBits()5104 static HObjectAccess ForHeapNumberValueLowestBits() {
5105 return HObjectAccess(kDouble,
5106 HeapNumber::kValueOffset,
5107 Representation::Integer32());
5108 }
5109
ForHeapNumberValueHighestBits()5110 static HObjectAccess ForHeapNumberValueHighestBits() {
5111 return HObjectAccess(kDouble,
5112 HeapNumber::kValueOffset + kIntSize,
5113 Representation::Integer32());
5114 }
5115
5116 static HObjectAccess ForOddballToNumber(
5117 Representation representation = Representation::Tagged()) {
5118 return HObjectAccess(kInobject, Oddball::kToNumberOffset, representation);
5119 }
5120
ForOddballTypeOf()5121 static HObjectAccess ForOddballTypeOf() {
5122 return HObjectAccess(kInobject, Oddball::kTypeOfOffset,
5123 Representation::HeapObject());
5124 }
5125
ForElementsPointer()5126 static HObjectAccess ForElementsPointer() {
5127 return HObjectAccess(kElementsPointer, JSObject::kElementsOffset);
5128 }
5129
ForLiteralsPointer()5130 static HObjectAccess ForLiteralsPointer() {
5131 return HObjectAccess(kInobject, JSFunction::kLiteralsOffset);
5132 }
5133
ForNextFunctionLinkPointer()5134 static HObjectAccess ForNextFunctionLinkPointer() {
5135 return HObjectAccess(kInobject, JSFunction::kNextFunctionLinkOffset);
5136 }
5137
ForArrayLength(ElementsKind elements_kind)5138 static HObjectAccess ForArrayLength(ElementsKind elements_kind) {
5139 return HObjectAccess(
5140 kArrayLengths,
5141 JSArray::kLengthOffset,
5142 IsFastElementsKind(elements_kind)
5143 ? Representation::Smi() : Representation::Tagged());
5144 }
5145
5146 static HObjectAccess ForAllocationSiteOffset(int offset);
5147
ForAllocationSiteList()5148 static HObjectAccess ForAllocationSiteList() {
5149 return HObjectAccess(kExternalMemory, 0, Representation::Tagged(),
5150 Handle<Name>::null(), false, false);
5151 }
5152
ForFixedArrayLength()5153 static HObjectAccess ForFixedArrayLength() {
5154 return HObjectAccess(
5155 kArrayLengths,
5156 FixedArray::kLengthOffset,
5157 Representation::Smi());
5158 }
5159
ForFixedTypedArrayBaseBasePointer()5160 static HObjectAccess ForFixedTypedArrayBaseBasePointer() {
5161 return HObjectAccess(kInobject, FixedTypedArrayBase::kBasePointerOffset,
5162 Representation::Tagged());
5163 }
5164
ForFixedTypedArrayBaseExternalPointer()5165 static HObjectAccess ForFixedTypedArrayBaseExternalPointer() {
5166 return HObjectAccess::ForObservableJSObjectOffset(
5167 FixedTypedArrayBase::kExternalPointerOffset,
5168 Representation::External());
5169 }
5170
ForStringHashField()5171 static HObjectAccess ForStringHashField() {
5172 return HObjectAccess(kInobject,
5173 String::kHashFieldOffset,
5174 Representation::Integer32());
5175 }
5176
ForStringLength()5177 static HObjectAccess ForStringLength() {
5178 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue);
5179 return HObjectAccess(
5180 kStringLengths,
5181 String::kLengthOffset,
5182 Representation::Smi());
5183 }
5184
ForConsStringFirst()5185 static HObjectAccess ForConsStringFirst() {
5186 return HObjectAccess(kInobject, ConsString::kFirstOffset);
5187 }
5188
ForConsStringSecond()5189 static HObjectAccess ForConsStringSecond() {
5190 return HObjectAccess(kInobject, ConsString::kSecondOffset);
5191 }
5192
ForPropertiesPointer()5193 static HObjectAccess ForPropertiesPointer() {
5194 return HObjectAccess(kInobject, JSObject::kPropertiesOffset);
5195 }
5196
ForPrototypeOrInitialMap()5197 static HObjectAccess ForPrototypeOrInitialMap() {
5198 return HObjectAccess(kInobject, JSFunction::kPrototypeOrInitialMapOffset);
5199 }
5200
ForSharedFunctionInfoPointer()5201 static HObjectAccess ForSharedFunctionInfoPointer() {
5202 return HObjectAccess(kInobject, JSFunction::kSharedFunctionInfoOffset);
5203 }
5204
ForCodeEntryPointer()5205 static HObjectAccess ForCodeEntryPointer() {
5206 return HObjectAccess(kInobject, JSFunction::kCodeEntryOffset);
5207 }
5208
ForCodeOffset()5209 static HObjectAccess ForCodeOffset() {
5210 return HObjectAccess(kInobject, SharedFunctionInfo::kCodeOffset);
5211 }
5212
ForOptimizedCodeMap()5213 static HObjectAccess ForOptimizedCodeMap() {
5214 return HObjectAccess(kInobject,
5215 SharedFunctionInfo::kOptimizedCodeMapOffset);
5216 }
5217
ForFunctionContextPointer()5218 static HObjectAccess ForFunctionContextPointer() {
5219 return HObjectAccess(kInobject, JSFunction::kContextOffset);
5220 }
5221
ForMap()5222 static HObjectAccess ForMap() {
5223 return HObjectAccess(kMaps, JSObject::kMapOffset);
5224 }
5225
ForPrototype()5226 static HObjectAccess ForPrototype() {
5227 return HObjectAccess(kMaps, Map::kPrototypeOffset);
5228 }
5229
ForMapAsInteger32()5230 static HObjectAccess ForMapAsInteger32() {
5231 return HObjectAccess(kMaps, JSObject::kMapOffset,
5232 Representation::Integer32());
5233 }
5234
ForMapInObjectPropertiesOrConstructorFunctionIndex()5235 static HObjectAccess ForMapInObjectPropertiesOrConstructorFunctionIndex() {
5236 return HObjectAccess(
5237 kInobject, Map::kInObjectPropertiesOrConstructorFunctionIndexOffset,
5238 Representation::UInteger8());
5239 }
5240
ForMapInstanceType()5241 static HObjectAccess ForMapInstanceType() {
5242 return HObjectAccess(kInobject,
5243 Map::kInstanceTypeOffset,
5244 Representation::UInteger8());
5245 }
5246
ForMapInstanceSize()5247 static HObjectAccess ForMapInstanceSize() {
5248 return HObjectAccess(kInobject,
5249 Map::kInstanceSizeOffset,
5250 Representation::UInteger8());
5251 }
5252
ForMapBitField()5253 static HObjectAccess ForMapBitField() {
5254 return HObjectAccess(kInobject,
5255 Map::kBitFieldOffset,
5256 Representation::UInteger8());
5257 }
5258
ForMapBitField2()5259 static HObjectAccess ForMapBitField2() {
5260 return HObjectAccess(kInobject,
5261 Map::kBitField2Offset,
5262 Representation::UInteger8());
5263 }
5264
ForMapBitField3()5265 static HObjectAccess ForMapBitField3() {
5266 return HObjectAccess(kInobject, Map::kBitField3Offset,
5267 Representation::Integer32());
5268 }
5269
ForMapDescriptors()5270 static HObjectAccess ForMapDescriptors() {
5271 return HObjectAccess(kInobject, Map::kDescriptorsOffset);
5272 }
5273
ForNameHashField()5274 static HObjectAccess ForNameHashField() {
5275 return HObjectAccess(kInobject,
5276 Name::kHashFieldOffset,
5277 Representation::Integer32());
5278 }
5279
ForMapInstanceTypeAndBitField()5280 static HObjectAccess ForMapInstanceTypeAndBitField() {
5281 STATIC_ASSERT((Map::kInstanceTypeAndBitFieldOffset & 1) == 0);
5282 // Ensure the two fields share one 16-bit word, endian-independent.
5283 STATIC_ASSERT((Map::kBitFieldOffset & ~1) ==
5284 (Map::kInstanceTypeOffset & ~1));
5285 return HObjectAccess(kInobject,
5286 Map::kInstanceTypeAndBitFieldOffset,
5287 Representation::UInteger16());
5288 }
5289
ForPropertyCellValue()5290 static HObjectAccess ForPropertyCellValue() {
5291 return HObjectAccess(kInobject, PropertyCell::kValueOffset);
5292 }
5293
ForPropertyCellDetails()5294 static HObjectAccess ForPropertyCellDetails() {
5295 return HObjectAccess(kInobject, PropertyCell::kDetailsOffset,
5296 Representation::Smi());
5297 }
5298
ForCellValue()5299 static HObjectAccess ForCellValue() {
5300 return HObjectAccess(kInobject, Cell::kValueOffset);
5301 }
5302
ForWeakCellValue()5303 static HObjectAccess ForWeakCellValue() {
5304 return HObjectAccess(kInobject, WeakCell::kValueOffset);
5305 }
5306
ForWeakCellNext()5307 static HObjectAccess ForWeakCellNext() {
5308 return HObjectAccess(kInobject, WeakCell::kNextOffset);
5309 }
5310
ForAllocationMementoSite()5311 static HObjectAccess ForAllocationMementoSite() {
5312 return HObjectAccess(kInobject, AllocationMemento::kAllocationSiteOffset);
5313 }
5314
ForCounter()5315 static HObjectAccess ForCounter() {
5316 return HObjectAccess(kExternalMemory, 0, Representation::Integer32(),
5317 Handle<Name>::null(), false, false);
5318 }
5319
ForExternalUInteger8()5320 static HObjectAccess ForExternalUInteger8() {
5321 return HObjectAccess(kExternalMemory, 0, Representation::UInteger8(),
5322 Handle<Name>::null(), false, false);
5323 }
5324
ForBoundTargetFunction()5325 static HObjectAccess ForBoundTargetFunction() {
5326 return HObjectAccess(kInobject,
5327 JSBoundFunction::kBoundTargetFunctionOffset);
5328 }
5329
ForBoundThis()5330 static HObjectAccess ForBoundThis() {
5331 return HObjectAccess(kInobject, JSBoundFunction::kBoundThisOffset);
5332 }
5333
ForBoundArguments()5334 static HObjectAccess ForBoundArguments() {
5335 return HObjectAccess(kInobject, JSBoundFunction::kBoundArgumentsOffset);
5336 }
5337
5338 // Create an access to an offset in a fixed array header.
5339 static HObjectAccess ForFixedArrayHeader(int offset);
5340
5341 // Create an access to an in-object property in a JSObject.
5342 // This kind of access must be used when the object |map| is known and
5343 // in-object properties are being accessed. Accesses of the in-object
5344 // properties can have different semantics depending on whether corresponding
5345 // property was added to the map or not.
5346 static HObjectAccess ForMapAndOffset(Handle<Map> map, int offset,
5347 Representation representation = Representation::Tagged());
5348
5349 // Create an access to an in-object property in a JSObject.
5350 // This kind of access can be used for accessing object header fields or
5351 // in-object properties if the map of the object is not known.
5352 static HObjectAccess ForObservableJSObjectOffset(int offset,
5353 Representation representation = Representation::Tagged()) {
5354 return ForMapAndOffset(Handle<Map>::null(), offset, representation);
5355 }
5356
5357 // Create an access to an in-object property in a JSArray.
5358 static HObjectAccess ForJSArrayOffset(int offset);
5359
5360 static HObjectAccess ForContextSlot(int index);
5361
5362 static HObjectAccess ForScriptContext(int index);
5363
5364 // Create an access to the backing store of an object.
5365 static HObjectAccess ForBackingStoreOffset(int offset,
5366 Representation representation = Representation::Tagged());
5367
5368 // Create an access to a resolved field (in-object or backing store).
5369 static HObjectAccess ForField(Handle<Map> map, int index,
5370 Representation representation,
5371 Handle<Name> name);
5372
ForJSTypedArrayLength()5373 static HObjectAccess ForJSTypedArrayLength() {
5374 return HObjectAccess::ForObservableJSObjectOffset(
5375 JSTypedArray::kLengthOffset);
5376 }
5377
ForJSArrayBufferBackingStore()5378 static HObjectAccess ForJSArrayBufferBackingStore() {
5379 return HObjectAccess::ForObservableJSObjectOffset(
5380 JSArrayBuffer::kBackingStoreOffset, Representation::External());
5381 }
5382
ForJSArrayBufferByteLength()5383 static HObjectAccess ForJSArrayBufferByteLength() {
5384 return HObjectAccess::ForObservableJSObjectOffset(
5385 JSArrayBuffer::kByteLengthOffset, Representation::Tagged());
5386 }
5387
ForJSArrayBufferBitField()5388 static HObjectAccess ForJSArrayBufferBitField() {
5389 return HObjectAccess::ForObservableJSObjectOffset(
5390 JSArrayBuffer::kBitFieldOffset, Representation::Integer32());
5391 }
5392
ForJSArrayBufferBitFieldSlot()5393 static HObjectAccess ForJSArrayBufferBitFieldSlot() {
5394 return HObjectAccess::ForObservableJSObjectOffset(
5395 JSArrayBuffer::kBitFieldSlot, Representation::Smi());
5396 }
5397
ForJSArrayBufferViewBuffer()5398 static HObjectAccess ForJSArrayBufferViewBuffer() {
5399 return HObjectAccess::ForObservableJSObjectOffset(
5400 JSArrayBufferView::kBufferOffset);
5401 }
5402
ForJSArrayBufferViewByteOffset()5403 static HObjectAccess ForJSArrayBufferViewByteOffset() {
5404 return HObjectAccess::ForObservableJSObjectOffset(
5405 JSArrayBufferView::kByteOffsetOffset);
5406 }
5407
ForJSArrayBufferViewByteLength()5408 static HObjectAccess ForJSArrayBufferViewByteLength() {
5409 return HObjectAccess::ForObservableJSObjectOffset(
5410 JSArrayBufferView::kByteLengthOffset);
5411 }
5412
ForJSGlobalObjectNativeContext()5413 static HObjectAccess ForJSGlobalObjectNativeContext() {
5414 return HObjectAccess(kInobject, JSGlobalObject::kNativeContextOffset);
5415 }
5416
ForJSRegExpFlags()5417 static HObjectAccess ForJSRegExpFlags() {
5418 return HObjectAccess(kInobject, JSRegExp::kFlagsOffset);
5419 }
5420
ForJSRegExpSource()5421 static HObjectAccess ForJSRegExpSource() {
5422 return HObjectAccess(kInobject, JSRegExp::kSourceOffset);
5423 }
5424
ForJSCollectionTable()5425 static HObjectAccess ForJSCollectionTable() {
5426 return HObjectAccess::ForObservableJSObjectOffset(
5427 JSCollection::kTableOffset);
5428 }
5429
5430 template <typename CollectionType>
ForOrderedHashTableNumberOfBuckets()5431 static HObjectAccess ForOrderedHashTableNumberOfBuckets() {
5432 return HObjectAccess(kInobject, CollectionType::kNumberOfBucketsOffset,
5433 Representation::Smi());
5434 }
5435
5436 template <typename CollectionType>
ForOrderedHashTableNumberOfElements()5437 static HObjectAccess ForOrderedHashTableNumberOfElements() {
5438 return HObjectAccess(kInobject, CollectionType::kNumberOfElementsOffset,
5439 Representation::Smi());
5440 }
5441
5442 template <typename CollectionType>
ForOrderedHashTableNumberOfDeletedElements()5443 static HObjectAccess ForOrderedHashTableNumberOfDeletedElements() {
5444 return HObjectAccess(kInobject,
5445 CollectionType::kNumberOfDeletedElementsOffset,
5446 Representation::Smi());
5447 }
5448
5449 template <typename CollectionType>
ForOrderedHashTableNextTable()5450 static HObjectAccess ForOrderedHashTableNextTable() {
5451 return HObjectAccess(kInobject, CollectionType::kNextTableOffset);
5452 }
5453
5454 template <typename CollectionType>
ForOrderedHashTableBucket(int bucket)5455 static HObjectAccess ForOrderedHashTableBucket(int bucket) {
5456 return HObjectAccess(kInobject, CollectionType::kHashTableStartOffset +
5457 (bucket * kPointerSize),
5458 Representation::Smi());
5459 }
5460
5461 // Access into the data table of an OrderedHashTable with a
5462 // known-at-compile-time bucket count.
5463 template <typename CollectionType, int kBucketCount>
ForOrderedHashTableDataTableIndex(int index)5464 static HObjectAccess ForOrderedHashTableDataTableIndex(int index) {
5465 return HObjectAccess(kInobject, CollectionType::kHashTableStartOffset +
5466 (kBucketCount * kPointerSize) +
5467 (index * kPointerSize));
5468 }
5469
Equals(HObjectAccess that)5470 inline bool Equals(HObjectAccess that) const {
5471 return value_ == that.value_; // portion and offset must match
5472 }
5473
5474 protected:
5475 void SetGVNFlags(HValue *instr, PropertyAccessType access_type);
5476
5477 private:
5478 // internal use only; different parts of an object or array
5479 enum Portion {
5480 kMaps, // map of an object
5481 kArrayLengths, // the length of an array
5482 kStringLengths, // the length of a string
5483 kElementsPointer, // elements pointer
5484 kBackingStore, // some field in the backing store
5485 kDouble, // some double field
5486 kInobject, // some other in-object field
5487 kExternalMemory // some field in external memory
5488 };
5489
HObjectAccess()5490 HObjectAccess() : value_(0) {}
5491
5492 HObjectAccess(Portion portion, int offset,
5493 Representation representation = Representation::Tagged(),
5494 Handle<Name> name = Handle<Name>::null(),
5495 bool immutable = false, bool existing_inobject_property = true)
5496 : value_(PortionField::encode(portion) |
5497 RepresentationField::encode(representation.kind()) |
5498 ImmutableField::encode(immutable ? 1 : 0) |
5499 ExistingInobjectPropertyField::encode(
5500 existing_inobject_property ? 1 : 0) |
5501 OffsetField::encode(offset)),
5502 name_(name) {
5503 // assert that the fields decode correctly
5504 DCHECK(this->offset() == offset);
5505 DCHECK(this->portion() == portion);
5506 DCHECK(this->immutable() == immutable);
5507 DCHECK(this->existing_inobject_property() == existing_inobject_property);
5508 DCHECK(RepresentationField::decode(value_) == representation.kind());
5509 DCHECK(!this->existing_inobject_property() || IsInobject());
5510 }
5511
5512 class PortionField : public BitField<Portion, 0, 3> {};
5513 class RepresentationField : public BitField<Representation::Kind, 3, 4> {};
5514 class ImmutableField : public BitField<bool, 7, 1> {};
5515 class ExistingInobjectPropertyField : public BitField<bool, 8, 1> {};
5516 class OffsetField : public BitField<int, 9, 23> {};
5517
5518 uint32_t value_; // encodes portion, representation, immutable, and offset
5519 Handle<Name> name_;
5520
5521 friend class HLoadNamedField;
5522 friend class HStoreNamedField;
5523 friend class SideEffectsTracker;
5524 friend std::ostream& operator<<(std::ostream& os,
5525 const HObjectAccess& access);
5526
portion()5527 inline Portion portion() const {
5528 return PortionField::decode(value_);
5529 }
5530 };
5531
5532
5533 std::ostream& operator<<(std::ostream& os, const HObjectAccess& access);
5534
5535
5536 class HLoadNamedField final : public HTemplateInstruction<2> {
5537 public:
5538 DECLARE_INSTRUCTION_FACTORY_P3(HLoadNamedField, HValue*,
5539 HValue*, HObjectAccess);
5540 DECLARE_INSTRUCTION_FACTORY_P5(HLoadNamedField, HValue*, HValue*,
5541 HObjectAccess, const UniqueSet<Map>*, HType);
5542
object()5543 HValue* object() const { return OperandAt(0); }
dependency()5544 HValue* dependency() const {
5545 DCHECK(HasDependency());
5546 return OperandAt(1);
5547 }
HasDependency()5548 bool HasDependency() const { return OperandAt(0) != OperandAt(1); }
access()5549 HObjectAccess access() const { return access_; }
field_representation()5550 Representation field_representation() const {
5551 return access_.representation();
5552 }
5553
maps()5554 const UniqueSet<Map>* maps() const { return maps_; }
5555
HasEscapingOperandAt(int index)5556 bool HasEscapingOperandAt(int index) override { return false; }
HasOutOfBoundsAccess(int size)5557 bool HasOutOfBoundsAccess(int size) override {
5558 return !access().IsInobject() || access().offset() >= size;
5559 }
RequiredInputRepresentation(int index)5560 Representation RequiredInputRepresentation(int index) override {
5561 if (index == 0) {
5562 // object must be external in case of external memory access
5563 return access().IsExternalMemory() ? Representation::External()
5564 : Representation::Tagged();
5565 }
5566 DCHECK(index == 1);
5567 return Representation::None();
5568 }
5569 Range* InferRange(Zone* zone) override;
5570 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5571
CanBeReplacedWith(HValue * other)5572 bool CanBeReplacedWith(HValue* other) const {
5573 if (!CheckFlag(HValue::kCantBeReplaced)) return false;
5574 if (!type().Equals(other->type())) return false;
5575 if (!representation().Equals(other->representation())) return false;
5576 if (!other->IsLoadNamedField()) return true;
5577 HLoadNamedField* that = HLoadNamedField::cast(other);
5578 if (this->maps_ == that->maps_) return true;
5579 if (this->maps_ == NULL || that->maps_ == NULL) return false;
5580 return this->maps_->IsSubset(that->maps_);
5581 }
5582
DECLARE_CONCRETE_INSTRUCTION(LoadNamedField)5583 DECLARE_CONCRETE_INSTRUCTION(LoadNamedField)
5584
5585 protected:
5586 bool DataEquals(HValue* other) override {
5587 HLoadNamedField* that = HLoadNamedField::cast(other);
5588 if (!this->access_.Equals(that->access_)) return false;
5589 if (this->maps_ == that->maps_) return true;
5590 return (this->maps_ != NULL &&
5591 that->maps_ != NULL &&
5592 this->maps_->Equals(that->maps_));
5593 }
5594
5595 private:
HLoadNamedField(HValue * object,HValue * dependency,HObjectAccess access)5596 HLoadNamedField(HValue* object,
5597 HValue* dependency,
5598 HObjectAccess access)
5599 : access_(access), maps_(NULL) {
5600 DCHECK_NOT_NULL(object);
5601 SetOperandAt(0, object);
5602 SetOperandAt(1, dependency ? dependency : object);
5603
5604 Representation representation = access.representation();
5605 if (representation.IsInteger8() ||
5606 representation.IsUInteger8() ||
5607 representation.IsInteger16() ||
5608 representation.IsUInteger16()) {
5609 set_representation(Representation::Integer32());
5610 } else if (representation.IsSmi()) {
5611 set_type(HType::Smi());
5612 if (SmiValuesAre32Bits()) {
5613 set_representation(Representation::Integer32());
5614 } else {
5615 set_representation(representation);
5616 }
5617 } else if (representation.IsDouble() ||
5618 representation.IsExternal() ||
5619 representation.IsInteger32()) {
5620 set_representation(representation);
5621 } else if (representation.IsHeapObject()) {
5622 set_type(HType::HeapObject());
5623 set_representation(Representation::Tagged());
5624 } else {
5625 set_representation(Representation::Tagged());
5626 }
5627 access.SetGVNFlags(this, LOAD);
5628 }
5629
HLoadNamedField(HValue * object,HValue * dependency,HObjectAccess access,const UniqueSet<Map> * maps,HType type)5630 HLoadNamedField(HValue* object,
5631 HValue* dependency,
5632 HObjectAccess access,
5633 const UniqueSet<Map>* maps,
5634 HType type)
5635 : HTemplateInstruction<2>(type), access_(access), maps_(maps) {
5636 DCHECK_NOT_NULL(maps);
5637 DCHECK_NE(0, maps->size());
5638
5639 DCHECK_NOT_NULL(object);
5640 SetOperandAt(0, object);
5641 SetOperandAt(1, dependency ? dependency : object);
5642
5643 DCHECK(access.representation().IsHeapObject());
5644 DCHECK(type.IsHeapObject());
5645 set_representation(Representation::Tagged());
5646
5647 access.SetGVNFlags(this, LOAD);
5648 }
5649
IsDeletable()5650 bool IsDeletable() const override { return true; }
5651
5652 HObjectAccess access_;
5653 const UniqueSet<Map>* maps_;
5654 };
5655
5656
5657 class HLoadFunctionPrototype final : public HUnaryOperation {
5658 public:
5659 DECLARE_INSTRUCTION_FACTORY_P1(HLoadFunctionPrototype, HValue*);
5660
function()5661 HValue* function() { return OperandAt(0); }
5662
RequiredInputRepresentation(int index)5663 Representation RequiredInputRepresentation(int index) override {
5664 return Representation::Tagged();
5665 }
5666
DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype)5667 DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype)
5668
5669 protected:
5670 bool DataEquals(HValue* other) override { return true; }
5671
5672 private:
HLoadFunctionPrototype(HValue * function)5673 explicit HLoadFunctionPrototype(HValue* function)
5674 : HUnaryOperation(function) {
5675 set_representation(Representation::Tagged());
5676 SetFlag(kUseGVN);
5677 SetDependsOnFlag(kCalls);
5678 }
5679 };
5680
5681 class ArrayInstructionInterface {
5682 public:
5683 virtual HValue* GetKey() = 0;
5684 virtual void SetKey(HValue* key) = 0;
5685 virtual ElementsKind elements_kind() const = 0;
5686 // TryIncreaseBaseOffset returns false if overflow would result.
5687 virtual bool TryIncreaseBaseOffset(uint32_t increase_by_value) = 0;
5688 virtual bool IsDehoisted() const = 0;
5689 virtual void SetDehoisted(bool is_dehoisted) = 0;
~ArrayInstructionInterface()5690 virtual ~ArrayInstructionInterface() { }
5691
KeyedAccessIndexRequirement(Representation r)5692 static Representation KeyedAccessIndexRequirement(Representation r) {
5693 return r.IsInteger32() || SmiValuesAre32Bits()
5694 ? Representation::Integer32() : Representation::Smi();
5695 }
5696 };
5697
5698
5699 static const int kDefaultKeyedHeaderOffsetSentinel = -1;
5700
5701 enum LoadKeyedHoleMode {
5702 NEVER_RETURN_HOLE,
5703 ALLOW_RETURN_HOLE,
5704 CONVERT_HOLE_TO_UNDEFINED
5705 };
5706
5707
5708 class HLoadKeyed final : public HTemplateInstruction<4>,
5709 public ArrayInstructionInterface {
5710 public:
5711 DECLARE_INSTRUCTION_FACTORY_P5(HLoadKeyed, HValue*, HValue*, HValue*, HValue*,
5712 ElementsKind);
5713 DECLARE_INSTRUCTION_FACTORY_P6(HLoadKeyed, HValue*, HValue*, HValue*, HValue*,
5714 ElementsKind, LoadKeyedHoleMode);
5715 DECLARE_INSTRUCTION_FACTORY_P7(HLoadKeyed, HValue*, HValue*, HValue*, HValue*,
5716 ElementsKind, LoadKeyedHoleMode, int);
5717
is_fixed_typed_array()5718 bool is_fixed_typed_array() const {
5719 return IsFixedTypedArrayElementsKind(elements_kind());
5720 }
elements()5721 HValue* elements() const { return OperandAt(0); }
key()5722 HValue* key() const { return OperandAt(1); }
dependency()5723 HValue* dependency() const {
5724 DCHECK(HasDependency());
5725 return OperandAt(2);
5726 }
HasDependency()5727 bool HasDependency() const { return OperandAt(0) != OperandAt(2); }
backing_store_owner()5728 HValue* backing_store_owner() const {
5729 DCHECK(HasBackingStoreOwner());
5730 return OperandAt(3);
5731 }
HasBackingStoreOwner()5732 bool HasBackingStoreOwner() const { return OperandAt(0) != OperandAt(3); }
base_offset()5733 uint32_t base_offset() const { return BaseOffsetField::decode(bit_field_); }
5734 bool TryIncreaseBaseOffset(uint32_t increase_by_value) override;
GetKey()5735 HValue* GetKey() override { return key(); }
SetKey(HValue * key)5736 void SetKey(HValue* key) override { SetOperandAt(1, key); }
IsDehoisted()5737 bool IsDehoisted() const override {
5738 return IsDehoistedField::decode(bit_field_);
5739 }
SetDehoisted(bool is_dehoisted)5740 void SetDehoisted(bool is_dehoisted) override {
5741 bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted);
5742 }
elements_kind()5743 ElementsKind elements_kind() const override {
5744 return ElementsKindField::decode(bit_field_);
5745 }
hole_mode()5746 LoadKeyedHoleMode hole_mode() const {
5747 return HoleModeField::decode(bit_field_);
5748 }
5749
RequiredInputRepresentation(int index)5750 Representation RequiredInputRepresentation(int index) override {
5751 // kind_fast: tagged[int32] (none)
5752 // kind_double: tagged[int32] (none)
5753 // kind_fixed_typed_array: external[int32] (none)
5754 // kind_external: external[int32] (none)
5755 if (index == 0) {
5756 return is_fixed_typed_array() ? Representation::External()
5757 : Representation::Tagged();
5758 }
5759 if (index == 1) {
5760 return ArrayInstructionInterface::KeyedAccessIndexRequirement(
5761 OperandAt(1)->representation());
5762 }
5763 if (index == 2) {
5764 return Representation::None();
5765 }
5766 DCHECK_EQ(3, index);
5767 return HasBackingStoreOwner() ? Representation::Tagged()
5768 : Representation::None();
5769 }
5770
observed_input_representation(int index)5771 Representation observed_input_representation(int index) override {
5772 return RequiredInputRepresentation(index);
5773 }
5774
5775 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5776
5777 bool UsesMustHandleHole() const;
5778 bool AllUsesCanTreatHoleAsNaN() const;
5779 bool RequiresHoleCheck() const;
5780
5781 Range* InferRange(Zone* zone) override;
5782
DECLARE_CONCRETE_INSTRUCTION(LoadKeyed)5783 DECLARE_CONCRETE_INSTRUCTION(LoadKeyed)
5784
5785 protected:
5786 bool DataEquals(HValue* other) override {
5787 if (!other->IsLoadKeyed()) return false;
5788 HLoadKeyed* other_load = HLoadKeyed::cast(other);
5789
5790 if (base_offset() != other_load->base_offset()) return false;
5791 return elements_kind() == other_load->elements_kind();
5792 }
5793
5794 private:
5795 HLoadKeyed(HValue* obj, HValue* key, HValue* dependency,
5796 HValue* backing_store_owner, ElementsKind elements_kind,
5797 LoadKeyedHoleMode mode = NEVER_RETURN_HOLE,
5798 int offset = kDefaultKeyedHeaderOffsetSentinel)
5799 : bit_field_(0) {
5800 offset = offset == kDefaultKeyedHeaderOffsetSentinel
5801 ? GetDefaultHeaderSizeForElementsKind(elements_kind)
5802 : offset;
5803 bit_field_ = ElementsKindField::encode(elements_kind) |
5804 HoleModeField::encode(mode) |
5805 BaseOffsetField::encode(offset);
5806
5807 SetOperandAt(0, obj);
5808 SetOperandAt(1, key);
5809 SetOperandAt(2, dependency != nullptr ? dependency : obj);
5810 SetOperandAt(3, backing_store_owner != nullptr ? backing_store_owner : obj);
5811 DCHECK_EQ(HasBackingStoreOwner(), is_fixed_typed_array());
5812
5813 if (!is_fixed_typed_array()) {
5814 // I can detect the case between storing double (holey and fast) and
5815 // smi/object by looking at elements_kind_.
5816 DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) ||
5817 IsFastDoubleElementsKind(elements_kind));
5818
5819 if (IsFastSmiOrObjectElementsKind(elements_kind)) {
5820 if (IsFastSmiElementsKind(elements_kind) &&
5821 (!IsHoleyElementsKind(elements_kind) ||
5822 mode == NEVER_RETURN_HOLE)) {
5823 set_type(HType::Smi());
5824 if (SmiValuesAre32Bits() && !RequiresHoleCheck()) {
5825 set_representation(Representation::Integer32());
5826 } else {
5827 set_representation(Representation::Smi());
5828 }
5829 } else {
5830 set_representation(Representation::Tagged());
5831 }
5832
5833 SetDependsOnFlag(kArrayElements);
5834 } else {
5835 set_representation(Representation::Double());
5836 SetDependsOnFlag(kDoubleArrayElements);
5837 }
5838 } else {
5839 if (elements_kind == FLOAT32_ELEMENTS ||
5840 elements_kind == FLOAT64_ELEMENTS) {
5841 set_representation(Representation::Double());
5842 } else {
5843 set_representation(Representation::Integer32());
5844 }
5845
5846 if (is_fixed_typed_array()) {
5847 SetDependsOnFlag(kExternalMemory);
5848 SetDependsOnFlag(kTypedArrayElements);
5849 } else {
5850 UNREACHABLE();
5851 }
5852 // Native code could change the specialized array.
5853 SetDependsOnFlag(kCalls);
5854 }
5855
5856 SetFlag(kUseGVN);
5857 }
5858
IsDeletable()5859 bool IsDeletable() const override { return !RequiresHoleCheck(); }
5860
5861 // Establish some checks around our packed fields
5862 enum LoadKeyedBits {
5863 kBitsForElementsKind = 5,
5864 kBitsForHoleMode = 2,
5865 kBitsForBaseOffset = 24,
5866 kBitsForIsDehoisted = 1,
5867
5868 kStartElementsKind = 0,
5869 kStartHoleMode = kStartElementsKind + kBitsForElementsKind,
5870 kStartBaseOffset = kStartHoleMode + kBitsForHoleMode,
5871 kStartIsDehoisted = kStartBaseOffset + kBitsForBaseOffset
5872 };
5873
5874 STATIC_ASSERT((kBitsForElementsKind + kBitsForHoleMode + kBitsForBaseOffset +
5875 kBitsForIsDehoisted) <= sizeof(uint32_t) * 8);
5876 STATIC_ASSERT(kElementsKindCount <= (1 << kBitsForElementsKind));
5877 class ElementsKindField:
5878 public BitField<ElementsKind, kStartElementsKind, kBitsForElementsKind>
5879 {}; // NOLINT
5880 class HoleModeField:
5881 public BitField<LoadKeyedHoleMode, kStartHoleMode, kBitsForHoleMode>
5882 {}; // NOLINT
5883 class BaseOffsetField:
5884 public BitField<uint32_t, kStartBaseOffset, kBitsForBaseOffset>
5885 {}; // NOLINT
5886 class IsDehoistedField:
5887 public BitField<bool, kStartIsDehoisted, kBitsForIsDehoisted>
5888 {}; // NOLINT
5889 uint32_t bit_field_;
5890 };
5891
5892
5893 // Indicates whether the store is a store to an entry that was previously
5894 // initialized or not.
5895 enum StoreFieldOrKeyedMode {
5896 // The entry could be either previously initialized or not.
5897 INITIALIZING_STORE,
5898 // At the time of this store it is guaranteed that the entry is already
5899 // initialized.
5900 STORE_TO_INITIALIZED_ENTRY
5901 };
5902
5903
5904 class HStoreNamedField final : public HTemplateInstruction<3> {
5905 public:
5906 DECLARE_INSTRUCTION_FACTORY_P3(HStoreNamedField, HValue*,
5907 HObjectAccess, HValue*);
5908 DECLARE_INSTRUCTION_FACTORY_P4(HStoreNamedField, HValue*,
5909 HObjectAccess, HValue*, StoreFieldOrKeyedMode);
5910
DECLARE_CONCRETE_INSTRUCTION(StoreNamedField)5911 DECLARE_CONCRETE_INSTRUCTION(StoreNamedField)
5912
5913 bool HasEscapingOperandAt(int index) override { return index == 1; }
HasOutOfBoundsAccess(int size)5914 bool HasOutOfBoundsAccess(int size) override {
5915 return !access().IsInobject() || access().offset() >= size;
5916 }
RequiredInputRepresentation(int index)5917 Representation RequiredInputRepresentation(int index) override {
5918 if (index == 0 && access().IsExternalMemory()) {
5919 // object must be external in case of external memory access
5920 return Representation::External();
5921 } else if (index == 1) {
5922 if (field_representation().IsInteger8() ||
5923 field_representation().IsUInteger8() ||
5924 field_representation().IsInteger16() ||
5925 field_representation().IsUInteger16() ||
5926 field_representation().IsInteger32()) {
5927 return Representation::Integer32();
5928 } else if (field_representation().IsDouble()) {
5929 return field_representation();
5930 } else if (field_representation().IsSmi()) {
5931 if (SmiValuesAre32Bits() &&
5932 store_mode() == STORE_TO_INITIALIZED_ENTRY) {
5933 return Representation::Integer32();
5934 }
5935 return field_representation();
5936 } else if (field_representation().IsExternal()) {
5937 return Representation::External();
5938 }
5939 }
5940 return Representation::Tagged();
5941 }
HandleSideEffectDominator(GVNFlag side_effect,HValue * dominator)5942 bool HandleSideEffectDominator(GVNFlag side_effect,
5943 HValue* dominator) override {
5944 DCHECK(side_effect == kNewSpacePromotion);
5945 if (!FLAG_use_write_barrier_elimination) return false;
5946 dominator_ = dominator;
5947 return false;
5948 }
5949 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
5950
object()5951 HValue* object() const { return OperandAt(0); }
value()5952 HValue* value() const { return OperandAt(1); }
transition()5953 HValue* transition() const { return OperandAt(2); }
5954
access()5955 HObjectAccess access() const { return access_; }
dominator()5956 HValue* dominator() const { return dominator_; }
has_transition()5957 bool has_transition() const { return HasTransitionField::decode(bit_field_); }
store_mode()5958 StoreFieldOrKeyedMode store_mode() const {
5959 return StoreModeField::decode(bit_field_);
5960 }
5961
transition_map()5962 Handle<Map> transition_map() const {
5963 if (has_transition()) {
5964 return Handle<Map>::cast(
5965 HConstant::cast(transition())->handle(isolate()));
5966 } else {
5967 return Handle<Map>();
5968 }
5969 }
5970
SetTransition(HConstant * transition)5971 void SetTransition(HConstant* transition) {
5972 DCHECK(!has_transition()); // Only set once.
5973 SetOperandAt(2, transition);
5974 bit_field_ = HasTransitionField::update(bit_field_, true);
5975 SetChangesFlag(kMaps);
5976 }
5977
NeedsWriteBarrier()5978 bool NeedsWriteBarrier() const {
5979 DCHECK(!field_representation().IsDouble() ||
5980 (FLAG_unbox_double_fields && access_.IsInobject()) ||
5981 !has_transition());
5982 if (field_representation().IsDouble()) return false;
5983 if (field_representation().IsSmi()) return false;
5984 if (field_representation().IsInteger32()) return false;
5985 if (field_representation().IsExternal()) return false;
5986 return StoringValueNeedsWriteBarrier(value()) &&
5987 ReceiverObjectNeedsWriteBarrier(object(), value(), dominator());
5988 }
5989
NeedsWriteBarrierForMap()5990 bool NeedsWriteBarrierForMap() {
5991 return ReceiverObjectNeedsWriteBarrier(object(), transition(),
5992 dominator());
5993 }
5994
SmiCheckForWriteBarrier()5995 SmiCheck SmiCheckForWriteBarrier() const {
5996 if (field_representation().IsHeapObject()) return OMIT_SMI_CHECK;
5997 if (value()->type().IsHeapObject()) return OMIT_SMI_CHECK;
5998 return INLINE_SMI_CHECK;
5999 }
6000
PointersToHereCheckForValue()6001 PointersToHereCheck PointersToHereCheckForValue() const {
6002 return PointersToHereCheckForObject(value(), dominator());
6003 }
6004
field_representation()6005 Representation field_representation() const {
6006 return access_.representation();
6007 }
6008
UpdateValue(HValue * value)6009 void UpdateValue(HValue* value) {
6010 SetOperandAt(1, value);
6011 }
6012
CanBeReplacedWith(HStoreNamedField * that)6013 bool CanBeReplacedWith(HStoreNamedField* that) const {
6014 if (!this->access().Equals(that->access())) return false;
6015 if (SmiValuesAre32Bits() &&
6016 this->field_representation().IsSmi() &&
6017 this->store_mode() == INITIALIZING_STORE &&
6018 that->store_mode() == STORE_TO_INITIALIZED_ENTRY) {
6019 // We cannot replace an initializing store to a smi field with a store to
6020 // an initialized entry on 64-bit architectures (with 32-bit smis).
6021 return false;
6022 }
6023 return true;
6024 }
6025
6026 private:
6027 HStoreNamedField(HValue* obj, HObjectAccess access, HValue* val,
6028 StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE)
access_(access)6029 : access_(access),
6030 dominator_(NULL),
6031 bit_field_(HasTransitionField::encode(false) |
6032 StoreModeField::encode(store_mode)) {
6033 // Stores to a non existing in-object property are allowed only to the
6034 // newly allocated objects (via HAllocate or HInnerAllocatedObject).
6035 DCHECK(!access.IsInobject() || access.existing_inobject_property() ||
6036 obj->IsAllocate() || obj->IsInnerAllocatedObject());
6037 SetOperandAt(0, obj);
6038 SetOperandAt(1, val);
6039 SetOperandAt(2, obj);
6040 access.SetGVNFlags(this, STORE);
6041 }
6042
6043 class HasTransitionField : public BitField<bool, 0, 1> {};
6044 class StoreModeField : public BitField<StoreFieldOrKeyedMode, 1, 1> {};
6045
6046 HObjectAccess access_;
6047 HValue* dominator_;
6048 uint32_t bit_field_;
6049 };
6050
6051 class HStoreKeyed final : public HTemplateInstruction<4>,
6052 public ArrayInstructionInterface {
6053 public:
6054 DECLARE_INSTRUCTION_FACTORY_P5(HStoreKeyed, HValue*, HValue*, HValue*,
6055 HValue*, ElementsKind);
6056 DECLARE_INSTRUCTION_FACTORY_P6(HStoreKeyed, HValue*, HValue*, HValue*,
6057 HValue*, ElementsKind, StoreFieldOrKeyedMode);
6058 DECLARE_INSTRUCTION_FACTORY_P7(HStoreKeyed, HValue*, HValue*, HValue*,
6059 HValue*, ElementsKind, StoreFieldOrKeyedMode,
6060 int);
6061
RequiredInputRepresentation(int index)6062 Representation RequiredInputRepresentation(int index) override {
6063 // kind_fast: tagged[int32] = tagged
6064 // kind_double: tagged[int32] = double
6065 // kind_smi : tagged[int32] = smi
6066 // kind_fixed_typed_array: tagged[int32] = (double | int32)
6067 // kind_external: external[int32] = (double | int32)
6068 if (index == 0) {
6069 return is_fixed_typed_array() ? Representation::External()
6070 : Representation::Tagged();
6071 } else if (index == 1) {
6072 return ArrayInstructionInterface::KeyedAccessIndexRequirement(
6073 OperandAt(1)->representation());
6074 } else if (index == 2) {
6075 return RequiredValueRepresentation(elements_kind(), store_mode());
6076 }
6077
6078 DCHECK_EQ(3, index);
6079 return HasBackingStoreOwner() ? Representation::Tagged()
6080 : Representation::None();
6081 }
6082
RequiredValueRepresentation(ElementsKind kind,StoreFieldOrKeyedMode mode)6083 static Representation RequiredValueRepresentation(
6084 ElementsKind kind, StoreFieldOrKeyedMode mode) {
6085 if (IsDoubleOrFloatElementsKind(kind)) {
6086 return Representation::Double();
6087 }
6088
6089 if (kind == FAST_SMI_ELEMENTS && SmiValuesAre32Bits() &&
6090 mode == STORE_TO_INITIALIZED_ENTRY) {
6091 return Representation::Integer32();
6092 }
6093
6094 if (IsFastSmiElementsKind(kind)) {
6095 return Representation::Smi();
6096 }
6097
6098 if (IsFixedTypedArrayElementsKind(kind)) {
6099 return Representation::Integer32();
6100 }
6101 return Representation::Tagged();
6102 }
6103
is_fixed_typed_array()6104 bool is_fixed_typed_array() const {
6105 return IsFixedTypedArrayElementsKind(elements_kind());
6106 }
6107
observed_input_representation(int index)6108 Representation observed_input_representation(int index) override {
6109 if (index != 2) return RequiredInputRepresentation(index);
6110 if (IsUninitialized()) {
6111 return Representation::None();
6112 }
6113 Representation r =
6114 RequiredValueRepresentation(elements_kind(), store_mode());
6115 // For fast object elements kinds, don't assume anything.
6116 if (r.IsTagged()) return Representation::None();
6117 return r;
6118 }
6119
elements()6120 HValue* elements() const { return OperandAt(0); }
key()6121 HValue* key() const { return OperandAt(1); }
value()6122 HValue* value() const { return OperandAt(2); }
backing_store_owner()6123 HValue* backing_store_owner() const {
6124 DCHECK(HasBackingStoreOwner());
6125 return OperandAt(3);
6126 }
HasBackingStoreOwner()6127 bool HasBackingStoreOwner() const { return OperandAt(0) != OperandAt(3); }
value_is_smi()6128 bool value_is_smi() const { return IsFastSmiElementsKind(elements_kind()); }
store_mode()6129 StoreFieldOrKeyedMode store_mode() const {
6130 return StoreModeField::decode(bit_field_);
6131 }
elements_kind()6132 ElementsKind elements_kind() const override {
6133 return ElementsKindField::decode(bit_field_);
6134 }
base_offset()6135 uint32_t base_offset() const { return base_offset_; }
6136 bool TryIncreaseBaseOffset(uint32_t increase_by_value) override;
GetKey()6137 HValue* GetKey() override { return key(); }
SetKey(HValue * key)6138 void SetKey(HValue* key) override { SetOperandAt(1, key); }
IsDehoisted()6139 bool IsDehoisted() const override {
6140 return IsDehoistedField::decode(bit_field_);
6141 }
SetDehoisted(bool is_dehoisted)6142 void SetDehoisted(bool is_dehoisted) override {
6143 bit_field_ = IsDehoistedField::update(bit_field_, is_dehoisted);
6144 }
IsUninitialized()6145 bool IsUninitialized() { return IsUninitializedField::decode(bit_field_); }
SetUninitialized(bool is_uninitialized)6146 void SetUninitialized(bool is_uninitialized) {
6147 bit_field_ = IsUninitializedField::update(bit_field_, is_uninitialized);
6148 }
6149
IsConstantHoleStore()6150 bool IsConstantHoleStore() {
6151 return value()->IsConstant() && HConstant::cast(value())->IsTheHole();
6152 }
6153
HandleSideEffectDominator(GVNFlag side_effect,HValue * dominator)6154 bool HandleSideEffectDominator(GVNFlag side_effect,
6155 HValue* dominator) override {
6156 DCHECK(side_effect == kNewSpacePromotion);
6157 dominator_ = dominator;
6158 return false;
6159 }
6160
dominator()6161 HValue* dominator() const { return dominator_; }
6162
NeedsWriteBarrier()6163 bool NeedsWriteBarrier() {
6164 if (value_is_smi()) {
6165 return false;
6166 } else {
6167 return StoringValueNeedsWriteBarrier(value()) &&
6168 ReceiverObjectNeedsWriteBarrier(elements(), value(), dominator());
6169 }
6170 }
6171
PointersToHereCheckForValue()6172 PointersToHereCheck PointersToHereCheckForValue() const {
6173 return PointersToHereCheckForObject(value(), dominator());
6174 }
6175
6176 bool NeedsCanonicalization();
6177
6178 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
6179
DECLARE_CONCRETE_INSTRUCTION(StoreKeyed)6180 DECLARE_CONCRETE_INSTRUCTION(StoreKeyed)
6181
6182 private:
6183 HStoreKeyed(HValue* obj, HValue* key, HValue* val,
6184 HValue* backing_store_owner, ElementsKind elements_kind,
6185 StoreFieldOrKeyedMode store_mode = INITIALIZING_STORE,
6186 int offset = kDefaultKeyedHeaderOffsetSentinel)
6187 : base_offset_(offset == kDefaultKeyedHeaderOffsetSentinel
6188 ? GetDefaultHeaderSizeForElementsKind(elements_kind)
6189 : offset),
6190 bit_field_(IsDehoistedField::encode(false) |
6191 IsUninitializedField::encode(false) |
6192 StoreModeField::encode(store_mode) |
6193 ElementsKindField::encode(elements_kind)),
6194 dominator_(NULL) {
6195 SetOperandAt(0, obj);
6196 SetOperandAt(1, key);
6197 SetOperandAt(2, val);
6198 SetOperandAt(3, backing_store_owner != nullptr ? backing_store_owner : obj);
6199 DCHECK_EQ(HasBackingStoreOwner(), is_fixed_typed_array());
6200
6201 if (IsFastObjectElementsKind(elements_kind)) {
6202 SetFlag(kTrackSideEffectDominators);
6203 SetDependsOnFlag(kNewSpacePromotion);
6204 }
6205 if (IsFastDoubleElementsKind(elements_kind)) {
6206 SetChangesFlag(kDoubleArrayElements);
6207 } else if (IsFastSmiElementsKind(elements_kind)) {
6208 SetChangesFlag(kArrayElements);
6209 } else if (is_fixed_typed_array()) {
6210 SetChangesFlag(kTypedArrayElements);
6211 SetChangesFlag(kExternalMemory);
6212 SetFlag(kTruncatingToNumber);
6213 } else {
6214 SetChangesFlag(kArrayElements);
6215 }
6216
6217 // {UNSIGNED_,}{BYTE,SHORT,INT}_ELEMENTS are truncating.
6218 if (elements_kind >= UINT8_ELEMENTS && elements_kind <= INT32_ELEMENTS) {
6219 SetFlag(kTruncatingToInt32);
6220 }
6221 }
6222
6223 class IsDehoistedField : public BitField<bool, 0, 1> {};
6224 class IsUninitializedField : public BitField<bool, 1, 1> {};
6225 class StoreModeField : public BitField<StoreFieldOrKeyedMode, 2, 1> {};
6226 class ElementsKindField : public BitField<ElementsKind, 3, 5> {};
6227
6228 uint32_t base_offset_;
6229 uint32_t bit_field_;
6230 HValue* dominator_;
6231 };
6232
6233 class HTransitionElementsKind final : public HTemplateInstruction<2> {
6234 public:
New(Isolate * isolate,Zone * zone,HValue * context,HValue * object,Handle<Map> original_map,Handle<Map> transitioned_map)6235 inline static HTransitionElementsKind* New(Isolate* isolate, Zone* zone,
6236 HValue* context, HValue* object,
6237 Handle<Map> original_map,
6238 Handle<Map> transitioned_map) {
6239 return new(zone) HTransitionElementsKind(context, object,
6240 original_map, transitioned_map);
6241 }
6242
RequiredInputRepresentation(int index)6243 Representation RequiredInputRepresentation(int index) override {
6244 return Representation::Tagged();
6245 }
6246
object()6247 HValue* object() const { return OperandAt(0); }
context()6248 HValue* context() const { return OperandAt(1); }
original_map()6249 Unique<Map> original_map() const { return original_map_; }
transitioned_map()6250 Unique<Map> transitioned_map() const { return transitioned_map_; }
from_kind()6251 ElementsKind from_kind() const {
6252 return FromElementsKindField::decode(bit_field_);
6253 }
to_kind()6254 ElementsKind to_kind() const {
6255 return ToElementsKindField::decode(bit_field_);
6256 }
map_is_stable()6257 bool map_is_stable() const { return MapIsStableField::decode(bit_field_); }
6258
6259 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
6260
DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind)6261 DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind)
6262
6263 protected:
6264 bool DataEquals(HValue* other) override {
6265 HTransitionElementsKind* instr = HTransitionElementsKind::cast(other);
6266 return original_map_ == instr->original_map_ &&
6267 transitioned_map_ == instr->transitioned_map_;
6268 }
6269
RedefinedOperandIndex()6270 int RedefinedOperandIndex() override { return 0; }
6271
6272 private:
HTransitionElementsKind(HValue * context,HValue * object,Handle<Map> original_map,Handle<Map> transitioned_map)6273 HTransitionElementsKind(HValue* context, HValue* object,
6274 Handle<Map> original_map,
6275 Handle<Map> transitioned_map)
6276 : original_map_(Unique<Map>(original_map)),
6277 transitioned_map_(Unique<Map>(transitioned_map)),
6278 bit_field_(
6279 FromElementsKindField::encode(original_map->elements_kind()) |
6280 ToElementsKindField::encode(transitioned_map->elements_kind()) |
6281 MapIsStableField::encode(transitioned_map->is_stable())) {
6282 SetOperandAt(0, object);
6283 SetOperandAt(1, context);
6284 SetFlag(kUseGVN);
6285 SetChangesFlag(kElementsKind);
6286 if (!IsSimpleMapChangeTransition(from_kind(), to_kind())) {
6287 SetChangesFlag(kElementsPointer);
6288 SetChangesFlag(kNewSpacePromotion);
6289 }
6290 set_representation(Representation::Tagged());
6291 }
6292
6293 class FromElementsKindField : public BitField<ElementsKind, 0, 5> {};
6294 class ToElementsKindField : public BitField<ElementsKind, 5, 5> {};
6295 class MapIsStableField : public BitField<bool, 10, 1> {};
6296
6297 Unique<Map> original_map_;
6298 Unique<Map> transitioned_map_;
6299 uint32_t bit_field_;
6300 };
6301
6302
6303 class HStringAdd final : public HBinaryOperation {
6304 public:
6305 static HInstruction* New(
6306 Isolate* isolate, Zone* zone, HValue* context, HValue* left,
6307 HValue* right, PretenureFlag pretenure_flag = NOT_TENURED,
6308 StringAddFlags flags = STRING_ADD_CHECK_BOTH,
6309 Handle<AllocationSite> allocation_site = Handle<AllocationSite>::null());
6310
flags()6311 StringAddFlags flags() const { return flags_; }
pretenure_flag()6312 PretenureFlag pretenure_flag() const { return pretenure_flag_; }
6313
RequiredInputRepresentation(int index)6314 Representation RequiredInputRepresentation(int index) override {
6315 return Representation::Tagged();
6316 }
6317
6318 std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
6319
DECLARE_CONCRETE_INSTRUCTION(StringAdd)6320 DECLARE_CONCRETE_INSTRUCTION(StringAdd)
6321
6322 protected:
6323 bool DataEquals(HValue* other) override {
6324 return flags_ == HStringAdd::cast(other)->flags_ &&
6325 pretenure_flag_ == HStringAdd::cast(other)->pretenure_flag_;
6326 }
6327
6328 private:
HStringAdd(HValue * context,HValue * left,HValue * right,PretenureFlag pretenure_flag,StringAddFlags flags,Handle<AllocationSite> allocation_site)6329 HStringAdd(HValue* context, HValue* left, HValue* right,
6330 PretenureFlag pretenure_flag, StringAddFlags flags,
6331 Handle<AllocationSite> allocation_site)
6332 : HBinaryOperation(context, left, right, HType::String()),
6333 flags_(flags),
6334 pretenure_flag_(pretenure_flag) {
6335 set_representation(Representation::Tagged());
6336 if ((flags & STRING_ADD_CONVERT) == STRING_ADD_CONVERT) {
6337 SetAllSideEffects();
6338 ClearFlag(kUseGVN);
6339 } else {
6340 SetChangesFlag(kNewSpacePromotion);
6341 SetFlag(kUseGVN);
6342 }
6343 SetDependsOnFlag(kMaps);
6344 if (FLAG_trace_pretenuring) {
6345 PrintF("HStringAdd with AllocationSite %p %s\n",
6346 allocation_site.is_null()
6347 ? static_cast<void*>(NULL)
6348 : static_cast<void*>(*allocation_site),
6349 pretenure_flag == TENURED ? "tenured" : "not tenured");
6350 }
6351 }
6352
IsDeletable()6353 bool IsDeletable() const final {
6354 return (flags_ & STRING_ADD_CONVERT) != STRING_ADD_CONVERT;
6355 }
6356
6357 const StringAddFlags flags_;
6358 const PretenureFlag pretenure_flag_;
6359 };
6360
6361
6362 class HStringCharCodeAt final : public HTemplateInstruction<3> {
6363 public:
6364 DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P2(HStringCharCodeAt,
6365 HValue*,
6366 HValue*);
6367
RequiredInputRepresentation(int index)6368 Representation RequiredInputRepresentation(int index) override {
6369 // The index is supposed to be Integer32.
6370 return index == 2
6371 ? Representation::Integer32()
6372 : Representation::Tagged();
6373 }
6374
context()6375 HValue* context() const { return OperandAt(0); }
string()6376 HValue* string() const { return OperandAt(1); }
index()6377 HValue* index() const { return OperandAt(2); }
6378
DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt)6379 DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt)
6380
6381 protected:
6382 bool DataEquals(HValue* other) override { return true; }
6383
InferRange(Zone * zone)6384 Range* InferRange(Zone* zone) override {
6385 return new(zone) Range(0, String::kMaxUtf16CodeUnit);
6386 }
6387
6388 private:
HStringCharCodeAt(HValue * context,HValue * string,HValue * index)6389 HStringCharCodeAt(HValue* context, HValue* string, HValue* index) {
6390 SetOperandAt(0, context);
6391 SetOperandAt(1, string);
6392 SetOperandAt(2, index);
6393 set_representation(Representation::Integer32());
6394 SetFlag(kUseGVN);
6395 SetDependsOnFlag(kMaps);
6396 SetDependsOnFlag(kStringChars);
6397 SetChangesFlag(kNewSpacePromotion);
6398 }
6399
6400 // No side effects: runtime function assumes string + number inputs.
IsDeletable()6401 bool IsDeletable() const override { return true; }
6402 };
6403
6404
6405 class HStringCharFromCode final : public HTemplateInstruction<2> {
6406 public:
6407 static HInstruction* New(Isolate* isolate, Zone* zone, HValue* context,
6408 HValue* char_code);
6409
RequiredInputRepresentation(int index)6410 Representation RequiredInputRepresentation(int index) override {
6411 return index == 0
6412 ? Representation::Tagged()
6413 : Representation::Integer32();
6414 }
6415
context()6416 HValue* context() const { return OperandAt(0); }
value()6417