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