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.
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 // If we had exited because of an exotic object behavior, then don't try to specialize.
151 if (graph.hasExitSite(node->origin.semantic, ExoticObjectMode))
152 return ArrayMode(Array::Generic);
154 // Note: our profiling currently doesn't give us good information in case we have
155 // an unlikely control flow path that sets the base to a non-cell value. Value
156 // profiling and prediction propagation will probably tell us that the value is
157 // either a cell or not, but that doesn't tell us which is more likely: that this
158 // is an array access on a cell (what we want and can optimize) or that the user is
159 // doing a crazy by-val access on a primitive (we can't easily optimize this and
160 // don't want to). So, for now, we assume that if the base is not a cell according
161 // to value profiling, but the array profile tells us something else, then we
162 // should just trust the array profile.
165 case Array::Undecided:
167 return withType(Array::ForceExit);
168 if (isInt32Speculation(value))
169 return withTypeAndConversion(Array::Int32, Array::Convert);
170 if (isFullNumberSpeculation(value))
171 return withTypeAndConversion(Array::Double, Array::Convert);
172 return withTypeAndConversion(Array::Contiguous, Array::Convert);
175 if (!value || isInt32Speculation(value))
177 if (isFullNumberSpeculation(value))
178 return withTypeAndConversion(Array::Double, Array::Convert);
179 return withTypeAndConversion(Array::Contiguous, Array::Convert);
182 if (flags & NodeBytecodeUsesAsInt)
183 return withTypeAndConversion(Array::Contiguous, Array::RageConvert);
184 if (!value || isFullNumberSpeculation(value))
186 return withTypeAndConversion(Array::Contiguous, Array::Convert);
188 case Array::Contiguous:
189 if (doesConversion() && (flags & NodeBytecodeUsesAsInt))
190 return withConversion(Array::RageConvert);
193 case Array::Unprofiled:
194 case Array::SelectUsingPredictions: {
197 if (isStringSpeculation(base))
198 return withType(Array::String);
200 if (isDirectArgumentsSpeculation(base) || isScopedArgumentsSpeculation(base)) {
201 // Handle out-of-bounds accesses as generic accesses.
202 if (graph.hasExitSite(node->origin.semantic, OutOfBounds) || !isInBounds())
203 return ArrayMode(Array::Generic);
205 if (isDirectArgumentsSpeculation(base))
206 return withType(Array::DirectArguments);
207 return withType(Array::ScopedArguments);
211 switch (node->op()) {
213 if (graph.hasExitSite(node->origin.semantic, OutOfBounds) || !isInBounds())
214 result = withSpeculation(Array::OutOfBounds);
216 result = withSpeculation(Array::InBounds);
220 result = withSpeculation(Array::InBounds);
224 if (isInt8ArraySpeculation(base))
225 return result.withType(Array::Int8Array);
227 if (isInt16ArraySpeculation(base))
228 return result.withType(Array::Int16Array);
230 if (isInt32ArraySpeculation(base))
231 return result.withType(Array::Int32Array);
233 if (isUint8ArraySpeculation(base))
234 return result.withType(Array::Uint8Array);
236 if (isUint8ClampedArraySpeculation(base))
237 return result.withType(Array::Uint8ClampedArray);
239 if (isUint16ArraySpeculation(base))
240 return result.withType(Array::Uint16Array);
242 if (isUint32ArraySpeculation(base))
243 return result.withType(Array::Uint32Array);
245 if (isFloat32ArraySpeculation(base))
246 return result.withType(Array::Float32Array);
248 if (isFloat64ArraySpeculation(base))
249 return result.withType(Array::Float64Array);
251 if (type() == Array::Unprofiled)
252 return ArrayMode(Array::ForceExit);
253 return ArrayMode(Array::Generic);
261 Structure* ArrayMode::originalArrayStructure(Graph& graph, const CodeOrigin& codeOrigin) const
263 JSGlobalObject* globalObject = graph.globalObjectFor(codeOrigin);
265 switch (arrayClass()) {
266 case Array::OriginalArray: {
269 return globalObject->originalArrayStructureForIndexingType(ArrayWithInt32);
271 return globalObject->originalArrayStructureForIndexingType(ArrayWithDouble);
272 case Array::Contiguous:
273 return globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous);
274 case Array::ArrayStorage:
275 return globalObject->originalArrayStructureForIndexingType(ArrayWithArrayStorage);
282 case Array::OriginalNonArray: {
283 TypedArrayType type = typedArrayType();
284 if (type == NotTypedArray)
287 return globalObject->typedArrayStructure(type);
295 Structure* ArrayMode::originalArrayStructure(Graph& graph, Node* node) const
297 return originalArrayStructure(graph, node->origin.semantic);
300 bool ArrayMode::alreadyChecked(Graph& graph, Node* node, AbstractValue& value, IndexingType shape) const
302 switch (arrayClass()) {
303 case Array::OriginalArray: {
304 if (value.m_structure.isTop())
306 for (unsigned i = value.m_structure.size(); i--;) {
307 Structure* structure = value.m_structure[i];
308 if ((structure->indexingType() & IndexingShapeMask) != shape)
310 if (!(structure->indexingType() & IsArray))
312 if (!graph.globalObjectFor(node->origin.semantic)->isOriginalArrayStructure(structure))
319 if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(shape | IsArray)))
321 if (value.m_structure.isTop())
323 for (unsigned i = value.m_structure.size(); i--;) {
324 Structure* structure = value.m_structure[i];
325 if ((structure->indexingType() & IndexingShapeMask) != shape)
327 if (!(structure->indexingType() & IsArray))
334 if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(shape) | asArrayModes(shape | IsArray)))
336 if (value.m_structure.isTop())
338 for (unsigned i = value.m_structure.size(); i--;) {
339 Structure* structure = value.m_structure[i];
340 if ((structure->indexingType() & IndexingShapeMask) != shape)
347 bool ArrayMode::alreadyChecked(Graph& graph, Node* node, AbstractValue& value) const
353 case Array::ForceExit:
357 return speculationChecked(value.m_type, SpecString);
360 return alreadyChecked(graph, node, value, Int32Shape);
363 return alreadyChecked(graph, node, value, DoubleShape);
365 case Array::Contiguous:
366 return alreadyChecked(graph, node, value, ContiguousShape);
368 case Array::ArrayStorage:
369 return alreadyChecked(graph, node, value, ArrayStorageShape);
371 case Array::SlowPutArrayStorage:
372 switch (arrayClass()) {
373 case Array::OriginalArray: {
379 if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(ArrayWithArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage)))
381 if (value.m_structure.isTop())
383 for (unsigned i = value.m_structure.size(); i--;) {
384 Structure* structure = value.m_structure[i];
385 if (!hasAnyArrayStorage(structure->indexingType()))
387 if (!(structure->indexingType() & IsArray))
394 if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage)))
396 if (value.m_structure.isTop())
398 for (unsigned i = value.m_structure.size(); i--;) {
399 Structure* structure = value.m_structure[i];
400 if (!hasAnyArrayStorage(structure->indexingType()))
406 case Array::DirectArguments:
407 return speculationChecked(value.m_type, SpecDirectArguments);
409 case Array::ScopedArguments:
410 return speculationChecked(value.m_type, SpecScopedArguments);
412 case Array::Int8Array:
413 return speculationChecked(value.m_type, SpecInt8Array);
415 case Array::Int16Array:
416 return speculationChecked(value.m_type, SpecInt16Array);
418 case Array::Int32Array:
419 return speculationChecked(value.m_type, SpecInt32Array);
421 case Array::Uint8Array:
422 return speculationChecked(value.m_type, SpecUint8Array);
424 case Array::Uint8ClampedArray:
425 return speculationChecked(value.m_type, SpecUint8ClampedArray);
427 case Array::Uint16Array:
428 return speculationChecked(value.m_type, SpecUint16Array);
430 case Array::Uint32Array:
431 return speculationChecked(value.m_type, SpecUint32Array);
433 case Array::Float32Array:
434 return speculationChecked(value.m_type, SpecFloat32Array);
436 case Array::Float64Array:
437 return speculationChecked(value.m_type, SpecFloat64Array);
439 case Array::SelectUsingPredictions:
440 case Array::Unprofiled:
441 case Array::Undecided:
449 const char* arrayTypeToString(Array::Type type)
452 case Array::SelectUsingPredictions:
453 return "SelectUsingPredictions";
454 case Array::Unprofiled:
458 case Array::ForceExit:
462 case Array::Undecided:
468 case Array::Contiguous:
470 case Array::ArrayStorage:
471 return "ArrayStorage";
472 case Array::SlowPutArrayStorage:
473 return "SlowPutArrayStorage";
474 case Array::DirectArguments:
475 return "DirectArguments";
476 case Array::ScopedArguments:
477 return "ScopedArguments";
478 case Array::Int8Array:
480 case Array::Int16Array:
482 case Array::Int32Array:
484 case Array::Uint8Array:
486 case Array::Uint8ClampedArray:
487 return "Uint8ClampedArray";
488 case Array::Uint16Array:
489 return "Uint16Array";
490 case Array::Uint32Array:
491 return "Uint32Array";
492 case Array::Float32Array:
493 return "Float32Array";
494 case Array::Float64Array:
495 return "Float64Array";
497 // Better to return something then it is to crash. Remember, this method
498 // is being called from our main diagnostic tool, the IR dumper. It's like
499 // a stack trace. So if we get here then probably something has already
505 const char* arrayClassToString(Array::Class arrayClass)
507 switch (arrayClass) {
510 case Array::OriginalArray:
511 return "OriginalArray";
512 case Array::NonArray:
514 case Array::OriginalNonArray:
515 return "OriginalNonArray";
516 case Array::PossiblyArray:
517 return "PossiblyArray";
523 const char* arraySpeculationToString(Array::Speculation speculation)
525 switch (speculation) {
526 case Array::SaneChain:
528 case Array::InBounds:
532 case Array::OutOfBounds:
533 return "OutOfBounds";
539 const char* arrayConversionToString(Array::Conversion conversion)
541 switch (conversion) {
546 case Array::RageConvert:
547 return "RageConvert";
553 IndexingType toIndexingShape(Array::Type type)
560 case Array::Contiguous:
561 return ContiguousShape;
562 case Array::ArrayStorage:
563 return ArrayStorageShape;
564 case Array::SlowPutArrayStorage:
565 return SlowPutArrayStorageShape;
567 return NoIndexingShape;
571 TypedArrayType toTypedArrayType(Array::Type type)
574 case Array::Int8Array:
576 case Array::Int16Array:
578 case Array::Int32Array:
580 case Array::Uint8Array:
582 case Array::Uint8ClampedArray:
583 return TypeUint8Clamped;
584 case Array::Uint16Array:
586 case Array::Uint32Array:
588 case Array::Float32Array:
590 case Array::Float64Array:
593 return NotTypedArray;
597 Array::Type toArrayType(TypedArrayType type)
601 return Array::Int8Array;
603 return Array::Int16Array;
605 return Array::Int32Array;
607 return Array::Uint8Array;
608 case TypeUint8Clamped:
609 return Array::Uint8ClampedArray;
611 return Array::Uint16Array;
613 return Array::Uint32Array;
615 return Array::Float32Array;
617 return Array::Float64Array;
619 return Array::Generic;
623 bool permitsBoundsCheckLowering(Array::Type type)
628 case Array::Contiguous:
629 case Array::Int8Array:
630 case Array::Int16Array:
631 case Array::Int32Array:
632 case Array::Uint8Array:
633 case Array::Uint8ClampedArray:
634 case Array::Uint16Array:
635 case Array::Uint32Array:
636 case Array::Float32Array:
637 case Array::Float64Array:
640 // These don't allow for bounds check lowering either because the bounds
641 // check involves something other than GetArrayLength (like ArrayStorage),
642 // or because the bounds check isn't a speculation (like String, sort of),
643 // or because the type implies an impure access.
648 bool ArrayMode::permitsBoundsCheckLowering() const
650 return DFG::permitsBoundsCheckLowering(type()) && isInBounds();
653 void ArrayMode::dump(PrintStream& out) const
655 out.print(type(), arrayClass(), speculation(), conversion());
658 } } // namespace JSC::DFG
662 void printInternal(PrintStream& out, JSC::DFG::Array::Type type)
664 out.print(JSC::DFG::arrayTypeToString(type));
667 void printInternal(PrintStream& out, JSC::DFG::Array::Class arrayClass)
669 out.print(JSC::DFG::arrayClassToString(arrayClass));
672 void printInternal(PrintStream& out, JSC::DFG::Array::Speculation speculation)
674 out.print(JSC::DFG::arraySpeculationToString(speculation));
677 void printInternal(PrintStream& out, JSC::DFG::Array::Conversion conversion)
679 out.print(JSC::DFG::arrayConversionToString(conversion));
684 #endif // ENABLE(DFG_JIT)