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