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