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