[JSC] CheckArray+NonArray is not filtering out Array in AI
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGArrayMode.cpp
1 /*
2  * Copyright (C) 2012-2018 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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. 
24  */
25
26 #include "config.h"
27 #include "DFGArrayMode.h"
28
29 #if ENABLE(DFG_JIT)
30
31 #include "ArrayPrototype.h"
32 #include "DFGAbstractValue.h"
33 #include "DFGGraph.h"
34 #include "JSCInlines.h"
35
36 namespace JSC { namespace DFG {
37
38 ArrayMode ArrayMode::fromObserved(const ConcurrentJSLocker& locker, ArrayProfile* profile, Array::Action action, bool makeSafe)
39 {
40     Array::Class nonArray;
41     if (profile->usesOriginalArrayStructures(locker))
42         nonArray = Array::OriginalNonArray;
43     else
44         nonArray = Array::NonArray;
45
46     auto handleContiguousModes = [&] (Array::Type type, ArrayModes observed) {
47         Array::Class isArray;
48         Array::Conversion converts;
49
50         RELEASE_ASSERT((observed & (asArrayModesIgnoringTypedArrays(toIndexingShape(type)) | asArrayModesIgnoringTypedArrays(toIndexingShape(type) | ArrayClass) | asArrayModesIgnoringTypedArrays(toIndexingShape(type) | ArrayClass | CopyOnWrite))) == observed);
51
52         if (observed & asArrayModesIgnoringTypedArrays(toIndexingShape(type))) {
53             if ((observed & asArrayModesIgnoringTypedArrays(toIndexingShape(type))) == observed)
54                 isArray = nonArray;
55             else
56                 isArray = Array::PossiblyArray;
57         } else
58             isArray = Array::Array;
59
60         if (action == Array::Write && (observed & asArrayModesIgnoringTypedArrays(toIndexingShape(type) | ArrayClass | CopyOnWrite)))
61             converts = Array::Convert;
62         else
63             converts = Array::AsIs;
64
65         return ArrayMode(type, isArray, converts, action).withProfile(locker, profile, makeSafe);
66     };
67
68     ArrayModes observed = profile->observedArrayModes(locker);
69     switch (observed) {
70     case 0:
71         return ArrayMode(Array::Unprofiled);
72     case asArrayModesIgnoringTypedArrays(NonArray):
73         if (action == Array::Write && !profile->mayInterceptIndexedAccesses(locker))
74             return ArrayMode(Array::SelectUsingArguments, nonArray, Array::OutOfBounds, Array::Convert, action);
75         return ArrayMode(Array::SelectUsingPredictions, nonArray, action).withSpeculationFromProfile(locker, profile, makeSafe);
76
77     case asArrayModesIgnoringTypedArrays(ArrayWithUndecided):
78         if (action == Array::Write)
79             return ArrayMode(Array::SelectUsingArguments, Array::Array, Array::OutOfBounds, Array::Convert, action);
80         return ArrayMode(Array::Undecided, Array::Array, Array::OutOfBounds, Array::AsIs, action).withProfile(locker, profile, makeSafe);
81         
82     case asArrayModesIgnoringTypedArrays(NonArray) | asArrayModesIgnoringTypedArrays(ArrayWithUndecided):
83         if (action == Array::Write && !profile->mayInterceptIndexedAccesses(locker))
84             return ArrayMode(Array::SelectUsingArguments, Array::PossiblyArray, Array::OutOfBounds, Array::Convert, action);
85         return ArrayMode(Array::SelectUsingPredictions, action).withSpeculationFromProfile(locker, profile, makeSafe);
86
87     case asArrayModesIgnoringTypedArrays(NonArrayWithInt32):
88     case asArrayModesIgnoringTypedArrays(ArrayWithInt32):
89     case asArrayModesIgnoringTypedArrays(CopyOnWriteArrayWithInt32):
90     case asArrayModesIgnoringTypedArrays(NonArrayWithInt32) | asArrayModesIgnoringTypedArrays(ArrayWithInt32):
91     case asArrayModesIgnoringTypedArrays(NonArrayWithInt32) | asArrayModesIgnoringTypedArrays(CopyOnWriteArrayWithInt32):
92     case asArrayModesIgnoringTypedArrays(ArrayWithInt32) | asArrayModesIgnoringTypedArrays(CopyOnWriteArrayWithInt32):
93     case asArrayModesIgnoringTypedArrays(NonArrayWithInt32) | asArrayModesIgnoringTypedArrays(ArrayWithInt32) | asArrayModesIgnoringTypedArrays(CopyOnWriteArrayWithInt32):
94         return handleContiguousModes(Array::Int32, observed);
95
96     case asArrayModesIgnoringTypedArrays(NonArrayWithDouble):
97     case asArrayModesIgnoringTypedArrays(ArrayWithDouble):
98     case asArrayModesIgnoringTypedArrays(CopyOnWriteArrayWithDouble):
99     case asArrayModesIgnoringTypedArrays(NonArrayWithDouble) | asArrayModesIgnoringTypedArrays(ArrayWithDouble):
100     case asArrayModesIgnoringTypedArrays(NonArrayWithDouble) | asArrayModesIgnoringTypedArrays(CopyOnWriteArrayWithDouble):
101     case asArrayModesIgnoringTypedArrays(ArrayWithDouble) | asArrayModesIgnoringTypedArrays(CopyOnWriteArrayWithDouble):
102     case asArrayModesIgnoringTypedArrays(NonArrayWithDouble) | asArrayModesIgnoringTypedArrays(ArrayWithDouble) | asArrayModesIgnoringTypedArrays(CopyOnWriteArrayWithDouble):
103         return handleContiguousModes(Array::Double, observed);
104
105     case asArrayModesIgnoringTypedArrays(NonArrayWithContiguous):
106     case asArrayModesIgnoringTypedArrays(ArrayWithContiguous):
107     case asArrayModesIgnoringTypedArrays(CopyOnWriteArrayWithContiguous):
108     case asArrayModesIgnoringTypedArrays(NonArrayWithContiguous) | asArrayModesIgnoringTypedArrays(ArrayWithContiguous):
109     case asArrayModesIgnoringTypedArrays(NonArrayWithContiguous) | asArrayModesIgnoringTypedArrays(CopyOnWriteArrayWithContiguous):
110     case asArrayModesIgnoringTypedArrays(ArrayWithContiguous) | asArrayModesIgnoringTypedArrays(CopyOnWriteArrayWithContiguous):
111     case asArrayModesIgnoringTypedArrays(NonArrayWithContiguous) | asArrayModesIgnoringTypedArrays(ArrayWithContiguous) | asArrayModesIgnoringTypedArrays(CopyOnWriteArrayWithContiguous):
112         return handleContiguousModes(Array::Contiguous, observed);
113
114     case asArrayModesIgnoringTypedArrays(NonArrayWithArrayStorage):
115         return ArrayMode(Array::ArrayStorage, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe);
116     case asArrayModesIgnoringTypedArrays(NonArrayWithSlowPutArrayStorage):
117     case asArrayModesIgnoringTypedArrays(NonArrayWithArrayStorage) | asArrayModesIgnoringTypedArrays(NonArrayWithSlowPutArrayStorage):
118         return ArrayMode(Array::SlowPutArrayStorage, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe);
119     case asArrayModesIgnoringTypedArrays(ArrayWithArrayStorage):
120         return ArrayMode(Array::ArrayStorage, Array::Array, Array::AsIs, action).withProfile(locker, profile, makeSafe);
121     case asArrayModesIgnoringTypedArrays(ArrayWithSlowPutArrayStorage):
122     case asArrayModesIgnoringTypedArrays(ArrayWithArrayStorage) | asArrayModesIgnoringTypedArrays(ArrayWithSlowPutArrayStorage):
123         return ArrayMode(Array::SlowPutArrayStorage, Array::Array, Array::AsIs, action).withProfile(locker, profile, makeSafe);
124     case asArrayModesIgnoringTypedArrays(NonArrayWithArrayStorage) | asArrayModesIgnoringTypedArrays(ArrayWithArrayStorage):
125         return ArrayMode(Array::ArrayStorage, Array::PossiblyArray, Array::AsIs, action).withProfile(locker, profile, makeSafe);
126     case asArrayModesIgnoringTypedArrays(NonArrayWithSlowPutArrayStorage) | asArrayModesIgnoringTypedArrays(ArrayWithSlowPutArrayStorage):
127     case asArrayModesIgnoringTypedArrays(NonArrayWithArrayStorage) | asArrayModesIgnoringTypedArrays(ArrayWithArrayStorage) | asArrayModesIgnoringTypedArrays(NonArrayWithSlowPutArrayStorage) | asArrayModesIgnoringTypedArrays(ArrayWithSlowPutArrayStorage):
128         return ArrayMode(Array::SlowPutArrayStorage, Array::PossiblyArray, Array::AsIs, action).withProfile(locker, profile, makeSafe);
129     case Int8ArrayMode:
130         return ArrayMode(Array::Int8Array, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe);
131     case Int16ArrayMode:
132         return ArrayMode(Array::Int16Array, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe);
133     case Int32ArrayMode:
134         return ArrayMode(Array::Int32Array, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe);
135     case Uint8ArrayMode:
136         return ArrayMode(Array::Uint8Array, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe);
137     case Uint8ClampedArrayMode:
138         return ArrayMode(Array::Uint8ClampedArray, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe);
139     case Uint16ArrayMode:
140         return ArrayMode(Array::Uint16Array, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe);
141     case Uint32ArrayMode:
142         return ArrayMode(Array::Uint32Array, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe);
143     case Float32ArrayMode:
144         return ArrayMode(Array::Float32Array, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe);
145     case Float64ArrayMode:
146         return ArrayMode(Array::Float64Array, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe);
147
148     default:
149         // If we have seen multiple TypedArray types, or a TypedArray and non-typed array, it doesn't make sense to try to convert the object since you can't convert typed arrays.
150         if (observed & ALL_TYPED_ARRAY_MODES)
151             return ArrayMode(Array::Generic, nonArray, Array::AsIs, action).withProfile(locker, profile, makeSafe);
152
153         if ((observed & asArrayModesIgnoringTypedArrays(NonArray)) && profile->mayInterceptIndexedAccesses(locker))
154             return ArrayMode(Array::SelectUsingPredictions).withSpeculationFromProfile(locker, profile, makeSafe);
155         
156         Array::Type type;
157         Array::Class arrayClass;
158         
159         if (shouldUseSlowPutArrayStorage(observed))
160             type = Array::SlowPutArrayStorage;
161         else if (shouldUseFastArrayStorage(observed))
162             type = Array::ArrayStorage;
163         else if (shouldUseContiguous(observed))
164             type = Array::Contiguous;
165         else if (shouldUseDouble(observed))
166             type = Array::Double;
167         else if (shouldUseInt32(observed))
168             type = Array::Int32;
169         else
170             type = Array::SelectUsingArguments;
171         
172         if (hasSeenArray(observed) && hasSeenNonArray(observed))
173             arrayClass = Array::PossiblyArray;
174         else if (hasSeenArray(observed))
175             arrayClass = Array::Array;
176         else if (hasSeenNonArray(observed))
177             arrayClass = nonArray;
178         else
179             arrayClass = Array::PossiblyArray;
180         
181         return ArrayMode(type, arrayClass, Array::Convert, action).withProfile(locker, profile, makeSafe);
182     }
183 }
184
185 static bool canBecomeGetArrayLength(Graph& graph, Node* node)
186 {
187     if (node->op() != GetById)
188         return false;
189     auto uid = graph.identifiers()[node->identifierNumber()];
190     return uid == graph.m_vm.propertyNames->length.impl();
191 }
192
193 ArrayMode ArrayMode::refine(
194     Graph& graph, Node* node,
195     SpeculatedType base, SpeculatedType index, SpeculatedType value) const
196 {
197     if (!base || !index) {
198         // It can be that we had a legitimate arrayMode but no incoming predictions. That'll
199         // happen if we inlined code based on, say, a global variable watchpoint, but later
200         // realized that the callsite could not have possibly executed. It may be worthwhile
201         // to fix that, but for now I'm leaving it as-is.
202         return ArrayMode(Array::ForceExit, action());
203     }
204     
205     if (!isInt32Speculation(index))
206         return ArrayMode(Array::Generic, action());
207     
208     // If we had exited because of an exotic object behavior, then don't try to specialize.
209     if (graph.hasExitSite(node->origin.semantic, ExoticObjectMode))
210         return ArrayMode(Array::Generic, action());
211     
212     // Note: our profiling currently doesn't give us good information in case we have
213     // an unlikely control flow path that sets the base to a non-cell value. Value
214     // profiling and prediction propagation will probably tell us that the value is
215     // either a cell or not, but that doesn't tell us which is more likely: that this
216     // is an array access on a cell (what we want and can optimize) or that the user is
217     // doing a crazy by-val access on a primitive (we can't easily optimize this and
218     // don't want to). So, for now, we assume that if the base is not a cell according
219     // to value profiling, but the array profile tells us something else, then we
220     // should just trust the array profile.
221
222     auto typedArrayResult = [&] (ArrayMode result) -> ArrayMode {
223         if (node->op() == PutByValDirect) {
224             // This is semantically identical to defineOwnProperty({configurable: true, writable:true, enumerable:true}),
225             // which we can't model as a simple store to the typed array since typed array indexed properties
226             // are non-configurable.
227             return ArrayMode(Array::Generic, action());
228         }
229         return result;
230     };
231     
232     switch (type()) {
233     case Array::SelectUsingArguments:
234         if (!value)
235             return withType(Array::ForceExit);
236         if (isInt32Speculation(value))
237             return withTypeAndConversion(Array::Int32, Array::Convert);
238         if (isFullNumberSpeculation(value))
239             return withTypeAndConversion(Array::Double, Array::Convert);
240         return withTypeAndConversion(Array::Contiguous, Array::Convert);
241     case Array::Undecided: {
242         // If we have an OriginalArray and the JSArray prototype chain is sane,
243         // any indexed access always return undefined. We have a fast path for that.
244         JSGlobalObject* globalObject = graph.globalObjectFor(node->origin.semantic);
245         Structure* arrayPrototypeStructure = globalObject->arrayPrototype()->structure(graph.m_vm);
246         Structure* objectPrototypeStructure = globalObject->objectPrototype()->structure(graph.m_vm);
247         if ((node->op() == GetByVal || canBecomeGetArrayLength(graph, node))
248             && isJSArrayWithOriginalStructure()
249             && !graph.hasExitSite(node->origin.semantic, OutOfBounds)
250             && arrayPrototypeStructure->transitionWatchpointSetIsStillValid()
251             && objectPrototypeStructure->transitionWatchpointSetIsStillValid()
252             && globalObject->arrayPrototypeChainIsSane()) {
253             graph.registerAndWatchStructureTransition(arrayPrototypeStructure);
254             graph.registerAndWatchStructureTransition(objectPrototypeStructure);
255             if (globalObject->arrayPrototypeChainIsSane())
256                 return withSpeculation(Array::SaneChain);
257         }
258         return ArrayMode(Array::Generic, action());
259     }
260     case Array::Int32:
261         if (!value || isInt32Speculation(value))
262             return *this;
263         if (isFullNumberSpeculation(value))
264             return withTypeAndConversion(Array::Double, Array::Convert);
265         return withTypeAndConversion(Array::Contiguous, Array::Convert);
266         
267     case Array::Double:
268         if (!value || isFullNumberSpeculation(value))
269             return *this;
270         return withTypeAndConversion(Array::Contiguous, Array::Convert);
271         
272     case Array::Contiguous:
273         return *this;
274
275     case Array::Int8Array:
276     case Array::Int16Array:
277     case Array::Int32Array:
278     case Array::Uint8Array:
279     case Array::Uint8ClampedArray:
280     case Array::Uint16Array:
281     case Array::Uint32Array:
282     case Array::Float32Array:
283     case Array::Float64Array:
284         if (node->op() == PutByVal) {
285             if (graph.hasExitSite(node->origin.semantic, OutOfBounds) || !isInBounds())
286                 return typedArrayResult(withSpeculation(Array::OutOfBounds));
287         }
288         return typedArrayResult(withSpeculation(Array::InBounds));
289     case Array::Unprofiled:
290     case Array::SelectUsingPredictions: {
291         base &= ~SpecOther;
292         
293         if (isStringSpeculation(base))
294             return withType(Array::String);
295         
296         if (isDirectArgumentsSpeculation(base) || isScopedArgumentsSpeculation(base)) {
297             // Handle out-of-bounds accesses as generic accesses.
298             Array::Type type = isDirectArgumentsSpeculation(base) ? Array::DirectArguments : Array::ScopedArguments;
299             if (graph.hasExitSite(node->origin.semantic, OutOfBounds) || !isInBounds()) {
300                 // FIXME: Support OOB access for ScopedArguments.
301                 // https://bugs.webkit.org/show_bug.cgi?id=179596
302                 if (type == Array::DirectArguments)
303                     return ArrayMode(type, Array::NonArray, Array::OutOfBounds, Array::AsIs, action());
304                 return ArrayMode(Array::Generic, action());
305             }
306             return withType(type);
307         }
308         
309         ArrayMode result;
310         switch (node->op()) {
311         case PutByVal:
312             if (graph.hasExitSite(node->origin.semantic, OutOfBounds) || !isInBounds())
313                 result = withSpeculation(Array::OutOfBounds);
314             else
315                 result = withSpeculation(Array::InBounds);
316             break;
317             
318         default:
319             result = withSpeculation(Array::InBounds);
320             break;
321         }
322
323         if (isInt8ArraySpeculation(base))
324             return typedArrayResult(result.withType(Array::Int8Array));
325         
326         if (isInt16ArraySpeculation(base))
327             return typedArrayResult(result.withType(Array::Int16Array));
328         
329         if (isInt32ArraySpeculation(base))
330             return typedArrayResult(result.withType(Array::Int32Array));
331         
332         if (isUint8ArraySpeculation(base))
333             return typedArrayResult(result.withType(Array::Uint8Array));
334         
335         if (isUint8ClampedArraySpeculation(base))
336             return typedArrayResult(result.withType(Array::Uint8ClampedArray));
337         
338         if (isUint16ArraySpeculation(base))
339             return typedArrayResult(result.withType(Array::Uint16Array));
340         
341         if (isUint32ArraySpeculation(base))
342             return typedArrayResult(result.withType(Array::Uint32Array));
343         
344         if (isFloat32ArraySpeculation(base))
345             return typedArrayResult(result.withType(Array::Float32Array));
346         
347         if (isFloat64ArraySpeculation(base))
348             return typedArrayResult(result.withType(Array::Float64Array));
349
350         if (type() == Array::Unprofiled)
351             return ArrayMode(Array::ForceExit, action());
352         return ArrayMode(Array::Generic, action());
353     }
354
355     default:
356         return *this;
357     }
358 }
359
360 Structure* ArrayMode::originalArrayStructure(Graph& graph, const CodeOrigin& codeOrigin) const
361 {
362     JSGlobalObject* globalObject = graph.globalObjectFor(codeOrigin);
363     
364     switch (arrayClass()) {
365     case Array::OriginalCopyOnWriteArray: {
366         if (conversion() == Array::AsIs) {
367             switch (type()) {
368             case Array::Int32:
369                 return globalObject->originalArrayStructureForIndexingType(CopyOnWriteArrayWithInt32);
370             case Array::Double:
371                 return globalObject->originalArrayStructureForIndexingType(CopyOnWriteArrayWithDouble);
372             case Array::Contiguous:
373                 return globalObject->originalArrayStructureForIndexingType(CopyOnWriteArrayWithContiguous);
374             default:
375                 CRASH();
376                 return nullptr;
377             }
378         }
379         FALLTHROUGH;
380     }
381
382     case Array::OriginalArray: {
383         switch (type()) {
384         case Array::Int32:
385             return globalObject->originalArrayStructureForIndexingType(ArrayWithInt32);
386         case Array::Double:
387             return globalObject->originalArrayStructureForIndexingType(ArrayWithDouble);
388         case Array::Contiguous:
389             return globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous);
390         case Array::Undecided:
391             return globalObject->originalArrayStructureForIndexingType(ArrayWithUndecided);
392         case Array::ArrayStorage:
393             return globalObject->originalArrayStructureForIndexingType(ArrayWithArrayStorage);
394         default:
395             CRASH();
396             return nullptr;
397         }
398     }
399         
400     case Array::OriginalNonArray: {
401         TypedArrayType type = typedArrayType();
402         if (type == NotTypedArray)
403             return nullptr;
404         
405         return globalObject->typedArrayStructureConcurrently(type);
406     }
407         
408     default:
409         return nullptr;
410     }
411 }
412
413 Structure* ArrayMode::originalArrayStructure(Graph& graph, Node* node) const
414 {
415     return originalArrayStructure(graph, node->origin.semantic);
416 }
417
418 bool ArrayMode::alreadyChecked(Graph& graph, Node* node, const AbstractValue& value, IndexingType shape) const
419 {
420     ASSERT(isSpecific());
421
422     IndexingType indexingModeMask = IsArray | IndexingShapeMask;
423     if (action() == Array::Write)
424         indexingModeMask |= CopyOnWrite;
425
426     switch (arrayClass()) {
427     case Array::Array: {
428         if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModesIgnoringTypedArrays(shape | IsArray)))
429             return true;
430         if (!value.m_structure.isFinite())
431             return false;
432         for (unsigned i = value.m_structure.size(); i--;) {
433             RegisteredStructure structure = value.m_structure[i];
434             if ((structure->indexingMode() & indexingModeMask) != (shape | IsArray))
435                 return false;
436         }
437         return true;
438     }
439
440     // Array::OriginalNonArray can be shown when the value is a TypedArray with original structure.
441     // But here, we already filtered TypedArrays. So, just handle it like a NonArray.
442     case Array::OriginalNonArray:
443     case Array::NonArray: {
444         if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModesIgnoringTypedArrays(shape)))
445             return true;
446         if (!value.m_structure.isFinite())
447             return false;
448         for (unsigned i = value.m_structure.size(); i--;) {
449             RegisteredStructure structure = value.m_structure[i];
450             if ((structure->indexingMode() & indexingModeMask) != shape)
451                 return false;
452         }
453         return true;
454     }
455
456     case Array::PossiblyArray: {
457         if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModesIgnoringTypedArrays(shape) | asArrayModesIgnoringTypedArrays(shape | IsArray)))
458             return true;
459         if (!value.m_structure.isFinite())
460             return false;
461         for (unsigned i = value.m_structure.size(); i--;) {
462             RegisteredStructure structure = value.m_structure[i];
463             if ((structure->indexingMode() & (indexingModeMask & ~IsArray)) != shape)
464                 return false;
465         }
466         return true;
467     }
468
469     // If ArrayMode is Array::OriginalCopyOnWriteArray or Array::OriginalArray, CheckArray is never emitted. Instead, we always emit CheckStructure.
470     // So, we should perform the same check to the CheckStructure here.
471     case Array::OriginalArray:
472     case Array::OriginalCopyOnWriteArray: {
473         if (!value.m_structure.isFinite())
474             return false;
475         Structure* originalStructure = originalArrayStructure(graph, node);
476         if (value.m_structure.size() != 1)
477             return false;
478         return value.m_structure.onlyStructure().get() == originalStructure;
479     }
480     }
481 }
482
483 bool ArrayMode::alreadyChecked(Graph& graph, Node* node, const AbstractValue& value) const
484 {
485     switch (type()) {
486     case Array::Generic:
487         return true;
488         
489     case Array::ForceExit:
490         return false;
491         
492     case Array::String:
493         return speculationChecked(value.m_type, SpecString);
494         
495     case Array::Int32:
496         return alreadyChecked(graph, node, value, Int32Shape);
497         
498     case Array::Double:
499         return alreadyChecked(graph, node, value, DoubleShape);
500         
501     case Array::Contiguous:
502         return alreadyChecked(graph, node, value, ContiguousShape);
503         
504     case Array::ArrayStorage:
505         return alreadyChecked(graph, node, value, ArrayStorageShape);
506
507     case Array::Undecided:
508         return alreadyChecked(graph, node, value, UndecidedShape);
509         
510     case Array::SlowPutArrayStorage:
511         switch (arrayClass()) {
512         case Array::OriginalArray: {
513             CRASH();
514             return false;
515         }
516         
517         case Array::Array: {
518             if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModesIgnoringTypedArrays(ArrayWithArrayStorage) | asArrayModesIgnoringTypedArrays(ArrayWithSlowPutArrayStorage)))
519                 return true;
520             if (value.m_structure.isTop())
521                 return false;
522             for (unsigned i = value.m_structure.size(); i--;) {
523                 RegisteredStructure structure = value.m_structure[i];
524                 if (!hasAnyArrayStorage(structure->indexingType()))
525                     return false;
526                 if (!(structure->indexingType() & IsArray))
527                     return false;
528             }
529             return true;
530         }
531         
532         default: {
533             if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModesIgnoringTypedArrays(NonArrayWithArrayStorage) | asArrayModesIgnoringTypedArrays(ArrayWithArrayStorage) | asArrayModesIgnoringTypedArrays(NonArrayWithSlowPutArrayStorage) | asArrayModesIgnoringTypedArrays(ArrayWithSlowPutArrayStorage)))
534                 return true;
535             if (value.m_structure.isTop())
536                 return false;
537             for (unsigned i = value.m_structure.size(); i--;) {
538                 RegisteredStructure structure = value.m_structure[i];
539                 if (!hasAnyArrayStorage(structure->indexingType()))
540                     return false;
541             }
542             return true;
543         } }
544         
545     case Array::DirectArguments:
546         return speculationChecked(value.m_type, SpecDirectArguments);
547         
548     case Array::ScopedArguments:
549         return speculationChecked(value.m_type, SpecScopedArguments);
550         
551     case Array::Int8Array:
552         return speculationChecked(value.m_type, SpecInt8Array);
553         
554     case Array::Int16Array:
555         return speculationChecked(value.m_type, SpecInt16Array);
556         
557     case Array::Int32Array:
558         return speculationChecked(value.m_type, SpecInt32Array);
559         
560     case Array::Uint8Array:
561         return speculationChecked(value.m_type, SpecUint8Array);
562         
563     case Array::Uint8ClampedArray:
564         return speculationChecked(value.m_type, SpecUint8ClampedArray);
565         
566     case Array::Uint16Array:
567         return speculationChecked(value.m_type, SpecUint16Array);
568         
569     case Array::Uint32Array:
570         return speculationChecked(value.m_type, SpecUint32Array);
571
572     case Array::Float32Array:
573         return speculationChecked(value.m_type, SpecFloat32Array);
574
575     case Array::Float64Array:
576         return speculationChecked(value.m_type, SpecFloat64Array);
577
578     case Array::AnyTypedArray:
579         return speculationChecked(value.m_type, SpecTypedArrayView);
580
581     case Array::SelectUsingPredictions:
582     case Array::Unprofiled:
583     case Array::SelectUsingArguments:
584         break;
585     }
586     
587     CRASH();
588     return false;
589 }
590
591 const char* arrayActionToString(Array::Action action)
592 {
593     switch (action) {
594     case Array::Read:
595         return "Read";
596     case Array::Write:
597         return "Write";
598     default:
599         return "Unknown!";
600     }
601 }
602
603 const char* arrayTypeToString(Array::Type type)
604 {
605     switch (type) {
606     case Array::SelectUsingPredictions:
607         return "SelectUsingPredictions";
608     case Array::SelectUsingArguments:
609         return "SelectUsingArguments";
610     case Array::Unprofiled:
611         return "Unprofiled";
612     case Array::Generic:
613         return "Generic";
614     case Array::ForceExit:
615         return "ForceExit";
616     case Array::String:
617         return "String";
618     case Array::Undecided:
619         return "Undecided";
620     case Array::Int32:
621         return "Int32";
622     case Array::Double:
623         return "Double";
624     case Array::Contiguous:
625         return "Contiguous";
626     case Array::ArrayStorage:
627         return "ArrayStorage";
628     case Array::SlowPutArrayStorage:
629         return "SlowPutArrayStorage";
630     case Array::DirectArguments:
631         return "DirectArguments";
632     case Array::ScopedArguments:
633         return "ScopedArguments";
634     case Array::Int8Array:
635         return "Int8Array";
636     case Array::Int16Array:
637         return "Int16Array";
638     case Array::Int32Array:
639         return "Int32Array";
640     case Array::Uint8Array:
641         return "Uint8Array";
642     case Array::Uint8ClampedArray:
643         return "Uint8ClampedArray";
644     case Array::Uint16Array:
645         return "Uint16Array";
646     case Array::Uint32Array:
647         return "Uint32Array";
648     case Array::Float32Array:
649         return "Float32Array";
650     case Array::Float64Array:
651         return "Float64Array";
652     case Array::AnyTypedArray:
653         return "AnyTypedArray";
654     default:
655         // Better to return something then it is to crash. Remember, this method
656         // is being called from our main diagnostic tool, the IR dumper. It's like
657         // a stack trace. So if we get here then probably something has already
658         // gone wrong.
659         return "Unknown!";
660     }
661 }
662
663 const char* arrayClassToString(Array::Class arrayClass)
664 {
665     switch (arrayClass) {
666     case Array::Array:
667         return "Array";
668     case Array::OriginalArray:
669         return "OriginalArray";
670     case Array::OriginalCopyOnWriteArray:
671         return "OriginalCopyOnWriteArray";
672     case Array::NonArray:
673         return "NonArray";
674     case Array::OriginalNonArray:
675         return "OriginalNonArray";
676     case Array::PossiblyArray:
677         return "PossiblyArray";
678     default:
679         return "Unknown!";
680     }
681 }
682
683 const char* arraySpeculationToString(Array::Speculation speculation)
684 {
685     switch (speculation) {
686     case Array::SaneChain:
687         return "SaneChain";
688     case Array::InBounds:
689         return "InBounds";
690     case Array::ToHole:
691         return "ToHole";
692     case Array::OutOfBounds:
693         return "OutOfBounds";
694     default:
695         return "Unknown!";
696     }
697 }
698
699 const char* arrayConversionToString(Array::Conversion conversion)
700 {
701     switch (conversion) {
702     case Array::AsIs:
703         return "AsIs";
704     case Array::Convert:
705         return "Convert";
706     default:
707         return "Unknown!";
708     }
709 }
710
711 IndexingType toIndexingShape(Array::Type type)
712 {
713     switch (type) {
714     case Array::Int32:
715         return Int32Shape;
716     case Array::Double:
717         return DoubleShape;
718     case Array::Contiguous:
719         return ContiguousShape;
720     case Array::Undecided:
721         return UndecidedShape;
722     case Array::ArrayStorage:
723         return ArrayStorageShape;
724     case Array::SlowPutArrayStorage:
725         return SlowPutArrayStorageShape;
726     default:
727         return NoIndexingShape;
728     }
729 }
730
731 TypedArrayType toTypedArrayType(Array::Type type)
732 {
733     switch (type) {
734     case Array::Int8Array:
735         return TypeInt8;
736     case Array::Int16Array:
737         return TypeInt16;
738     case Array::Int32Array:
739         return TypeInt32;
740     case Array::Uint8Array:
741         return TypeUint8;
742     case Array::Uint8ClampedArray:
743         return TypeUint8Clamped;
744     case Array::Uint16Array:
745         return TypeUint16;
746     case Array::Uint32Array:
747         return TypeUint32;
748     case Array::Float32Array:
749         return TypeFloat32;
750     case Array::Float64Array:
751         return TypeFloat64;
752     case Array::AnyTypedArray:
753         RELEASE_ASSERT_NOT_REACHED();
754         return NotTypedArray;
755     default:
756         return NotTypedArray;
757     }
758 }
759
760 Array::Type toArrayType(TypedArrayType type)
761 {
762     switch (type) {
763     case TypeInt8:
764         return Array::Int8Array;
765     case TypeInt16:
766         return Array::Int16Array;
767     case TypeInt32:
768         return Array::Int32Array;
769     case TypeUint8:
770         return Array::Uint8Array;
771     case TypeUint8Clamped:
772         return Array::Uint8ClampedArray;
773     case TypeUint16:
774         return Array::Uint16Array;
775     case TypeUint32:
776         return Array::Uint32Array;
777     case TypeFloat32:
778         return Array::Float32Array;
779     case TypeFloat64:
780         return Array::Float64Array;
781     default:
782         return Array::Generic;
783     }
784 }
785
786 Array::Type refineTypedArrayType(Array::Type oldType, TypedArrayType newType)
787 {
788     if (oldType == Array::Generic)
789         return oldType;
790     Array::Type newArrayType = toArrayType(newType);
791     if (newArrayType == Array::Generic)
792         return newArrayType;
793
794     if (oldType != newArrayType)
795         return Array::AnyTypedArray;
796     return oldType;
797 }
798
799 bool permitsBoundsCheckLowering(Array::Type type)
800 {
801     switch (type) {
802     case Array::Int32:
803     case Array::Double:
804     case Array::Contiguous:
805     case Array::ArrayStorage:
806     case Array::SlowPutArrayStorage:
807     case Array::Int8Array:
808     case Array::Int16Array:
809     case Array::Int32Array:
810     case Array::Uint8Array:
811     case Array::Uint8ClampedArray:
812     case Array::Uint16Array:
813     case Array::Uint32Array:
814     case Array::Float32Array:
815     case Array::Float64Array:
816     case Array::AnyTypedArray:
817         return true;
818     default:
819         // These don't allow for bounds check lowering either because the bounds
820         // check isn't a speculation (like String, sort of) or because the type implies an impure access.
821         return false;
822     }
823 }
824
825 bool ArrayMode::permitsBoundsCheckLowering() const
826 {
827     return DFG::permitsBoundsCheckLowering(type()) && isInBounds();
828 }
829
830 void ArrayMode::dump(PrintStream& out) const
831 {
832     out.print(type(), "+", arrayClass(), "+", speculation(), "+", conversion(), "+", action());
833 }
834
835 } } // namespace JSC::DFG
836
837 namespace WTF {
838
839 void printInternal(PrintStream& out, JSC::DFG::Array::Action action)
840 {
841     out.print(JSC::DFG::arrayActionToString(action));
842 }
843
844 void printInternal(PrintStream& out, JSC::DFG::Array::Type type)
845 {
846     out.print(JSC::DFG::arrayTypeToString(type));
847 }
848
849 void printInternal(PrintStream& out, JSC::DFG::Array::Class arrayClass)
850 {
851     out.print(JSC::DFG::arrayClassToString(arrayClass));
852 }
853
854 void printInternal(PrintStream& out, JSC::DFG::Array::Speculation speculation)
855 {
856     out.print(JSC::DFG::arraySpeculationToString(speculation));
857 }
858
859 void printInternal(PrintStream& out, JSC::DFG::Array::Conversion conversion)
860 {
861     out.print(JSC::DFG::arrayConversionToString(conversion));
862 }
863
864 } // namespace WTF
865
866 #endif // ENABLE(DFG_JIT)
867