0bfdfccc6d32aedb480c7389adcbe165b77b4e23
[WebKit-https.git] / Source / JavaScriptCore / ftl / FTLCapabilities.cpp
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 #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 static bool verboseCapabilities()
36 {
37     return verboseCompilationEnabled() || Options::verboseFTLFailure();
38 }
39
40 inline 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 GetLocal:
48     case SetLocal:
49     case PutStack:
50     case KillStack:
51     case GetStack:
52     case MovHint:
53     case ZombieHint:
54     case Phantom:
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 ArrayifyToStructure:
67     case PutStructure:
68     case GetButterfly:
69     case NewObject:
70     case NewArray:
71     case NewArrayBuffer:
72     case GetByOffset:
73     case GetGetterSetterByOffset:
74     case GetGetter:
75     case GetSetter:
76     case PutByOffset:
77     case GetGlobalVar:
78     case PutGlobalVar:
79     case ValueAdd:
80     case ArithAdd:
81     case ArithClz32:
82     case ArithSub:
83     case ArithMul:
84     case ArithDiv:
85     case ArithMod:
86     case ArithMin:
87     case ArithMax:
88     case ArithAbs:
89     case ArithSin:
90     case ArithCos:
91     case ArithPow:
92     case ArithSqrt:
93     case ArithLog:
94     case ArithFRound:
95     case ArithNegate:
96     case UInt32ToNumber:
97     case CompareEqConstant:
98     case Jump:
99     case ForceOSRExit:
100     case Phi:
101     case Upsilon:
102     case ExtractOSREntryLocal:
103     case LoopHint:
104     case SkipScope:
105     case CreateActivation:
106     case NewFunction:
107     case GetClosureVar:
108     case PutClosureVar:
109     case CreateDirectArguments:
110     case CreateScopedArguments:
111     case CreateClonedArguments:
112     case GetFromArguments:
113     case PutToArguments:
114     case InvalidationPoint:
115     case StringCharAt:
116     case CheckCell:
117     case CheckBadCell:
118     case CheckNotEmpty:
119     case StringCharCodeAt:
120     case AllocatePropertyStorage:
121     case ReallocatePropertyStorage:
122     case GetTypedArrayByteOffset:
123     case NotifyWrite:
124     case StoreBarrier:
125     case StoreBarrierWithNullCheck:
126     case Call:
127     case Construct:
128     case CallVarargs:
129     case CallForwardVarargs:
130     case ConstructVarargs:
131     case ConstructForwardVarargs:
132     case LoadVarargs:
133     case NativeCall:
134     case NativeConstruct:
135     case ValueToInt32:
136     case Branch:
137     case LogicalNot:
138     case CheckInBounds:
139     case ConstantStoragePointer:
140     case Check:
141     case CountExecution:
142     case GetExecutable:
143     case GetScope:
144     case GetCallee:
145     case GetArgumentCount:
146     case ToString:
147     case CallStringConstructor:
148     case MakeRope:
149     case NewArrayWithSize:
150     case GetById:
151     case ToThis:
152     case MultiGetByOffset:
153     case MultiPutByOffset:
154     case ToPrimitive:
155     case Throw:
156     case ThrowReferenceError:
157     case Unreachable:
158     case IsUndefined:
159     case IsBoolean:
160     case IsNumber:
161     case IsString:
162     case IsObject:
163     case IsObjectOrNull:
164     case IsFunction:
165     case CheckHasInstance:
166     case InstanceOf:
167     case DoubleRep:
168     case ValueRep:
169     case Int52Rep:
170     case DoubleConstant:
171     case Int52Constant:
172     case BooleanToNumber:
173     case HasGenericProperty:
174     case HasStructureProperty:
175     case GetDirectPname:
176     case GetEnumerableLength:
177     case GetPropertyEnumerator:
178     case GetEnumeratorStructurePname:
179     case GetEnumeratorGenericPname:
180     case ToIndexString:
181     case BottomValue:
182     case PhantomNewObject:
183     case PhantomNewFunction:
184     case PhantomCreateActivation:
185     case PutHint:
186     case CheckStructureImmediate:
187     case MaterializeNewObject:
188     case MaterializeCreateActivation:
189     case PhantomDirectArguments:
190     case PhantomClonedArguments:
191     case GetMyArgumentByVal:
192     case ForwardVarargs:
193     case Switch:
194     case TypeOf:
195         // These are OK.
196         break;
197     case Identity:
198         // No backend handles this because it will be optimized out. But we may check
199         // for capabilities before optimization. It would be a deep error to remove this
200         // case because it would prevent us from catching bugs where the FTL backend
201         // pipeline failed to optimize out an Identity.
202         break;
203     case In:
204         if (node->child2().useKind() == CellUse)
205             break;
206         return CannotCompile;
207     case PutByIdDirect:
208     case PutById:
209         if (node->child1().useKind() == CellUse)
210             break;
211         return CannotCompile;
212     case GetIndexedPropertyStorage:
213         if (node->arrayMode().type() == Array::String)
214             break;
215         if (isTypedView(node->arrayMode().typedArrayType()))
216             break;
217         return CannotCompile;
218     case CheckArray:
219         switch (node->arrayMode().type()) {
220         case Array::Int32:
221         case Array::Double:
222         case Array::Contiguous:
223         case Array::DirectArguments:
224         case Array::ScopedArguments:
225             break;
226         default:
227             if (isTypedView(node->arrayMode().typedArrayType()))
228                 break;
229             return CannotCompile;
230         }
231         break;
232     case GetArrayLength:
233         switch (node->arrayMode().type()) {
234         case Array::Int32:
235         case Array::Double:
236         case Array::Contiguous:
237         case Array::String:
238         case Array::DirectArguments:
239         case Array::ScopedArguments:
240             break;
241         default:
242             if (isTypedView(node->arrayMode().typedArrayType()))
243                 break;
244             return CannotCompile;
245         }
246         break;
247     case HasIndexedProperty:
248         switch (node->arrayMode().type()) {
249         case Array::ForceExit:
250         case Array::Int32:
251         case Array::Double:
252         case Array::Contiguous:
253             break;
254         default:
255             return CannotCompile;
256         }
257         break;
258     case GetByVal:
259         switch (node->arrayMode().type()) {
260         case Array::ForceExit:
261         case Array::Generic:
262         case Array::String:
263         case Array::Int32:
264         case Array::Double:
265         case Array::Contiguous:
266         case Array::DirectArguments:
267         case Array::ScopedArguments:
268             break;
269         default:
270             if (isTypedView(node->arrayMode().typedArrayType()))
271                 return CanCompileAndOSREnter;
272             return CannotCompile;
273         }
274         break;
275     case PutByVal:
276     case PutByValAlias:
277     case PutByValDirect:
278         switch (node->arrayMode().type()) {
279         case Array::ForceExit:
280         case Array::Generic:
281         case Array::Int32:
282         case Array::Double:
283         case Array::Contiguous:
284             break;
285         default:
286             if (isTypedView(node->arrayMode().typedArrayType()))
287                 return CanCompileAndOSREnter;
288             return CannotCompile;
289         }
290         break;
291     case ArrayPush:
292     case ArrayPop:
293         switch (node->arrayMode().type()) {
294         case Array::Int32:
295         case Array::Contiguous:
296         case Array::Double:
297             break;
298         default:
299             return CannotCompile;
300         }
301         break;
302     case CompareEq:
303         if (node->isBinaryUseKind(Int32Use))
304             break;
305         if (node->isBinaryUseKind(Int52RepUse))
306             break;
307         if (node->isBinaryUseKind(DoubleRepUse))
308             break;
309         if (node->isBinaryUseKind(StringIdentUse))
310             break;
311         if (node->isBinaryUseKind(ObjectUse))
312             break;
313         if (node->isBinaryUseKind(UntypedUse))
314             break;
315         if (node->isBinaryUseKind(BooleanUse))
316             break;
317         if (node->isBinaryUseKind(ObjectUse, ObjectOrOtherUse))
318             break;
319         if (node->isBinaryUseKind(ObjectOrOtherUse, ObjectUse))
320             break;
321         return CannotCompile;
322     case CompareStrictEq:
323         if (node->isBinaryUseKind(Int32Use))
324             break;
325         if (node->isBinaryUseKind(Int52RepUse))
326             break;
327         if (node->isBinaryUseKind(DoubleRepUse))
328             break;
329         if (node->isBinaryUseKind(StringIdentUse))
330             break;
331         if (node->isBinaryUseKind(ObjectUse))
332             break;
333         if (node->isBinaryUseKind(BooleanUse))
334             break;
335         if (node->isBinaryUseKind(MiscUse, UntypedUse))
336             break;
337         if (node->isBinaryUseKind(UntypedUse, MiscUse))
338             break;
339         if (node->isBinaryUseKind(StringIdentUse, NotStringVarUse))
340             break;
341         if (node->isBinaryUseKind(NotStringVarUse, StringIdentUse))
342             break;
343         return CannotCompile;
344     case CompareLess:
345     case CompareLessEq:
346     case CompareGreater:
347     case CompareGreaterEq:
348         if (node->isBinaryUseKind(Int32Use))
349             break;
350         if (node->isBinaryUseKind(Int52RepUse))
351             break;
352         if (node->isBinaryUseKind(DoubleRepUse))
353             break;
354         if (node->isBinaryUseKind(UntypedUse))
355             break;
356         return CannotCompile;
357     default:
358         // Don't know how to handle anything else.
359         return CannotCompile;
360     }
361     return CanCompileAndOSREnter;
362 }
363
364 CapabilityLevel canCompile(Graph& graph)
365 {
366     if (graph.m_codeBlock->instructionCount() > Options::maximumFTLCandidateInstructionCount()) {
367         if (verboseCapabilities())
368             dataLog("FTL rejecting ", *graph.m_codeBlock, " because it's too big.\n");
369         return CannotCompile;
370     }
371     
372     if (graph.m_codeBlock->codeType() != FunctionCode) {
373         if (verboseCapabilities())
374             dataLog("FTL rejecting ", *graph.m_codeBlock, " because it doesn't belong to a function.\n");
375         return CannotCompile;
376     }
377     
378     CapabilityLevel result = CanCompileAndOSREnter;
379     
380     for (BlockIndex blockIndex = graph.numBlocks(); blockIndex--;) {
381         BasicBlock* block = graph.block(blockIndex);
382         if (!block)
383             continue;
384         
385         // We don't care if we can compile blocks that the CFA hasn't visited.
386         if (!block->cfaHasVisited)
387             continue;
388         
389         for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
390             Node* node = block->at(nodeIndex);
391             
392             for (unsigned childIndex = graph.numChildren(node); childIndex--;) {
393                 Edge edge = graph.child(node, childIndex);
394                 if (!edge)
395                     continue;
396                 switch (edge.useKind()) {
397                 case UntypedUse:
398                 case Int32Use:
399                 case KnownInt32Use:
400                 case Int52RepUse:
401                 case NumberUse:
402                 case DoubleRepUse:
403                 case DoubleRepRealUse:
404                 case BooleanUse:
405                 case CellUse:
406                 case KnownCellUse:
407                 case ObjectUse:
408                 case FunctionUse:
409                 case ObjectOrOtherUse:
410                 case StringUse:
411                 case KnownStringUse:
412                 case StringObjectUse:
413                 case StringOrStringObjectUse:
414                 case FinalObjectUse:
415                 case NotCellUse:
416                 case OtherUse:
417                 case MiscUse:
418                 case StringIdentUse:
419                 case NotStringVarUse:
420                 case MachineIntUse:
421                 case DoubleRepMachineIntUse:
422                     // These are OK.
423                     break;
424                 default:
425                     // Don't know how to handle anything else.
426                     if (verboseCapabilities()) {
427                         dataLog("FTL rejecting node in ", *graph.m_codeBlock, " because of bad use kind: ", edge.useKind(), " in node:\n");
428                         graph.dump(WTF::dataFile(), "    ", node);
429                     }
430                     return CannotCompile;
431                 }
432             }
433             
434             switch (canCompile(node)) {
435             case CannotCompile: 
436                 if (verboseCapabilities()) {
437                     dataLog("FTL rejecting node in ", *graph.m_codeBlock, ":\n");
438                     graph.dump(WTF::dataFile(), "    ", node);
439                 }
440                 return CannotCompile;
441                 
442             case CanCompile:
443                 if (result == CanCompileAndOSREnter && verboseCompilationEnabled()) {
444                     dataLog("FTL disabling OSR entry because of node:\n");
445                     graph.dump(WTF::dataFile(), "    ", node);
446                 }
447                 result = CanCompile;
448                 break;
449                 
450             case CanCompileAndOSREnter:
451                 break;
452             }
453             
454             if (node->op() == ForceOSRExit)
455                 break;
456         }
457     }
458     
459     return result;
460 }
461
462 } } // namespace JSC::FTL
463
464 #endif // ENABLE(FTL_JIT)
465