2 * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "FTLCapabilities.h"
31 namespace JSC { namespace FTL {
35 static bool verboseCapabilities()
37 return verboseCompilationEnabled() || Options::verboseFTLFailure();
40 inline CapabilityLevel canCompile(Node* node)
42 // NOTE: If we ever have phantom arguments, we can compile them but we cannot
67 case ArrayifyToStructure:
74 case GetGetterSetterByOffset:
99 case CompareEqConstant:
104 case ExtractOSREntryLocal:
107 case CreateActivation:
111 case CreateDirectArguments:
112 case CreateScopedArguments:
113 case CreateClonedArguments:
114 case GetFromArguments:
116 case InvalidationPoint:
121 case StringCharCodeAt:
122 case AllocatePropertyStorage:
123 case ReallocatePropertyStorage:
124 case GetTypedArrayByteOffset:
127 case StoreBarrierWithNullCheck:
131 case CallForwardVarargs:
132 case ConstructVarargs:
133 case ConstructForwardVarargs:
136 case NativeConstruct:
141 case ConstantStoragePointer:
147 case GetArgumentCount:
149 case CallStringConstructor:
151 case NewArrayWithSize:
154 case MultiGetByOffset:
155 case MultiPutByOffset:
158 case ThrowReferenceError:
167 case CheckHasInstance:
174 case BooleanToNumber:
175 case HasGenericProperty:
176 case HasStructureProperty:
178 case GetEnumerableLength:
179 case GetPropertyEnumerator:
180 case GetEnumeratorStructurePname:
181 case GetEnumeratorGenericPname:
184 case PhantomNewObject:
185 case PhantomNewFunction:
186 case PhantomCreateActivation:
188 case CheckStructureImmediate:
189 case MaterializeNewObject:
190 case MaterializeCreateActivation:
191 case PhantomDirectArguments:
192 case PhantomClonedArguments:
193 case GetMyArgumentByVal:
200 // No backend handles this because it will be optimized out. But we may check
201 // for capabilities before optimization. It would be a deep error to remove this
202 // case because it would prevent us from catching bugs where the FTL backend
203 // pipeline failed to optimize out an Identity.
206 if (node->child2().useKind() == CellUse)
208 return CannotCompile;
211 if (node->child1().useKind() == CellUse)
213 return CannotCompile;
214 case GetIndexedPropertyStorage:
215 if (node->arrayMode().type() == Array::String)
217 if (isTypedView(node->arrayMode().typedArrayType()))
219 return CannotCompile;
221 switch (node->arrayMode().type()) {
224 case Array::Contiguous:
225 case Array::DirectArguments:
226 case Array::ScopedArguments:
229 if (isTypedView(node->arrayMode().typedArrayType()))
231 return CannotCompile;
235 switch (node->arrayMode().type()) {
238 case Array::Contiguous:
240 case Array::DirectArguments:
241 case Array::ScopedArguments:
244 if (isTypedView(node->arrayMode().typedArrayType()))
246 return CannotCompile;
249 case HasIndexedProperty:
250 switch (node->arrayMode().type()) {
251 case Array::ForceExit:
254 case Array::Contiguous:
257 return CannotCompile;
261 switch (node->arrayMode().type()) {
262 case Array::ForceExit:
267 case Array::Contiguous:
268 case Array::DirectArguments:
269 case Array::ScopedArguments:
272 if (isTypedView(node->arrayMode().typedArrayType()))
273 return CanCompileAndOSREnter;
274 return CannotCompile;
280 switch (node->arrayMode().type()) {
281 case Array::ForceExit:
285 case Array::Contiguous:
288 if (isTypedView(node->arrayMode().typedArrayType()))
289 return CanCompileAndOSREnter;
290 return CannotCompile;
295 switch (node->arrayMode().type()) {
297 case Array::Contiguous:
301 return CannotCompile;
305 if (node->isBinaryUseKind(Int32Use))
307 if (node->isBinaryUseKind(Int52RepUse))
309 if (node->isBinaryUseKind(DoubleRepUse))
311 if (node->isBinaryUseKind(StringIdentUse))
313 if (node->isBinaryUseKind(ObjectUse))
315 if (node->isBinaryUseKind(UntypedUse))
317 if (node->isBinaryUseKind(BooleanUse))
319 if (node->isBinaryUseKind(ObjectUse, ObjectOrOtherUse))
321 if (node->isBinaryUseKind(ObjectOrOtherUse, ObjectUse))
323 return CannotCompile;
324 case CompareStrictEq:
325 if (node->isBinaryUseKind(Int32Use))
327 if (node->isBinaryUseKind(Int52RepUse))
329 if (node->isBinaryUseKind(DoubleRepUse))
331 if (node->isBinaryUseKind(StringIdentUse))
333 if (node->isBinaryUseKind(ObjectUse))
335 if (node->isBinaryUseKind(BooleanUse))
337 if (node->isBinaryUseKind(MiscUse, UntypedUse))
339 if (node->isBinaryUseKind(UntypedUse, MiscUse))
341 if (node->isBinaryUseKind(StringIdentUse, NotStringVarUse))
343 if (node->isBinaryUseKind(NotStringVarUse, StringIdentUse))
345 return CannotCompile;
349 case CompareGreaterEq:
350 if (node->isBinaryUseKind(Int32Use))
352 if (node->isBinaryUseKind(Int52RepUse))
354 if (node->isBinaryUseKind(DoubleRepUse))
356 if (node->isBinaryUseKind(UntypedUse))
358 return CannotCompile;
360 // Don't know how to handle anything else.
361 return CannotCompile;
363 return CanCompileAndOSREnter;
366 CapabilityLevel canCompile(Graph& graph)
368 if (graph.m_codeBlock->instructionCount() > Options::maximumFTLCandidateInstructionCount()) {
369 if (verboseCapabilities())
370 dataLog("FTL rejecting ", *graph.m_codeBlock, " because it's too big.\n");
371 return CannotCompile;
374 if (graph.m_codeBlock->codeType() != FunctionCode) {
375 if (verboseCapabilities())
376 dataLog("FTL rejecting ", *graph.m_codeBlock, " because it doesn't belong to a function.\n");
377 return CannotCompile;
380 CapabilityLevel result = CanCompileAndOSREnter;
382 for (BlockIndex blockIndex = graph.numBlocks(); blockIndex--;) {
383 BasicBlock* block = graph.block(blockIndex);
387 // We don't care if we can compile blocks that the CFA hasn't visited.
388 if (!block->cfaHasVisited)
391 for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
392 Node* node = block->at(nodeIndex);
394 for (unsigned childIndex = graph.numChildren(node); childIndex--;) {
395 Edge edge = graph.child(node, childIndex);
398 switch (edge.useKind()) {
405 case DoubleRepRealUse:
411 case ObjectOrOtherUse:
414 case StringObjectUse:
415 case StringOrStringObjectUse:
421 case NotStringVarUse:
423 case DoubleRepMachineIntUse:
427 // Don't know how to handle anything else.
428 if (verboseCapabilities()) {
429 dataLog("FTL rejecting node in ", *graph.m_codeBlock, " because of bad use kind: ", edge.useKind(), " in node:\n");
430 graph.dump(WTF::dataFile(), " ", node);
432 return CannotCompile;
436 switch (canCompile(node)) {
438 if (verboseCapabilities()) {
439 dataLog("FTL rejecting node in ", *graph.m_codeBlock, ":\n");
440 graph.dump(WTF::dataFile(), " ", node);
442 return CannotCompile;
445 if (result == CanCompileAndOSREnter && verboseCompilationEnabled()) {
446 dataLog("FTL disabling OSR entry because of node:\n");
447 graph.dump(WTF::dataFile(), " ", node);
452 case CanCompileAndOSREnter:
456 if (node->op() == ForceOSRExit)
464 } } // namespace JSC::FTL
466 #endif // ENABLE(FTL_JIT)