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