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