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