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