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