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