[JSC] Add support for typed arrays to the Array profiling
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGArrayMode.cpp
1 /*
2  * Copyright (C) 2012-2015 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 "DFGAbstractValue.h"
32 #include "DFGGraph.h"
33 #include "JSCInlines.h"
34
35 namespace JSC { namespace DFG {
36
37 ArrayMode ArrayMode::fromObserved(const ConcurrentJITLocker& locker, ArrayProfile* profile, Array::Action action, bool makeSafe)
38 {
39     Array::Class nonArray;
40     if (profile->usesOriginalArrayStructures(locker))
41         nonArray = Array::OriginalNonArray;
42     else
43         nonArray = Array::NonArray;
44     
45     ArrayModes observed = profile->observedArrayModes(locker);
46     switch (observed) {
47     case 0:
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);
53
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);
58         
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);
63
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);
70
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);
77
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);
84
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);
100     case Int8ArrayMode:
101         return ArrayMode(Array::Int8Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe);
102     case Int16ArrayMode:
103         return ArrayMode(Array::Int16Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe);
104     case Int32ArrayMode:
105         return ArrayMode(Array::Int32Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe);
106     case Uint8ArrayMode:
107         return ArrayMode(Array::Uint8Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe);
108     case Uint8ClampedArrayMode:
109         return ArrayMode(Array::Uint8ClampedArray, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe);
110     case Uint16ArrayMode:
111         return ArrayMode(Array::Uint16Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe);
112     case Uint32ArrayMode:
113         return ArrayMode(Array::Uint32Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe);
114     case Float32ArrayMode:
115         return ArrayMode(Array::Float32Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe);
116     case Float64ArrayMode:
117         return ArrayMode(Array::Float64Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe);
118
119     default:
120         if ((observed & asArrayModes(NonArray)) && profile->mayInterceptIndexedAccesses(locker))
121             return ArrayMode(Array::SelectUsingPredictions).withSpeculationFromProfile(locker, profile, makeSafe);
122         
123         Array::Type type;
124         Array::Class arrayClass;
125         
126         if (shouldUseSlowPutArrayStorage(observed))
127             type = Array::SlowPutArrayStorage;
128         else if (shouldUseFastArrayStorage(observed))
129             type = Array::ArrayStorage;
130         else if (shouldUseContiguous(observed))
131             type = Array::Contiguous;
132         else if (shouldUseDouble(observed))
133             type = Array::Double;
134         else if (shouldUseInt32(observed))
135             type = Array::Int32;
136         else
137             type = Array::Undecided;
138         
139         if (hasSeenArray(observed) && hasSeenNonArray(observed))
140             arrayClass = Array::PossiblyArray;
141         else if (hasSeenArray(observed))
142             arrayClass = Array::Array;
143         else if (hasSeenNonArray(observed))
144             arrayClass = nonArray;
145         else
146             arrayClass = Array::PossiblyArray;
147         
148         return ArrayMode(type, arrayClass, Array::Convert).withProfile(locker, profile, makeSafe);
149     }
150 }
151
152 ArrayMode ArrayMode::refine(
153     Graph& graph, Node* node,
154     SpeculatedType base, SpeculatedType index, SpeculatedType value,
155     NodeFlags flags) const
156 {
157     if (!base || !index) {
158         // It can be that we had a legitimate arrayMode but no incoming predictions. That'll
159         // happen if we inlined code based on, say, a global variable watchpoint, but later
160         // realized that the callsite could not have possibly executed. It may be worthwhile
161         // to fix that, but for now I'm leaving it as-is.
162         return ArrayMode(Array::ForceExit);
163     }
164     
165     if (!isInt32Speculation(index))
166         return ArrayMode(Array::Generic);
167     
168     // If we had exited because of an exotic object behavior, then don't try to specialize.
169     if (graph.hasExitSite(node->origin.semantic, ExoticObjectMode))
170         return ArrayMode(Array::Generic);
171     
172     // Note: our profiling currently doesn't give us good information in case we have
173     // an unlikely control flow path that sets the base to a non-cell value. Value
174     // profiling and prediction propagation will probably tell us that the value is
175     // either a cell or not, but that doesn't tell us which is more likely: that this
176     // is an array access on a cell (what we want and can optimize) or that the user is
177     // doing a crazy by-val access on a primitive (we can't easily optimize this and
178     // don't want to). So, for now, we assume that if the base is not a cell according
179     // to value profiling, but the array profile tells us something else, then we
180     // should just trust the array profile.
181     
182     switch (type()) {
183     case Array::Undecided:
184         if (!value)
185             return withType(Array::ForceExit);
186         if (isInt32Speculation(value))
187             return withTypeAndConversion(Array::Int32, Array::Convert);
188         if (isFullNumberSpeculation(value))
189             return withTypeAndConversion(Array::Double, Array::Convert);
190         return withTypeAndConversion(Array::Contiguous, Array::Convert);
191         
192     case Array::Int32:
193         if (!value || isInt32Speculation(value))
194             return *this;
195         if (isFullNumberSpeculation(value))
196             return withTypeAndConversion(Array::Double, Array::Convert);
197         return withTypeAndConversion(Array::Contiguous, Array::Convert);
198         
199     case Array::Double:
200         if (flags & NodeBytecodeUsesAsInt)
201             return withTypeAndConversion(Array::Contiguous, Array::RageConvert);
202         if (!value || isFullNumberSpeculation(value))
203             return *this;
204         return withTypeAndConversion(Array::Contiguous, Array::Convert);
205         
206     case Array::Contiguous:
207         if (doesConversion() && (flags & NodeBytecodeUsesAsInt))
208             return withConversion(Array::RageConvert);
209         return *this;
210
211     case Array::Int8Array:
212     case Array::Int16Array:
213     case Array::Int32Array:
214     case Array::Uint8Array:
215     case Array::Uint8ClampedArray:
216     case Array::Uint16Array:
217     case Array::Uint32Array:
218     case Array::Float32Array:
219     case Array::Float64Array:
220         switch (node->op()) {
221         case PutByVal:
222             if (graph.hasExitSite(node->origin.semantic, OutOfBounds) || !isInBounds())
223                 return withSpeculation(Array::OutOfBounds);
224             return withSpeculation(Array::InBounds);
225         default:
226             return withSpeculation(Array::InBounds);
227         }
228         return *this;
229     case Array::Unprofiled:
230     case Array::SelectUsingPredictions: {
231         base &= ~SpecOther;
232         
233         if (isStringSpeculation(base))
234             return withType(Array::String);
235         
236         if (isDirectArgumentsSpeculation(base) || isScopedArgumentsSpeculation(base)) {
237             // Handle out-of-bounds accesses as generic accesses.
238             if (graph.hasExitSite(node->origin.semantic, OutOfBounds) || !isInBounds())
239                 return ArrayMode(Array::Generic);
240             
241             if (isDirectArgumentsSpeculation(base))
242                 return withType(Array::DirectArguments);
243             return withType(Array::ScopedArguments);
244         }
245         
246         ArrayMode result;
247         switch (node->op()) {
248         case PutByVal:
249             if (graph.hasExitSite(node->origin.semantic, OutOfBounds) || !isInBounds())
250                 result = withSpeculation(Array::OutOfBounds);
251             else
252                 result = withSpeculation(Array::InBounds);
253             break;
254             
255         default:
256             result = withSpeculation(Array::InBounds);
257             break;
258         }
259         
260         if (isInt8ArraySpeculation(base))
261             return result.withType(Array::Int8Array);
262         
263         if (isInt16ArraySpeculation(base))
264             return result.withType(Array::Int16Array);
265         
266         if (isInt32ArraySpeculation(base))
267             return result.withType(Array::Int32Array);
268         
269         if (isUint8ArraySpeculation(base))
270             return result.withType(Array::Uint8Array);
271         
272         if (isUint8ClampedArraySpeculation(base))
273             return result.withType(Array::Uint8ClampedArray);
274         
275         if (isUint16ArraySpeculation(base))
276             return result.withType(Array::Uint16Array);
277         
278         if (isUint32ArraySpeculation(base))
279             return result.withType(Array::Uint32Array);
280         
281         if (isFloat32ArraySpeculation(base))
282             return result.withType(Array::Float32Array);
283         
284         if (isFloat64ArraySpeculation(base))
285             return result.withType(Array::Float64Array);
286
287         if (type() == Array::Unprofiled)
288             return ArrayMode(Array::ForceExit);
289         return ArrayMode(Array::Generic);
290     }
291
292     default:
293         return *this;
294     }
295 }
296
297 Structure* ArrayMode::originalArrayStructure(Graph& graph, const CodeOrigin& codeOrigin) const
298 {
299     JSGlobalObject* globalObject = graph.globalObjectFor(codeOrigin);
300     
301     switch (arrayClass()) {
302     case Array::OriginalArray: {
303         switch (type()) {
304         case Array::Int32:
305             return globalObject->originalArrayStructureForIndexingType(ArrayWithInt32);
306         case Array::Double:
307             return globalObject->originalArrayStructureForIndexingType(ArrayWithDouble);
308         case Array::Contiguous:
309             return globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous);
310         case Array::ArrayStorage:
311             return globalObject->originalArrayStructureForIndexingType(ArrayWithArrayStorage);
312         default:
313             CRASH();
314             return 0;
315         }
316     }
317         
318     case Array::OriginalNonArray: {
319         TypedArrayType type = typedArrayType();
320         if (type == NotTypedArray)
321             return 0;
322         
323         return globalObject->typedArrayStructure(type);
324     }
325         
326     default:
327         return 0;
328     }
329 }
330
331 Structure* ArrayMode::originalArrayStructure(Graph& graph, Node* node) const
332 {
333     return originalArrayStructure(graph, node->origin.semantic);
334 }
335
336 bool ArrayMode::alreadyChecked(Graph& graph, Node* node, AbstractValue& value, IndexingType shape) const
337 {
338     switch (arrayClass()) {
339     case Array::OriginalArray: {
340         if (value.m_structure.isTop())
341             return false;
342         for (unsigned i = value.m_structure.size(); i--;) {
343             Structure* structure = value.m_structure[i];
344             if ((structure->indexingType() & IndexingShapeMask) != shape)
345                 return false;
346             if (!(structure->indexingType() & IsArray))
347                 return false;
348             if (!graph.globalObjectFor(node->origin.semantic)->isOriginalArrayStructure(structure))
349                 return false;
350         }
351         return true;
352     }
353         
354     case Array::Array: {
355         if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(shape | IsArray)))
356             return true;
357         if (value.m_structure.isTop())
358             return false;
359         for (unsigned i = value.m_structure.size(); i--;) {
360             Structure* structure = value.m_structure[i];
361             if ((structure->indexingType() & IndexingShapeMask) != shape)
362                 return false;
363             if (!(structure->indexingType() & IsArray))
364                 return false;
365         }
366         return true;
367     }
368         
369     default: {
370         if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(shape) | asArrayModes(shape | IsArray)))
371             return true;
372         if (value.m_structure.isTop())
373             return false;
374         for (unsigned i = value.m_structure.size(); i--;) {
375             Structure* structure = value.m_structure[i];
376             if ((structure->indexingType() & IndexingShapeMask) != shape)
377                 return false;
378         }
379         return true;
380     } }
381 }
382
383 bool ArrayMode::alreadyChecked(Graph& graph, Node* node, AbstractValue& value) const
384 {
385     switch (type()) {
386     case Array::Generic:
387         return true;
388         
389     case Array::ForceExit:
390         return false;
391         
392     case Array::String:
393         return speculationChecked(value.m_type, SpecString);
394         
395     case Array::Int32:
396         return alreadyChecked(graph, node, value, Int32Shape);
397         
398     case Array::Double:
399         return alreadyChecked(graph, node, value, DoubleShape);
400         
401     case Array::Contiguous:
402         return alreadyChecked(graph, node, value, ContiguousShape);
403         
404     case Array::ArrayStorage:
405         return alreadyChecked(graph, node, value, ArrayStorageShape);
406         
407     case Array::SlowPutArrayStorage:
408         switch (arrayClass()) {
409         case Array::OriginalArray: {
410             CRASH();
411             return false;
412         }
413         
414         case Array::Array: {
415             if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(ArrayWithArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage)))
416                 return true;
417             if (value.m_structure.isTop())
418                 return false;
419             for (unsigned i = value.m_structure.size(); i--;) {
420                 Structure* structure = value.m_structure[i];
421                 if (!hasAnyArrayStorage(structure->indexingType()))
422                     return false;
423                 if (!(structure->indexingType() & IsArray))
424                     return false;
425             }
426             return true;
427         }
428         
429         default: {
430             if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage)))
431                 return true;
432             if (value.m_structure.isTop())
433                 return false;
434             for (unsigned i = value.m_structure.size(); i--;) {
435                 Structure* structure = value.m_structure[i];
436                 if (!hasAnyArrayStorage(structure->indexingType()))
437                     return false;
438             }
439             return true;
440         } }
441         
442     case Array::DirectArguments:
443         return speculationChecked(value.m_type, SpecDirectArguments);
444         
445     case Array::ScopedArguments:
446         return speculationChecked(value.m_type, SpecScopedArguments);
447         
448     case Array::Int8Array:
449         return speculationChecked(value.m_type, SpecInt8Array);
450         
451     case Array::Int16Array:
452         return speculationChecked(value.m_type, SpecInt16Array);
453         
454     case Array::Int32Array:
455         return speculationChecked(value.m_type, SpecInt32Array);
456         
457     case Array::Uint8Array:
458         return speculationChecked(value.m_type, SpecUint8Array);
459         
460     case Array::Uint8ClampedArray:
461         return speculationChecked(value.m_type, SpecUint8ClampedArray);
462         
463     case Array::Uint16Array:
464         return speculationChecked(value.m_type, SpecUint16Array);
465         
466     case Array::Uint32Array:
467         return speculationChecked(value.m_type, SpecUint32Array);
468
469     case Array::Float32Array:
470         return speculationChecked(value.m_type, SpecFloat32Array);
471
472     case Array::Float64Array:
473         return speculationChecked(value.m_type, SpecFloat64Array);
474         
475     case Array::SelectUsingPredictions:
476     case Array::Unprofiled:
477     case Array::Undecided:
478         break;
479     }
480     
481     CRASH();
482     return false;
483 }
484
485 const char* arrayTypeToString(Array::Type type)
486 {
487     switch (type) {
488     case Array::SelectUsingPredictions:
489         return "SelectUsingPredictions";
490     case Array::Unprofiled:
491         return "Unprofiled";
492     case Array::Generic:
493         return "Generic";
494     case Array::ForceExit:
495         return "ForceExit";
496     case Array::String:
497         return "String";
498     case Array::Undecided:
499         return "Undecided";
500     case Array::Int32:
501         return "Int32";
502     case Array::Double:
503         return "Double";
504     case Array::Contiguous:
505         return "Contiguous";
506     case Array::ArrayStorage:
507         return "ArrayStorage";
508     case Array::SlowPutArrayStorage:
509         return "SlowPutArrayStorage";
510     case Array::DirectArguments:
511         return "DirectArguments";
512     case Array::ScopedArguments:
513         return "ScopedArguments";
514     case Array::Int8Array:
515         return "Int8Array";
516     case Array::Int16Array:
517         return "Int16Array";
518     case Array::Int32Array:
519         return "Int32Array";
520     case Array::Uint8Array:
521         return "Uint8Array";
522     case Array::Uint8ClampedArray:
523         return "Uint8ClampedArray";
524     case Array::Uint16Array:
525         return "Uint16Array";
526     case Array::Uint32Array:
527         return "Uint32Array";
528     case Array::Float32Array:
529         return "Float32Array";
530     case Array::Float64Array:
531         return "Float64Array";
532     default:
533         // Better to return something then it is to crash. Remember, this method
534         // is being called from our main diagnostic tool, the IR dumper. It's like
535         // a stack trace. So if we get here then probably something has already
536         // gone wrong.
537         return "Unknown!";
538     }
539 }
540
541 const char* arrayClassToString(Array::Class arrayClass)
542 {
543     switch (arrayClass) {
544     case Array::Array:
545         return "Array";
546     case Array::OriginalArray:
547         return "OriginalArray";
548     case Array::NonArray:
549         return "NonArray";
550     case Array::OriginalNonArray:
551         return "OriginalNonArray";
552     case Array::PossiblyArray:
553         return "PossiblyArray";
554     default:
555         return "Unknown!";
556     }
557 }
558
559 const char* arraySpeculationToString(Array::Speculation speculation)
560 {
561     switch (speculation) {
562     case Array::SaneChain:
563         return "SaneChain";
564     case Array::InBounds:
565         return "InBounds";
566     case Array::ToHole:
567         return "ToHole";
568     case Array::OutOfBounds:
569         return "OutOfBounds";
570     default:
571         return "Unknown!";
572     }
573 }
574
575 const char* arrayConversionToString(Array::Conversion conversion)
576 {
577     switch (conversion) {
578     case Array::AsIs:
579         return "AsIs";
580     case Array::Convert:
581         return "Convert";
582     case Array::RageConvert:
583         return "RageConvert";
584     default:
585         return "Unknown!";
586     }
587 }
588
589 IndexingType toIndexingShape(Array::Type type)
590 {
591     switch (type) {
592     case Array::Int32:
593         return Int32Shape;
594     case Array::Double:
595         return DoubleShape;
596     case Array::Contiguous:
597         return ContiguousShape;
598     case Array::ArrayStorage:
599         return ArrayStorageShape;
600     case Array::SlowPutArrayStorage:
601         return SlowPutArrayStorageShape;
602     default:
603         return NoIndexingShape;
604     }
605 }
606
607 TypedArrayType toTypedArrayType(Array::Type type)
608 {
609     switch (type) {
610     case Array::Int8Array:
611         return TypeInt8;
612     case Array::Int16Array:
613         return TypeInt16;
614     case Array::Int32Array:
615         return TypeInt32;
616     case Array::Uint8Array:
617         return TypeUint8;
618     case Array::Uint8ClampedArray:
619         return TypeUint8Clamped;
620     case Array::Uint16Array:
621         return TypeUint16;
622     case Array::Uint32Array:
623         return TypeUint32;
624     case Array::Float32Array:
625         return TypeFloat32;
626     case Array::Float64Array:
627         return TypeFloat64;
628     default:
629         return NotTypedArray;
630     }
631 }
632
633 Array::Type toArrayType(TypedArrayType type)
634 {
635     switch (type) {
636     case TypeInt8:
637         return Array::Int8Array;
638     case TypeInt16:
639         return Array::Int16Array;
640     case TypeInt32:
641         return Array::Int32Array;
642     case TypeUint8:
643         return Array::Uint8Array;
644     case TypeUint8Clamped:
645         return Array::Uint8ClampedArray;
646     case TypeUint16:
647         return Array::Uint16Array;
648     case TypeUint32:
649         return Array::Uint32Array;
650     case TypeFloat32:
651         return Array::Float32Array;
652     case TypeFloat64:
653         return Array::Float64Array;
654     default:
655         return Array::Generic;
656     }
657 }
658
659 bool permitsBoundsCheckLowering(Array::Type type)
660 {
661     switch (type) {
662     case Array::Int32:
663     case Array::Double:
664     case Array::Contiguous:
665     case Array::Int8Array:
666     case Array::Int16Array:
667     case Array::Int32Array:
668     case Array::Uint8Array:
669     case Array::Uint8ClampedArray:
670     case Array::Uint16Array:
671     case Array::Uint32Array:
672     case Array::Float32Array:
673     case Array::Float64Array:
674         return true;
675     default:
676         // These don't allow for bounds check lowering either because the bounds
677         // check involves something other than GetArrayLength (like ArrayStorage),
678         // or because the bounds check isn't a speculation (like String, sort of),
679         // or because the type implies an impure access.
680         return false;
681     }
682 }
683
684 bool ArrayMode::permitsBoundsCheckLowering() const
685 {
686     return DFG::permitsBoundsCheckLowering(type()) && isInBounds();
687 }
688
689 void ArrayMode::dump(PrintStream& out) const
690 {
691     out.print(type(), arrayClass(), speculation(), conversion());
692 }
693
694 } } // namespace JSC::DFG
695
696 namespace WTF {
697
698 void printInternal(PrintStream& out, JSC::DFG::Array::Type type)
699 {
700     out.print(JSC::DFG::arrayTypeToString(type));
701 }
702
703 void printInternal(PrintStream& out, JSC::DFG::Array::Class arrayClass)
704 {
705     out.print(JSC::DFG::arrayClassToString(arrayClass));
706 }
707
708 void printInternal(PrintStream& out, JSC::DFG::Array::Speculation speculation)
709 {
710     out.print(JSC::DFG::arraySpeculationToString(speculation));
711 }
712
713 void printInternal(PrintStream& out, JSC::DFG::Array::Conversion conversion)
714 {
715     out.print(JSC::DFG::arrayConversionToString(conversion));
716 }
717
718 } // namespace WTF
719
720 #endif // ENABLE(DFG_JIT)
721