REGRESSION (172175-172177): Change in for...in processing causes properties added...
[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 PutStack:
122     case KillStack:
123     case GetStack:
124     case MovHint:
125     case ZombieHint:
126     case Phantom:
127     case HardPhantom:
128     case Upsilon:
129     case Phi:
130     case Flush:
131     case PhantomLocal:
132     case GetLocalUnlinked:
133     case SetArgument:
134     case BitAnd:
135     case BitOr:
136     case BitXor:
137     case BitLShift:
138     case BitRShift:
139     case BitURShift:
140     case ValueToInt32:
141     case UInt32ToNumber:
142     case DoubleAsInt32:
143     case ArithAdd:
144     case ArithSub:
145     case ArithNegate:
146     case ArithMul:
147     case ArithIMul:
148     case ArithDiv:
149     case ArithMod:
150     case ArithAbs:
151     case ArithMin:
152     case ArithMax:
153     case ArithPow:
154     case ArithSqrt:
155     case ArithFRound:
156     case ArithSin:
157     case ArithCos:
158     case ArithLog:
159     case ValueAdd:
160     case GetById:
161     case GetByIdFlush:
162     case PutById:
163     case PutByIdFlush:
164     case PutByIdDirect:
165     case CheckStructure:
166     case GetExecutable:
167     case GetButterfly:
168     case CheckArray:
169     case Arrayify:
170     case ArrayifyToStructure:
171     case GetScope:
172     case SkipScope:
173     case GetClosureRegisters:
174     case GetClosureVar:
175     case PutClosureVar:
176     case GetGlobalVar:
177     case PutGlobalVar:
178     case VarInjectionWatchpoint:
179     case CheckCell:
180     case CheckBadCell:
181     case CheckNotEmpty:
182     case AllocationProfileWatchpoint:
183     case RegExpExec:
184     case RegExpTest:
185     case CompareLess:
186     case CompareLessEq:
187     case CompareGreater:
188     case CompareGreaterEq:
189     case CompareEq:
190     case CompareEqConstant:
191     case CompareStrictEq:
192     case Call:
193     case Construct:
194     case CallVarargs:
195     case ConstructVarargs:
196     case LoadVarargs:
197     case CallForwardVarargs:
198     case NewObject:
199     case NewArray:
200     case NewArrayWithSize:
201     case NewArrayBuffer:
202     case NewRegexp:
203     case Breakpoint:
204     case ProfileWillCall:
205     case ProfileDidCall:
206     case ProfileType:
207     case ProfileControlFlow:
208     case CheckHasInstance:
209     case InstanceOf:
210     case IsUndefined:
211     case IsBoolean:
212     case IsNumber:
213     case IsString:
214     case IsObject:
215     case IsObjectOrNull:
216     case IsFunction:
217     case TypeOf:
218     case LogicalNot:
219     case ToPrimitive:
220     case ToString:
221     case NewStringObject:
222     case MakeRope:
223     case In:
224     case CreateActivation:
225     case CreateArguments:
226     case PhantomArguments:
227     case TearOffArguments:
228     case GetMyArgumentsLength:
229     case GetMyArgumentByVal:
230     case GetMyArgumentsLengthSafe:
231     case GetMyArgumentByValSafe:
232     case CheckArgumentsNotCreated:
233     case NewFunctionNoCheck:
234     case NewFunction:
235     case NewFunctionExpression:
236     case Jump:
237     case Branch:
238     case Switch:
239     case Return:
240     case Throw:
241     case ThrowReferenceError:
242     case CountExecution:
243     case ForceOSRExit:
244     case CheckWatchdogTimer:
245     case StringFromCharCode:
246     case NewTypedArray:
247     case Unreachable:
248     case ExtractOSREntryLocal:
249     case CheckTierUpInLoop:
250     case CheckTierUpAtReturn:
251     case CheckTierUpAndOSREnter:
252     case LoopHint:
253     case StoreBarrier:
254     case StoreBarrierWithNullCheck:
255     case InvalidationPoint:
256     case NotifyWrite:
257     case TypedArrayWatchpoint:
258     case CheckInBounds:
259     case ConstantStoragePointer:
260     case Check:
261     case MultiGetByOffset:
262     case MultiPutByOffset:
263     case ValueRep:
264     case DoubleRep:
265     case Int52Rep:
266     case BooleanToNumber:
267     case FiatInt52:
268     case GetGetter:
269     case GetSetter:
270     case GetEnumerableLength:
271     case HasGenericProperty:
272     case HasStructureProperty:
273     case HasIndexedProperty:
274     case GetDirectPname:
275     case GetPropertyEnumerator:
276     case GetEnumeratorStructurePname:
277     case GetEnumeratorGenericPname:
278     case ToIndexString:
279     case PhantomNewObject:
280     case PutHint:
281     case CheckStructureImmediate:
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