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