[DFG][FTL] Support MapSet / SetAdd intrinsics
[WebKit-https.git] / Source / JavaScriptCore / ftl / FTLCapabilities.cpp
1 /*
2  * Copyright (C) 2013-2017 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 CheckStructureOrEmpty:
69     case DoubleAsInt32:
70     case ArrayifyToStructure:
71     case PutStructure:
72     case GetButterfly:
73     case GetButterflyWithoutCaging:
74     case NewObject:
75     case NewStringObject:
76     case NewArray:
77     case NewArrayWithSpread:
78     case Spread:
79     case NewArrayBuffer:
80     case NewTypedArray:
81     case GetByOffset:
82     case GetGetterSetterByOffset:
83     case GetGetter:
84     case GetSetter:
85     case PutByOffset:
86     case GetGlobalVar:
87     case GetGlobalLexicalVariable:
88     case PutGlobalVariable:
89     case ValueAdd:
90     case StrCat:
91     case ArithAdd:
92     case ArithClz32:
93     case ArithSub:
94     case ArithMul:
95     case ArithDiv:
96     case ArithMod:
97     case ArithMin:
98     case ArithMax:
99     case ArithAbs:
100     case ArithPow:
101     case ArithRandom:
102     case ArithRound:
103     case ArithFloor:
104     case ArithCeil:
105     case ArithTrunc:
106     case ArithSqrt:
107     case ArithFRound:
108     case ArithNegate:
109     case ArithUnary:
110     case UInt32ToNumber:
111     case Jump:
112     case ForceOSRExit:
113     case Phi:
114     case Upsilon:
115     case ExtractOSREntryLocal:
116     case ExtractCatchLocal:
117     case LoopHint:
118     case SkipScope:
119     case GetGlobalObject:
120     case GetGlobalThis:
121     case CreateActivation:
122     case PushWithScope:
123     case NewFunction:
124     case NewGeneratorFunction:
125     case NewAsyncFunction:
126     case NewAsyncGeneratorFunction:
127     case GetClosureVar:
128     case PutClosureVar:
129     case CreateDirectArguments:
130     case CreateScopedArguments:
131     case CreateClonedArguments:
132     case GetFromArguments:
133     case PutToArguments:
134     case GetArgument:
135     case InvalidationPoint:
136     case StringCharAt:
137     case CheckCell:
138     case CheckBadCell:
139     case CheckNotEmpty:
140     case CheckStringIdent:
141     case CheckTraps:
142     case StringCharCodeAt:
143     case StringFromCharCode:
144     case AllocatePropertyStorage:
145     case ReallocatePropertyStorage:
146     case NukeStructureAndSetButterfly:
147     case GetTypedArrayByteOffset:
148     case GetPrototypeOf:
149     case NotifyWrite:
150     case StoreBarrier:
151     case FencedStoreBarrier:
152     case Call:
153     case DirectCall:
154     case TailCall:
155     case DirectTailCall:
156     case TailCallInlinedCaller:
157     case DirectTailCallInlinedCaller:
158     case Construct:
159     case DirectConstruct:
160     case CallVarargs:
161     case CallEval:
162     case TailCallVarargs:
163     case TailCallVarargsInlinedCaller:
164     case ConstructVarargs:
165     case CallForwardVarargs:
166     case TailCallForwardVarargs:
167     case TailCallForwardVarargsInlinedCaller:
168     case ConstructForwardVarargs:
169     case LoadVarargs:
170     case ValueToInt32:
171     case Branch:
172     case LogicalNot:
173     case CheckInBounds:
174     case ConstantStoragePointer:
175     case Check:
176     case CountExecution:
177     case SuperSamplerBegin:
178     case SuperSamplerEnd:
179     case GetExecutable:
180     case GetScope:
181     case GetCallee:
182     case GetArgumentCountIncludingThis:
183     case ToNumber:
184     case ToString:
185     case ToObject:
186     case CallObjectConstructor:
187     case CallStringConstructor:
188     case MakeRope:
189     case NewArrayWithSize:
190     case TryGetById:
191     case GetById:
192     case GetByIdFlush:
193     case GetByIdWithThis:
194     case ToThis:
195     case MultiGetByOffset:
196     case MultiPutByOffset:
197     case ToPrimitive:
198     case Throw:
199     case ThrowStaticError:
200     case Unreachable:
201     case In:
202     case HasOwnProperty:
203     case IsCellWithType:
204     case MapHash:
205     case GetMapBucket:
206     case GetMapBucketHead:
207     case GetMapBucketNext:
208     case LoadKeyFromMapBucket:
209     case LoadValueFromMapBucket:
210     case SetAdd:
211     case MapSet:
212     case WeakMapGet:
213     case IsEmpty:
214     case IsUndefined:
215     case IsBoolean:
216     case IsNumber:
217     case IsObject:
218     case IsObjectOrNull:
219     case IsFunction:
220     case IsTypedArrayView:
221     case CheckTypeInfoFlags:
222     case OverridesHasInstance:
223     case InstanceOf:
224     case InstanceOfCustom:
225     case DoubleRep:
226     case ValueRep:
227     case Int52Rep:
228     case DoubleConstant:
229     case Int52Constant:
230     case BooleanToNumber:
231     case HasGenericProperty:
232     case HasStructureProperty:
233     case GetDirectPname:
234     case GetEnumerableLength:
235     case GetIndexedPropertyStorage:
236     case GetPropertyEnumerator:
237     case GetEnumeratorStructurePname:
238     case GetEnumeratorGenericPname:
239     case ToIndexString:
240     case BottomValue:
241     case PhantomNewObject:
242     case PhantomNewFunction:
243     case PhantomNewGeneratorFunction:
244     case PhantomNewAsyncGeneratorFunction:
245     case PhantomNewAsyncFunction:
246     case PhantomCreateActivation:
247     case PutHint:
248     case CheckStructureImmediate:
249     case MaterializeNewObject:
250     case MaterializeCreateActivation:
251     case PhantomDirectArguments:
252     case PhantomCreateRest:
253     case PhantomSpread:
254     case PhantomNewArrayWithSpread:
255     case PhantomClonedArguments:
256     case GetMyArgumentByVal:
257     case GetMyArgumentByValOutOfBounds:
258     case ForwardVarargs:
259     case EntrySwitch:
260     case Switch:
261     case TypeOf:
262     case PutById:
263     case PutByIdDirect:
264     case PutByIdFlush:
265     case PutByIdWithThis:
266     case PutGetterById:
267     case PutSetterById:
268     case PutGetterSetterById:
269     case PutGetterByVal:
270     case PutSetterByVal:
271     case CreateRest:
272     case GetRestLength:
273     case RegExpExec:
274     case RegExpTest:
275     case NewRegexp:
276     case StringReplace:
277     case StringReplaceRegExp: 
278     case GetRegExpObjectLastIndex:
279     case SetRegExpObjectLastIndex:
280     case RecordRegExpCachedResult:
281     case SetFunctionName:
282     case LogShadowChickenPrologue:
283     case LogShadowChickenTail:
284     case ResolveScope:
285     case ResolveScopeForHoistingFuncDeclInEval:
286     case GetDynamicVar:
287     case PutDynamicVar:
288     case CompareEq:
289     case CompareEqPtr:
290     case CompareLess:
291     case CompareLessEq:
292     case CompareGreater:
293     case CompareGreaterEq:
294     case CompareBelow:
295     case CompareBelowEq:
296     case CompareStrictEq:
297     case DefineDataProperty:
298     case DefineAccessorProperty:
299     case StringSlice:
300     case ToLowerCase:
301     case NumberToStringWithRadix:
302     case NumberToStringWithValidRadixConstant:
303     case CheckSubClass:
304     case CallDOM:
305     case CallDOMGetter:
306     case ArraySlice:
307     case ArrayIndexOf:
308     case ParseInt:
309     case AtomicsAdd:
310     case AtomicsAnd:
311     case AtomicsCompareExchange:
312     case AtomicsExchange:
313     case AtomicsLoad:
314     case AtomicsOr:
315     case AtomicsStore:
316     case AtomicsSub:
317     case AtomicsXor:
318     case AtomicsIsLockFree:
319     case InitializeEntrypointArguments:
320     case CPUIntrinsic:
321         // These are OK.
322         break;
323
324     case Identity:
325         // No backend handles this because it will be optimized out. But we may check
326         // for capabilities before optimization. It would be a deep error to remove this
327         // case because it would prevent us from catching bugs where the FTL backend
328         // pipeline failed to optimize out an Identity.
329         break;
330     case Arrayify:
331         switch (node->arrayMode().type()) {
332         case Array::Int32:
333         case Array::Double:
334         case Array::Contiguous:
335             break;
336         default:
337             return CannotCompile;
338         }
339         break;
340     case CheckArray:
341         switch (node->arrayMode().type()) {
342         case Array::Int32:
343         case Array::Double:
344         case Array::Contiguous:
345         case Array::DirectArguments:
346         case Array::ScopedArguments:
347             break;
348         default:
349             if (isTypedView(node->arrayMode().typedArrayType()))
350                 break;
351             return CannotCompile;
352         }
353         break;
354     case GetArrayLength:
355         switch (node->arrayMode().type()) {
356         case Array::Undecided:
357         case Array::Int32:
358         case Array::Double:
359         case Array::Contiguous:
360         case Array::String:
361         case Array::DirectArguments:
362         case Array::ScopedArguments:
363             break;
364         default:
365             if (node->arrayMode().isSomeTypedArrayView())
366                 break;
367             return CannotCompile;
368         }
369         break;
370     case GetVectorLength:
371         switch (node->arrayMode().type()) {
372         case Array::ArrayStorage:
373         case Array::SlowPutArrayStorage:
374             break;
375         default:
376             RELEASE_ASSERT_NOT_REACHED();
377         }
378         break;
379     case HasIndexedProperty:
380         switch (node->arrayMode().type()) {
381         case Array::ForceExit:
382         case Array::Int32:
383         case Array::Double:
384         case Array::Contiguous:
385             break;
386         default:
387             return CannotCompile;
388         }
389         break;
390     case GetByVal:
391         switch (node->arrayMode().type()) {
392         case Array::ForceExit:
393         case Array::Generic:
394         case Array::String:
395         case Array::Int32:
396         case Array::Double:
397         case Array::Contiguous:
398         case Array::Undecided:
399         case Array::DirectArguments:
400         case Array::ScopedArguments:
401         case Array::ArrayStorage:
402         case Array::SlowPutArrayStorage:
403             break;
404         default:
405             if (isTypedView(node->arrayMode().typedArrayType()))
406                 return CanCompileAndOSREnter;
407             return CannotCompile;
408         }
409         break;
410     case GetByValWithThis:
411         break;
412     case PutByVal:
413     case PutByValAlias:
414     case PutByValDirect:
415         switch (node->arrayMode().type()) {
416         case Array::ForceExit:
417         case Array::Generic:
418         case Array::Int32:
419         case Array::Double:
420         case Array::Contiguous:
421             break;
422         default:
423             if (isTypedView(node->arrayMode().typedArrayType()))
424                 return CanCompileAndOSREnter;
425             return CannotCompile;
426         }
427         break;
428     case PutByValWithThis:
429         break;
430     case ArrayPush:
431     case ArrayPop:
432         switch (node->arrayMode().type()) {
433         case Array::Int32:
434         case Array::Contiguous:
435         case Array::Double:
436             break;
437         default:
438             return CannotCompile;
439         }
440         break;
441     default:
442         // Don't know how to handle anything else.
443         return CannotCompile;
444     }
445     return CanCompileAndOSREnter;
446 }
447
448 CapabilityLevel canCompile(Graph& graph)
449 {
450     if (graph.m_codeBlock->instructionCount() > Options::maximumFTLCandidateInstructionCount()) {
451         if (verboseCapabilities())
452             dataLog("FTL rejecting ", *graph.m_codeBlock, " because it's too big.\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 ArrayUse:
496                 case FunctionUse:
497                 case ObjectOrOtherUse:
498                 case StringUse:
499                 case StringOrOtherUse:
500                 case KnownStringUse:
501                 case KnownPrimitiveUse:
502                 case StringObjectUse:
503                 case StringOrStringObjectUse:
504                 case SymbolUse:
505                 case MapObjectUse:
506                 case SetObjectUse:
507                 case WeakMapObjectUse:
508                 case WeakSetObjectUse:
509                 case FinalObjectUse:
510                 case RegExpObjectUse:
511                 case ProxyObjectUse:
512                 case DerivedArrayUse:
513                 case NotCellUse:
514                 case OtherUse:
515                 case MiscUse:
516                 case StringIdentUse:
517                 case NotStringVarUse:
518                 case NotSymbolUse:
519                 case AnyIntUse:
520                 case DoubleRepAnyIntUse:
521                     // These are OK.
522                     break;
523                 default:
524                     // Don't know how to handle anything else.
525                     if (verboseCapabilities()) {
526                         dataLog("FTL rejecting node in ", *graph.m_codeBlock, " because of bad use kind: ", edge.useKind(), " in node:\n");
527                         graph.dump(WTF::dataFile(), "    ", node);
528                     }
529                     return CannotCompile;
530                 }
531             }
532             
533             switch (canCompile(node)) {
534             case CannotCompile: 
535                 if (verboseCapabilities()) {
536                     dataLog("FTL rejecting node in ", *graph.m_codeBlock, ":\n");
537                     graph.dump(WTF::dataFile(), "    ", node);
538                 }
539                 return CannotCompile;
540                 
541             case CanCompile:
542                 if (result == CanCompileAndOSREnter && verboseCompilationEnabled()) {
543                     dataLog("FTL disabling OSR entry because of node:\n");
544                     graph.dump(WTF::dataFile(), "    ", node);
545                 }
546                 result = CanCompile;
547                 break;
548                 
549             case CanCompileAndOSREnter:
550                 break;
551             }
552             
553             if (node->op() == ForceOSRExit)
554                 break;
555         }
556     }
557     
558     return result;
559 }
560
561 } } // namespace JSC::FTL
562
563 #endif // ENABLE(FTL_JIT)
564