2 * Copyright (C) 2012 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 "Operations.h"
35 namespace JSC
{ namespace DFG
{
37 ArrayMode
ArrayMode::fromObserved(ArrayProfile
* profile
, Array::Action action
, bool makeSafe
)
39 ArrayModes observed
= profile
->observedArrayModes();
42 return ArrayMode(Array::Unprofiled
);
43 case asArrayModes(NonArray
):
44 if (action
== Array::Write
&& !profile
->mayInterceptIndexedAccesses())
45 return ArrayMode(Array::Undecided
, Array::NonArray
, Array::OutOfBounds
, Array::Convert
);
46 return ArrayMode(Array::SelectUsingPredictions
);
48 case asArrayModes(ArrayWithUndecided
):
49 if (action
== Array::Write
)
50 return ArrayMode(Array::Undecided
, Array::Array
, Array::OutOfBounds
, Array::Convert
);
51 return ArrayMode(Array::Generic
);
53 case asArrayModes(NonArray
) | asArrayModes(ArrayWithUndecided
):
54 if (action
== Array::Write
&& !profile
->mayInterceptIndexedAccesses())
55 return ArrayMode(Array::Undecided
, Array::PossiblyArray
, Array::OutOfBounds
, Array::Convert
);
56 return ArrayMode(Array::SelectUsingPredictions
);
58 case asArrayModes(NonArrayWithInt32
):
59 return ArrayMode(Array::Int32
, Array::NonArray
, Array::AsIs
).withProfile(profile
, makeSafe
);
60 case asArrayModes(ArrayWithInt32
):
61 return ArrayMode(Array::Int32
, Array::Array
, Array::AsIs
).withProfile(profile
, makeSafe
);
62 case asArrayModes(NonArrayWithInt32
) | asArrayModes(ArrayWithInt32
):
63 return ArrayMode(Array::Int32
, Array::PossiblyArray
, Array::AsIs
).withProfile(profile
, makeSafe
);
65 case asArrayModes(NonArrayWithDouble
):
66 return ArrayMode(Array::Double
, Array::NonArray
, Array::AsIs
).withProfile(profile
, makeSafe
);
67 case asArrayModes(ArrayWithDouble
):
68 return ArrayMode(Array::Double
, Array::Array
, Array::AsIs
).withProfile(profile
, makeSafe
);
69 case asArrayModes(NonArrayWithDouble
) | asArrayModes(ArrayWithDouble
):
70 return ArrayMode(Array::Double
, Array::PossiblyArray
, Array::AsIs
).withProfile(profile
, makeSafe
);
72 case asArrayModes(NonArrayWithContiguous
):
73 return ArrayMode(Array::Contiguous
, Array::NonArray
, Array::AsIs
).withProfile(profile
, makeSafe
);
74 case asArrayModes(ArrayWithContiguous
):
75 return ArrayMode(Array::Contiguous
, Array::Array
, Array::AsIs
).withProfile(profile
, makeSafe
);
76 case asArrayModes(NonArrayWithContiguous
) | asArrayModes(ArrayWithContiguous
):
77 return ArrayMode(Array::Contiguous
, Array::PossiblyArray
, Array::AsIs
).withProfile(profile
, makeSafe
);
79 case asArrayModes(NonArrayWithArrayStorage
):
80 return ArrayMode(Array::ArrayStorage
, Array::NonArray
, Array::AsIs
).withProfile(profile
, makeSafe
);
81 case asArrayModes(NonArrayWithSlowPutArrayStorage
):
82 case asArrayModes(NonArrayWithArrayStorage
) | asArrayModes(NonArrayWithSlowPutArrayStorage
):
83 return ArrayMode(Array::SlowPutArrayStorage
, Array::NonArray
, Array::AsIs
).withProfile(profile
, makeSafe
);
84 case asArrayModes(ArrayWithArrayStorage
):
85 return ArrayMode(Array::ArrayStorage
, Array::Array
, Array::AsIs
).withProfile(profile
, makeSafe
);
86 case asArrayModes(ArrayWithSlowPutArrayStorage
):
87 case asArrayModes(ArrayWithArrayStorage
) | asArrayModes(ArrayWithSlowPutArrayStorage
):
88 return ArrayMode(Array::SlowPutArrayStorage
, Array::Array
, Array::AsIs
).withProfile(profile
, makeSafe
);
89 case asArrayModes(NonArrayWithArrayStorage
) | asArrayModes(ArrayWithArrayStorage
):
90 return ArrayMode(Array::ArrayStorage
, Array::PossiblyArray
, Array::AsIs
).withProfile(profile
, makeSafe
);
91 case asArrayModes(NonArrayWithSlowPutArrayStorage
) | asArrayModes(ArrayWithSlowPutArrayStorage
):
92 case asArrayModes(NonArrayWithArrayStorage
) | asArrayModes(ArrayWithArrayStorage
) | asArrayModes(NonArrayWithSlowPutArrayStorage
) | asArrayModes(ArrayWithSlowPutArrayStorage
):
93 return ArrayMode(Array::SlowPutArrayStorage
, Array::PossiblyArray
, Array::AsIs
).withProfile(profile
, makeSafe
);
96 if ((observed
& asArrayModes(NonArray
)) && profile
->mayInterceptIndexedAccesses())
97 return ArrayMode(Array::SelectUsingPredictions
);
100 Array::Class arrayClass
;
102 if (shouldUseSlowPutArrayStorage(observed
))
103 type
= Array::SlowPutArrayStorage
;
104 else if (shouldUseFastArrayStorage(observed
))
105 type
= Array::ArrayStorage
;
106 else if (shouldUseContiguous(observed
))
107 type
= Array::Contiguous
;
108 else if (shouldUseDouble(observed
))
109 type
= Array::Double
;
110 else if (shouldUseInt32(observed
))
113 type
= Array::Undecided
;
115 if (hasSeenArray(observed
) && hasSeenNonArray(observed
))
116 arrayClass
= Array::PossiblyArray
;
117 else if (hasSeenArray(observed
))
118 arrayClass
= Array::Array
;
119 else if (hasSeenNonArray(observed
))
120 arrayClass
= Array::NonArray
;
122 arrayClass
= Array::PossiblyArray
;
124 return ArrayMode(type
, arrayClass
, Array::Convert
).withProfile(profile
, makeSafe
);
128 ArrayMode
ArrayMode::refine(SpeculatedType base
, SpeculatedType index
, SpeculatedType value
, NodeFlags flags
) const
130 if (!base
|| !index
) {
131 // It can be that we had a legitimate arrayMode but no incoming predictions. That'll
132 // happen if we inlined code based on, say, a global variable watchpoint, but later
133 // realized that the callsite could not have possibly executed. It may be worthwhile
134 // to fix that, but for now I'm leaving it as-is.
135 return ArrayMode(Array::ForceExit
);
138 if (!isInt32Speculation(index
))
139 return ArrayMode(Array::Generic
);
141 // Note: our profiling currently doesn't give us good information in case we have
142 // an unlikely control flow path that sets the base to a non-cell value. Value
143 // profiling and prediction propagation will probably tell us that the value is
144 // either a cell or not, but that doesn't tell us which is more likely: that this
145 // is an array access on a cell (what we want and can optimize) or that the user is
146 // doing a crazy by-val access on a primitive (we can't easily optimize this and
147 // don't want to). So, for now, we assume that if the base is not a cell according
148 // to value profiling, but the array profile tells us something else, then we
149 // should just trust the array profile.
152 case Array::Unprofiled
:
153 return ArrayMode(Array::ForceExit
);
155 case Array::Undecided
:
157 return withType(Array::ForceExit
);
158 if (isInt32Speculation(value
))
159 return withTypeAndConversion(Array::Int32
, Array::Convert
);
160 if (isNumberSpeculation(value
))
161 return withTypeAndConversion(Array::Double
, Array::Convert
);
162 return withTypeAndConversion(Array::Contiguous
, Array::Convert
);
165 if (!value
|| isInt32Speculation(value
))
167 if (isNumberSpeculation(value
))
168 return withTypeAndConversion(Array::Double
, Array::Convert
);
169 return withTypeAndConversion(Array::Contiguous
, Array::Convert
);
172 if (flags
& NodeUsedAsInt
)
173 return withTypeAndConversion(Array::Contiguous
, Array::RageConvert
);
174 if (!value
|| isNumberSpeculation(value
))
176 return withTypeAndConversion(Array::Contiguous
, Array::Convert
);
178 case Array::Contiguous
:
179 if (doesConversion() && (flags
& NodeUsedAsInt
))
180 return withConversion(Array::RageConvert
);
183 case Array::SelectUsingPredictions
:
186 if (isStringSpeculation(base
))
187 return ArrayMode(Array::String
);
189 if (isArgumentsSpeculation(base
))
190 return ArrayMode(Array::Arguments
);
192 if (isInt8ArraySpeculation(base
))
193 return ArrayMode(Array::Int8Array
);
195 if (isInt16ArraySpeculation(base
))
196 return ArrayMode(Array::Int16Array
);
198 if (isInt32ArraySpeculation(base
))
199 return ArrayMode(Array::Int32Array
);
201 if (isUint8ArraySpeculation(base
))
202 return ArrayMode(Array::Uint8Array
);
204 if (isUint8ClampedArraySpeculation(base
))
205 return ArrayMode(Array::Uint8ClampedArray
);
207 if (isUint16ArraySpeculation(base
))
208 return ArrayMode(Array::Uint16Array
);
210 if (isUint32ArraySpeculation(base
))
211 return ArrayMode(Array::Uint32Array
);
213 if (isFloat32ArraySpeculation(base
))
214 return ArrayMode(Array::Float32Array
);
216 if (isFloat64ArraySpeculation(base
))
217 return ArrayMode(Array::Float64Array
);
219 return ArrayMode(Array::Generic
);
226 Structure
* ArrayMode::originalArrayStructure(Graph
& graph
, const CodeOrigin
& codeOrigin
) const
228 if (!isJSArrayWithOriginalStructure())
231 JSGlobalObject
* globalObject
= graph
.globalObjectFor(codeOrigin
);
235 return globalObject
->originalArrayStructureForIndexingType(ArrayWithInt32
);
237 return globalObject
->originalArrayStructureForIndexingType(ArrayWithDouble
);
238 case Array::Contiguous
:
239 return globalObject
->originalArrayStructureForIndexingType(ArrayWithContiguous
);
240 case Array::ArrayStorage
:
241 return globalObject
->originalArrayStructureForIndexingType(ArrayWithArrayStorage
);
248 Structure
* ArrayMode::originalArrayStructure(Graph
& graph
, Node
* node
) const
250 return originalArrayStructure(graph
, node
->codeOrigin
);
253 bool ArrayMode::alreadyChecked(Graph
& graph
, Node
* node
, AbstractValue
& value
, IndexingType shape
) const
255 switch (arrayClass()) {
256 case Array::OriginalArray
:
257 return value
.m_currentKnownStructure
.hasSingleton()
258 && (value
.m_currentKnownStructure
.singleton()->indexingType() & IndexingShapeMask
) == shape
259 && (value
.m_currentKnownStructure
.singleton()->indexingType() & IsArray
)
260 && graph
.globalObjectFor(node
->codeOrigin
)->isOriginalArrayStructure(value
.m_currentKnownStructure
.singleton());
263 if (arrayModesAlreadyChecked(value
.m_arrayModes
, asArrayModes(shape
| IsArray
)))
265 return value
.m_currentKnownStructure
.hasSingleton()
266 && (value
.m_currentKnownStructure
.singleton()->indexingType() & IndexingShapeMask
) == shape
267 && (value
.m_currentKnownStructure
.singleton()->indexingType() & IsArray
);
270 if (arrayModesAlreadyChecked(value
.m_arrayModes
, asArrayModes(shape
) | asArrayModes(shape
| IsArray
)))
272 return value
.m_currentKnownStructure
.hasSingleton()
273 && (value
.m_currentKnownStructure
.singleton()->indexingType() & IndexingShapeMask
) == shape
;
277 bool ArrayMode::alreadyChecked(Graph
& graph
, Node
* node
, AbstractValue
& value
) const
283 case Array::ForceExit
:
287 return speculationChecked(value
.m_type
, SpecString
);
290 return alreadyChecked(graph
, node
, value
, Int32Shape
);
293 return alreadyChecked(graph
, node
, value
, DoubleShape
);
295 case Array::Contiguous
:
296 return alreadyChecked(graph
, node
, value
, ContiguousShape
);
298 case Array::ArrayStorage
:
299 return alreadyChecked(graph
, node
, value
, ArrayStorageShape
);
301 case Array::SlowPutArrayStorage
:
302 switch (arrayClass()) {
303 case Array::OriginalArray
:
308 if (arrayModesAlreadyChecked(value
.m_arrayModes
, asArrayModes(ArrayWithArrayStorage
) | asArrayModes(ArrayWithSlowPutArrayStorage
)))
310 return value
.m_currentKnownStructure
.hasSingleton()
311 && hasArrayStorage(value
.m_currentKnownStructure
.singleton()->indexingType())
312 && (value
.m_currentKnownStructure
.singleton()->indexingType() & IsArray
);
315 if (arrayModesAlreadyChecked(value
.m_arrayModes
, asArrayModes(NonArrayWithArrayStorage
) | asArrayModes(ArrayWithArrayStorage
) | asArrayModes(NonArrayWithSlowPutArrayStorage
) | asArrayModes(ArrayWithSlowPutArrayStorage
)))
317 return value
.m_currentKnownStructure
.hasSingleton()
318 && hasArrayStorage(value
.m_currentKnownStructure
.singleton()->indexingType());
321 case Array::Arguments
:
322 return speculationChecked(value
.m_type
, SpecArguments
);
324 case Array::Int8Array
:
325 return speculationChecked(value
.m_type
, SpecInt8Array
);
327 case Array::Int16Array
:
328 return speculationChecked(value
.m_type
, SpecInt16Array
);
330 case Array::Int32Array
:
331 return speculationChecked(value
.m_type
, SpecInt32Array
);
333 case Array::Uint8Array
:
334 return speculationChecked(value
.m_type
, SpecUint8Array
);
336 case Array::Uint8ClampedArray
:
337 return speculationChecked(value
.m_type
, SpecUint8ClampedArray
);
339 case Array::Uint16Array
:
340 return speculationChecked(value
.m_type
, SpecUint16Array
);
342 case Array::Uint32Array
:
343 return speculationChecked(value
.m_type
, SpecUint32Array
);
345 case Array::Float32Array
:
346 return speculationChecked(value
.m_type
, SpecFloat32Array
);
348 case Array::Float64Array
:
349 return speculationChecked(value
.m_type
, SpecFloat64Array
);
351 case Array::SelectUsingPredictions
:
352 case Array::Unprofiled
:
353 case Array::Undecided
:
361 const char* arrayTypeToString(Array::Type type
)
364 case Array::SelectUsingPredictions
:
365 return "SelectUsingPredictions";
366 case Array::Unprofiled
:
370 case Array::ForceExit
:
374 case Array::Undecided
:
380 case Array::Contiguous
:
382 case Array::ArrayStorage
:
383 return "ArrayStorage";
384 case Array::SlowPutArrayStorage
:
385 return "SlowPutArrayStorage";
386 case Array::Arguments
:
388 case Array::Int8Array
:
390 case Array::Int16Array
:
392 case Array::Int32Array
:
394 case Array::Uint8Array
:
396 case Array::Uint8ClampedArray
:
397 return "Uint8ClampedArray";
398 case Array::Uint16Array
:
399 return "Uint16Array";
400 case Array::Uint32Array
:
401 return "Uint32Array";
402 case Array::Float32Array
:
403 return "Float32Array";
404 case Array::Float64Array
:
405 return "Float64Array";
407 // Better to return something then it is to crash. Remember, this method
408 // is being called from our main diagnostic tool, the IR dumper. It's like
409 // a stack trace. So if we get here then probably something has already
415 const char* arrayClassToString(Array::Class arrayClass
)
417 switch (arrayClass
) {
420 case Array::OriginalArray
:
421 return "OriginalArray";
422 case Array::NonArray
:
424 case Array::PossiblyArray
:
425 return "PossiblyArray";
431 const char* arraySpeculationToString(Array::Speculation speculation
)
433 switch (speculation
) {
434 case Array::SaneChain
:
436 case Array::InBounds
:
440 case Array::OutOfBounds
:
441 return "OutOfBounds";
447 const char* arrayConversionToString(Array::Conversion conversion
)
449 switch (conversion
) {
454 case Array::RageConvert
:
455 return "RageConvert";
461 void ArrayMode::dump(PrintStream
& out
) const
463 out
.print(type(), arrayClass(), speculation(), conversion());
466 } } // namespace JSC::DFG
470 void printInternal(PrintStream
& out
, JSC::DFG::Array::Type type
)
472 out
.print(JSC::DFG::arrayTypeToString(type
));
475 void printInternal(PrintStream
& out
, JSC::DFG::Array::Class arrayClass
)
477 out
.print(JSC::DFG::arrayClassToString(arrayClass
));
480 void printInternal(PrintStream
& out
, JSC::DFG::Array::Speculation speculation
)
482 out
.print(JSC::DFG::arraySpeculationToString(speculation
));
485 void printInternal(PrintStream
& out
, JSC::DFG::Array::Conversion conversion
)
487 out
.print(JSC::DFG::arrayConversionToString(conversion
));
492 #endif // ENABLE(DFG_JIT)