3985d769ce6a3cef69be8f72bf40c800956475b5
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGArrayMode.cpp
1 /*
2  * Copyright (C) 2012 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
33 namespace JSC { namespace DFG {
34
35 Array::Mode fromObserved(ArrayProfile* profile, Array::Action action, bool makeSafe)
36 {
37     switch (profile->observedArrayModes()) {
38     case 0:
39         return Array::Unprofiled;
40     case asArrayModes(NonArray):
41         if (action == Array::Write && !profile->mayInterceptIndexedAccesses())
42             return Array::ToContiguous; // FIXME: we don't know whether to go to contiguous or array storage. We're making a static guess here. In future we should use exit profiling for this.
43         return Array::Undecided;
44     case asArrayModes(NonArrayWithContiguous):
45         return makeSafe ? Array::ContiguousOutOfBounds : (profile->mayStoreToHole() ? Array::ContiguousToTail : Array::Contiguous);
46     case asArrayModes(ArrayWithContiguous):
47         return makeSafe ? Array::ArrayWithContiguousOutOfBounds : (profile->mayStoreToHole() ? Array::ArrayWithContiguousToTail : Array::ArrayWithContiguous);
48     case asArrayModes(NonArrayWithContiguous) | asArrayModes(ArrayWithContiguous):
49         return makeSafe ? Array::PossiblyArrayWithContiguousOutOfBounds : (profile->mayStoreToHole() ? Array::PossiblyArrayWithContiguousToTail : Array::PossiblyArrayWithContiguous);
50     case asArrayModes(NonArrayWithArrayStorage):
51         return makeSafe ? Array::ArrayStorageOutOfBounds : (profile->mayStoreToHole() ? Array::ArrayStorageToHole : Array::ArrayStorage);
52     case asArrayModes(NonArrayWithSlowPutArrayStorage):
53     case asArrayModes(NonArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage):
54         return Array::SlowPutArrayStorage;
55     case asArrayModes(ArrayWithArrayStorage):
56         return makeSafe ? Array::ArrayWithArrayStorageOutOfBounds : (profile->mayStoreToHole() ? Array::ArrayWithArrayStorageToHole : Array::ArrayWithArrayStorage);
57     case asArrayModes(ArrayWithSlowPutArrayStorage):
58     case asArrayModes(ArrayWithArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage):
59         return Array::ArrayWithSlowPutArrayStorage;
60     case asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage):
61         return makeSafe ? Array::PossiblyArrayWithArrayStorageOutOfBounds : (profile->mayStoreToHole() ? Array::PossiblyArrayWithArrayStorageToHole : Array::PossiblyArrayWithArrayStorage);
62     case asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage):
63     case asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage):
64         return Array::PossiblyArrayWithSlowPutArrayStorage;
65     case asArrayModes(NonArrayWithContiguous) | asArrayModes(NonArrayWithArrayStorage):
66         return Array::ToArrayStorage;
67     case asArrayModes(ArrayWithContiguous) | asArrayModes(ArrayWithArrayStorage):
68         return Array::ArrayToArrayStorage;
69     case asArrayModes(NonArrayWithContiguous) | asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithContiguous) | asArrayModes(ArrayWithArrayStorage):
70         return Array::PossiblyArrayToArrayStorage;
71     case asArrayModes(NonArray) | asArrayModes(NonArrayWithContiguous):
72         if (action == Array::Write && !profile->mayInterceptIndexedAccesses())
73             return Array::ToContiguous;
74         return Array::Undecided;
75     case asArrayModes(NonArray) | asArrayModes(NonArrayWithContiguous) | asArrayModes(NonArrayWithArrayStorage):
76     case asArrayModes(NonArray) | asArrayModes(NonArrayWithArrayStorage):
77         if (action == Array::Write && !profile->mayInterceptIndexedAccesses())
78             return Array::ToArrayStorage;
79         return Array::Undecided;
80     case asArrayModes(NonArray) | asArrayModes(NonArrayWithSlowPutArrayStorage):
81     case asArrayModes(NonArray) | asArrayModes(NonArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage):
82         if (action == Array::Write && !profile->mayInterceptIndexedAccesses())
83             return Array::ToSlowPutArrayStorage;
84         return Array::Undecided;
85     default:
86         // We know that this is possibly a kind of array for which, though there is no
87         // useful data in the array profile, we may be able to extract useful data from
88         // the value profiles of the inputs. Hence, we leave it as undecided, and let
89         // the predictions propagator decide later.
90         return Array::Undecided;
91     }
92 }
93
94 Array::Mode refineArrayMode(Array::Mode arrayMode, SpeculatedType base, SpeculatedType index)
95 {
96     if (!base || !index) {
97         // It can be that we had a legitimate arrayMode but no incoming predictions. That'll
98         // happen if we inlined code based on, say, a global variable watchpoint, but later
99         // realized that the callsite could not have possibly executed. It may be worthwhile
100         // to fix that, but for now I'm leaving it as-is.
101         return Array::ForceExit;
102     }
103     
104     if (!isInt32Speculation(index) || !isCellSpeculation(base))
105         return Array::Generic;
106     
107     if (arrayMode == Array::Unprofiled) {
108         // If the indexing type wasn't recorded in the array profile but the values are
109         // base=cell property=int, then we know that this access didn't execute.
110         return Array::ForceExit;
111     }
112     
113     if (arrayMode != Array::Undecided)
114         return arrayMode;
115     
116     if (isStringSpeculation(base))
117         return Array::String;
118     
119     if (isArgumentsSpeculation(base))
120         return Array::Arguments;
121     
122     if (isInt8ArraySpeculation(base))
123         return Array::Int8Array;
124     
125     if (isInt16ArraySpeculation(base))
126         return Array::Int16Array;
127     
128     if (isInt32ArraySpeculation(base))
129         return Array::Int32Array;
130     
131     if (isUint8ArraySpeculation(base))
132         return Array::Uint8Array;
133     
134     if (isUint8ClampedArraySpeculation(base))
135         return Array::Uint8ClampedArray;
136     
137     if (isUint16ArraySpeculation(base))
138         return Array::Uint16Array;
139     
140     if (isUint32ArraySpeculation(base))
141         return Array::Uint32Array;
142     
143     if (isFloat32ArraySpeculation(base))
144         return Array::Float32Array;
145     
146     if (isFloat64ArraySpeculation(base))
147         return Array::Float64Array;
148     
149     return Array::Generic;
150 }
151
152 bool modeAlreadyChecked(AbstractValue& value, Array::Mode arrayMode)
153 {
154     switch (arrayMode) {
155     case Array::Generic:
156         return true;
157         
158     case Array::ForceExit:
159         return false;
160         
161     case Array::String:
162         return isStringSpeculation(value.m_type);
163         
164     case Array::Contiguous:
165     case Array::ContiguousToTail:
166     case Array::ContiguousOutOfBounds:
167     case Array::PossiblyArrayWithContiguous:
168     case Array::PossiblyArrayWithContiguousToTail:
169     case Array::PossiblyArrayWithContiguousOutOfBounds:
170         return value.m_currentKnownStructure.hasSingleton()
171             && hasContiguous(value.m_currentKnownStructure.singleton()->indexingType());
172         
173     case Array::ArrayWithContiguous:
174     case Array::ArrayWithContiguousToTail:
175     case Array::ArrayWithContiguousOutOfBounds:
176         return value.m_currentKnownStructure.hasSingleton()
177             && hasContiguous(value.m_currentKnownStructure.singleton()->indexingType())
178             && (value.m_currentKnownStructure.singleton()->indexingType() & IsArray);
179
180     case Array::ArrayStorage:
181     case Array::ArrayStorageToHole:
182     case Array::ArrayStorageOutOfBounds:
183     case Array::PossiblyArrayWithArrayStorage:
184     case Array::PossiblyArrayWithArrayStorageToHole:
185     case Array::PossiblyArrayWithArrayStorageOutOfBounds:
186         return value.m_currentKnownStructure.hasSingleton()
187             && hasFastArrayStorage(value.m_currentKnownStructure.singleton()->indexingType());
188         
189     case Array::SlowPutArrayStorage:
190     case Array::PossiblyArrayWithSlowPutArrayStorage:
191         return value.m_currentKnownStructure.hasSingleton()
192             && hasArrayStorage(value.m_currentKnownStructure.singleton()->indexingType());
193         
194     case Array::ArrayWithArrayStorage:
195     case Array::ArrayWithArrayStorageToHole:
196     case Array::ArrayWithArrayStorageOutOfBounds:
197         return value.m_currentKnownStructure.hasSingleton()
198             && hasFastArrayStorage(value.m_currentKnownStructure.singleton()->indexingType())
199             && (value.m_currentKnownStructure.singleton()->indexingType() & IsArray);
200         
201     case Array::ArrayWithSlowPutArrayStorage:
202         return value.m_currentKnownStructure.hasSingleton()
203             && hasArrayStorage(value.m_currentKnownStructure.singleton()->indexingType())
204             && (value.m_currentKnownStructure.singleton()->indexingType() & IsArray);
205         
206     case ALL_EFFECTFUL_MODES:
207         return false;
208         
209     case Array::Arguments:
210         return isArgumentsSpeculation(value.m_type);
211         
212     case Array::Int8Array:
213         return isInt8ArraySpeculation(value.m_type);
214         
215     case Array::Int16Array:
216         return isInt16ArraySpeculation(value.m_type);
217         
218     case Array::Int32Array:
219         return isInt32ArraySpeculation(value.m_type);
220         
221     case Array::Uint8Array:
222         return isUint8ArraySpeculation(value.m_type);
223         
224     case Array::Uint8ClampedArray:
225         return isUint8ClampedArraySpeculation(value.m_type);
226         
227     case Array::Uint16Array:
228         return isUint16ArraySpeculation(value.m_type);
229         
230     case Array::Uint32Array:
231         return isUint32ArraySpeculation(value.m_type);
232
233     case Array::Float32Array:
234         return isFloat32ArraySpeculation(value.m_type);
235
236     case Array::Float64Array:
237         return isFloat64ArraySpeculation(value.m_type);
238         
239     case Array::Undecided:
240     case Array::Unprofiled:
241         break;
242     }
243     
244     ASSERT_NOT_REACHED();
245     return false;
246 }
247
248 const char* modeToString(Array::Mode mode)
249 {
250     switch (mode) {
251     case Array::Undecided:
252         return "Undecided";
253     case Array::Unprofiled:
254         return "Unprofiled";
255     case Array::Generic:
256         return "Generic";
257     case Array::ForceExit:
258         return "ForceExit";
259     case Array::String:
260         return "String";
261     case Array::Contiguous:
262         return "Contiguous";
263     case Array::ContiguousToTail:
264         return "ContiguousToTail";
265     case Array::ContiguousOutOfBounds:
266         return "ContiguousOutOfBounds";
267     case Array::ArrayWithContiguous:
268         return "ArrayWithContiguous";
269     case Array::ArrayWithContiguousToTail:
270         return "ArrayWithContiguousToTail";
271     case Array::ArrayWithContiguousOutOfBounds:
272         return "ArrayWithContiguousOutOfBounds";
273     case Array::PossiblyArrayWithContiguous:
274         return "PossiblyArrayWithContiguous";
275     case Array::PossiblyArrayWithContiguousToTail:
276         return "PossiblyArrayWithContiguousToTail";
277     case Array::PossiblyArrayWithContiguousOutOfBounds:
278         return "PossiblyArrayWithContiguousOutOfBounds";
279     case Array::ArrayStorage:
280         return "ArrayStorage";
281     case Array::ArrayStorageToHole:
282         return "ArrayStorageToHole";
283     case Array::SlowPutArrayStorage:
284         return "SlowPutArrayStorage";
285     case Array::ArrayStorageOutOfBounds:
286         return "ArrayStorageOutOfBounds";
287     case Array::ArrayWithArrayStorage:
288         return "ArrayWithArrayStorage";
289     case Array::ArrayWithArrayStorageToHole:
290         return "ArrayWithArrayStorageToHole";
291     case Array::ArrayWithSlowPutArrayStorage:
292         return "ArrayWithSlowPutArrayStorage";
293     case Array::ArrayWithArrayStorageOutOfBounds:
294         return "ArrayWithArrayStorageOutOfBounds";
295     case Array::PossiblyArrayWithArrayStorage:
296         return "PossiblyArrayWithArrayStorage";
297     case Array::PossiblyArrayWithArrayStorageToHole:
298         return "PossiblyArrayWithArrayStorageToHole";
299     case Array::PossiblyArrayWithSlowPutArrayStorage:
300         return "PossiblyArrayWithSlowPutArrayStorage";
301     case Array::PossiblyArrayWithArrayStorageOutOfBounds:
302         return "PossiblyArrayWithArrayStorageOutOfBounds";
303     case Array::ToContiguous:
304         return "ToContiguous";
305     case Array::ToArrayStorage:
306         return "ToArrayStorage";
307     case Array::ToSlowPutArrayStorage:
308         return "ToSlowPutArrayStorage";
309     case Array::ArrayToArrayStorage:
310         return "ArrayToArrayStorage";
311     case Array::PossiblyArrayToArrayStorage:
312         return "PossiblyArrayToArrayStorage";
313     case Array::Arguments:
314         return "Arguments";
315     case Array::Int8Array:
316         return "Int8Array";
317     case Array::Int16Array:
318         return "Int16Array";
319     case Array::Int32Array:
320         return "Int32Array";
321     case Array::Uint8Array:
322         return "Uint8Array";
323     case Array::Uint8ClampedArray:
324         return "Uint8ClampedArray";
325     case Array::Uint16Array:
326         return "Uint16Array";
327     case Array::Uint32Array:
328         return "Uint32Array";
329     case Array::Float32Array:
330         return "Float32Array";
331     case Array::Float64Array:
332         return "Float64Array";
333     default:
334         // Better to return something then it is to crash. Remember, this method
335         // is being called from our main diagnostic tool, the IR dumper. It's like
336         // a stack trace. So if we get here then probably something has already
337         // gone wrong.
338         return "Unknown!";
339     }
340 }
341
342 } } // namespace JSC::DFG
343
344 #endif // ENABLE(DFG_JIT)
345