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#include "config.h"
27#include "FTLCapabilities.h"
28
29#if ENABLE(FTL_JIT)
30
31namespace JSC { namespace FTL {
32
33using namespace DFG;
34
35static bool verboseCapabilities()
36{
37    return verboseCompilationEnabled() || Options::verboseFTLFailure();
38}
39
40inline CapabilityLevel canCompile(Node* node)
41{
42    // NOTE: If we ever have phantom arguments, we can compile them but we cannot
43    // OSR enter.
44
45    switch (node->op()) {
46    case JSConstant:
47    case WeakJSConstant:
48    case GetMyArgumentsLength:
49    case GetLocal:
50    case SetLocal:
51    case MovHint:
52    case ZombieHint:
53    case Phantom:
54    case HardPhantom:
55    case Flush:
56    case PhantomLocal:
57    case SetArgument:
58    case Return:
59    case BitAnd:
60    case BitOr:
61    case BitXor:
62    case BitRShift:
63    case BitLShift:
64    case BitURShift:
65    case CheckStructure:
66    case StructureTransitionWatchpoint:
67    case ArrayifyToStructure:
68    case PutStructure:
69    case PhantomPutStructure:
70    case GetButterfly:
71    case NewObject:
72    case NewArray:
73    case NewArrayBuffer:
74    case GetByOffset:
75    case PutByOffset:
76    case GetGlobalVar:
77    case PutGlobalVar:
78    case ValueAdd:
79    case ArithAdd:
80    case ArithSub:
81    case ArithMul:
82    case ArithDiv:
83    case ArithMod:
84    case ArithMin:
85    case ArithMax:
86    case ArithAbs:
87    case ArithSin:
88    case ArithCos:
89    case ArithSqrt:
90    case ArithFRound:
91    case ArithNegate:
92    case UInt32ToNumber:
93    case CompareEqConstant:
94    case Jump:
95    case ForceOSRExit:
96    case Phi:
97    case Upsilon:
98    case ExtractOSREntryLocal:
99    case LoopHint:
100    case GetMyScope:
101    case SkipScope:
102    case GetClosureRegisters:
103    case GetClosureVar:
104    case PutClosureVar:
105    case InvalidationPoint:
106    case StringCharAt:
107    case CheckFunction:
108    case StringCharCodeAt:
109    case AllocatePropertyStorage:
110    case ReallocatePropertyStorage:
111    case FunctionReentryWatchpoint:
112    case TypedArrayWatchpoint:
113    case GetTypedArrayByteOffset:
114    case VariableWatchpoint:
115    case NotifyWrite:
116    case StoreBarrier:
117    case StoreBarrierWithNullCheck:
118    case Call:
119    case Construct:
120    case ValueToInt32:
121    case Branch:
122    case LogicalNot:
123    case CheckInBounds:
124    case ConstantStoragePointer:
125    case Check:
126    case CountExecution:
127    case CheckExecutable:
128    case GetScope:
129    case AllocationProfileWatchpoint:
130    case CheckArgumentsNotCreated:
131    case GetCallee:
132    case ToString:
133    case MakeRope:
134    case NewArrayWithSize:
135    case GetById:
136    case ToThis:
137    case MultiGetByOffset:
138    case MultiPutByOffset:
139    case ToPrimitive:
140    case PhantomArguments:
141    case Throw:
142    case ThrowReferenceError:
143    case Unreachable:
144    case GetMyArgumentByVal:
145    case IsUndefined:
146    case IsBoolean:
147    case IsNumber:
148    case IsString:
149    case IsObject:
150    case IsFunction:
151    case CheckHasInstance:
152    case InstanceOf:
153    case DoubleRep:
154    case ValueRep:
155    case Int52Rep:
156    case DoubleConstant:
157    case Int52Constant:
158    case BooleanToNumber:
159        // These are OK.
160        break;
161    case Identity:
162        // No backend handles this because it will be optimized out. But we may check
163        // for capabilities before optimization. It would be a deep error to remove this
164        // case because it would prevent us from catching bugs where the FTL backend
165        // pipeline failed to optimize out an Identity.
166        break;
167    case PutByIdDirect:
168    case PutById:
169        if (node->child1().useKind() == CellUse)
170            break;
171        return CannotCompile;
172    case GetIndexedPropertyStorage:
173        if (node->arrayMode().type() == Array::String)
174            break;
175        if (isTypedView(node->arrayMode().typedArrayType()))
176            break;
177        return CannotCompile;
178    case CheckArray:
179        switch (node->arrayMode().type()) {
180        case Array::Int32:
181        case Array::Double:
182        case Array::Contiguous:
183            break;
184        default:
185            if (isTypedView(node->arrayMode().typedArrayType()))
186                break;
187            return CannotCompile;
188        }
189        break;
190    case GetArrayLength:
191        switch (node->arrayMode().type()) {
192        case Array::Int32:
193        case Array::Double:
194        case Array::Contiguous:
195        case Array::String:
196            break;
197        default:
198            if (isTypedView(node->arrayMode().typedArrayType()))
199                break;
200            return CannotCompile;
201        }
202        break;
203    case GetByVal:
204        switch (node->arrayMode().type()) {
205        case Array::ForceExit:
206        case Array::Generic:
207        case Array::String:
208        case Array::Int32:
209        case Array::Double:
210        case Array::Contiguous:
211            break;
212        default:
213            if (isTypedView(node->arrayMode().typedArrayType()))
214                return CanCompileAndOSREnter;
215            return CannotCompile;
216        }
217        break;
218    case PutByVal:
219    case PutByValAlias:
220    case PutByValDirect:
221        switch (node->arrayMode().type()) {
222        case Array::ForceExit:
223        case Array::Generic:
224        case Array::Int32:
225        case Array::Double:
226        case Array::Contiguous:
227            break;
228        default:
229            if (isTypedView(node->arrayMode().typedArrayType()))
230                return CanCompileAndOSREnter;
231            return CannotCompile;
232        }
233        break;
234    case ArrayPush:
235    case ArrayPop:
236        switch (node->arrayMode().type()) {
237        case Array::Int32:
238        case Array::Contiguous:
239        case Array::Double:
240            break;
241        default:
242            return CannotCompile;
243        }
244        break;
245    case CompareEq:
246        if (node->isBinaryUseKind(Int32Use))
247            break;
248        if (node->isBinaryUseKind(Int52RepUse))
249            break;
250        if (node->isBinaryUseKind(DoubleRepUse))
251            break;
252        if (node->isBinaryUseKind(StringIdentUse))
253            break;
254        if (node->isBinaryUseKind(ObjectUse))
255            break;
256        if (node->isBinaryUseKind(UntypedUse))
257            break;
258        if (node->isBinaryUseKind(BooleanUse))
259            break;
260        if (node->isBinaryUseKind(ObjectUse, ObjectOrOtherUse))
261            break;
262        if (node->isBinaryUseKind(ObjectOrOtherUse, ObjectUse))
263            break;
264        return CannotCompile;
265    case CompareStrictEq:
266        if (node->isBinaryUseKind(Int32Use))
267            break;
268        if (node->isBinaryUseKind(Int52RepUse))
269            break;
270        if (node->isBinaryUseKind(DoubleRepUse))
271            break;
272        if (node->isBinaryUseKind(StringIdentUse))
273            break;
274        if (node->isBinaryUseKind(ObjectUse))
275            break;
276        if (node->isBinaryUseKind(BooleanUse))
277            break;
278        if (node->isBinaryUseKind(MiscUse, UntypedUse))
279            break;
280        if (node->isBinaryUseKind(UntypedUse, MiscUse))
281            break;
282        if (node->isBinaryUseKind(StringIdentUse, NotStringVarUse))
283            break;
284        if (node->isBinaryUseKind(NotStringVarUse, StringIdentUse))
285            break;
286        return CannotCompile;
287    case CompareLess:
288    case CompareLessEq:
289    case CompareGreater:
290    case CompareGreaterEq:
291        if (node->isBinaryUseKind(Int32Use))
292            break;
293        if (node->isBinaryUseKind(Int52RepUse))
294            break;
295        if (node->isBinaryUseKind(DoubleRepUse))
296            break;
297        if (node->isBinaryUseKind(UntypedUse))
298            break;
299        return CannotCompile;
300    case Switch:
301        switch (node->switchData()->kind) {
302        case SwitchImm:
303        case SwitchChar:
304            break;
305        default:
306            return CannotCompile;
307        }
308        break;
309    default:
310        // Don't know how to handle anything else.
311        return CannotCompile;
312    }
313    return CanCompileAndOSREnter;
314}
315
316CapabilityLevel canCompile(Graph& graph)
317{
318    if (graph.m_codeBlock->instructionCount() > Options::maximumFTLCandidateInstructionCount()) {
319        if (verboseCapabilities())
320            dataLog("FTL rejecting ", *graph.m_codeBlock, " because it's too big.\n");
321        return CannotCompile;
322    }
323
324    if (graph.m_codeBlock->codeType() != FunctionCode) {
325        if (verboseCapabilities())
326            dataLog("FTL rejecting ", *graph.m_codeBlock, " because it doesn't belong to a function.\n");
327        return CannotCompile;
328    }
329
330    if (graph.m_codeBlock->needsActivation()) {
331        // Need this because although we also don't support
332        // CreateActivation/TearOffActivation, we might not see those nodes in case of
333        // OSR entry.
334        // FIXME: Support activations.
335        // https://bugs.webkit.org/show_bug.cgi?id=129576
336        if (verboseCapabilities())
337            dataLog("FTL rejecting ", *graph.m_codeBlock, " because it uses activations.\n");
338        return CannotCompile;
339    }
340
341    CapabilityLevel result = CanCompileAndOSREnter;
342
343    for (BlockIndex blockIndex = graph.numBlocks(); blockIndex--;) {
344        BasicBlock* block = graph.block(blockIndex);
345        if (!block)
346            continue;
347
348        // We don't care if we can compile blocks that the CFA hasn't visited.
349        if (!block->cfaHasVisited)
350            continue;
351
352        for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
353            Node* node = block->at(nodeIndex);
354
355            for (unsigned childIndex = graph.numChildren(node); childIndex--;) {
356                Edge edge = graph.child(node, childIndex);
357                if (!edge)
358                    continue;
359                switch (edge.useKind()) {
360                case UntypedUse:
361                case Int32Use:
362                case KnownInt32Use:
363                case Int52RepUse:
364                case NumberUse:
365                case DoubleRepUse:
366                case DoubleRepRealUse:
367                case BooleanUse:
368                case CellUse:
369                case KnownCellUse:
370                case ObjectUse:
371                case ObjectOrOtherUse:
372                case StringUse:
373                case KnownStringUse:
374                case StringObjectUse:
375                case StringOrStringObjectUse:
376                case FinalObjectUse:
377                case NotCellUse:
378                case OtherUse:
379                case MiscUse:
380                case StringIdentUse:
381                case NotStringVarUse:
382                case MachineIntUse:
383                case DoubleRepMachineIntUse:
384                    // These are OK.
385                    break;
386                default:
387                    // Don't know how to handle anything else.
388                    if (verboseCapabilities()) {
389                        dataLog("FTL rejecting node in ", *graph.m_codeBlock, " because of bad use kind: ", edge.useKind(), " in node:\n");
390                        graph.dump(WTF::dataFile(), "    ", node);
391                    }
392                    return CannotCompile;
393                }
394            }
395
396            switch (canCompile(node)) {
397            case CannotCompile:
398                if (verboseCapabilities()) {
399                    dataLog("FTL rejecting node in ", *graph.m_codeBlock, ":\n");
400                    graph.dump(WTF::dataFile(), "    ", node);
401                }
402                return CannotCompile;
403
404            case CanCompile:
405                if (result == CanCompileAndOSREnter && verboseCompilationEnabled()) {
406                    dataLog("FTL disabling OSR entry because of node:\n");
407                    graph.dump(WTF::dataFile(), "    ", node);
408                }
409                result = CanCompile;
410                break;
411
412            case CanCompileAndOSREnter:
413                break;
414            }
415
416            if (node->op() == ForceOSRExit)
417                break;
418        }
419    }
420
421    return result;
422}
423
424} } // namespace JSC::FTL
425
426#endif // ENABLE(FTL_JIT)
427
428