1/*
2 * Copyright (C) 2013, 2014 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
33namespace JSC { namespace DFG {
34
35template<typename AbstractStateType>
36class SafeToExecuteEdge {
37public:
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 FinalObjectUse:
57        case ObjectOrOtherUse:
58        case StringIdentUse:
59        case StringUse:
60        case StringObjectUse:
61        case StringOrStringObjectUse:
62        case NotStringVarUse:
63        case NotCellUse:
64        case OtherUse:
65        case MiscUse:
66        case MachineIntUse:
67        case DoubleRepMachineIntUse:
68            return;
69
70        case KnownInt32Use:
71            if (m_state.forNode(edge).m_type & ~SpecInt32)
72                m_result = false;
73            return;
74
75        case KnownCellUse:
76            if (m_state.forNode(edge).m_type & ~SpecCell)
77                m_result = false;
78            return;
79
80        case KnownStringUse:
81            if (m_state.forNode(edge).m_type & ~SpecString)
82                m_result = false;
83            return;
84
85        case LastUseKind:
86            RELEASE_ASSERT_NOT_REACHED();
87            break;
88        }
89        RELEASE_ASSERT_NOT_REACHED();
90    }
91
92    bool result() const { return m_result; }
93private:
94    AbstractStateType& m_state;
95    bool m_result;
96};
97
98// Determines if it's safe to execute a node within the given abstract state. This may
99// return false conservatively. If it returns true, then you can hoist the given node
100// up to the given point and expect that it will not crash. This doesn't guarantee that
101// the node will produce the result you wanted other than not crashing.
102template<typename AbstractStateType>
103bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
104{
105    SafeToExecuteEdge<AbstractStateType> safeToExecuteEdge(state);
106    DFG_NODE_DO_TO_CHILDREN(graph, node, safeToExecuteEdge);
107    if (!safeToExecuteEdge.result())
108        return false;
109
110    switch (node->op()) {
111    case JSConstant:
112    case DoubleConstant:
113    case Int52Constant:
114    case WeakJSConstant:
115    case Identity:
116    case ToThis:
117    case CreateThis:
118    case GetCallee:
119    case GetLocal:
120    case SetLocal:
121    case MovHint:
122    case ZombieHint:
123    case GetArgument:
124    case Phantom:
125    case HardPhantom:
126    case Upsilon:
127    case Phi:
128    case Flush:
129    case PhantomLocal:
130    case GetLocalUnlinked:
131    case SetArgument:
132    case BitAnd:
133    case BitOr:
134    case BitXor:
135    case BitLShift:
136    case BitRShift:
137    case BitURShift:
138    case ValueToInt32:
139    case UInt32ToNumber:
140    case DoubleAsInt32:
141    case ArithAdd:
142    case ArithSub:
143    case ArithNegate:
144    case ArithMul:
145    case ArithIMul:
146    case ArithDiv:
147    case ArithMod:
148    case ArithAbs:
149    case ArithMin:
150    case ArithMax:
151    case ArithSqrt:
152    case ArithFRound:
153    case ArithSin:
154    case ArithCos:
155    case ValueAdd:
156    case GetById:
157    case GetByIdFlush:
158    case PutById:
159    case PutByIdFlush:
160    case PutByIdDirect:
161    case CheckStructure:
162    case CheckExecutable:
163    case GetButterfly:
164    case CheckArray:
165    case Arrayify:
166    case ArrayifyToStructure:
167    case GetScope:
168    case GetMyScope:
169    case SkipTopScope:
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 CheckFunction:
179    case AllocationProfileWatchpoint:
180    case RegExpExec:
181    case RegExpTest:
182    case CompareLess:
183    case CompareLessEq:
184    case CompareGreater:
185    case CompareGreaterEq:
186    case CompareEq:
187    case CompareEqConstant:
188    case CompareStrictEq:
189    case Call:
190    case Construct:
191    case NewObject:
192    case NewArray:
193    case NewArrayWithSize:
194    case NewArrayBuffer:
195    case NewRegexp:
196    case Breakpoint:
197    case ProfileWillCall:
198    case ProfileDidCall:
199    case CheckHasInstance:
200    case InstanceOf:
201    case IsUndefined:
202    case IsBoolean:
203    case IsNumber:
204    case IsString:
205    case IsObject:
206    case IsFunction:
207    case TypeOf:
208    case LogicalNot:
209    case ToPrimitive:
210    case ToString:
211    case NewStringObject:
212    case MakeRope:
213    case In:
214    case CreateActivation:
215    case TearOffActivation:
216    case CreateArguments:
217    case PhantomArguments:
218    case TearOffArguments:
219    case GetMyArgumentsLength:
220    case GetMyArgumentByVal:
221    case GetMyArgumentsLengthSafe:
222    case GetMyArgumentByValSafe:
223    case CheckArgumentsNotCreated:
224    case NewFunctionNoCheck:
225    case NewFunction:
226    case NewFunctionExpression:
227    case Jump:
228    case Branch:
229    case Switch:
230    case Return:
231    case Throw:
232    case ThrowReferenceError:
233    case CountExecution:
234    case ForceOSRExit:
235    case CheckWatchdogTimer:
236    case StringFromCharCode:
237    case NewTypedArray:
238    case Unreachable:
239    case ExtractOSREntryLocal:
240    case CheckTierUpInLoop:
241    case CheckTierUpAtReturn:
242    case CheckTierUpAndOSREnter:
243    case LoopHint:
244    case StoreBarrier:
245    case StoreBarrierWithNullCheck:
246    case InvalidationPoint:
247    case NotifyWrite:
248    case FunctionReentryWatchpoint:
249    case TypedArrayWatchpoint:
250    case CheckInBounds:
251    case ConstantStoragePointer:
252    case Check:
253    case MultiGetByOffset:
254    case MultiPutByOffset:
255    case ValueRep:
256    case DoubleRep:
257    case Int52Rep:
258    case BooleanToNumber:
259    case FiatInt52:
260        return true;
261
262    case GetByVal:
263    case GetIndexedPropertyStorage:
264    case GetArrayLength:
265    case ArrayPush:
266    case ArrayPop:
267    case StringCharAt:
268    case StringCharCodeAt:
269        return node->arrayMode().alreadyChecked(graph, node, state.forNode(node->child1()));
270
271    case GetTypedArrayByteOffset:
272        return !(state.forNode(node->child1()).m_type & ~(SpecTypedArrayView));
273
274    case PutByValDirect:
275    case PutByVal:
276    case PutByValAlias:
277        return node->arrayMode().modeForPut().alreadyChecked(
278            graph, node, state.forNode(graph.varArgChild(node, 0)));
279
280    case StructureTransitionWatchpoint:
281        return state.forNode(node->child1()).m_futurePossibleStructure.isSubsetOf(
282            StructureSet(node->structure()));
283
284    case PutStructure:
285    case PhantomPutStructure:
286    case AllocatePropertyStorage:
287    case ReallocatePropertyStorage:
288        return state.forNode(node->child1()).m_currentKnownStructure.isSubsetOf(
289            StructureSet(node->structureTransitionData().previousStructure));
290
291    case GetByOffset:
292    case PutByOffset:
293        return state.forNode(node->child1()).m_currentKnownStructure.isValidOffset(
294            graph.m_storageAccessData[node->storageAccessDataIndex()].offset);
295
296    case LastNodeType:
297        RELEASE_ASSERT_NOT_REACHED();
298        return false;
299    }
300
301    RELEASE_ASSERT_NOT_REACHED();
302    return false;
303}
304
305} } // namespace JSC::DFG
306
307#endif // ENABLE(DFG_JIT)
308
309#endif // DFGSafeToExecute_h
310
311