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