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