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