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