[JSC] Implement isFinite / isNaN in JS and make DFG ToNumber accept non number values
[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 CheckIdent:
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 TailCallVarargs:
146     case TailCallVarargsInlinedCaller:
147     case ConstructVarargs:
148     case CallForwardVarargs:
149     case TailCallForwardVarargs:
150     case TailCallForwardVarargsInlinedCaller:
151     case ConstructForwardVarargs:
152     case LoadVarargs:
153     case ValueToInt32:
154     case Branch:
155     case LogicalNot:
156     case CheckInBounds:
157     case ConstantStoragePointer:
158     case Check:
159     case CountExecution:
160     case GetExecutable:
161     case GetScope:
162     case GetCallee:
163     case GetArgumentCountIncludingThis:
164     case ToNumber:
165     case ToString:
166     case CallObjectConstructor:
167     case CallStringConstructor:
168     case MakeRope:
169     case NewArrayWithSize:
170     case TryGetById:
171     case GetById:
172     case GetByIdFlush:
173     case GetByIdWithThis:
174     case ToThis:
175     case MultiGetByOffset:
176     case MultiPutByOffset:
177     case ToPrimitive:
178     case Throw:
179     case ThrowReferenceError:
180     case Unreachable:
181     case IsJSArray:
182     case IsEmpty:
183     case IsUndefined:
184     case IsBoolean:
185     case IsNumber:
186     case IsString:
187     case IsObject:
188     case IsObjectOrNull:
189     case IsFunction:
190     case IsRegExpObject:
191     case IsTypedArrayView:
192     case CheckTypeInfoFlags:
193     case OverridesHasInstance:
194     case InstanceOf:
195     case InstanceOfCustom:
196     case DoubleRep:
197     case ValueRep:
198     case Int52Rep:
199     case DoubleConstant:
200     case Int52Constant:
201     case BooleanToNumber:
202     case HasGenericProperty:
203     case HasStructureProperty:
204     case GetDirectPname:
205     case GetEnumerableLength:
206     case GetPropertyEnumerator:
207     case GetEnumeratorStructurePname:
208     case GetEnumeratorGenericPname:
209     case ToIndexString:
210     case BottomValue:
211     case PhantomNewObject:
212     case PhantomNewFunction:
213     case PhantomNewGeneratorFunction:
214     case PhantomCreateActivation:
215     case PutHint:
216     case CheckStructureImmediate:
217     case MaterializeNewObject:
218     case MaterializeCreateActivation:
219     case PhantomDirectArguments:
220     case PhantomClonedArguments:
221     case GetMyArgumentByVal:
222     case GetMyArgumentByValOutOfBounds:
223     case ForwardVarargs:
224     case Switch:
225     case TypeOf:
226     case PutGetterById:
227     case PutSetterById:
228     case PutGetterSetterById:
229     case PutGetterByVal:
230     case PutSetterByVal:
231     case CopyRest:
232     case GetRestLength:
233     case RegExpExec:
234     case RegExpTest:
235     case NewRegexp:
236     case StringReplace:
237     case StringReplaceRegExp: 
238     case GetRegExpObjectLastIndex:
239     case SetRegExpObjectLastIndex:
240     case RecordRegExpCachedResult:
241     case SetFunctionName:
242     case LogShadowChickenPrologue:
243     case LogShadowChickenTail:
244     case ResolveScope:
245     case GetDynamicVar:
246     case PutDynamicVar:
247         // These are OK.
248         break;
249
250     case Identity:
251         // No backend handles this because it will be optimized out. But we may check
252         // for capabilities before optimization. It would be a deep error to remove this
253         // case because it would prevent us from catching bugs where the FTL backend
254         // pipeline failed to optimize out an Identity.
255         break;
256     case In:
257         if (node->child2().useKind() == CellUse)
258             break;
259         return CannotCompile;
260     case PutByIdDirect:
261     case PutById:
262     case PutByIdFlush:
263         if (node->child1().useKind() == CellUse)
264             break;
265         return CannotCompile;
266     case PutByIdWithThis:
267         break;
268     case GetIndexedPropertyStorage:
269         if (node->arrayMode().type() == Array::String)
270             break;
271         if (isTypedView(node->arrayMode().typedArrayType()))
272             break;
273         return CannotCompile;
274     case CheckArray:
275         switch (node->arrayMode().type()) {
276         case Array::Int32:
277         case Array::Double:
278         case Array::Contiguous:
279         case Array::DirectArguments:
280         case Array::ScopedArguments:
281             break;
282         default:
283             if (isTypedView(node->arrayMode().typedArrayType()))
284                 break;
285             return CannotCompile;
286         }
287         break;
288     case GetArrayLength:
289         switch (node->arrayMode().type()) {
290         case Array::Int32:
291         case Array::Double:
292         case Array::Contiguous:
293         case Array::String:
294         case Array::DirectArguments:
295         case Array::ScopedArguments:
296             break;
297         default:
298             if (node->arrayMode().isSomeTypedArrayView())
299                 break;
300             return CannotCompile;
301         }
302         break;
303     case HasIndexedProperty:
304         switch (node->arrayMode().type()) {
305         case Array::ForceExit:
306         case Array::Int32:
307         case Array::Double:
308         case Array::Contiguous:
309             break;
310         default:
311             return CannotCompile;
312         }
313         break;
314     case GetByVal:
315         switch (node->arrayMode().type()) {
316         case Array::ForceExit:
317         case Array::Generic:
318         case Array::String:
319         case Array::Int32:
320         case Array::Double:
321         case Array::Contiguous:
322         case Array::Undecided:
323         case Array::DirectArguments:
324         case Array::ScopedArguments:
325             break;
326         default:
327             if (isTypedView(node->arrayMode().typedArrayType()))
328                 return CanCompileAndOSREnter;
329             return CannotCompile;
330         }
331         break;
332     case GetByValWithThis:
333         break;
334     case PutByVal:
335     case PutByValAlias:
336     case PutByValDirect:
337         switch (node->arrayMode().type()) {
338         case Array::ForceExit:
339         case Array::Generic:
340         case Array::Int32:
341         case Array::Double:
342         case Array::Contiguous:
343             break;
344         default:
345             if (isTypedView(node->arrayMode().typedArrayType()))
346                 return CanCompileAndOSREnter;
347             return CannotCompile;
348         }
349         break;
350     case PutByValWithThis:
351         break;
352     case ArrayPush:
353     case ArrayPop:
354         switch (node->arrayMode().type()) {
355         case Array::Int32:
356         case Array::Contiguous:
357         case Array::Double:
358             break;
359         default:
360             return CannotCompile;
361         }
362         break;
363     case CompareEq:
364         if (node->isBinaryUseKind(Int32Use))
365             break;
366         if (node->isBinaryUseKind(Int52RepUse))
367             break;
368         if (node->isBinaryUseKind(DoubleRepUse))
369             break;
370         if (node->isBinaryUseKind(StringIdentUse))
371             break;
372         if (node->isBinaryUseKind(StringUse))
373             break;
374         if (node->isBinaryUseKind(SymbolUse))
375             break;
376         if (node->isBinaryUseKind(ObjectUse))
377             break;
378         if (node->isBinaryUseKind(UntypedUse))
379             break;
380         if (node->isBinaryUseKind(BooleanUse))
381             break;
382         if (node->isBinaryUseKind(ObjectUse, ObjectOrOtherUse))
383             break;
384         if (node->isBinaryUseKind(ObjectOrOtherUse, ObjectUse))
385             break;
386         if (node->child1().useKind() == OtherUse || node->child2().useKind() == OtherUse)
387             break;
388         return CannotCompile;
389     case CompareStrictEq:
390         if (node->isBinaryUseKind(Int32Use))
391             break;
392         if (node->isBinaryUseKind(Int52RepUse))
393             break;
394         if (node->isBinaryUseKind(DoubleRepUse))
395             break;
396         if (node->isBinaryUseKind(StringIdentUse))
397             break;
398         if (node->isBinaryUseKind(StringUse))
399             break;
400         if (node->isBinaryUseKind(ObjectUse, UntypedUse))
401             break;
402         if (node->isBinaryUseKind(UntypedUse, ObjectUse))
403             break;
404         if (node->isBinaryUseKind(ObjectUse))
405             break;
406         if (node->isBinaryUseKind(BooleanUse))
407             break;
408         if (node->isBinaryUseKind(UntypedUse))
409             break;
410         if (node->isBinaryUseKind(SymbolUse))
411             break;
412         if (node->isBinaryUseKind(MiscUse, UntypedUse))
413             break;
414         if (node->isBinaryUseKind(UntypedUse, MiscUse))
415             break;
416         if (node->isBinaryUseKind(StringIdentUse, NotStringVarUse))
417             break;
418         if (node->isBinaryUseKind(NotStringVarUse, StringIdentUse))
419             break;
420         return CannotCompile;
421     case CompareLess:
422     case CompareLessEq:
423     case CompareGreater:
424     case CompareGreaterEq:
425         if (node->isBinaryUseKind(Int32Use))
426             break;
427         if (node->isBinaryUseKind(Int52RepUse))
428             break;
429         if (node->isBinaryUseKind(DoubleRepUse))
430             break;
431         if (node->isBinaryUseKind(StringIdentUse))
432             break;
433         if (node->isBinaryUseKind(StringUse))
434             break;
435         if (node->isBinaryUseKind(UntypedUse))
436             break;
437         return CannotCompile;
438     default:
439         // Don't know how to handle anything else.
440         return CannotCompile;
441     }
442     return CanCompileAndOSREnter;
443 }
444
445 CapabilityLevel canCompile(Graph& graph)
446 {
447     if (graph.m_codeBlock->instructionCount() > Options::maximumFTLCandidateInstructionCount()) {
448         if (verboseCapabilities())
449             dataLog("FTL rejecting ", *graph.m_codeBlock, " because it's too big.\n");
450         return CannotCompile;
451     }
452     
453     if (graph.m_codeBlock->codeType() != FunctionCode) {
454         if (verboseCapabilities())
455             dataLog("FTL rejecting ", *graph.m_codeBlock, " because it doesn't belong to a function.\n");
456         return CannotCompile;
457     }
458
459     if (UNLIKELY(graph.m_codeBlock->ownerScriptExecutable()->neverFTLOptimize())) {
460         if (verboseCapabilities())
461             dataLog("FTL rejecting ", *graph.m_codeBlock, " because it is marked as never FTL compile.\n");
462         return CannotCompile;
463     }
464     
465     CapabilityLevel result = CanCompileAndOSREnter;
466     
467     for (BlockIndex blockIndex = graph.numBlocks(); blockIndex--;) {
468         BasicBlock* block = graph.block(blockIndex);
469         if (!block)
470             continue;
471         
472         // We don't care if we can compile blocks that the CFA hasn't visited.
473         if (!block->cfaHasVisited)
474             continue;
475         
476         for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
477             Node* node = block->at(nodeIndex);
478             
479             for (unsigned childIndex = graph.numChildren(node); childIndex--;) {
480                 Edge edge = graph.child(node, childIndex);
481                 if (!edge)
482                     continue;
483                 switch (edge.useKind()) {
484                 case UntypedUse:
485                 case Int32Use:
486                 case KnownInt32Use:
487                 case Int52RepUse:
488                 case NumberUse:
489                 case RealNumberUse:
490                 case DoubleRepUse:
491                 case DoubleRepRealUse:
492                 case BooleanUse:
493                 case KnownBooleanUse:
494                 case CellUse:
495                 case KnownCellUse:
496                 case CellOrOtherUse:
497                 case ObjectUse:
498                 case FunctionUse:
499                 case ObjectOrOtherUse:
500                 case StringUse:
501                 case StringOrOtherUse:
502                 case KnownStringUse:
503                 case KnownPrimitiveUse:
504                 case StringObjectUse:
505                 case StringOrStringObjectUse:
506                 case SymbolUse:
507                 case FinalObjectUse:
508                 case RegExpObjectUse:
509                 case NotCellUse:
510                 case OtherUse:
511                 case MiscUse:
512                 case StringIdentUse:
513                 case NotStringVarUse:
514                 case AnyIntUse:
515                 case DoubleRepAnyIntUse:
516                     // These are OK.
517                     break;
518                 default:
519                     // Don't know how to handle anything else.
520                     if (verboseCapabilities()) {
521                         dataLog("FTL rejecting node in ", *graph.m_codeBlock, " because of bad use kind: ", edge.useKind(), " in node:\n");
522                         graph.dump(WTF::dataFile(), "    ", node);
523                     }
524                     return CannotCompile;
525                 }
526             }
527             
528             switch (canCompile(node)) {
529             case CannotCompile: 
530                 if (verboseCapabilities()) {
531                     dataLog("FTL rejecting node in ", *graph.m_codeBlock, ":\n");
532                     graph.dump(WTF::dataFile(), "    ", node);
533                 }
534                 return CannotCompile;
535                 
536             case CanCompile:
537                 if (result == CanCompileAndOSREnter && verboseCompilationEnabled()) {
538                     dataLog("FTL disabling OSR entry because of node:\n");
539                     graph.dump(WTF::dataFile(), "    ", node);
540                 }
541                 result = CanCompile;
542                 break;
543                 
544             case CanCompileAndOSREnter:
545                 break;
546             }
547             
548             if (node->op() == ForceOSRExit)
549                 break;
550         }
551     }
552     
553     return result;
554 }
555
556 } } // namespace JSC::FTL
557
558 #endif // ENABLE(FTL_JIT)
559