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