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