2 * Copyright (C) 2012-2015 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #ifndef DFGArrayMode_h
27 #define DFGArrayMode_h
31 #include "ArrayProfile.h"
32 #include "DFGNodeFlags.h"
33 #include "SpeculatedType.h"
45 // Use a namespace + enum instead of enum alone to avoid the namespace collision
46 // that would otherwise occur, since we say things like "Int8Array" and "JSArray"
47 // in lots of other places, to mean subtly different things.
55 SelectUsingPredictions
, // Implies that we need predictions to decide. We will never get to the backend in this mode.
56 Unprofiled
, // Implies that array profiling didn't see anything. But that could be because the operands didn't comply with basic type assumptions (base is cell, property is int). This either becomes Generic or ForceExit depending on value profiling.
57 ForceExit
, // Implies that we have no idea how to execute this operation, so we should just give up.
83 NonArray
, // Definitely some object that is not a JSArray.
84 OriginalNonArray
, // Definitely some object that is not a JSArray, but that object has the original structure.
85 Array
, // Definitely a JSArray, and may or may not have custom properties or have undergone some other bizarre transitions.
86 OriginalArray
, // Definitely a JSArray, and still has one of the primordial JSArray structures for the global object that this code block (possibly inlined code block) belongs to.
87 PossiblyArray
// Some object that may or may not be a JSArray.
91 SaneChain
, // In bounds and the array prototype chain is still intact, i.e. loading a hole doesn't require special treatment.
93 InBounds
, // In bounds and not loading a hole.
94 ToHole
, // Potentially storing to a hole.
95 OutOfBounds
// Out-of-bounds access and anything can happen.
103 const char* arrayTypeToString(Array::Type
);
104 const char* arrayClassToString(Array::Class
);
105 const char* arraySpeculationToString(Array::Speculation
);
106 const char* arrayConversionToString(Array::Conversion
);
108 IndexingType
toIndexingShape(Array::Type
);
110 TypedArrayType
toTypedArrayType(Array::Type
);
111 Array::Type
toArrayType(TypedArrayType
);
113 bool permitsBoundsCheckLowering(Array::Type
);
119 u
.asBytes
.type
= Array::SelectUsingPredictions
;
120 u
.asBytes
.arrayClass
= Array::NonArray
;
121 u
.asBytes
.speculation
= Array::InBounds
;
122 u
.asBytes
.conversion
= Array::AsIs
;
125 explicit ArrayMode(Array::Type type
)
127 u
.asBytes
.type
= type
;
128 u
.asBytes
.arrayClass
= Array::NonArray
;
129 u
.asBytes
.speculation
= Array::InBounds
;
130 u
.asBytes
.conversion
= Array::AsIs
;
133 ArrayMode(Array::Type type
, Array::Class arrayClass
)
135 u
.asBytes
.type
= type
;
136 u
.asBytes
.arrayClass
= arrayClass
;
137 u
.asBytes
.speculation
= Array::InBounds
;
138 u
.asBytes
.conversion
= Array::AsIs
;
141 ArrayMode(Array::Type type
, Array::Class arrayClass
, Array::Speculation speculation
, Array::Conversion conversion
)
143 u
.asBytes
.type
= type
;
144 u
.asBytes
.arrayClass
= arrayClass
;
145 u
.asBytes
.speculation
= speculation
;
146 u
.asBytes
.conversion
= conversion
;
149 ArrayMode(Array::Type type
, Array::Class arrayClass
, Array::Conversion conversion
)
151 u
.asBytes
.type
= type
;
152 u
.asBytes
.arrayClass
= arrayClass
;
153 u
.asBytes
.speculation
= Array::InBounds
;
154 u
.asBytes
.conversion
= conversion
;
157 Array::Type
type() const { return static_cast<Array::Type
>(u
.asBytes
.type
); }
158 Array::Class
arrayClass() const { return static_cast<Array::Class
>(u
.asBytes
.arrayClass
); }
159 Array::Speculation
speculation() const { return static_cast<Array::Speculation
>(u
.asBytes
.speculation
); }
160 Array::Conversion
conversion() const { return static_cast<Array::Conversion
>(u
.asBytes
.conversion
); }
162 unsigned asWord() const { return u
.asWord
; }
164 static ArrayMode
fromWord(unsigned word
)
166 return ArrayMode(word
);
169 static ArrayMode
fromObserved(const ConcurrentJITLocker
&, ArrayProfile
*, Array::Action
, bool makeSafe
);
171 ArrayMode
withSpeculation(Array::Speculation speculation
) const
173 return ArrayMode(type(), arrayClass(), speculation
, conversion());
176 ArrayMode
withArrayClass(Array::Class arrayClass
) const
178 return ArrayMode(type(), arrayClass
, speculation(), conversion());
181 ArrayMode
withSpeculationFromProfile(const ConcurrentJITLocker
& locker
, ArrayProfile
* profile
, bool makeSafe
) const
183 Array::Speculation mySpeculation
;
186 mySpeculation
= Array::OutOfBounds
;
187 else if (profile
->mayStoreToHole(locker
))
188 mySpeculation
= Array::ToHole
;
190 mySpeculation
= Array::InBounds
;
192 return withSpeculation(mySpeculation
);
195 ArrayMode
withProfile(const ConcurrentJITLocker
& locker
, ArrayProfile
* profile
, bool makeSafe
) const
197 Array::Class myArrayClass
;
200 if (profile
->usesOriginalArrayStructures(locker
) && benefitsFromOriginalArray())
201 myArrayClass
= Array::OriginalArray
;
203 myArrayClass
= Array::Array
;
205 myArrayClass
= arrayClass();
207 return withArrayClass(myArrayClass
).withSpeculationFromProfile(locker
, profile
, makeSafe
);
210 ArrayMode
withType(Array::Type type
) const
212 return ArrayMode(type
, arrayClass(), speculation(), conversion());
215 ArrayMode
withConversion(Array::Conversion conversion
) const
217 return ArrayMode(type(), arrayClass(), speculation(), conversion
);
220 ArrayMode
withTypeAndConversion(Array::Type type
, Array::Conversion conversion
) const
222 return ArrayMode(type
, arrayClass(), speculation(), conversion
);
225 ArrayMode
refine(Graph
&, Node
*, SpeculatedType base
, SpeculatedType index
, SpeculatedType value
= SpecNone
) const;
227 bool alreadyChecked(Graph
&, Node
*, const AbstractValue
&) const;
229 void dump(PrintStream
&) const;
231 bool usesButterfly() const
236 case Array::Contiguous
:
237 case Array::ArrayStorage
:
238 case Array::SlowPutArrayStorage
:
245 bool isJSArray() const
247 switch (arrayClass()) {
249 case Array::OriginalArray
:
256 bool isJSArrayWithOriginalStructure() const
258 return arrayClass() == Array::OriginalArray
;
261 bool isSaneChain() const
263 return speculation() == Array::SaneChain
;
266 bool isInBounds() const
268 switch (speculation()) {
269 case Array::SaneChain
:
270 case Array::InBounds
:
277 bool mayStoreToHole() const
279 return !isInBounds();
282 bool isOutOfBounds() const
284 return speculation() == Array::OutOfBounds
;
287 bool isSlowPut() const
289 return type() == Array::SlowPutArrayStorage
;
292 bool canCSEStorage() const
295 case Array::SelectUsingPredictions
:
296 case Array::Unprofiled
:
297 case Array::ForceExit
:
299 case Array::DirectArguments
:
300 case Array::ScopedArguments
:
307 bool lengthNeedsStorage() const
310 case Array::Undecided
:
313 case Array::Contiguous
:
314 case Array::ArrayStorage
:
315 case Array::SlowPutArrayStorage
:
322 ArrayMode
modeForPut() const
326 case Array::DirectArguments
:
327 case Array::ScopedArguments
:
328 return ArrayMode(Array::Generic
);
334 bool isSpecific() const
337 case Array::SelectUsingPredictions
:
338 case Array::Unprofiled
:
339 case Array::ForceExit
:
341 case Array::Undecided
:
348 bool supportsLength() const
351 case Array::SelectUsingPredictions
:
352 case Array::Unprofiled
:
353 case Array::ForceExit
:
358 case Array::Contiguous
:
359 case Array::ArrayStorage
:
360 case Array::SlowPutArrayStorage
:
367 bool permitsBoundsCheckLowering() const;
369 bool benefitsFromOriginalArray() const
374 case Array::Contiguous
:
375 case Array::ArrayStorage
:
382 // Returns 0 if this is not OriginalArray.
383 Structure
* originalArrayStructure(Graph
&, const CodeOrigin
&) const;
384 Structure
* originalArrayStructure(Graph
&, Node
*) const;
386 bool doesConversion() const
388 return conversion() != Array::AsIs
;
391 bool structureWouldPassArrayModeFiltering(Structure
* structure
)
393 return arrayModesAlreadyChecked(arrayModeFromStructure(structure
), arrayModesThatPassFiltering());
396 ArrayModes
arrayModesThatPassFiltering() const
400 return ALL_ARRAY_MODES
;
402 return arrayModesWithIndexingShape(Int32Shape
);
404 return arrayModesWithIndexingShape(DoubleShape
);
405 case Array::Contiguous
:
406 return arrayModesWithIndexingShape(ContiguousShape
);
407 case Array::ArrayStorage
:
408 return arrayModesWithIndexingShape(ArrayStorageShape
);
409 case Array::SlowPutArrayStorage
:
410 return arrayModesWithIndexingShapes(SlowPutArrayStorageShape
, ArrayStorageShape
);
412 return asArrayModes(NonArray
);
416 bool getIndexedPropertyStorageMayTriggerGC() const
418 return type() == Array::String
;
421 IndexingType
shapeMask() const
423 return toIndexingShape(type());
426 TypedArrayType
typedArrayType() const
428 return toTypedArrayType(type());
431 bool operator==(const ArrayMode
& other
) const
433 return type() == other
.type()
434 && arrayClass() == other
.arrayClass()
435 && speculation() == other
.speculation()
436 && conversion() == other
.conversion();
439 bool operator!=(const ArrayMode
& other
) const
441 return !(*this == other
);
444 explicit ArrayMode(unsigned word
)
449 ArrayModes
arrayModesWithIndexingShape(IndexingType shape
) const
451 switch (arrayClass()) {
452 case Array::NonArray
:
453 case Array::OriginalNonArray
:
454 return asArrayModes(shape
);
456 case Array::OriginalArray
:
457 return asArrayModes(shape
| IsArray
);
458 case Array::PossiblyArray
:
459 return asArrayModes(shape
) | asArrayModes(shape
| IsArray
);
461 // This is only necessary for C++ compilers that don't understand enums.
466 ArrayModes
arrayModesWithIndexingShapes(IndexingType shape1
, IndexingType shape2
) const
468 ArrayModes arrayMode1
= arrayModesWithIndexingShape(shape1
);
469 ArrayModes arrayMode2
= arrayModesWithIndexingShape(shape2
);
470 return arrayMode1
| arrayMode2
;
473 bool alreadyChecked(Graph
&, Node
*, const AbstractValue
&, IndexingType shape
) const;
486 static inline bool canCSEStorage(const ArrayMode
& arrayMode
)
488 return arrayMode
.canCSEStorage();
491 static inline bool lengthNeedsStorage(const ArrayMode
& arrayMode
)
493 return arrayMode
.lengthNeedsStorage();
496 static inline bool neverNeedsStorage(const ArrayMode
&)
501 } } // namespace JSC::DFG
506 void printInternal(PrintStream
&, JSC::DFG::Array::Type
);
507 void printInternal(PrintStream
&, JSC::DFG::Array::Class
);
508 void printInternal(PrintStream
&, JSC::DFG::Array::Speculation
);
509 void printInternal(PrintStream
&, JSC::DFG::Array::Conversion
);
513 #endif // ENABLE(DFG_JIT)
515 #endif // DFGArrayMode_h