]>
Commit | Line | Data |
---|---|---|
81345200 | 1 | /* |
ed1e77d3 | 2 | * Copyright (C) 2013-2015 Apple Inc. All rights reserved. |
81345200 A |
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 DFGSafeToExecute_h | |
27 | #define DFGSafeToExecute_h | |
28 | ||
29 | #if ENABLE(DFG_JIT) | |
30 | ||
31 | #include "DFGGraph.h" | |
32 | ||
33 | namespace JSC { namespace DFG { | |
34 | ||
35 | template<typename AbstractStateType> | |
36 | class SafeToExecuteEdge { | |
37 | public: | |
38 | SafeToExecuteEdge(AbstractStateType& state) | |
39 | : m_state(state) | |
40 | , m_result(true) | |
41 | { | |
42 | } | |
43 | ||
44 | void operator()(Node*, Edge edge) | |
45 | { | |
46 | switch (edge.useKind()) { | |
47 | case UntypedUse: | |
48 | case Int32Use: | |
49 | case DoubleRepUse: | |
50 | case DoubleRepRealUse: | |
51 | case Int52RepUse: | |
52 | case NumberUse: | |
ed1e77d3 | 53 | case RealNumberUse: |
81345200 A |
54 | case BooleanUse: |
55 | case CellUse: | |
56 | case ObjectUse: | |
ed1e77d3 | 57 | case FunctionUse: |
81345200 A |
58 | case FinalObjectUse: |
59 | case ObjectOrOtherUse: | |
60 | case StringIdentUse: | |
61 | case StringUse: | |
62 | case StringObjectUse: | |
63 | case StringOrStringObjectUse: | |
64 | case NotStringVarUse: | |
65 | case NotCellUse: | |
66 | case OtherUse: | |
67 | case MiscUse: | |
68 | case MachineIntUse: | |
69 | case DoubleRepMachineIntUse: | |
70 | return; | |
71 | ||
72 | case KnownInt32Use: | |
73 | if (m_state.forNode(edge).m_type & ~SpecInt32) | |
74 | m_result = false; | |
75 | return; | |
76 | ||
77 | case KnownCellUse: | |
78 | if (m_state.forNode(edge).m_type & ~SpecCell) | |
79 | m_result = false; | |
80 | return; | |
81 | ||
82 | case KnownStringUse: | |
83 | if (m_state.forNode(edge).m_type & ~SpecString) | |
84 | m_result = false; | |
85 | return; | |
86 | ||
87 | case LastUseKind: | |
88 | RELEASE_ASSERT_NOT_REACHED(); | |
89 | break; | |
90 | } | |
91 | RELEASE_ASSERT_NOT_REACHED(); | |
92 | } | |
93 | ||
94 | bool result() const { return m_result; } | |
95 | private: | |
96 | AbstractStateType& m_state; | |
97 | bool m_result; | |
98 | }; | |
99 | ||
100 | // Determines if it's safe to execute a node within the given abstract state. This may | |
101 | // return false conservatively. If it returns true, then you can hoist the given node | |
102 | // up to the given point and expect that it will not crash. This doesn't guarantee that | |
103 | // the node will produce the result you wanted other than not crashing. | |
104 | template<typename AbstractStateType> | |
105 | bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node) | |
106 | { | |
107 | SafeToExecuteEdge<AbstractStateType> safeToExecuteEdge(state); | |
108 | DFG_NODE_DO_TO_CHILDREN(graph, node, safeToExecuteEdge); | |
109 | if (!safeToExecuteEdge.result()) | |
110 | return false; | |
111 | ||
112 | switch (node->op()) { | |
113 | case JSConstant: | |
114 | case DoubleConstant: | |
115 | case Int52Constant: | |
81345200 A |
116 | case Identity: |
117 | case ToThis: | |
118 | case CreateThis: | |
119 | case GetCallee: | |
ed1e77d3 | 120 | case GetArgumentCount: |
81345200 A |
121 | case GetLocal: |
122 | case SetLocal: | |
ed1e77d3 A |
123 | case PutStack: |
124 | case KillStack: | |
125 | case GetStack: | |
81345200 A |
126 | case MovHint: |
127 | case ZombieHint: | |
81345200 | 128 | case Phantom: |
81345200 A |
129 | case Upsilon: |
130 | case Phi: | |
131 | case Flush: | |
132 | case PhantomLocal: | |
133 | case GetLocalUnlinked: | |
134 | case SetArgument: | |
135 | case BitAnd: | |
136 | case BitOr: | |
137 | case BitXor: | |
138 | case BitLShift: | |
139 | case BitRShift: | |
140 | case BitURShift: | |
141 | case ValueToInt32: | |
142 | case UInt32ToNumber: | |
143 | case DoubleAsInt32: | |
144 | case ArithAdd: | |
ed1e77d3 | 145 | case ArithClz32: |
81345200 A |
146 | case ArithSub: |
147 | case ArithNegate: | |
148 | case ArithMul: | |
149 | case ArithIMul: | |
150 | case ArithDiv: | |
151 | case ArithMod: | |
152 | case ArithAbs: | |
153 | case ArithMin: | |
154 | case ArithMax: | |
ed1e77d3 | 155 | case ArithPow: |
81345200 A |
156 | case ArithSqrt: |
157 | case ArithFRound: | |
ed1e77d3 | 158 | case ArithRound: |
81345200 A |
159 | case ArithSin: |
160 | case ArithCos: | |
ed1e77d3 | 161 | case ArithLog: |
81345200 A |
162 | case ValueAdd: |
163 | case GetById: | |
164 | case GetByIdFlush: | |
165 | case PutById: | |
166 | case PutByIdFlush: | |
167 | case PutByIdDirect: | |
168 | case CheckStructure: | |
ed1e77d3 | 169 | case GetExecutable: |
81345200 A |
170 | case GetButterfly: |
171 | case CheckArray: | |
172 | case Arrayify: | |
173 | case ArrayifyToStructure: | |
174 | case GetScope: | |
81345200 | 175 | case SkipScope: |
81345200 A |
176 | case GetClosureVar: |
177 | case PutClosureVar: | |
178 | case GetGlobalVar: | |
179 | case PutGlobalVar: | |
81345200 | 180 | case VarInjectionWatchpoint: |
ed1e77d3 A |
181 | case CheckCell: |
182 | case CheckBadCell: | |
183 | case CheckNotEmpty: | |
81345200 A |
184 | case RegExpExec: |
185 | case RegExpTest: | |
186 | case CompareLess: | |
187 | case CompareLessEq: | |
188 | case CompareGreater: | |
189 | case CompareGreaterEq: | |
190 | case CompareEq: | |
191 | case CompareEqConstant: | |
192 | case CompareStrictEq: | |
193 | case Call: | |
194 | case Construct: | |
ed1e77d3 A |
195 | case CallVarargs: |
196 | case ConstructVarargs: | |
197 | case LoadVarargs: | |
198 | case CallForwardVarargs: | |
199 | case ConstructForwardVarargs: | |
81345200 A |
200 | case NewObject: |
201 | case NewArray: | |
202 | case NewArrayWithSize: | |
203 | case NewArrayBuffer: | |
204 | case NewRegexp: | |
205 | case Breakpoint: | |
206 | case ProfileWillCall: | |
207 | case ProfileDidCall: | |
ed1e77d3 A |
208 | case ProfileType: |
209 | case ProfileControlFlow: | |
81345200 A |
210 | case CheckHasInstance: |
211 | case InstanceOf: | |
212 | case IsUndefined: | |
213 | case IsBoolean: | |
214 | case IsNumber: | |
215 | case IsString: | |
216 | case IsObject: | |
ed1e77d3 | 217 | case IsObjectOrNull: |
81345200 A |
218 | case IsFunction: |
219 | case TypeOf: | |
220 | case LogicalNot: | |
221 | case ToPrimitive: | |
222 | case ToString: | |
ed1e77d3 | 223 | case CallStringConstructor: |
81345200 A |
224 | case NewStringObject: |
225 | case MakeRope: | |
226 | case In: | |
227 | case CreateActivation: | |
ed1e77d3 A |
228 | case CreateDirectArguments: |
229 | case CreateScopedArguments: | |
230 | case CreateClonedArguments: | |
231 | case GetFromArguments: | |
232 | case PutToArguments: | |
81345200 | 233 | case NewFunction: |
81345200 A |
234 | case Jump: |
235 | case Branch: | |
236 | case Switch: | |
237 | case Return: | |
238 | case Throw: | |
239 | case ThrowReferenceError: | |
240 | case CountExecution: | |
241 | case ForceOSRExit: | |
242 | case CheckWatchdogTimer: | |
243 | case StringFromCharCode: | |
244 | case NewTypedArray: | |
245 | case Unreachable: | |
246 | case ExtractOSREntryLocal: | |
247 | case CheckTierUpInLoop: | |
248 | case CheckTierUpAtReturn: | |
249 | case CheckTierUpAndOSREnter: | |
ed1e77d3 | 250 | case CheckTierUpWithNestedTriggerAndOSREnter: |
81345200 A |
251 | case LoopHint: |
252 | case StoreBarrier: | |
81345200 A |
253 | case InvalidationPoint: |
254 | case NotifyWrite: | |
81345200 A |
255 | case CheckInBounds: |
256 | case ConstantStoragePointer: | |
257 | case Check: | |
258 | case MultiGetByOffset: | |
259 | case MultiPutByOffset: | |
260 | case ValueRep: | |
261 | case DoubleRep: | |
262 | case Int52Rep: | |
263 | case BooleanToNumber: | |
264 | case FiatInt52: | |
ed1e77d3 A |
265 | case GetGetter: |
266 | case GetSetter: | |
267 | case GetEnumerableLength: | |
268 | case HasGenericProperty: | |
269 | case HasStructureProperty: | |
270 | case HasIndexedProperty: | |
271 | case GetDirectPname: | |
272 | case GetPropertyEnumerator: | |
273 | case GetEnumeratorStructurePname: | |
274 | case GetEnumeratorGenericPname: | |
275 | case ToIndexString: | |
276 | case PhantomNewObject: | |
277 | case PhantomNewFunction: | |
278 | case PhantomCreateActivation: | |
279 | case PutHint: | |
280 | case CheckStructureImmediate: | |
281 | case MaterializeNewObject: | |
282 | case MaterializeCreateActivation: | |
283 | case PhantomDirectArguments: | |
284 | case PhantomClonedArguments: | |
285 | case GetMyArgumentByVal: | |
286 | case ForwardVarargs: | |
81345200 | 287 | return true; |
ed1e77d3 A |
288 | |
289 | case NativeCall: | |
290 | case NativeConstruct: | |
291 | return false; // TODO: add a check for already checked. https://bugs.webkit.org/show_bug.cgi?id=133769 | |
292 | ||
293 | case BottomValue: | |
294 | // If in doubt, assume that this isn't safe to execute, just because we have no way of | |
295 | // compiling this node. | |
296 | return false; | |
297 | ||
81345200 A |
298 | case GetByVal: |
299 | case GetIndexedPropertyStorage: | |
300 | case GetArrayLength: | |
301 | case ArrayPush: | |
302 | case ArrayPop: | |
303 | case StringCharAt: | |
304 | case StringCharCodeAt: | |
305 | return node->arrayMode().alreadyChecked(graph, node, state.forNode(node->child1())); | |
306 | ||
307 | case GetTypedArrayByteOffset: | |
308 | return !(state.forNode(node->child1()).m_type & ~(SpecTypedArrayView)); | |
309 | ||
310 | case PutByValDirect: | |
311 | case PutByVal: | |
312 | case PutByValAlias: | |
313 | return node->arrayMode().modeForPut().alreadyChecked( | |
314 | graph, node, state.forNode(graph.varArgChild(node, 0))); | |
315 | ||
81345200 | 316 | case PutStructure: |
81345200 A |
317 | case AllocatePropertyStorage: |
318 | case ReallocatePropertyStorage: | |
ed1e77d3 A |
319 | return state.forNode(node->child1()).m_structure.isSubsetOf( |
320 | StructureSet(node->transition()->previous)); | |
81345200 A |
321 | |
322 | case GetByOffset: | |
ed1e77d3 A |
323 | case GetGetterSetterByOffset: |
324 | case PutByOffset: { | |
325 | StructureAbstractValue& value = state.forNode(node->child1()).m_structure; | |
326 | if (value.isTop()) | |
327 | return false; | |
328 | PropertyOffset offset = node->storageAccessData().offset; | |
329 | for (unsigned i = value.size(); i--;) { | |
330 | if (!value[i]->isValidOffset(offset)) | |
331 | return false; | |
332 | } | |
333 | return true; | |
334 | } | |
81345200 A |
335 | |
336 | case LastNodeType: | |
337 | RELEASE_ASSERT_NOT_REACHED(); | |
338 | return false; | |
339 | } | |
340 | ||
341 | RELEASE_ASSERT_NOT_REACHED(); | |
342 | return false; | |
343 | } | |
344 | ||
345 | } } // namespace JSC::DFG | |
346 | ||
347 | #endif // ENABLE(DFG_JIT) | |
348 | ||
349 | #endif // DFGSafeToExecute_h | |
350 |