[JSC] Clean up FTL Capabilities for CompareEq
[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 NewFunction:
118     case NewGeneratorFunction:
119     case GetClosureVar:
120     case PutClosureVar:
121     case CreateDirectArguments:
122     case CreateScopedArguments:
123     case CreateClonedArguments:
124     case GetFromArguments:
125     case PutToArguments:
126     case InvalidationPoint:
127     case StringCharAt:
128     case CheckCell:
129     case CheckBadCell:
130     case CheckNotEmpty:
131     case CheckStringIdent:
132     case CheckWatchdogTimer:
133     case StringCharCodeAt:
134     case StringFromCharCode:
135     case AllocatePropertyStorage:
136     case ReallocatePropertyStorage:
137     case GetTypedArrayByteOffset:
138     case NotifyWrite:
139     case StoreBarrier:
140     case Call:
141     case TailCall:
142     case TailCallInlinedCaller:
143     case Construct:
144     case CallVarargs:
145     case CallEval:
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 GetArgumentCountIncludingThis:
165     case ToNumber:
166     case ToString:
167     case CallObjectConstructor:
168     case CallStringConstructor:
169     case MakeRope:
170     case NewArrayWithSize:
171     case TryGetById:
172     case GetById:
173     case GetByIdFlush:
174     case GetByIdWithThis:
175     case ToThis:
176     case MultiGetByOffset:
177     case MultiPutByOffset:
178     case ToPrimitive:
179     case Throw:
180     case ThrowReferenceError:
181     case Unreachable:
182     case IsJSArray:
183     case IsEmpty:
184     case IsUndefined:
185     case IsBoolean:
186     case IsNumber:
187     case IsString:
188     case IsObject:
189     case IsObjectOrNull:
190     case IsFunction:
191     case IsRegExpObject:
192     case IsTypedArrayView:
193     case CheckTypeInfoFlags:
194     case OverridesHasInstance:
195     case InstanceOf:
196     case InstanceOfCustom:
197     case DoubleRep:
198     case ValueRep:
199     case Int52Rep:
200     case DoubleConstant:
201     case Int52Constant:
202     case BooleanToNumber:
203     case HasGenericProperty:
204     case HasStructureProperty:
205     case GetDirectPname:
206     case GetEnumerableLength:
207     case GetPropertyEnumerator:
208     case GetEnumeratorStructurePname:
209     case GetEnumeratorGenericPname:
210     case ToIndexString:
211     case BottomValue:
212     case PhantomNewObject:
213     case PhantomNewFunction:
214     case PhantomNewGeneratorFunction:
215     case PhantomCreateActivation:
216     case PutHint:
217     case CheckStructureImmediate:
218     case MaterializeNewObject:
219     case MaterializeCreateActivation:
220     case PhantomDirectArguments:
221     case PhantomClonedArguments:
222     case GetMyArgumentByVal:
223     case GetMyArgumentByValOutOfBounds:
224     case ForwardVarargs:
225     case Switch:
226     case TypeOf:
227     case PutGetterById:
228     case PutSetterById:
229     case PutGetterSetterById:
230     case PutGetterByVal:
231     case PutSetterByVal:
232     case CreateRest:
233     case GetRestLength:
234     case RegExpExec:
235     case RegExpTest:
236     case NewRegexp:
237     case StringReplace:
238     case StringReplaceRegExp: 
239     case GetRegExpObjectLastIndex:
240     case SetRegExpObjectLastIndex:
241     case RecordRegExpCachedResult:
242     case SetFunctionName:
243     case LogShadowChickenPrologue:
244     case LogShadowChickenTail:
245     case ResolveScope:
246     case GetDynamicVar:
247     case PutDynamicVar:
248     case CompareEq:
249     case CompareEqPtr:
250     case CompareStrictEq:
251         // These are OK.
252         break;
253
254     case Identity:
255         // No backend handles this because it will be optimized out. But we may check
256         // for capabilities before optimization. It would be a deep error to remove this
257         // case because it would prevent us from catching bugs where the FTL backend
258         // pipeline failed to optimize out an Identity.
259         break;
260     case In:
261         if (node->child2().useKind() == CellUse)
262             break;
263         return CannotCompile;
264     case PutByIdDirect:
265     case PutById:
266     case PutByIdFlush:
267         if (node->child1().useKind() == CellUse)
268             break;
269         return CannotCompile;
270     case PutByIdWithThis:
271         break;
272     case GetIndexedPropertyStorage:
273         if (node->arrayMode().type() == Array::String)
274             break;
275         if (isTypedView(node->arrayMode().typedArrayType()))
276             break;
277         return CannotCompile;
278     case CheckArray:
279         switch (node->arrayMode().type()) {
280         case Array::Int32:
281         case Array::Double:
282         case Array::Contiguous:
283         case Array::DirectArguments:
284         case Array::ScopedArguments:
285             break;
286         default:
287             if (isTypedView(node->arrayMode().typedArrayType()))
288                 break;
289             return CannotCompile;
290         }
291         break;
292     case GetArrayLength:
293         switch (node->arrayMode().type()) {
294         case Array::Int32:
295         case Array::Double:
296         case Array::Contiguous:
297         case Array::String:
298         case Array::DirectArguments:
299         case Array::ScopedArguments:
300             break;
301         default:
302             if (node->arrayMode().isSomeTypedArrayView())
303                 break;
304             return CannotCompile;
305         }
306         break;
307     case HasIndexedProperty:
308         switch (node->arrayMode().type()) {
309         case Array::ForceExit:
310         case Array::Int32:
311         case Array::Double:
312         case Array::Contiguous:
313             break;
314         default:
315             return CannotCompile;
316         }
317         break;
318     case GetByVal:
319         switch (node->arrayMode().type()) {
320         case Array::ForceExit:
321         case Array::Generic:
322         case Array::String:
323         case Array::Int32:
324         case Array::Double:
325         case Array::Contiguous:
326         case Array::Undecided:
327         case Array::DirectArguments:
328         case Array::ScopedArguments:
329             break;
330         default:
331             if (isTypedView(node->arrayMode().typedArrayType()))
332                 return CanCompileAndOSREnter;
333             return CannotCompile;
334         }
335         break;
336     case GetByValWithThis:
337         break;
338     case PutByVal:
339     case PutByValAlias:
340     case PutByValDirect:
341         switch (node->arrayMode().type()) {
342         case Array::ForceExit:
343         case Array::Generic:
344         case Array::Int32:
345         case Array::Double:
346         case Array::Contiguous:
347             break;
348         default:
349             if (isTypedView(node->arrayMode().typedArrayType()))
350                 return CanCompileAndOSREnter;
351             return CannotCompile;
352         }
353         break;
354     case PutByValWithThis:
355         break;
356     case ArrayPush:
357     case ArrayPop:
358         switch (node->arrayMode().type()) {
359         case Array::Int32:
360         case Array::Contiguous:
361         case Array::Double:
362             break;
363         default:
364             return CannotCompile;
365         }
366         break;
367     case CompareLess:
368     case CompareLessEq:
369     case CompareGreater:
370     case CompareGreaterEq:
371         if (node->isBinaryUseKind(Int32Use))
372             break;
373         if (node->isBinaryUseKind(Int52RepUse))
374             break;
375         if (node->isBinaryUseKind(DoubleRepUse))
376             break;
377         if (node->isBinaryUseKind(StringIdentUse))
378             break;
379         if (node->isBinaryUseKind(StringUse))
380             break;
381         if (node->isBinaryUseKind(UntypedUse))
382             break;
383         return CannotCompile;
384     default:
385         // Don't know how to handle anything else.
386         return CannotCompile;
387     }
388     return CanCompileAndOSREnter;
389 }
390
391 CapabilityLevel canCompile(Graph& graph)
392 {
393     if (graph.m_codeBlock->instructionCount() > Options::maximumFTLCandidateInstructionCount()) {
394         if (verboseCapabilities())
395             dataLog("FTL rejecting ", *graph.m_codeBlock, " because it's too big.\n");
396         return CannotCompile;
397     }
398     
399     if (graph.m_codeBlock->codeType() != FunctionCode) {
400         if (verboseCapabilities())
401             dataLog("FTL rejecting ", *graph.m_codeBlock, " because it doesn't belong to a function.\n");
402         return CannotCompile;
403     }
404
405     if (UNLIKELY(graph.m_codeBlock->ownerScriptExecutable()->neverFTLOptimize())) {
406         if (verboseCapabilities())
407             dataLog("FTL rejecting ", *graph.m_codeBlock, " because it is marked as never FTL compile.\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 StringOrOtherUse:
448                 case KnownStringUse:
449                 case KnownPrimitiveUse:
450                 case StringObjectUse:
451                 case StringOrStringObjectUse:
452                 case SymbolUse:
453                 case FinalObjectUse:
454                 case RegExpObjectUse:
455                 case NotCellUse:
456                 case OtherUse:
457                 case MiscUse:
458                 case StringIdentUse:
459                 case NotStringVarUse:
460                 case AnyIntUse:
461                 case DoubleRepAnyIntUse:
462                     // These are OK.
463                     break;
464                 default:
465                     // Don't know how to handle anything else.
466                     if (verboseCapabilities()) {
467                         dataLog("FTL rejecting node in ", *graph.m_codeBlock, " because of bad use kind: ", edge.useKind(), " in node:\n");
468                         graph.dump(WTF::dataFile(), "    ", node);
469                     }
470                     return CannotCompile;
471                 }
472             }
473             
474             switch (canCompile(node)) {
475             case CannotCompile: 
476                 if (verboseCapabilities()) {
477                     dataLog("FTL rejecting node in ", *graph.m_codeBlock, ":\n");
478                     graph.dump(WTF::dataFile(), "    ", node);
479                 }
480                 return CannotCompile;
481                 
482             case CanCompile:
483                 if (result == CanCompileAndOSREnter && verboseCompilationEnabled()) {
484                     dataLog("FTL disabling OSR entry because of node:\n");
485                     graph.dump(WTF::dataFile(), "    ", node);
486                 }
487                 result = CanCompile;
488                 break;
489                 
490             case CanCompileAndOSREnter:
491                 break;
492             }
493             
494             if (node->op() == ForceOSRExit)
495                 break;
496         }
497     }
498     
499     return result;
500 }
501
502 } } // namespace JSC::FTL
503
504 #endif // ENABLE(FTL_JIT)
505