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