f99179f2d4bc5dfb2bc747b2d9c6821d2b8d7a37
[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 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 CheckWatchdogTimer:
138     case StringCharCodeAt:
139     case StringFromCharCode:
140     case AllocatePropertyStorage:
141     case ReallocatePropertyStorage:
142     case GetTypedArrayByteOffset:
143     case NotifyWrite:
144     case StoreBarrier:
145     case FencedStoreBarrier:
146     case Call:
147     case DirectCall:
148     case TailCall:
149     case DirectTailCall:
150     case TailCallInlinedCaller:
151     case DirectTailCallInlinedCaller:
152     case Construct:
153     case DirectConstruct:
154     case CallVarargs:
155     case CallEval:
156     case TailCallVarargs:
157     case TailCallVarargsInlinedCaller:
158     case ConstructVarargs:
159     case CallForwardVarargs:
160     case TailCallForwardVarargs:
161     case TailCallForwardVarargsInlinedCaller:
162     case ConstructForwardVarargs:
163     case LoadVarargs:
164     case ValueToInt32:
165     case Branch:
166     case LogicalNot:
167     case CheckInBounds:
168     case ConstantStoragePointer:
169     case Check:
170     case CountExecution:
171     case GetExecutable:
172     case GetScope:
173     case GetCallee:
174     case GetArgumentCountIncludingThis:
175     case ToNumber:
176     case ToString:
177     case CallObjectConstructor:
178     case CallStringConstructor:
179     case MakeRope:
180     case NewArrayWithSize:
181     case TryGetById:
182     case GetById:
183     case GetByIdFlush:
184     case GetByIdWithThis:
185     case ToThis:
186     case MultiGetByOffset:
187     case MultiPutByOffset:
188     case ToPrimitive:
189     case Throw:
190     case ThrowStaticError:
191     case Unreachable:
192     case In:
193     case HasOwnProperty:
194     case IsCellWithType:
195     case MapHash:
196     case GetMapBucket:
197     case LoadFromJSMapBucket:
198     case IsNonEmptyMapBucket:
199     case IsEmpty:
200     case IsUndefined:
201     case IsBoolean:
202     case IsNumber:
203     case IsObject:
204     case IsObjectOrNull:
205     case IsFunction:
206     case IsTypedArrayView:
207     case CheckTypeInfoFlags:
208     case OverridesHasInstance:
209     case InstanceOf:
210     case InstanceOfCustom:
211     case DoubleRep:
212     case ValueRep:
213     case Int52Rep:
214     case DoubleConstant:
215     case Int52Constant:
216     case BooleanToNumber:
217     case HasGenericProperty:
218     case HasStructureProperty:
219     case GetDirectPname:
220     case GetEnumerableLength:
221     case GetIndexedPropertyStorage:
222     case GetPropertyEnumerator:
223     case GetEnumeratorStructurePname:
224     case GetEnumeratorGenericPname:
225     case ToIndexString:
226     case BottomValue:
227     case PhantomNewObject:
228     case PhantomNewFunction:
229     case PhantomNewGeneratorFunction:
230     case PhantomNewAsyncFunction:
231     case PhantomCreateActivation:
232     case PutHint:
233     case CheckStructureImmediate:
234     case MaterializeNewObject:
235     case MaterializeCreateActivation:
236     case PhantomDirectArguments:
237     case PhantomCreateRest:
238     case PhantomClonedArguments:
239     case GetMyArgumentByVal:
240     case GetMyArgumentByValOutOfBounds:
241     case ForwardVarargs:
242     case Switch:
243     case TypeOf:
244     case PutById:
245     case PutByIdDirect:
246     case PutByIdFlush:
247     case PutByIdWithThis:
248     case PutGetterById:
249     case PutSetterById:
250     case PutGetterSetterById:
251     case PutGetterByVal:
252     case PutSetterByVal:
253     case CreateRest:
254     case GetRestLength:
255     case RegExpExec:
256     case RegExpTest:
257     case NewRegexp:
258     case StringReplace:
259     case StringReplaceRegExp: 
260     case GetRegExpObjectLastIndex:
261     case SetRegExpObjectLastIndex:
262     case RecordRegExpCachedResult:
263     case SetFunctionName:
264     case LogShadowChickenPrologue:
265     case LogShadowChickenTail:
266     case ResolveScope:
267     case GetDynamicVar:
268     case PutDynamicVar:
269     case CompareEq:
270     case CompareEqPtr:
271     case CompareLess:
272     case CompareLessEq:
273     case CompareGreater:
274     case CompareGreaterEq:
275     case CompareStrictEq:
276     case DefineDataProperty:
277     case DefineAccessorProperty:
278     case ToLowerCase:
279     case CheckDOM:
280     case CallDOM:
281     case CallDOMGetter:
282         // These are OK.
283         break;
284
285     case Identity:
286         // No backend handles this because it will be optimized out. But we may check
287         // for capabilities before optimization. It would be a deep error to remove this
288         // case because it would prevent us from catching bugs where the FTL backend
289         // pipeline failed to optimize out an Identity.
290         break;
291     case CheckArray:
292         switch (node->arrayMode().type()) {
293         case Array::Int32:
294         case Array::Double:
295         case Array::Contiguous:
296         case Array::DirectArguments:
297         case Array::ScopedArguments:
298             break;
299         default:
300             if (isTypedView(node->arrayMode().typedArrayType()))
301                 break;
302             return CannotCompile;
303         }
304         break;
305     case GetArrayLength:
306         switch (node->arrayMode().type()) {
307         case Array::Undecided:
308         case Array::Int32:
309         case Array::Double:
310         case Array::Contiguous:
311         case Array::String:
312         case Array::DirectArguments:
313         case Array::ScopedArguments:
314             break;
315         default:
316             if (node->arrayMode().isSomeTypedArrayView())
317                 break;
318             return CannotCompile;
319         }
320         break;
321     case HasIndexedProperty:
322         switch (node->arrayMode().type()) {
323         case Array::ForceExit:
324         case Array::Int32:
325         case Array::Double:
326         case Array::Contiguous:
327             break;
328         default:
329             return CannotCompile;
330         }
331         break;
332     case GetByVal:
333         switch (node->arrayMode().type()) {
334         case Array::ForceExit:
335         case Array::Generic:
336         case Array::String:
337         case Array::Int32:
338         case Array::Double:
339         case Array::Contiguous:
340         case Array::Undecided:
341         case Array::DirectArguments:
342         case Array::ScopedArguments:
343             break;
344         default:
345             if (isTypedView(node->arrayMode().typedArrayType()))
346                 return CanCompileAndOSREnter;
347             return CannotCompile;
348         }
349         break;
350     case GetByValWithThis:
351         break;
352     case PutByVal:
353     case PutByValAlias:
354     case PutByValDirect:
355         switch (node->arrayMode().type()) {
356         case Array::ForceExit:
357         case Array::Generic:
358         case Array::Int32:
359         case Array::Double:
360         case Array::Contiguous:
361             break;
362         default:
363             if (isTypedView(node->arrayMode().typedArrayType()))
364                 return CanCompileAndOSREnter;
365             return CannotCompile;
366         }
367         break;
368     case PutByValWithThis:
369         break;
370     case ArrayPush:
371     case ArrayPop:
372         switch (node->arrayMode().type()) {
373         case Array::Int32:
374         case Array::Contiguous:
375         case Array::Double:
376             break;
377         default:
378             return CannotCompile;
379         }
380         break;
381     default:
382         // Don't know how to handle anything else.
383         return CannotCompile;
384     }
385     return CanCompileAndOSREnter;
386 }
387
388 CapabilityLevel canCompile(Graph& graph)
389 {
390     if (graph.m_codeBlock->instructionCount() > Options::maximumFTLCandidateInstructionCount()) {
391         if (verboseCapabilities())
392             dataLog("FTL rejecting ", *graph.m_codeBlock, " because it's too big.\n");
393         return CannotCompile;
394     }
395     
396     if (graph.m_codeBlock->codeType() != FunctionCode) {
397         if (verboseCapabilities())
398             dataLog("FTL rejecting ", *graph.m_codeBlock, " because it doesn't belong to a function.\n");
399         return CannotCompile;
400     }
401
402     if (UNLIKELY(graph.m_codeBlock->ownerScriptExecutable()->neverFTLOptimize())) {
403         if (verboseCapabilities())
404             dataLog("FTL rejecting ", *graph.m_codeBlock, " because it is marked as never FTL compile.\n");
405         return CannotCompile;
406     }
407     
408     CapabilityLevel result = CanCompileAndOSREnter;
409     
410     for (BlockIndex blockIndex = graph.numBlocks(); blockIndex--;) {
411         BasicBlock* block = graph.block(blockIndex);
412         if (!block)
413             continue;
414         
415         // We don't care if we can compile blocks that the CFA hasn't visited.
416         if (!block->cfaHasVisited)
417             continue;
418         
419         for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
420             Node* node = block->at(nodeIndex);
421             
422             for (unsigned childIndex = graph.numChildren(node); childIndex--;) {
423                 Edge edge = graph.child(node, childIndex);
424                 if (!edge)
425                     continue;
426                 switch (edge.useKind()) {
427                 case UntypedUse:
428                 case Int32Use:
429                 case KnownInt32Use:
430                 case Int52RepUse:
431                 case NumberUse:
432                 case RealNumberUse:
433                 case DoubleRepUse:
434                 case DoubleRepRealUse:
435                 case BooleanUse:
436                 case KnownBooleanUse:
437                 case CellUse:
438                 case KnownCellUse:
439                 case CellOrOtherUse:
440                 case ObjectUse:
441                 case ArrayUse:
442                 case FunctionUse:
443                 case ObjectOrOtherUse:
444                 case StringUse:
445                 case StringOrOtherUse:
446                 case KnownStringUse:
447                 case KnownPrimitiveUse:
448                 case StringObjectUse:
449                 case StringOrStringObjectUse:
450                 case SymbolUse:
451                 case MapObjectUse:
452                 case SetObjectUse:
453                 case FinalObjectUse:
454                 case RegExpObjectUse:
455                 case ProxyObjectUse:
456                 case DerivedArrayUse:
457                 case NotCellUse:
458                 case OtherUse:
459                 case MiscUse:
460                 case StringIdentUse:
461                 case NotStringVarUse:
462                 case AnyIntUse:
463                 case DoubleRepAnyIntUse:
464                     // These are OK.
465                     break;
466                 default:
467                     // Don't know how to handle anything else.
468                     if (verboseCapabilities()) {
469                         dataLog("FTL rejecting node in ", *graph.m_codeBlock, " because of bad use kind: ", edge.useKind(), " in node:\n");
470                         graph.dump(WTF::dataFile(), "    ", node);
471                     }
472                     return CannotCompile;
473                 }
474             }
475             
476             switch (canCompile(node)) {
477             case CannotCompile: 
478                 if (verboseCapabilities()) {
479                     dataLog("FTL rejecting node in ", *graph.m_codeBlock, ":\n");
480                     graph.dump(WTF::dataFile(), "    ", node);
481                 }
482                 return CannotCompile;
483                 
484             case CanCompile:
485                 if (result == CanCompileAndOSREnter && verboseCompilationEnabled()) {
486                     dataLog("FTL disabling OSR entry because of node:\n");
487                     graph.dump(WTF::dataFile(), "    ", node);
488                 }
489                 result = CanCompile;
490                 break;
491                 
492             case CanCompileAndOSREnter:
493                 break;
494             }
495             
496             if (node->op() == ForceOSRExit)
497                 break;
498         }
499     }
500     
501     return result;
502 }
503
504 } } // namespace JSC::FTL
505
506 #endif // ENABLE(FTL_JIT)
507