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