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