2ff3038d57b3752be9d877291aea0423f0b4e62e
[WebKit-https.git] / Source / JavaScriptCore / ftl / FTLCapabilities.cpp
1 /*
2  * Copyright (C) 2013 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
31 namespace JSC { namespace FTL {
32
33 using namespace DFG;
34
35 inline bool canCompile(Node* node)
36 {
37     switch (node->op()) {
38     case JSConstant:
39     case WeakJSConstant:
40     case GetLocal:
41     case SetLocal:
42     case MovHintAndCheck:
43     case MovHint:
44     case ZombieHint:
45     case Phantom:
46     case Flush:
47     case PhantomLocal:
48     case SetArgument:
49     case Return:
50     case BitAnd:
51     case BitOr:
52     case BitXor:
53     case BitRShift:
54     case BitLShift:
55     case BitURShift:
56     case CheckStructure:
57     case StructureTransitionWatchpoint:
58     case ArrayifyToStructure:
59     case PutStructure:
60     case PhantomPutStructure:
61     case GetButterfly:
62     case GetByOffset:
63     case PutByOffset:
64     case GetGlobalVar:
65     case PutGlobalVar:
66     case ValueAdd:
67     case ArithAdd:
68     case ArithSub:
69     case ArithMul:
70     case ArithDiv:
71     case ArithMod:
72     case ArithMin:
73     case ArithMax:
74     case ArithAbs:
75     case ArithNegate:
76     case UInt32ToNumber:
77     case Int32ToDouble:
78     case CompareEqConstant:
79     case CompareStrictEqConstant:
80     case Jump:
81     case ForceOSRExit:
82     case Phi:
83     case Upsilon:
84         // These are OK.
85         break;
86     case GetArrayLength:
87         switch (node->arrayMode().type()) {
88         case Array::Int32:
89         case Array::Double:
90         case Array::Contiguous:
91             break;
92         default:
93             return false;
94         }
95         break;
96     case GetByVal:
97         switch (node->arrayMode().type()) {
98         case Array::ForceExit:
99             return true;
100         case Array::Int32:
101         case Array::Double:
102         case Array::Contiguous:
103             break;
104         default:
105             return false;
106         }
107         switch (node->arrayMode().speculation()) {
108         case Array::SaneChain:
109         case Array::InBounds:
110             break;
111         default:
112             return false;
113         }
114         break;
115     case PutByVal:
116     case PutByValAlias:
117         switch (node->arrayMode().type()) {
118         case Array::ForceExit:
119             return true;
120         case Array::Int32:
121         case Array::Double:
122         case Array::Contiguous:
123             break;
124         default:
125             return false;
126         }
127         break;
128     case CompareEq:
129     case CompareStrictEq:
130         if (node->isBinaryUseKind(Int32Use))
131             break;
132         if (node->isBinaryUseKind(NumberUse))
133             break;
134         if (node->isBinaryUseKind(ObjectUse))
135             break;
136         return false;
137     case CompareLess:
138     case CompareLessEq:
139     case CompareGreater:
140     case CompareGreaterEq:
141         if (node->isBinaryUseKind(Int32Use))
142             break;
143         if (node->isBinaryUseKind(NumberUse))
144             break;
145         return false;
146     case Branch:
147     case LogicalNot:
148         switch (node->child1().useKind()) {
149         case BooleanUse:
150         case Int32Use:
151         case NumberUse:
152         case ObjectOrOtherUse:
153             break;
154         default:
155             return false;
156         }
157         break;
158     case Switch:
159         switch (node->switchData()->kind) {
160         case SwitchImm:
161         case SwitchChar:
162             break;
163         default:
164             return false;
165         }
166         break;
167     default:
168         // Don't know how to handle anything else.
169         return false;
170     }
171     return true;
172 }
173
174 bool canCompile(Graph& graph)
175 {
176     for (BlockIndex blockIndex = graph.numBlocks(); blockIndex--;) {
177         BasicBlock* block = graph.block(blockIndex);
178         if (!block)
179             continue;
180         
181         // We don't care if we can compile blocks that the CFA hasn't visited.
182         if (!block->cfaHasVisited)
183             continue;
184         
185         for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
186             Node* node = block->at(nodeIndex);
187             
188             for (unsigned childIndex = graph.numChildren(node); childIndex--;) {
189                 Edge edge = graph.child(node, childIndex);
190                 if (!edge)
191                     continue;
192                 switch (edge.useKind()) {
193                 case UntypedUse:
194                 case Int32Use:
195                 case KnownInt32Use:
196                 case NumberUse:
197                 case KnownNumberUse:
198                 case RealNumberUse:
199                 case BooleanUse:
200                 case CellUse:
201                 case KnownCellUse:
202                 case ObjectUse:
203                 case ObjectOrOtherUse:
204                 case StringUse:
205                     // These are OK.
206                     break;
207                 default:
208                     // Don't know how to handle anything else.
209                     if (verboseCompilationEnabled()) {
210                         dataLog("FTL rejecting node because of bad use kind: ", edge.useKind(), " in node:\n");
211                         graph.dump(WTF::dataFile(), "    ", node);
212                     }
213                     return false;
214                 }
215             }
216             
217             if (!canCompile(node)) {
218                 if (verboseCompilationEnabled()) {
219                     dataLog("FTL rejecting node:\n");
220                     graph.dump(WTF::dataFile(), "    ", node);
221                 }
222                 return false;
223             }
224             
225             // We don't care if we can compile anything after a force-exit.
226             if (node->op() == ForceOSRExit)
227                 break;
228         }
229     }
230     
231     return true;
232 }
233
234 } } // namespace JSC::FTL
235
236 #endif // ENABLE(FTL_JIT)
237