]> git.saurik.com Git - apple/javascriptcore.git/blob - ftl/FTLCapabilities.cpp
JavaScriptCore-7600.1.4.11.8.tar.gz
[apple/javascriptcore.git] / ftl / FTLCapabilities.cpp
1 /*
2 * Copyright (C) 2013, 2014 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 WeakJSConstant:
48 case GetMyArgumentsLength:
49 case GetLocal:
50 case SetLocal:
51 case MovHint:
52 case ZombieHint:
53 case Phantom:
54 case HardPhantom:
55 case Flush:
56 case PhantomLocal:
57 case SetArgument:
58 case Return:
59 case BitAnd:
60 case BitOr:
61 case BitXor:
62 case BitRShift:
63 case BitLShift:
64 case BitURShift:
65 case CheckStructure:
66 case StructureTransitionWatchpoint:
67 case ArrayifyToStructure:
68 case PutStructure:
69 case PhantomPutStructure:
70 case GetButterfly:
71 case NewObject:
72 case NewArray:
73 case NewArrayBuffer:
74 case GetByOffset:
75 case PutByOffset:
76 case GetGlobalVar:
77 case PutGlobalVar:
78 case ValueAdd:
79 case ArithAdd:
80 case ArithSub:
81 case ArithMul:
82 case ArithDiv:
83 case ArithMod:
84 case ArithMin:
85 case ArithMax:
86 case ArithAbs:
87 case ArithSin:
88 case ArithCos:
89 case ArithSqrt:
90 case ArithFRound:
91 case ArithNegate:
92 case UInt32ToNumber:
93 case CompareEqConstant:
94 case Jump:
95 case ForceOSRExit:
96 case Phi:
97 case Upsilon:
98 case ExtractOSREntryLocal:
99 case LoopHint:
100 case GetMyScope:
101 case SkipScope:
102 case GetClosureRegisters:
103 case GetClosureVar:
104 case PutClosureVar:
105 case InvalidationPoint:
106 case StringCharAt:
107 case CheckFunction:
108 case StringCharCodeAt:
109 case AllocatePropertyStorage:
110 case ReallocatePropertyStorage:
111 case FunctionReentryWatchpoint:
112 case TypedArrayWatchpoint:
113 case GetTypedArrayByteOffset:
114 case VariableWatchpoint:
115 case NotifyWrite:
116 case StoreBarrier:
117 case StoreBarrierWithNullCheck:
118 case Call:
119 case Construct:
120 case ValueToInt32:
121 case Branch:
122 case LogicalNot:
123 case CheckInBounds:
124 case ConstantStoragePointer:
125 case Check:
126 case CountExecution:
127 case CheckExecutable:
128 case GetScope:
129 case AllocationProfileWatchpoint:
130 case CheckArgumentsNotCreated:
131 case GetCallee:
132 case ToString:
133 case MakeRope:
134 case NewArrayWithSize:
135 case GetById:
136 case ToThis:
137 case MultiGetByOffset:
138 case MultiPutByOffset:
139 case ToPrimitive:
140 case PhantomArguments:
141 case Throw:
142 case ThrowReferenceError:
143 case Unreachable:
144 case GetMyArgumentByVal:
145 case IsUndefined:
146 case IsBoolean:
147 case IsNumber:
148 case IsString:
149 case IsObject:
150 case IsFunction:
151 case CheckHasInstance:
152 case InstanceOf:
153 case DoubleRep:
154 case ValueRep:
155 case Int52Rep:
156 case DoubleConstant:
157 case Int52Constant:
158 case BooleanToNumber:
159 // These are OK.
160 break;
161 case Identity:
162 // No backend handles this because it will be optimized out. But we may check
163 // for capabilities before optimization. It would be a deep error to remove this
164 // case because it would prevent us from catching bugs where the FTL backend
165 // pipeline failed to optimize out an Identity.
166 break;
167 case PutByIdDirect:
168 case PutById:
169 if (node->child1().useKind() == CellUse)
170 break;
171 return CannotCompile;
172 case GetIndexedPropertyStorage:
173 if (node->arrayMode().type() == Array::String)
174 break;
175 if (isTypedView(node->arrayMode().typedArrayType()))
176 break;
177 return CannotCompile;
178 case CheckArray:
179 switch (node->arrayMode().type()) {
180 case Array::Int32:
181 case Array::Double:
182 case Array::Contiguous:
183 break;
184 default:
185 if (isTypedView(node->arrayMode().typedArrayType()))
186 break;
187 return CannotCompile;
188 }
189 break;
190 case GetArrayLength:
191 switch (node->arrayMode().type()) {
192 case Array::Int32:
193 case Array::Double:
194 case Array::Contiguous:
195 case Array::String:
196 break;
197 default:
198 if (isTypedView(node->arrayMode().typedArrayType()))
199 break;
200 return CannotCompile;
201 }
202 break;
203 case GetByVal:
204 switch (node->arrayMode().type()) {
205 case Array::ForceExit:
206 case Array::Generic:
207 case Array::String:
208 case Array::Int32:
209 case Array::Double:
210 case Array::Contiguous:
211 break;
212 default:
213 if (isTypedView(node->arrayMode().typedArrayType()))
214 return CanCompileAndOSREnter;
215 return CannotCompile;
216 }
217 break;
218 case PutByVal:
219 case PutByValAlias:
220 case PutByValDirect:
221 switch (node->arrayMode().type()) {
222 case Array::ForceExit:
223 case Array::Generic:
224 case Array::Int32:
225 case Array::Double:
226 case Array::Contiguous:
227 break;
228 default:
229 if (isTypedView(node->arrayMode().typedArrayType()))
230 return CanCompileAndOSREnter;
231 return CannotCompile;
232 }
233 break;
234 case ArrayPush:
235 case ArrayPop:
236 switch (node->arrayMode().type()) {
237 case Array::Int32:
238 case Array::Contiguous:
239 case Array::Double:
240 break;
241 default:
242 return CannotCompile;
243 }
244 break;
245 case CompareEq:
246 if (node->isBinaryUseKind(Int32Use))
247 break;
248 if (node->isBinaryUseKind(Int52RepUse))
249 break;
250 if (node->isBinaryUseKind(DoubleRepUse))
251 break;
252 if (node->isBinaryUseKind(StringIdentUse))
253 break;
254 if (node->isBinaryUseKind(ObjectUse))
255 break;
256 if (node->isBinaryUseKind(UntypedUse))
257 break;
258 if (node->isBinaryUseKind(BooleanUse))
259 break;
260 if (node->isBinaryUseKind(ObjectUse, ObjectOrOtherUse))
261 break;
262 if (node->isBinaryUseKind(ObjectOrOtherUse, ObjectUse))
263 break;
264 return CannotCompile;
265 case CompareStrictEq:
266 if (node->isBinaryUseKind(Int32Use))
267 break;
268 if (node->isBinaryUseKind(Int52RepUse))
269 break;
270 if (node->isBinaryUseKind(DoubleRepUse))
271 break;
272 if (node->isBinaryUseKind(StringIdentUse))
273 break;
274 if (node->isBinaryUseKind(ObjectUse))
275 break;
276 if (node->isBinaryUseKind(BooleanUse))
277 break;
278 if (node->isBinaryUseKind(MiscUse, UntypedUse))
279 break;
280 if (node->isBinaryUseKind(UntypedUse, MiscUse))
281 break;
282 if (node->isBinaryUseKind(StringIdentUse, NotStringVarUse))
283 break;
284 if (node->isBinaryUseKind(NotStringVarUse, StringIdentUse))
285 break;
286 return CannotCompile;
287 case CompareLess:
288 case CompareLessEq:
289 case CompareGreater:
290 case CompareGreaterEq:
291 if (node->isBinaryUseKind(Int32Use))
292 break;
293 if (node->isBinaryUseKind(Int52RepUse))
294 break;
295 if (node->isBinaryUseKind(DoubleRepUse))
296 break;
297 if (node->isBinaryUseKind(UntypedUse))
298 break;
299 return CannotCompile;
300 case Switch:
301 switch (node->switchData()->kind) {
302 case SwitchImm:
303 case SwitchChar:
304 break;
305 default:
306 return CannotCompile;
307 }
308 break;
309 default:
310 // Don't know how to handle anything else.
311 return CannotCompile;
312 }
313 return CanCompileAndOSREnter;
314 }
315
316 CapabilityLevel canCompile(Graph& graph)
317 {
318 if (graph.m_codeBlock->instructionCount() > Options::maximumFTLCandidateInstructionCount()) {
319 if (verboseCapabilities())
320 dataLog("FTL rejecting ", *graph.m_codeBlock, " because it's too big.\n");
321 return CannotCompile;
322 }
323
324 if (graph.m_codeBlock->codeType() != FunctionCode) {
325 if (verboseCapabilities())
326 dataLog("FTL rejecting ", *graph.m_codeBlock, " because it doesn't belong to a function.\n");
327 return CannotCompile;
328 }
329
330 if (graph.m_codeBlock->needsActivation()) {
331 // Need this because although we also don't support
332 // CreateActivation/TearOffActivation, we might not see those nodes in case of
333 // OSR entry.
334 // FIXME: Support activations.
335 // https://bugs.webkit.org/show_bug.cgi?id=129576
336 if (verboseCapabilities())
337 dataLog("FTL rejecting ", *graph.m_codeBlock, " because it uses activations.\n");
338 return CannotCompile;
339 }
340
341 CapabilityLevel result = CanCompileAndOSREnter;
342
343 for (BlockIndex blockIndex = graph.numBlocks(); blockIndex--;) {
344 BasicBlock* block = graph.block(blockIndex);
345 if (!block)
346 continue;
347
348 // We don't care if we can compile blocks that the CFA hasn't visited.
349 if (!block->cfaHasVisited)
350 continue;
351
352 for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
353 Node* node = block->at(nodeIndex);
354
355 for (unsigned childIndex = graph.numChildren(node); childIndex--;) {
356 Edge edge = graph.child(node, childIndex);
357 if (!edge)
358 continue;
359 switch (edge.useKind()) {
360 case UntypedUse:
361 case Int32Use:
362 case KnownInt32Use:
363 case Int52RepUse:
364 case NumberUse:
365 case DoubleRepUse:
366 case DoubleRepRealUse:
367 case BooleanUse:
368 case CellUse:
369 case KnownCellUse:
370 case ObjectUse:
371 case ObjectOrOtherUse:
372 case StringUse:
373 case KnownStringUse:
374 case StringObjectUse:
375 case StringOrStringObjectUse:
376 case FinalObjectUse:
377 case NotCellUse:
378 case OtherUse:
379 case MiscUse:
380 case StringIdentUse:
381 case NotStringVarUse:
382 case MachineIntUse:
383 case DoubleRepMachineIntUse:
384 // These are OK.
385 break;
386 default:
387 // Don't know how to handle anything else.
388 if (verboseCapabilities()) {
389 dataLog("FTL rejecting node in ", *graph.m_codeBlock, " because of bad use kind: ", edge.useKind(), " in node:\n");
390 graph.dump(WTF::dataFile(), " ", node);
391 }
392 return CannotCompile;
393 }
394 }
395
396 switch (canCompile(node)) {
397 case CannotCompile:
398 if (verboseCapabilities()) {
399 dataLog("FTL rejecting node in ", *graph.m_codeBlock, ":\n");
400 graph.dump(WTF::dataFile(), " ", node);
401 }
402 return CannotCompile;
403
404 case CanCompile:
405 if (result == CanCompileAndOSREnter && verboseCompilationEnabled()) {
406 dataLog("FTL disabling OSR entry because of node:\n");
407 graph.dump(WTF::dataFile(), " ", node);
408 }
409 result = CanCompile;
410 break;
411
412 case CanCompileAndOSREnter:
413 break;
414 }
415
416 if (node->op() == ForceOSRExit)
417 break;
418 }
419 }
420
421 return result;
422 }
423
424 } } // namespace JSC::FTL
425
426 #endif // ENABLE(FTL_JIT)
427