302365ff006e2c3dcdc53ae9bd2ebf663b9d97f6
[WebKit-https.git] / Source / JavaScriptCore / bytecode / ArrayProfile.h
1 /*
2  * Copyright (C) 2012, 2013 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 #ifndef ArrayProfile_h
27 #define ArrayProfile_h
28
29 #include "ConcurrentJITLock.h"
30 #include "JSArray.h"
31 #include "Structure.h"
32 #include <wtf/HashMap.h>
33 #include <wtf/SegmentedVector.h>
34
35 namespace JSC {
36
37 class CodeBlock;
38 class LLIntOffsetsExtractor;
39
40 // This is a bitfield where each bit represents an IndexingType that we have seen.
41 // There are 32 indexing types, so an unsigned is enough.
42 typedef unsigned ArrayModes;
43
44 #define asArrayModes(type) \
45     (static_cast<unsigned>(1) << static_cast<unsigned>(type))
46
47 #define ALL_NON_ARRAY_ARRAY_MODES                       \
48     (asArrayModes(NonArray)                             \
49     | asArrayModes(NonArrayWithInt32)                   \
50     | asArrayModes(NonArrayWithDouble)                  \
51     | asArrayModes(NonArrayWithContiguous)              \
52     | asArrayModes(NonArrayWithArrayStorage)            \
53     | asArrayModes(NonArrayWithSlowPutArrayStorage))
54
55 #define ALL_ARRAY_ARRAY_MODES                           \
56     (asArrayModes(ArrayClass)                           \
57     | asArrayModes(ArrayWithUndecided)                  \
58     | asArrayModes(ArrayWithInt32)                      \
59     | asArrayModes(ArrayWithDouble)                     \
60     | asArrayModes(ArrayWithContiguous)                 \
61     | asArrayModes(ArrayWithArrayStorage)               \
62     | asArrayModes(ArrayWithSlowPutArrayStorage))
63
64 #define ALL_ARRAY_MODES (ALL_NON_ARRAY_ARRAY_MODES | ALL_ARRAY_ARRAY_MODES)
65
66 inline ArrayModes arrayModeFromStructure(Structure* structure)
67 {
68     return asArrayModes(structure->indexingType());
69 }
70
71 void dumpArrayModes(PrintStream&, ArrayModes);
72 MAKE_PRINT_ADAPTOR(ArrayModesDump, ArrayModes, dumpArrayModes);
73
74 inline bool mergeArrayModes(ArrayModes& left, ArrayModes right)
75 {
76     ArrayModes newModes = left | right;
77     if (newModes == left)
78         return false;
79     left = newModes;
80     return true;
81 }
82
83 inline bool arrayModesAreClearOrTop(ArrayModes modes)
84 {
85     return !modes || modes == ALL_ARRAY_MODES;
86 }
87
88 // Checks if proven is a subset of expected.
89 inline bool arrayModesAlreadyChecked(ArrayModes proven, ArrayModes expected)
90 {
91     return (expected | proven) == expected;
92 }
93
94 inline bool arrayModesInclude(ArrayModes arrayModes, IndexingType shape)
95 {
96     return !!(arrayModes & (asArrayModes(NonArray | shape) | asArrayModes(ArrayClass | shape)));
97 }
98
99 inline bool shouldUseSlowPutArrayStorage(ArrayModes arrayModes)
100 {
101     return arrayModesInclude(arrayModes, SlowPutArrayStorageShape);
102 }
103
104 inline bool shouldUseFastArrayStorage(ArrayModes arrayModes)
105 {
106     return arrayModesInclude(arrayModes, ArrayStorageShape);
107 }
108
109 inline bool shouldUseContiguous(ArrayModes arrayModes)
110 {
111     return arrayModesInclude(arrayModes, ContiguousShape);
112 }
113
114 inline bool shouldUseDouble(ArrayModes arrayModes)
115 {
116     return arrayModesInclude(arrayModes, DoubleShape);
117 }
118
119 inline bool shouldUseInt32(ArrayModes arrayModes)
120 {
121     return arrayModesInclude(arrayModes, Int32Shape);
122 }
123
124 inline bool hasSeenArray(ArrayModes arrayModes)
125 {
126     return arrayModes & ALL_ARRAY_ARRAY_MODES;
127 }
128
129 inline bool hasSeenNonArray(ArrayModes arrayModes)
130 {
131     return arrayModes & ALL_NON_ARRAY_ARRAY_MODES;
132 }
133
134 class ArrayProfile {
135 public:
136     ArrayProfile()
137         : m_bytecodeOffset(std::numeric_limits<unsigned>::max())
138         , m_lastSeenStructureID(0)
139         , m_mayStoreToHole(false)
140         , m_outOfBounds(false)
141         , m_mayInterceptIndexedAccesses(false)
142         , m_usesOriginalArrayStructures(true)
143         , m_didPerformFirstRunPruning(false)
144         , m_observedArrayModes(0)
145     {
146     }
147     
148     ArrayProfile(unsigned bytecodeOffset)
149         : m_bytecodeOffset(bytecodeOffset)
150         , m_lastSeenStructureID(0)
151         , m_mayStoreToHole(false)
152         , m_outOfBounds(false)
153         , m_mayInterceptIndexedAccesses(false)
154         , m_usesOriginalArrayStructures(true)
155         , m_didPerformFirstRunPruning(false)
156         , m_observedArrayModes(0)
157     {
158     }
159     
160     unsigned bytecodeOffset() const { return m_bytecodeOffset; }
161     
162     StructureID* addressOfLastSeenStructureID() { return &m_lastSeenStructureID; }
163     ArrayModes* addressOfArrayModes() { return &m_observedArrayModes; }
164     bool* addressOfMayStoreToHole() { return &m_mayStoreToHole; }
165     bool* addressOfOutOfBounds() { return &m_outOfBounds; }
166     
167     void observeStructure(Structure* structure)
168     {
169         m_lastSeenStructureID = structure->id();
170     }
171     
172     void computeUpdatedPrediction(const ConcurrentJITLocker&, CodeBlock*);
173     
174     ArrayModes observedArrayModes(const ConcurrentJITLocker&) const { return m_observedArrayModes; }
175     bool mayInterceptIndexedAccesses(const ConcurrentJITLocker&) const { return m_mayInterceptIndexedAccesses; }
176     
177     bool mayStoreToHole(const ConcurrentJITLocker&) const { return m_mayStoreToHole; }
178     bool outOfBounds(const ConcurrentJITLocker&) const { return m_outOfBounds; }
179     
180     bool usesOriginalArrayStructures(const ConcurrentJITLocker&) const { return m_usesOriginalArrayStructures; }
181     
182     CString briefDescription(const ConcurrentJITLocker&, CodeBlock*);
183     CString briefDescriptionWithoutUpdating(const ConcurrentJITLocker&);
184     
185 private:
186     friend class LLIntOffsetsExtractor;
187     
188     static Structure* polymorphicStructure() { return static_cast<Structure*>(reinterpret_cast<void*>(1)); }
189     
190     unsigned m_bytecodeOffset;
191     StructureID m_lastSeenStructureID;
192     bool m_mayStoreToHole; // This flag may become overloaded to indicate other special cases that were encountered during array access, as it depends on indexing type. Since we currently have basically just one indexing type (two variants of ArrayStorage), this flag for now just means exactly what its name implies.
193     bool m_outOfBounds;
194     bool m_mayInterceptIndexedAccesses : 1;
195     bool m_usesOriginalArrayStructures : 1;
196     bool m_didPerformFirstRunPruning : 1;
197     ArrayModes m_observedArrayModes;
198 };
199
200 typedef SegmentedVector<ArrayProfile, 4, 0> ArrayProfileVector;
201
202 } // namespace JSC
203
204 #endif // ArrayProfile_h
205