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