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.
27 #include "DFGArrayMode.h"
31 #include "DFGAbstractValue.h"
33 #include "JSCInlines.h"
35 namespace JSC
{ namespace DFG
{
37 ArrayMode
ArrayMode::fromObserved(const ConcurrentJITLocker
& locker
, ArrayProfile
* profile
, Array::Action action
, bool makeSafe
)
39 Array::Class nonArray
;
40 if (profile
->usesOriginalArrayStructures(locker
))
41 nonArray
= Array::OriginalNonArray
;
43 nonArray
= Array::NonArray
;
45 ArrayModes observed
= profile
->observedArrayModes(locker
);
48 return ArrayMode(Array::Unprofiled
);
49 case asArrayModes(NonArray
):
50 if (action
== Array::Write
&& !profile
->mayInterceptIndexedAccesses(locker
))
51 return ArrayMode(Array::Undecided
, nonArray
, Array::OutOfBounds
, Array::Convert
);
52 return ArrayMode(Array::SelectUsingPredictions
, nonArray
).withSpeculationFromProfile(locker
, profile
, makeSafe
);
54 case asArrayModes(ArrayWithUndecided
):
55 if (action
== Array::Write
)
56 return ArrayMode(Array::Undecided
, Array::Array
, Array::OutOfBounds
, Array::Convert
);
57 return ArrayMode(Array::Generic
);
59 case asArrayModes(NonArray
) | asArrayModes(ArrayWithUndecided
):
60 if (action
== Array::Write
&& !profile
->mayInterceptIndexedAccesses(locker
))
61 return ArrayMode(Array::Undecided
, Array::PossiblyArray
, Array::OutOfBounds
, Array::Convert
);
62 return ArrayMode(Array::SelectUsingPredictions
).withSpeculationFromProfile(locker
, profile
, makeSafe
);
64 case asArrayModes(NonArrayWithInt32
):
65 return ArrayMode(Array::Int32
, nonArray
, Array::AsIs
).withProfile(locker
, profile
, makeSafe
);
66 case asArrayModes(ArrayWithInt32
):
67 return ArrayMode(Array::Int32
, Array::Array
, Array::AsIs
).withProfile(locker
, profile
, makeSafe
);
68 case asArrayModes(NonArrayWithInt32
) | asArrayModes(ArrayWithInt32
):
69 return ArrayMode(Array::Int32
, Array::PossiblyArray
, Array::AsIs
).withProfile(locker
, profile
, makeSafe
);
71 case asArrayModes(NonArrayWithDouble
):
72 return ArrayMode(Array::Double
, nonArray
, Array::AsIs
).withProfile(locker
, profile
, makeSafe
);
73 case asArrayModes(ArrayWithDouble
):
74 return ArrayMode(Array::Double
, Array::Array
, Array::AsIs
).withProfile(locker
, profile
, makeSafe
);
75 case asArrayModes(NonArrayWithDouble
) | asArrayModes(ArrayWithDouble
):
76 return ArrayMode(Array::Double
, Array::PossiblyArray
, Array::AsIs
).withProfile(locker
, profile
, makeSafe
);
78 case asArrayModes(NonArrayWithContiguous
):
79 return ArrayMode(Array::Contiguous
, nonArray
, Array::AsIs
).withProfile(locker
, profile
, makeSafe
);
80 case asArrayModes(ArrayWithContiguous
):
81 return ArrayMode(Array::Contiguous
, Array::Array
, Array::AsIs
).withProfile(locker
, profile
, makeSafe
);
82 case asArrayModes(NonArrayWithContiguous
) | asArrayModes(ArrayWithContiguous
):
83 return ArrayMode(Array::Contiguous
, Array::PossiblyArray
, Array::AsIs
).withProfile(locker
, profile
, makeSafe
);
85 case asArrayModes(NonArrayWithArrayStorage
):
86 return ArrayMode(Array::ArrayStorage
, nonArray
, Array::AsIs
).withProfile(locker
, profile
, makeSafe
);
87 case asArrayModes(NonArrayWithSlowPutArrayStorage
):
88 case asArrayModes(NonArrayWithArrayStorage
) | asArrayModes(NonArrayWithSlowPutArrayStorage
):
89 return ArrayMode(Array::SlowPutArrayStorage
, nonArray
, Array::AsIs
).withProfile(locker
, profile
, makeSafe
);
90 case asArrayModes(ArrayWithArrayStorage
):
91 return ArrayMode(Array::ArrayStorage
, Array::Array
, Array::AsIs
).withProfile(locker
, profile
, makeSafe
);
92 case asArrayModes(ArrayWithSlowPutArrayStorage
):
93 case asArrayModes(ArrayWithArrayStorage
) | asArrayModes(ArrayWithSlowPutArrayStorage
):
94 return ArrayMode(Array::SlowPutArrayStorage
, Array::Array
, Array::AsIs
).withProfile(locker
, profile
, makeSafe
);
95 case asArrayModes(NonArrayWithArrayStorage
) | asArrayModes(ArrayWithArrayStorage
):
96 return ArrayMode(Array::ArrayStorage
, Array::PossiblyArray
, Array::AsIs
).withProfile(locker
, profile
, makeSafe
);
97 case asArrayModes(NonArrayWithSlowPutArrayStorage
) | asArrayModes(ArrayWithSlowPutArrayStorage
):
98 case asArrayModes(NonArrayWithArrayStorage
) | asArrayModes(ArrayWithArrayStorage
) | asArrayModes(NonArrayWithSlowPutArrayStorage
) | asArrayModes(ArrayWithSlowPutArrayStorage
):
99 return ArrayMode(Array::SlowPutArrayStorage
, Array::PossiblyArray
, Array::AsIs
).withProfile(locker
, profile
, makeSafe
);
102 if ((observed
& asArrayModes(NonArray
)) && profile
->mayInterceptIndexedAccesses(locker
))
103 return ArrayMode(Array::SelectUsingPredictions
).withSpeculationFromProfile(locker
, profile
, makeSafe
);
106 Array::Class arrayClass
;
108 if (shouldUseSlowPutArrayStorage(observed
))
109 type
= Array::SlowPutArrayStorage
;
110 else if (shouldUseFastArrayStorage(observed
))
111 type
= Array::ArrayStorage
;
112 else if (shouldUseContiguous(observed
))
113 type
= Array::Contiguous
;
114 else if (shouldUseDouble(observed
))
115 type
= Array::Double
;
116 else if (shouldUseInt32(observed
))
119 type
= Array::Undecided
;
121 if (hasSeenArray(observed
) && hasSeenNonArray(observed
))
122 arrayClass
= Array::PossiblyArray
;
123 else if (hasSeenArray(observed
))
124 arrayClass
= Array::Array
;
125 else if (hasSeenNonArray(observed
))
126 arrayClass
= nonArray
;
128 arrayClass
= Array::PossiblyArray
;
130 return ArrayMode(type
, arrayClass
, Array::Convert
).withProfile(locker
, profile
, makeSafe
);
134 ArrayMode
ArrayMode::refine(
135 Graph
& graph
, Node
* node
,
136 SpeculatedType base
, SpeculatedType index
, SpeculatedType value
,
137 NodeFlags flags
) const
139 if (!base
|| !index
) {
140 // It can be that we had a legitimate arrayMode but no incoming predictions. That'll
141 // happen if we inlined code based on, say, a global variable watchpoint, but later
142 // realized that the callsite could not have possibly executed. It may be worthwhile
143 // to fix that, but for now I'm leaving it as-is.
144 return ArrayMode(Array::ForceExit
);
147 if (!isInt32Speculation(index
))
148 return ArrayMode(Array::Generic
);
150 // Note: our profiling currently doesn't give us good information in case we have
151 // an unlikely control flow path that sets the base to a non-cell value. Value
152 // profiling and prediction propagation will probably tell us that the value is
153 // either a cell or not, but that doesn't tell us which is more likely: that this
154 // is an array access on a cell (what we want and can optimize) or that the user is
155 // doing a crazy by-val access on a primitive (we can't easily optimize this and
156 // don't want to). So, for now, we assume that if the base is not a cell according
157 // to value profiling, but the array profile tells us something else, then we
158 // should just trust the array profile.
161 case Array::Unprofiled
:
162 return ArrayMode(Array::ForceExit
);
164 case Array::Undecided
:
166 return withType(Array::ForceExit
);
167 if (isInt32Speculation(value
))
168 return withTypeAndConversion(Array::Int32
, Array::Convert
);
169 if (isFullNumberSpeculation(value
))
170 return withTypeAndConversion(Array::Double
, Array::Convert
);
171 return withTypeAndConversion(Array::Contiguous
, Array::Convert
);
174 if (!value
|| isInt32Speculation(value
))
176 if (isFullNumberSpeculation(value
))
177 return withTypeAndConversion(Array::Double
, Array::Convert
);
178 return withTypeAndConversion(Array::Contiguous
, Array::Convert
);
181 if (flags
& NodeBytecodeUsesAsInt
)
182 return withTypeAndConversion(Array::Contiguous
, Array::RageConvert
);
183 if (!value
|| isFullNumberSpeculation(value
))
185 return withTypeAndConversion(Array::Contiguous
, Array::Convert
);
187 case Array::Contiguous
:
188 if (doesConversion() && (flags
& NodeBytecodeUsesAsInt
))
189 return withConversion(Array::RageConvert
);
192 case Array::SelectUsingPredictions
: {
195 if (isStringSpeculation(base
))
196 return withType(Array::String
);
198 if (isArgumentsSpeculation(base
))
199 return withType(Array::Arguments
);
202 switch (node
->op()) {
204 if (graph
.hasExitSite(node
->origin
.semantic
, OutOfBounds
) || !isInBounds())
205 result
= withSpeculation(Array::OutOfBounds
);
207 result
= withSpeculation(Array::InBounds
);
211 result
= withSpeculation(Array::InBounds
);
215 if (isInt8ArraySpeculation(base
))
216 return result
.withType(Array::Int8Array
);
218 if (isInt16ArraySpeculation(base
))
219 return result
.withType(Array::Int16Array
);
221 if (isInt32ArraySpeculation(base
))
222 return result
.withType(Array::Int32Array
);
224 if (isUint8ArraySpeculation(base
))
225 return result
.withType(Array::Uint8Array
);
227 if (isUint8ClampedArraySpeculation(base
))
228 return result
.withType(Array::Uint8ClampedArray
);
230 if (isUint16ArraySpeculation(base
))
231 return result
.withType(Array::Uint16Array
);
233 if (isUint32ArraySpeculation(base
))
234 return result
.withType(Array::Uint32Array
);
236 if (isFloat32ArraySpeculation(base
))
237 return result
.withType(Array::Float32Array
);
239 if (isFloat64ArraySpeculation(base
))
240 return result
.withType(Array::Float64Array
);
242 return ArrayMode(Array::Generic
);
250 Structure
* ArrayMode::originalArrayStructure(Graph
& graph
, const CodeOrigin
& codeOrigin
) const
252 JSGlobalObject
* globalObject
= graph
.globalObjectFor(codeOrigin
);
254 switch (arrayClass()) {
255 case Array::OriginalArray
: {
258 return globalObject
->originalArrayStructureForIndexingType(ArrayWithInt32
);
260 return globalObject
->originalArrayStructureForIndexingType(ArrayWithDouble
);
261 case Array::Contiguous
:
262 return globalObject
->originalArrayStructureForIndexingType(ArrayWithContiguous
);
263 case Array::ArrayStorage
:
264 return globalObject
->originalArrayStructureForIndexingType(ArrayWithArrayStorage
);
271 case Array::OriginalNonArray
: {
272 TypedArrayType type
= typedArrayType();
273 if (type
== NotTypedArray
)
276 return globalObject
->typedArrayStructure(type
);
284 Structure
* ArrayMode::originalArrayStructure(Graph
& graph
, Node
* node
) const
286 return originalArrayStructure(graph
, node
->origin
.semantic
);
289 bool ArrayMode::alreadyChecked(Graph
& graph
, Node
* node
, AbstractValue
& value
, IndexingType shape
) const
291 switch (arrayClass()) {
292 case Array::OriginalArray
:
293 return value
.m_currentKnownStructure
.hasSingleton()
294 && (value
.m_currentKnownStructure
.singleton()->indexingType() & IndexingShapeMask
) == shape
295 && (value
.m_currentKnownStructure
.singleton()->indexingType() & IsArray
)
296 && graph
.globalObjectFor(node
->origin
.semantic
)->isOriginalArrayStructure(value
.m_currentKnownStructure
.singleton());
299 if (arrayModesAlreadyChecked(value
.m_arrayModes
, asArrayModes(shape
| IsArray
)))
301 return value
.m_currentKnownStructure
.hasSingleton()
302 && (value
.m_currentKnownStructure
.singleton()->indexingType() & IndexingShapeMask
) == shape
303 && (value
.m_currentKnownStructure
.singleton()->indexingType() & IsArray
);
306 if (arrayModesAlreadyChecked(value
.m_arrayModes
, asArrayModes(shape
) | asArrayModes(shape
| IsArray
)))
308 return value
.m_currentKnownStructure
.hasSingleton()
309 && (value
.m_currentKnownStructure
.singleton()->indexingType() & IndexingShapeMask
) == shape
;
313 bool ArrayMode::alreadyChecked(Graph
& graph
, Node
* node
, AbstractValue
& value
) const
319 case Array::ForceExit
:
323 return speculationChecked(value
.m_type
, SpecString
);
326 return alreadyChecked(graph
, node
, value
, Int32Shape
);
329 return alreadyChecked(graph
, node
, value
, DoubleShape
);
331 case Array::Contiguous
:
332 return alreadyChecked(graph
, node
, value
, ContiguousShape
);
334 case Array::ArrayStorage
:
335 return alreadyChecked(graph
, node
, value
, ArrayStorageShape
);
337 case Array::SlowPutArrayStorage
:
338 switch (arrayClass()) {
339 case Array::OriginalArray
:
344 if (arrayModesAlreadyChecked(value
.m_arrayModes
, asArrayModes(ArrayWithArrayStorage
) | asArrayModes(ArrayWithSlowPutArrayStorage
)))
346 return value
.m_currentKnownStructure
.hasSingleton()
347 && hasAnyArrayStorage(value
.m_currentKnownStructure
.singleton()->indexingType())
348 && (value
.m_currentKnownStructure
.singleton()->indexingType() & IsArray
);
351 if (arrayModesAlreadyChecked(value
.m_arrayModes
, asArrayModes(NonArrayWithArrayStorage
) | asArrayModes(ArrayWithArrayStorage
) | asArrayModes(NonArrayWithSlowPutArrayStorage
) | asArrayModes(ArrayWithSlowPutArrayStorage
)))
353 return value
.m_currentKnownStructure
.hasSingleton()
354 && hasAnyArrayStorage(value
.m_currentKnownStructure
.singleton()->indexingType());
357 case Array::Arguments
:
358 return speculationChecked(value
.m_type
, SpecArguments
);
360 case Array::Int8Array
:
361 return speculationChecked(value
.m_type
, SpecInt8Array
);
363 case Array::Int16Array
:
364 return speculationChecked(value
.m_type
, SpecInt16Array
);
366 case Array::Int32Array
:
367 return speculationChecked(value
.m_type
, SpecInt32Array
);
369 case Array::Uint8Array
:
370 return speculationChecked(value
.m_type
, SpecUint8Array
);
372 case Array::Uint8ClampedArray
:
373 return speculationChecked(value
.m_type
, SpecUint8ClampedArray
);
375 case Array::Uint16Array
:
376 return speculationChecked(value
.m_type
, SpecUint16Array
);
378 case Array::Uint32Array
:
379 return speculationChecked(value
.m_type
, SpecUint32Array
);
381 case Array::Float32Array
:
382 return speculationChecked(value
.m_type
, SpecFloat32Array
);
384 case Array::Float64Array
:
385 return speculationChecked(value
.m_type
, SpecFloat64Array
);
387 case Array::SelectUsingPredictions
:
388 case Array::Unprofiled
:
389 case Array::Undecided
:
397 const char* arrayTypeToString(Array::Type type
)
400 case Array::SelectUsingPredictions
:
401 return "SelectUsingPredictions";
402 case Array::Unprofiled
:
406 case Array::ForceExit
:
410 case Array::Undecided
:
416 case Array::Contiguous
:
418 case Array::ArrayStorage
:
419 return "ArrayStorage";
420 case Array::SlowPutArrayStorage
:
421 return "SlowPutArrayStorage";
422 case Array::Arguments
:
424 case Array::Int8Array
:
426 case Array::Int16Array
:
428 case Array::Int32Array
:
430 case Array::Uint8Array
:
432 case Array::Uint8ClampedArray
:
433 return "Uint8ClampedArray";
434 case Array::Uint16Array
:
435 return "Uint16Array";
436 case Array::Uint32Array
:
437 return "Uint32Array";
438 case Array::Float32Array
:
439 return "Float32Array";
440 case Array::Float64Array
:
441 return "Float64Array";
443 // Better to return something then it is to crash. Remember, this method
444 // is being called from our main diagnostic tool, the IR dumper. It's like
445 // a stack trace. So if we get here then probably something has already
451 const char* arrayClassToString(Array::Class arrayClass
)
453 switch (arrayClass
) {
456 case Array::OriginalArray
:
457 return "OriginalArray";
458 case Array::NonArray
:
460 case Array::OriginalNonArray
:
461 return "OriginalNonArray";
462 case Array::PossiblyArray
:
463 return "PossiblyArray";
469 const char* arraySpeculationToString(Array::Speculation speculation
)
471 switch (speculation
) {
472 case Array::SaneChain
:
474 case Array::InBounds
:
478 case Array::OutOfBounds
:
479 return "OutOfBounds";
485 const char* arrayConversionToString(Array::Conversion conversion
)
487 switch (conversion
) {
492 case Array::RageConvert
:
493 return "RageConvert";
499 IndexingType
toIndexingShape(Array::Type type
)
506 case Array::Contiguous
:
507 return ContiguousShape
;
508 case Array::ArrayStorage
:
509 return ArrayStorageShape
;
510 case Array::SlowPutArrayStorage
:
511 return SlowPutArrayStorageShape
;
513 return NoIndexingShape
;
517 TypedArrayType
toTypedArrayType(Array::Type type
)
520 case Array::Int8Array
:
522 case Array::Int16Array
:
524 case Array::Int32Array
:
526 case Array::Uint8Array
:
528 case Array::Uint8ClampedArray
:
529 return TypeUint8Clamped
;
530 case Array::Uint16Array
:
532 case Array::Uint32Array
:
534 case Array::Float32Array
:
536 case Array::Float64Array
:
539 return NotTypedArray
;
543 Array::Type
toArrayType(TypedArrayType type
)
547 return Array::Int8Array
;
549 return Array::Int16Array
;
551 return Array::Int32Array
;
553 return Array::Uint8Array
;
554 case TypeUint8Clamped
:
555 return Array::Uint8ClampedArray
;
557 return Array::Uint16Array
;
559 return Array::Uint32Array
;
561 return Array::Float32Array
;
563 return Array::Float64Array
;
565 return Array::Generic
;
569 bool permitsBoundsCheckLowering(Array::Type type
)
574 case Array::Contiguous
:
575 case Array::Int8Array
:
576 case Array::Int16Array
:
577 case Array::Int32Array
:
578 case Array::Uint8Array
:
579 case Array::Uint8ClampedArray
:
580 case Array::Uint16Array
:
581 case Array::Uint32Array
:
582 case Array::Float32Array
:
583 case Array::Float64Array
:
586 // These don't allow for bounds check lowering either because the bounds
587 // check involves something other than GetArrayLength (like ArrayStorage),
588 // or because the bounds check isn't a speculation (like String, sort of),
589 // or because the type implies an impure access.
594 bool ArrayMode::permitsBoundsCheckLowering() const
596 return DFG::permitsBoundsCheckLowering(type()) && isInBounds();
599 void ArrayMode::dump(PrintStream
& out
) const
601 out
.print(type(), arrayClass(), speculation(), conversion());
604 } } // namespace JSC::DFG
608 void printInternal(PrintStream
& out
, JSC::DFG::Array::Type type
)
610 out
.print(JSC::DFG::arrayTypeToString(type
));
613 void printInternal(PrintStream
& out
, JSC::DFG::Array::Class arrayClass
)
615 out
.print(JSC::DFG::arrayClassToString(arrayClass
));
618 void printInternal(PrintStream
& out
, JSC::DFG::Array::Speculation speculation
)
620 out
.print(JSC::DFG::arraySpeculationToString(speculation
));
623 void printInternal(PrintStream
& out
, JSC::DFG::Array::Conversion conversion
)
625 out
.print(JSC::DFG::arrayConversionToString(conversion
));
630 #endif // ENABLE(DFG_JIT)