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