01c8e87af523d8b6868193277220f359469591ee
[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     case RegExpExec:
222     case RegExpTest:
223     case NewRegexp:
224         // These are OK.
225         break;
226
227     case Identity:
228         // No backend handles this because it will be optimized out. But we may check
229         // for capabilities before optimization. It would be a deep error to remove this
230         // case because it would prevent us from catching bugs where the FTL backend
231         // pipeline failed to optimize out an Identity.
232         break;
233     case In:
234         if (node->child2().useKind() == CellUse)
235             break;
236         return CannotCompile;
237     case PutByIdDirect:
238     case PutById:
239     case PutByIdFlush:
240         if (node->child1().useKind() == CellUse)
241             break;
242         return CannotCompile;
243     case GetIndexedPropertyStorage:
244         if (node->arrayMode().type() == Array::String)
245             break;
246         if (isTypedView(node->arrayMode().typedArrayType()))
247             break;
248         return CannotCompile;
249     case CheckArray:
250         switch (node->arrayMode().type()) {
251         case Array::Int32:
252         case Array::Double:
253         case Array::Contiguous:
254         case Array::DirectArguments:
255         case Array::ScopedArguments:
256             break;
257         default:
258             if (isTypedView(node->arrayMode().typedArrayType()))
259                 break;
260             return CannotCompile;
261         }
262         break;
263     case GetArrayLength:
264         switch (node->arrayMode().type()) {
265         case Array::Int32:
266         case Array::Double:
267         case Array::Contiguous:
268         case Array::String:
269         case Array::DirectArguments:
270         case Array::ScopedArguments:
271             break;
272         default:
273             if (node->arrayMode().isSomeTypedArrayView())
274                 break;
275             return CannotCompile;
276         }
277         break;
278     case HasIndexedProperty:
279         switch (node->arrayMode().type()) {
280         case Array::ForceExit:
281         case Array::Int32:
282         case Array::Double:
283         case Array::Contiguous:
284             break;
285         default:
286             return CannotCompile;
287         }
288         break;
289     case GetByVal:
290         switch (node->arrayMode().type()) {
291         case Array::ForceExit:
292         case Array::Generic:
293         case Array::String:
294         case Array::Int32:
295         case Array::Double:
296         case Array::Contiguous:
297         case Array::Undecided:
298         case Array::DirectArguments:
299         case Array::ScopedArguments:
300             break;
301         default:
302             if (isTypedView(node->arrayMode().typedArrayType()))
303                 return CanCompileAndOSREnter;
304             return CannotCompile;
305         }
306         break;
307     case PutByVal:
308     case PutByValAlias:
309     case PutByValDirect:
310         switch (node->arrayMode().type()) {
311         case Array::ForceExit:
312         case Array::Generic:
313         case Array::Int32:
314         case Array::Double:
315         case Array::Contiguous:
316             break;
317         default:
318             if (isTypedView(node->arrayMode().typedArrayType()))
319                 return CanCompileAndOSREnter;
320             return CannotCompile;
321         }
322         break;
323     case ArrayPush:
324     case ArrayPop:
325         switch (node->arrayMode().type()) {
326         case Array::Int32:
327         case Array::Contiguous:
328         case Array::Double:
329             break;
330         default:
331             return CannotCompile;
332         }
333         break;
334     case CompareEq:
335         if (node->isBinaryUseKind(Int32Use))
336             break;
337         if (node->isBinaryUseKind(Int52RepUse))
338             break;
339         if (node->isBinaryUseKind(DoubleRepUse))
340             break;
341         if (node->isBinaryUseKind(StringIdentUse))
342             break;
343         if (node->isBinaryUseKind(StringUse))
344             break;
345         if (node->isBinaryUseKind(SymbolUse))
346             break;
347         if (node->isBinaryUseKind(ObjectUse))
348             break;
349         if (node->isBinaryUseKind(UntypedUse))
350             break;
351         if (node->isBinaryUseKind(BooleanUse))
352             break;
353         if (node->isBinaryUseKind(ObjectUse, ObjectOrOtherUse))
354             break;
355         if (node->isBinaryUseKind(ObjectOrOtherUse, ObjectUse))
356             break;
357         if (node->child1().useKind() == OtherUse || node->child2().useKind() == OtherUse)
358             break;
359         return CannotCompile;
360     case CompareStrictEq:
361         if (node->isBinaryUseKind(Int32Use))
362             break;
363         if (node->isBinaryUseKind(Int52RepUse))
364             break;
365         if (node->isBinaryUseKind(DoubleRepUse))
366             break;
367         if (node->isBinaryUseKind(StringIdentUse))
368             break;
369         if (node->isBinaryUseKind(StringUse))
370             break;
371         if (node->isBinaryUseKind(ObjectUse, UntypedUse))
372             break;
373         if (node->isBinaryUseKind(UntypedUse, ObjectUse))
374             break;
375         if (node->isBinaryUseKind(ObjectUse))
376             break;
377         if (node->isBinaryUseKind(BooleanUse))
378             break;
379         if (node->isBinaryUseKind(SymbolUse))
380             break;
381         if (node->isBinaryUseKind(MiscUse, UntypedUse))
382             break;
383         if (node->isBinaryUseKind(UntypedUse, MiscUse))
384             break;
385         if (node->isBinaryUseKind(StringIdentUse, NotStringVarUse))
386             break;
387         if (node->isBinaryUseKind(NotStringVarUse, StringIdentUse))
388             break;
389         return CannotCompile;
390     case CompareLess:
391     case CompareLessEq:
392     case CompareGreater:
393     case CompareGreaterEq:
394         if (node->isBinaryUseKind(Int32Use))
395             break;
396         if (node->isBinaryUseKind(Int52RepUse))
397             break;
398         if (node->isBinaryUseKind(DoubleRepUse))
399             break;
400         if (node->isBinaryUseKind(UntypedUse))
401             break;
402         return CannotCompile;
403     default:
404         // Don't know how to handle anything else.
405         return CannotCompile;
406     }
407     return CanCompileAndOSREnter;
408 }
409
410 CapabilityLevel canCompile(Graph& graph)
411 {
412     if (graph.m_codeBlock->instructionCount() > Options::maximumFTLCandidateInstructionCount()) {
413         if (verboseCapabilities())
414             dataLog("FTL rejecting ", *graph.m_codeBlock, " because it's too big.\n");
415         return CannotCompile;
416     }
417     
418     if (graph.m_codeBlock->codeType() != FunctionCode) {
419         if (verboseCapabilities())
420             dataLog("FTL rejecting ", *graph.m_codeBlock, " because it doesn't belong to a function.\n");
421         return CannotCompile;
422     }
423     
424     CapabilityLevel result = CanCompileAndOSREnter;
425     
426     for (BlockIndex blockIndex = graph.numBlocks(); blockIndex--;) {
427         BasicBlock* block = graph.block(blockIndex);
428         if (!block)
429             continue;
430         
431         // We don't care if we can compile blocks that the CFA hasn't visited.
432         if (!block->cfaHasVisited)
433             continue;
434         
435         for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
436             Node* node = block->at(nodeIndex);
437             
438             for (unsigned childIndex = graph.numChildren(node); childIndex--;) {
439                 Edge edge = graph.child(node, childIndex);
440                 if (!edge)
441                     continue;
442                 switch (edge.useKind()) {
443                 case UntypedUse:
444                 case Int32Use:
445                 case KnownInt32Use:
446                 case Int52RepUse:
447                 case NumberUse:
448                 case RealNumberUse:
449                 case DoubleRepUse:
450                 case DoubleRepRealUse:
451                 case BooleanUse:
452                 case KnownBooleanUse:
453                 case CellUse:
454                 case KnownCellUse:
455                 case CellOrOtherUse:
456                 case ObjectUse:
457                 case FunctionUse:
458                 case ObjectOrOtherUse:
459                 case StringUse:
460                 case KnownStringUse:
461                 case KnownPrimitiveUse:
462                 case StringObjectUse:
463                 case StringOrStringObjectUse:
464                 case SymbolUse:
465                 case FinalObjectUse:
466                 case NotCellUse:
467                 case OtherUse:
468                 case MiscUse:
469                 case StringIdentUse:
470                 case NotStringVarUse:
471                 case MachineIntUse:
472                 case DoubleRepMachineIntUse:
473                     // These are OK.
474                     break;
475                 default:
476                     // Don't know how to handle anything else.
477                     if (verboseCapabilities()) {
478                         dataLog("FTL rejecting node in ", *graph.m_codeBlock, " because of bad use kind: ", edge.useKind(), " in node:\n");
479                         graph.dump(WTF::dataFile(), "    ", node);
480                     }
481                     return CannotCompile;
482                 }
483             }
484             
485             switch (canCompile(node)) {
486             case CannotCompile: 
487                 if (verboseCapabilities()) {
488                     dataLog("FTL rejecting node in ", *graph.m_codeBlock, ":\n");
489                     graph.dump(WTF::dataFile(), "    ", node);
490                 }
491                 return CannotCompile;
492                 
493             case CanCompile:
494                 if (result == CanCompileAndOSREnter && verboseCompilationEnabled()) {
495                     dataLog("FTL disabling OSR entry because of node:\n");
496                     graph.dump(WTF::dataFile(), "    ", node);
497                 }
498                 result = CanCompile;
499                 break;
500                 
501             case CanCompileAndOSREnter:
502                 break;
503             }
504             
505             if (node->op() == ForceOSRExit)
506                 break;
507         }
508     }
509     
510     return result;
511 }
512
513 } } // namespace JSC::FTL
514
515 #endif // ENABLE(FTL_JIT)
516