[JSC] Optimize more cases of something-compared-to-null/undefined
[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 RealNumberUse:
54         case BooleanUse:
55         case CellUse:
56         case ObjectUse:
57         case FunctionUse:
58         case FinalObjectUse:
59         case ObjectOrOtherUse:
60         case StringIdentUse:
61         case StringUse:
62         case SymbolUse:
63         case StringObjectUse:
64         case StringOrStringObjectUse:
65         case NotStringVarUse:
66         case NotCellUse:
67         case OtherUse:
68         case MiscUse:
69         case MachineIntUse:
70         case DoubleRepMachineIntUse:
71             return;
72             
73         case KnownInt32Use:
74             if (m_state.forNode(edge).m_type & ~SpecInt32)
75                 m_result = false;
76             return;
77             
78         case KnownCellUse:
79             if (m_state.forNode(edge).m_type & ~SpecCell)
80                 m_result = false;
81             return;
82             
83         case KnownStringUse:
84             if (m_state.forNode(edge).m_type & ~SpecString)
85                 m_result = false;
86             return;
87             
88         case LastUseKind:
89             RELEASE_ASSERT_NOT_REACHED();
90             break;
91         }
92         RELEASE_ASSERT_NOT_REACHED();
93     }
94     
95     bool result() const { return m_result; }
96 private:
97     AbstractStateType& m_state;
98     bool m_result;
99 };
100
101 // Determines if it's safe to execute a node within the given abstract state. This may
102 // return false conservatively. If it returns true, then you can hoist the given node
103 // up to the given point and expect that it will not crash. It also guarantees that the
104 // node will not produce a malformed JSValue or object pointer when executed in the
105 // given state. But this doesn't guarantee that the node will produce the result you
106 // wanted. For example, you may have a GetByOffset from a prototype that only makes
107 // semantic sense if you've also checked that some nearer prototype doesn't also have
108 // a property of the same name. This could still return true even if that check hadn't
109 // been performed in the given abstract state. That's fine though: the load can still
110 // safely execute before that check, so long as that check continues to guard any
111 // user-observable things done to the loaded value.
112 template<typename AbstractStateType>
113 bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
114 {
115     SafeToExecuteEdge<AbstractStateType> safeToExecuteEdge(state);
116     DFG_NODE_DO_TO_CHILDREN(graph, node, safeToExecuteEdge);
117     if (!safeToExecuteEdge.result())
118         return false;
119
120     switch (node->op()) {
121     case JSConstant:
122     case DoubleConstant:
123     case Int52Constant:
124     case Identity:
125     case ToThis:
126     case CreateThis:
127     case GetCallee:
128     case GetArgumentCount:
129     case GetLocal:
130     case SetLocal:
131     case PutStack:
132     case KillStack:
133     case GetStack:
134     case MovHint:
135     case ZombieHint:
136     case Phantom:
137     case Upsilon:
138     case Phi:
139     case Flush:
140     case PhantomLocal:
141     case GetLocalUnlinked:
142     case SetArgument:
143     case BitAnd:
144     case BitOr:
145     case BitXor:
146     case BitLShift:
147     case BitRShift:
148     case BitURShift:
149     case ValueToInt32:
150     case UInt32ToNumber:
151     case DoubleAsInt32:
152     case ArithAdd:
153     case ArithClz32:
154     case ArithSub:
155     case ArithNegate:
156     case ArithMul:
157     case ArithIMul:
158     case ArithDiv:
159     case ArithMod:
160     case ArithAbs:
161     case ArithMin:
162     case ArithMax:
163     case ArithPow:
164     case ArithSqrt:
165     case ArithFRound:
166     case ArithRound:
167     case ArithSin:
168     case ArithCos:
169     case ArithLog:
170     case ValueAdd:
171     case GetById:
172     case GetByIdFlush:
173     case PutById:
174     case PutByIdFlush:
175     case PutByIdDirect:
176     case CheckStructure:
177     case GetExecutable:
178     case GetButterfly:
179     case CheckArray:
180     case Arrayify:
181     case ArrayifyToStructure:
182     case GetScope:
183     case LoadArrowFunctionThis:
184     case SkipScope:
185     case GetClosureVar:
186     case PutClosureVar:
187     case GetGlobalVar:
188     case PutGlobalVar:
189     case VarInjectionWatchpoint:
190     case CheckCell:
191     case CheckBadCell:
192     case CheckNotEmpty:
193     case CheckIdent:
194     case RegExpExec:
195     case RegExpTest:
196     case CompareLess:
197     case CompareLessEq:
198     case CompareGreater:
199     case CompareGreaterEq:
200     case CompareEq:
201     case CompareStrictEq:
202     case Call:
203     case Construct:
204     case CallVarargs:
205     case ConstructVarargs:
206     case LoadVarargs:
207     case CallForwardVarargs:
208     case ConstructForwardVarargs:
209     case NewObject:
210     case NewArray:
211     case NewArrayWithSize:
212     case NewArrayBuffer:
213     case NewRegexp:
214     case Breakpoint:
215     case ProfileWillCall:
216     case ProfileDidCall:
217     case ProfileType:
218     case ProfileControlFlow:
219     case CheckHasInstance:
220     case InstanceOf:
221     case IsUndefined:
222     case IsBoolean:
223     case IsNumber:
224     case IsString:
225     case IsObject:
226     case IsObjectOrNull:
227     case IsFunction:
228     case TypeOf:
229     case LogicalNot:
230     case ToPrimitive:
231     case ToString:
232     case CallStringConstructor:
233     case NewStringObject:
234     case MakeRope:
235     case In:
236     case CreateActivation:
237     case CreateDirectArguments:
238     case CreateScopedArguments:
239     case CreateClonedArguments:
240     case GetFromArguments:
241     case PutToArguments:
242     case NewArrowFunction:
243     case NewFunction:
244     case Jump:
245     case Branch:
246     case Switch:
247     case Return:
248     case Throw:
249     case ThrowReferenceError:
250     case CountExecution:
251     case ForceOSRExit:
252     case CheckWatchdogTimer:
253     case StringFromCharCode:
254     case NewTypedArray:
255     case Unreachable:
256     case ExtractOSREntryLocal:
257     case CheckTierUpInLoop:
258     case CheckTierUpAtReturn:
259     case CheckTierUpAndOSREnter:
260     case CheckTierUpWithNestedTriggerAndOSREnter:
261     case LoopHint:
262     case StoreBarrier:
263     case InvalidationPoint:
264     case NotifyWrite:
265     case CheckInBounds:
266     case ConstantStoragePointer:
267     case Check:
268     case MultiPutByOffset:
269     case ValueRep:
270     case DoubleRep:
271     case Int52Rep:
272     case BooleanToNumber:
273     case FiatInt52:
274     case GetGetter:
275     case GetSetter:
276     case GetEnumerableLength:
277     case HasGenericProperty:
278     case HasStructureProperty:
279     case HasIndexedProperty:
280     case GetDirectPname:
281     case GetPropertyEnumerator:
282     case GetEnumeratorStructurePname:
283     case GetEnumeratorGenericPname:
284     case ToIndexString:
285     case PhantomNewObject:
286     case PhantomNewFunction:
287     case PhantomCreateActivation:
288     case PutHint:
289     case CheckStructureImmediate:
290     case MaterializeNewObject:
291     case MaterializeCreateActivation:
292     case PhantomDirectArguments:
293     case PhantomClonedArguments:
294     case GetMyArgumentByVal:
295     case ForwardVarargs:
296         return true;
297
298     case BottomValue:
299         // If in doubt, assume that this isn't safe to execute, just because we have no way of
300         // compiling this node.
301         return false;
302
303     case GetByVal:
304     case GetIndexedPropertyStorage:
305     case GetArrayLength:
306     case ArrayPush:
307     case ArrayPop:
308     case StringCharAt:
309     case StringCharCodeAt:
310         return node->arrayMode().alreadyChecked(graph, node, state.forNode(node->child1()));
311         
312     case GetTypedArrayByteOffset:
313         return !(state.forNode(node->child1()).m_type & ~(SpecTypedArrayView));
314             
315     case PutByValDirect:
316     case PutByVal:
317     case PutByValAlias:
318         return node->arrayMode().modeForPut().alreadyChecked(
319             graph, node, state.forNode(graph.varArgChild(node, 0)));
320
321     case PutStructure:
322     case AllocatePropertyStorage:
323     case ReallocatePropertyStorage:
324         return state.forNode(node->child1()).m_structure.isSubsetOf(
325             StructureSet(node->transition()->previous));
326         
327     case GetByOffset:
328     case GetGetterSetterByOffset:
329     case PutByOffset: {
330         PropertyOffset offset = node->storageAccessData().offset;
331
332         if (state.structureClobberState() == StructuresAreWatched) {
333             if (JSObject* knownBase = node->child1()->dynamicCastConstant<JSObject*>()) {
334                 if (graph.isSafeToLoad(knownBase, offset))
335                     return true;
336             }
337         }
338         
339         StructureAbstractValue& value = state.forNode(node->child1()).m_structure;
340         if (value.isInfinite())
341             return false;
342         for (unsigned i = value.size(); i--;) {
343             if (!value[i]->isValidOffset(offset))
344                 return false;
345         }
346         return true;
347     }
348         
349     case MultiGetByOffset: {
350         // We can't always guarantee that the MultiGetByOffset is safe to execute if it
351         // contains loads from prototypes. If the load requires a check in IR, which is rare, then
352         // we currently claim that we don't know if it's safe to execute because finding that
353         // check in the abstract state would be hard. If the load requires watchpoints, we just
354         // check if we're not in a clobbered state (i.e. in between a side effect and an
355         // invalidation point).
356         for (const MultiGetByOffsetCase& getCase : node->multiGetByOffsetData().cases) {
357             GetByOffsetMethod method = getCase.method();
358             switch (method.kind()) {
359             case GetByOffsetMethod::Invalid:
360                 RELEASE_ASSERT_NOT_REACHED();
361                 break;
362             case GetByOffsetMethod::Constant: // OK because constants are always safe to execute.
363             case GetByOffsetMethod::Load: // OK because the MultiGetByOffset has its own checks for loading from self.
364                 break;
365             case GetByOffsetMethod::LoadFromPrototype:
366                 // Only OK if the state isn't clobbered. That's almost always the case.
367                 if (state.structureClobberState() != StructuresAreWatched)
368                     return false;
369                 if (!graph.isSafeToLoad(method.prototype()->cast<JSObject*>(), method.offset()))
370                     return false;
371                 break;
372             }
373         }
374         return true;
375     }
376
377     case LastNodeType:
378         RELEASE_ASSERT_NOT_REACHED();
379         return false;
380     }
381     
382     RELEASE_ASSERT_NOT_REACHED();
383     return false;
384 }
385
386 } } // namespace JSC::DFG
387
388 #endif // ENABLE(DFG_JIT)
389
390 #endif // DFGSafeToExecute_h
391