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