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