2 * Copyright (C) 2012, 2013, 2014 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.
81 NonArray
, // Definitely some object that is not a JSArray.
82 OriginalNonArray
, // Definitely some object that is not a JSArray, but that object has the original structure.
83 Array
, // Definitely a JSArray, and may or may not have custom properties or have undergone some other bizarre transitions.
84 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.
85 PossiblyArray
// Some object that may or may not be a JSArray.
89 SaneChain
, // In bounds and the array prototype chain is still intact, i.e. loading a hole doesn't require special treatment.
90 InBounds
, // In bounds and not loading a hole.
91 ToHole
, // Potentially storing to a hole.
92 OutOfBounds
// Out-of-bounds access and anything can happen.
101 const char* arrayTypeToString(Array::Type
);
102 const char* arrayClassToString(Array::Class
);
103 const char* arraySpeculationToString(Array::Speculation
);
104 const char* arrayConversionToString(Array::Conversion
);
106 IndexingType
toIndexingShape(Array::Type
);
108 TypedArrayType
toTypedArrayType(Array::Type
);
109 Array::Type
toArrayType(TypedArrayType
);
111 bool permitsBoundsCheckLowering(Array::Type
);
117 u
.asBytes
.type
= Array::SelectUsingPredictions
;
118 u
.asBytes
.arrayClass
= Array::NonArray
;
119 u
.asBytes
.speculation
= Array::InBounds
;
120 u
.asBytes
.conversion
= Array::AsIs
;
123 explicit ArrayMode(Array::Type type
)
125 u
.asBytes
.type
= type
;
126 u
.asBytes
.arrayClass
= Array::NonArray
;
127 u
.asBytes
.speculation
= Array::InBounds
;
128 u
.asBytes
.conversion
= Array::AsIs
;
131 ArrayMode(Array::Type type
, Array::Class arrayClass
)
133 u
.asBytes
.type
= type
;
134 u
.asBytes
.arrayClass
= arrayClass
;
135 u
.asBytes
.speculation
= Array::InBounds
;
136 u
.asBytes
.conversion
= Array::AsIs
;
139 ArrayMode(Array::Type type
, Array::Class arrayClass
, Array::Speculation speculation
, Array::Conversion conversion
)
141 u
.asBytes
.type
= type
;
142 u
.asBytes
.arrayClass
= arrayClass
;
143 u
.asBytes
.speculation
= speculation
;
144 u
.asBytes
.conversion
= conversion
;
147 ArrayMode(Array::Type type
, Array::Class arrayClass
, Array::Conversion conversion
)
149 u
.asBytes
.type
= type
;
150 u
.asBytes
.arrayClass
= arrayClass
;
151 u
.asBytes
.speculation
= Array::InBounds
;
152 u
.asBytes
.conversion
= conversion
;
155 Array::Type
type() const { return static_cast<Array::Type
>(u
.asBytes
.type
); }
156 Array::Class
arrayClass() const { return static_cast<Array::Class
>(u
.asBytes
.arrayClass
); }
157 Array::Speculation
speculation() const { return static_cast<Array::Speculation
>(u
.asBytes
.speculation
); }
158 Array::Conversion
conversion() const { return static_cast<Array::Conversion
>(u
.asBytes
.conversion
); }
160 unsigned asWord() const { return u
.asWord
; }
162 static ArrayMode
fromWord(unsigned word
)
164 return ArrayMode(word
);
167 static ArrayMode
fromObserved(const ConcurrentJITLocker
&, ArrayProfile
*, Array::Action
, bool makeSafe
);
169 ArrayMode
withSpeculation(Array::Speculation speculation
) const
171 return ArrayMode(type(), arrayClass(), speculation
, conversion());
174 ArrayMode
withArrayClass(Array::Class arrayClass
) const
176 return ArrayMode(type(), arrayClass
, speculation(), conversion());
179 ArrayMode
withSpeculationFromProfile(const ConcurrentJITLocker
& locker
, ArrayProfile
* profile
, bool makeSafe
) const
181 Array::Speculation mySpeculation
;
184 mySpeculation
= Array::OutOfBounds
;
185 else if (profile
->mayStoreToHole(locker
))
186 mySpeculation
= Array::ToHole
;
188 mySpeculation
= Array::InBounds
;
190 return withSpeculation(mySpeculation
);
193 ArrayMode
withProfile(const ConcurrentJITLocker
& locker
, ArrayProfile
* profile
, bool makeSafe
) const
195 Array::Class myArrayClass
;
198 if (profile
->usesOriginalArrayStructures(locker
) && benefitsFromOriginalArray())
199 myArrayClass
= Array::OriginalArray
;
201 myArrayClass
= Array::Array
;
203 myArrayClass
= arrayClass();
205 return withArrayClass(myArrayClass
).withSpeculationFromProfile(locker
, profile
, makeSafe
);
208 ArrayMode
withType(Array::Type type
) const
210 return ArrayMode(type
, arrayClass(), speculation(), conversion());
213 ArrayMode
withConversion(Array::Conversion conversion
) const
215 return ArrayMode(type(), arrayClass(), speculation(), conversion
);
218 ArrayMode
withTypeAndConversion(Array::Type type
, Array::Conversion conversion
) const
220 return ArrayMode(type
, arrayClass(), speculation(), conversion
);
223 ArrayMode
refine(Graph
&, Node
*, SpeculatedType base
, SpeculatedType index
, SpeculatedType value
= SpecNone
, NodeFlags
= 0) const;
225 bool alreadyChecked(Graph
&, Node
*, AbstractValue
&) const;
227 void dump(PrintStream
&) const;
229 bool usesButterfly() const
234 case Array::Contiguous
:
235 case Array::ArrayStorage
:
236 case Array::SlowPutArrayStorage
:
243 bool isJSArray() const
245 switch (arrayClass()) {
247 case Array::OriginalArray
:
254 bool isJSArrayWithOriginalStructure() const
256 return arrayClass() == Array::OriginalArray
;
259 bool isSaneChain() const
261 return speculation() == Array::SaneChain
;
264 bool isInBounds() const
266 switch (speculation()) {
267 case Array::SaneChain
:
268 case Array::InBounds
:
275 bool mayStoreToHole() const
277 return !isInBounds();
280 bool isOutOfBounds() const
282 return speculation() == Array::OutOfBounds
;
285 bool isSlowPut() const
287 return type() == Array::SlowPutArrayStorage
;
290 bool canCSEStorage() const
293 case Array::SelectUsingPredictions
:
294 case Array::Unprofiled
:
295 case Array::ForceExit
:
297 case Array::Arguments
:
304 bool lengthNeedsStorage() const
307 case Array::Undecided
:
310 case Array::Contiguous
:
311 case Array::ArrayStorage
:
312 case Array::SlowPutArrayStorage
:
319 ArrayMode
modeForPut() const
323 return ArrayMode(Array::Generic
);
324 #if USE(JSVALUE32_64)
325 case Array::Arguments
:
326 return ArrayMode(Array::Generic
);
333 bool isSpecific() const
336 case Array::SelectUsingPredictions
:
337 case Array::Unprofiled
:
338 case Array::ForceExit
:
340 case Array::Undecided
:
347 bool supportsLength() const
350 case Array::SelectUsingPredictions
:
351 case Array::Unprofiled
:
352 case Array::ForceExit
:
357 case Array::Contiguous
:
358 case Array::ArrayStorage
:
359 case Array::SlowPutArrayStorage
:
366 bool permitsBoundsCheckLowering() const;
368 bool benefitsFromOriginalArray() const
373 case Array::Contiguous
:
374 case Array::ArrayStorage
:
381 // Returns 0 if this is not OriginalArray.
382 Structure
* originalArrayStructure(Graph
&, const CodeOrigin
&) const;
383 Structure
* originalArrayStructure(Graph
&, Node
*) const;
385 bool doesConversion() const
387 return conversion() != Array::AsIs
;
390 bool structureWouldPassArrayModeFiltering(Structure
* structure
)
392 return arrayModesAlreadyChecked(arrayModeFromStructure(structure
), arrayModesThatPassFiltering());
395 ArrayModes
arrayModesThatPassFiltering() const
399 return ALL_ARRAY_MODES
;
401 return arrayModesWithIndexingShape(Int32Shape
);
403 return arrayModesWithIndexingShape(DoubleShape
);
404 case Array::Contiguous
:
405 return arrayModesWithIndexingShape(ContiguousShape
);
406 case Array::ArrayStorage
:
407 return arrayModesWithIndexingShape(ArrayStorageShape
);
408 case Array::SlowPutArrayStorage
:
409 return arrayModesWithIndexingShapes(SlowPutArrayStorageShape
, ArrayStorageShape
);
411 return asArrayModes(NonArray
);
415 bool getIndexedPropertyStorageMayTriggerGC() const
417 return type() == Array::String
;
420 IndexingType
shapeMask() const
422 return toIndexingShape(type());
425 TypedArrayType
typedArrayType() const
427 return toTypedArrayType(type());
430 bool operator==(const ArrayMode
& other
) const
432 return type() == other
.type()
433 && arrayClass() == other
.arrayClass()
434 && speculation() == other
.speculation()
435 && conversion() == other
.conversion();
438 bool operator!=(const ArrayMode
& other
) const
440 return !(*this == other
);
443 explicit ArrayMode(unsigned word
)
448 ArrayModes
arrayModesWithIndexingShape(IndexingType shape
) const
450 switch (arrayClass()) {
451 case Array::NonArray
:
452 case Array::OriginalNonArray
:
453 return asArrayModes(shape
);
455 case Array::OriginalArray
:
456 return asArrayModes(shape
| IsArray
);
457 case Array::PossiblyArray
:
458 return asArrayModes(shape
) | asArrayModes(shape
| IsArray
);
460 // This is only necessary for C++ compilers that don't understand enums.
465 ArrayModes
arrayModesWithIndexingShapes(IndexingType shape1
, IndexingType shape2
) const
467 ArrayModes arrayMode1
= arrayModesWithIndexingShape(shape1
);
468 ArrayModes arrayMode2
= arrayModesWithIndexingShape(shape2
);
469 return arrayMode1
| arrayMode2
;
472 bool alreadyChecked(Graph
&, Node
*, AbstractValue
&, IndexingType shape
) const;
485 static inline bool canCSEStorage(const ArrayMode
& arrayMode
)
487 return arrayMode
.canCSEStorage();
490 static inline bool lengthNeedsStorage(const ArrayMode
& arrayMode
)
492 return arrayMode
.lengthNeedsStorage();
495 static inline bool neverNeedsStorage(const ArrayMode
&)
500 } } // namespace JSC::DFG
505 void printInternal(PrintStream
&, JSC::DFG::Array::Type
);
506 void printInternal(PrintStream
&, JSC::DFG::Array::Class
);
507 void printInternal(PrintStream
&, JSC::DFG::Array::Speculation
);
508 void printInternal(PrintStream
&, JSC::DFG::Array::Conversion
);
512 #endif // ENABLE(DFG_JIT)
514 #endif // DFGArrayMode_h