[DFG] DFG should handle String#toString
[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 Arrayify:
71     case ArrayifyToStructure:
72     case PutStructure:
73     case GetButterfly:
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 ValueNegate:
90     case ValueAdd:
91     case StrCat:
92     case ArithAdd:
93     case ArithClz32:
94     case ArithSub:
95     case ArithMul:
96     case ArithDiv:
97     case ArithMod:
98     case ArithMin:
99     case ArithMax:
100     case ArithAbs:
101     case ArithPow:
102     case ArithRandom:
103     case ArithRound:
104     case ArithFloor:
105     case ArithCeil:
106     case ArithTrunc:
107     case ArithSqrt:
108     case ArithFRound:
109     case ArithNegate:
110     case ArithUnary:
111     case UInt32ToNumber:
112     case Jump:
113     case ForceOSRExit:
114     case Phi:
115     case Upsilon:
116     case ExtractOSREntryLocal:
117     case ExtractCatchLocal:
118     case ClearCatchLocals:
119     case LoopHint:
120     case SkipScope:
121     case GetGlobalObject:
122     case GetGlobalThis:
123     case CreateActivation:
124     case PushWithScope:
125     case NewFunction:
126     case NewGeneratorFunction:
127     case NewAsyncFunction:
128     case NewAsyncGeneratorFunction:
129     case GetClosureVar:
130     case PutClosureVar:
131     case CreateDirectArguments:
132     case CreateScopedArguments:
133     case CreateClonedArguments:
134     case GetFromArguments:
135     case PutToArguments:
136     case GetArgument:
137     case InvalidationPoint:
138     case StringCharAt:
139     case CheckCell:
140     case CheckBadCell:
141     case CheckNotEmpty:
142     case AssertNotEmpty:
143     case CheckStringIdent:
144     case CheckTraps:
145     case StringCharCodeAt:
146     case StringFromCharCode:
147     case AllocatePropertyStorage:
148     case ReallocatePropertyStorage:
149     case NukeStructureAndSetButterfly:
150     case GetTypedArrayByteOffset:
151     case GetPrototypeOf:
152     case NotifyWrite:
153     case StoreBarrier:
154     case FencedStoreBarrier:
155     case Call:
156     case DirectCall:
157     case TailCall:
158     case DirectTailCall:
159     case TailCallInlinedCaller:
160     case DirectTailCallInlinedCaller:
161     case Construct:
162     case DirectConstruct:
163     case CallVarargs:
164     case CallEval:
165     case TailCallVarargs:
166     case TailCallVarargsInlinedCaller:
167     case ConstructVarargs:
168     case CallForwardVarargs:
169     case TailCallForwardVarargs:
170     case TailCallForwardVarargsInlinedCaller:
171     case ConstructForwardVarargs:
172     case LoadVarargs:
173     case ValueToInt32:
174     case Branch:
175     case LogicalNot:
176     case CheckInBounds:
177     case ConstantStoragePointer:
178     case Check:
179     case CheckVarargs:
180     case CheckArray:
181     case CountExecution:
182     case SuperSamplerBegin:
183     case SuperSamplerEnd:
184     case GetExecutable:
185     case GetScope:
186     case GetCallee:
187     case SetCallee:
188     case GetArgumentCountIncludingThis:
189     case SetArgumentCountIncludingThis:
190     case ToNumber:
191     case ToString:
192     case ToObject:
193     case CallObjectConstructor:
194     case CallStringConstructor:
195     case ObjectCreate:
196     case MakeRope:
197     case NewArrayWithSize:
198     case TryGetById:
199     case GetById:
200     case GetByIdFlush:
201     case GetByIdWithThis:
202     case GetByIdDirect:
203     case GetByIdDirectFlush:
204     case ToThis:
205     case MultiGetByOffset:
206     case MultiPutByOffset:
207     case ToPrimitive:
208     case Throw:
209     case ThrowStaticError:
210     case Unreachable:
211     case InByVal:
212     case InById:
213     case HasOwnProperty:
214     case IsCellWithType:
215     case MapHash:
216     case NormalizeMapKey:
217     case GetMapBucket:
218     case GetMapBucketHead:
219     case GetMapBucketNext:
220     case LoadKeyFromMapBucket:
221     case LoadValueFromMapBucket:
222     case ExtractValueFromWeakMapGet:
223     case SetAdd:
224     case MapSet:
225     case WeakMapGet:
226     case WeakSetAdd:
227     case WeakMapSet:
228     case IsEmpty:
229     case IsUndefined:
230     case IsBoolean:
231     case IsNumber:
232     case NumberIsInteger:
233     case IsObject:
234     case IsObjectOrNull:
235     case IsFunction:
236     case IsTypedArrayView:
237     case CheckTypeInfoFlags:
238     case OverridesHasInstance:
239     case InstanceOf:
240     case InstanceOfCustom:
241     case DoubleRep:
242     case ValueRep:
243     case Int52Rep:
244     case DoubleConstant:
245     case Int52Constant:
246     case BooleanToNumber:
247     case HasGenericProperty:
248     case HasStructureProperty:
249     case HasIndexedProperty:
250     case GetDirectPname:
251     case GetEnumerableLength:
252     case GetIndexedPropertyStorage:
253     case GetPropertyEnumerator:
254     case GetEnumeratorStructurePname:
255     case GetEnumeratorGenericPname:
256     case ToIndexString:
257     case BottomValue:
258     case PhantomNewObject:
259     case PhantomNewFunction:
260     case PhantomNewGeneratorFunction:
261     case PhantomNewAsyncGeneratorFunction:
262     case PhantomNewAsyncFunction:
263     case PhantomCreateActivation:
264     case PhantomNewRegexp:
265     case PutHint:
266     case CheckStructureImmediate:
267     case MaterializeNewObject:
268     case MaterializeCreateActivation:
269     case PhantomDirectArguments:
270     case PhantomCreateRest:
271     case PhantomSpread:
272     case PhantomNewArrayWithSpread:
273     case PhantomNewArrayBuffer:
274     case PhantomClonedArguments:
275     case GetMyArgumentByVal:
276     case GetMyArgumentByValOutOfBounds:
277     case ForwardVarargs:
278     case EntrySwitch:
279     case Switch:
280     case TypeOf:
281     case PutById:
282     case PutByIdDirect:
283     case PutByIdFlush:
284     case PutByIdWithThis:
285     case PutGetterById:
286     case PutSetterById:
287     case PutGetterSetterById:
288     case PutGetterByVal:
289     case PutSetterByVal:
290     case DeleteById:
291     case DeleteByVal:
292     case CreateRest:
293     case GetRestLength:
294     case RegExpExec:
295     case RegExpExecNonGlobalOrSticky:
296     case RegExpTest:
297     case RegExpMatchFast:
298     case RegExpMatchFastGlobal:
299     case NewRegexp:
300     case StringReplace:
301     case StringReplaceRegExp: 
302     case GetRegExpObjectLastIndex:
303     case SetRegExpObjectLastIndex:
304     case RecordRegExpCachedResult:
305     case SetFunctionName:
306     case LogShadowChickenPrologue:
307     case LogShadowChickenTail:
308     case ResolveScope:
309     case ResolveScopeForHoistingFuncDeclInEval:
310     case GetDynamicVar:
311     case PutDynamicVar:
312     case CompareEq:
313     case CompareEqPtr:
314     case CompareLess:
315     case CompareLessEq:
316     case CompareGreater:
317     case CompareGreaterEq:
318     case CompareBelow:
319     case CompareBelowEq:
320     case CompareStrictEq:
321     case SameValue:
322     case DefineDataProperty:
323     case DefineAccessorProperty:
324     case StringValueOf:
325     case StringSlice:
326     case ToLowerCase:
327     case NumberToStringWithRadix:
328     case NumberToStringWithValidRadixConstant:
329     case CheckSubClass:
330     case CallDOM:
331     case CallDOMGetter:
332     case ArraySlice:
333     case ArrayIndexOf:
334     case ArrayPop:
335     case ArrayPush:
336     case ParseInt:
337     case AtomicsAdd:
338     case AtomicsAnd:
339     case AtomicsCompareExchange:
340     case AtomicsExchange:
341     case AtomicsLoad:
342     case AtomicsOr:
343     case AtomicsStore:
344     case AtomicsSub:
345     case AtomicsXor:
346     case AtomicsIsLockFree:
347     case InitializeEntrypointArguments:
348     case CPUIntrinsic:
349     case GetArrayLength:
350     case GetVectorLength:
351     case GetByVal:
352     case GetByValWithThis:
353     case PutByVal:
354     case PutByValAlias:
355     case PutByValDirect:
356     case PutByValWithThis:
357     case MatchStructure:
358     case FilterCallLinkStatus:
359     case FilterGetByIdStatus:
360     case FilterPutByIdStatus:
361     case FilterInByIdStatus:
362     case CreateThis:
363     case DataViewGetInt:
364     case DataViewGetFloat:
365     case DataViewSet:
366         // These are OK.
367         break;
368
369     case Identity:
370         // No backend handles this because it will be optimized out. But we may check
371         // for capabilities before optimization. It would be a deep error to remove this
372         // case because it would prevent us from catching bugs where the FTL backend
373         // pipeline failed to optimize out an Identity.
374         break;
375
376     case IdentityWithProfile:
377     case CheckTierUpInLoop:
378     case CheckTierUpAndOSREnter:
379     case CheckTierUpAtReturn:
380     case FiatInt52:
381     case ArithIMul:
382     case ProfileType:
383     case ProfileControlFlow:
384     case LastNodeType:
385         return CannotCompile;
386     }
387     return CanCompileAndOSREnter;
388 }
389
390 CapabilityLevel canCompile(Graph& graph)
391 {
392     if (graph.m_codeBlock->instructionCount() > Options::maximumFTLCandidateInstructionCount()) {
393         if (verboseCapabilities())
394             dataLog("FTL rejecting ", *graph.m_codeBlock, " because it's too big.\n");
395         return CannotCompile;
396     }
397     
398     if (UNLIKELY(graph.m_codeBlock->ownerScriptExecutable()->neverFTLOptimize())) {
399         if (verboseCapabilities())
400             dataLog("FTL rejecting ", *graph.m_codeBlock, " because it is marked as never FTL compile.\n");
401         return CannotCompile;
402     }
403     
404     CapabilityLevel result = CanCompileAndOSREnter;
405     
406     for (BlockIndex blockIndex = graph.numBlocks(); blockIndex--;) {
407         BasicBlock* block = graph.block(blockIndex);
408         if (!block)
409             continue;
410         
411         // We don't care if we can compile blocks that the CFA hasn't visited.
412         if (!block->cfaHasVisited)
413             continue;
414         
415         for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
416             Node* node = block->at(nodeIndex);
417             
418             for (unsigned childIndex = graph.numChildren(node); childIndex--;) {
419                 Edge edge = graph.child(node, childIndex);
420                 if (!edge)
421                     continue;
422                 switch (edge.useKind()) {
423                 case UntypedUse:
424                 case Int32Use:
425                 case KnownInt32Use:
426                 case Int52RepUse:
427                 case NumberUse:
428                 case RealNumberUse:
429                 case DoubleRepUse:
430                 case DoubleRepRealUse:
431                 case BooleanUse:
432                 case KnownBooleanUse:
433                 case CellUse:
434                 case KnownCellUse:
435                 case CellOrOtherUse:
436                 case ObjectUse:
437                 case ArrayUse:
438                 case FunctionUse:
439                 case ObjectOrOtherUse:
440                 case StringUse:
441                 case StringOrOtherUse:
442                 case KnownStringUse:
443                 case KnownPrimitiveUse:
444                 case StringObjectUse:
445                 case StringOrStringObjectUse:
446                 case SymbolUse:
447                 case BigIntUse:
448                 case MapObjectUse:
449                 case SetObjectUse:
450                 case WeakMapObjectUse:
451                 case WeakSetObjectUse:
452                 case DataViewObjectUse:
453                 case FinalObjectUse:
454                 case RegExpObjectUse:
455                 case ProxyObjectUse:
456                 case DerivedArrayUse:
457                 case NotCellUse:
458                 case OtherUse:
459                 case KnownOtherUse:
460                 case MiscUse:
461                 case StringIdentUse:
462                 case NotStringVarUse:
463                 case NotSymbolUse:
464                 case AnyIntUse:
465                 case DoubleRepAnyIntUse:
466                     // These are OK.
467                     break;
468                 default:
469                     // Don't know how to handle anything else.
470                     if (verboseCapabilities()) {
471                         dataLog("FTL rejecting node in ", *graph.m_codeBlock, " because of bad use kind: ", edge.useKind(), " in node:\n");
472                         graph.dump(WTF::dataFile(), "    ", node);
473                     }
474                     return CannotCompile;
475                 }
476             }
477             
478             switch (canCompile(node)) {
479             case CannotCompile: 
480                 if (verboseCapabilities()) {
481                     dataLog("FTL rejecting node in ", *graph.m_codeBlock, ":\n");
482                     graph.dump(WTF::dataFile(), "    ", node);
483                 }
484                 return CannotCompile;
485                 
486             case CanCompile:
487                 if (result == CanCompileAndOSREnter && verboseCompilationEnabled()) {
488                     dataLog("FTL disabling OSR entry because of node:\n");
489                     graph.dump(WTF::dataFile(), "    ", node);
490                 }
491                 result = CanCompile;
492                 break;
493                 
494             case CanCompileAndOSREnter:
495                 break;
496             }
497             
498             if (node->op() == ForceOSRExit)
499                 break;
500         }
501     }
502     
503     return result;
504 }
505
506 } } // namespace JSC::FTL
507
508 #endif // ENABLE(FTL_JIT)
509