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