1/*
2 * Copyright (C) 2013-2017 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
31namespace JSC { namespace FTL {
32
33using namespace DFG;
34
35static bool verboseCapabilities()
36{
37 return verboseCompilationEnabled() || Options::verboseFTLFailure();
38}
39
40inline 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 SetArgumentDefinitely:
60 case SetArgumentMaybe:
61 case Return:
62 case ArithBitNot:
63 case ArithBitAnd:
64 case ArithBitOr:
65 case ArithBitXor:
66 case ArithBitRShift:
67 case ArithBitLShift:
68 case BitURShift:
69 case CheckStructure:
70 case CheckStructureOrEmpty:
71 case DoubleAsInt32:
72 case Arrayify:
73 case ArrayifyToStructure:
74 case PutStructure:
75 case GetButterfly:
76 case NewObject:
77 case NewPromise:
78 case NewGenerator:
79 case NewAsyncGenerator:
80 case NewStringObject:
81 case NewSymbol:
82 case NewArray:
83 case NewArrayWithSpread:
84 case Spread:
85 case NewArrayBuffer:
86 case NewTypedArray:
87 case GetByOffset:
88 case GetGetterSetterByOffset:
89 case GetGetter:
90 case GetSetter:
91 case PutByOffset:
92 case GetGlobalVar:
93 case GetGlobalLexicalVariable:
94 case PutGlobalVariable:
95 case ValueBitAnd:
96 case ValueBitXor:
97 case ValueBitOr:
98 case ValueBitNot:
99 case ValueBitLShift:
100 case ValueBitRShift:
101 case ValueNegate:
102 case ValueAdd:
103 case ValueSub:
104 case ValueMul:
105 case ValueDiv:
106 case ValueMod:
107 case ValuePow:
108 case Inc:
109 case Dec:
110 case StrCat:
111 case ArithAdd:
112 case ArithClz32:
113 case ArithSub:
114 case ArithMul:
115 case ArithDiv:
116 case ArithMod:
117 case ArithMin:
118 case ArithMax:
119 case ArithAbs:
120 case ArithPow:
121 case ArithRandom:
122 case ArithRound:
123 case ArithFloor:
124 case ArithCeil:
125 case ArithTrunc:
126 case ArithSqrt:
127 case ArithFRound:
128 case ArithNegate:
129 case ArithUnary:
130 case UInt32ToNumber:
131 case Jump:
132 case ForceOSRExit:
133 case Phi:
134 case Upsilon:
135 case ExtractOSREntryLocal:
136 case ExtractCatchLocal:
137 case ClearCatchLocals:
138 case LoopHint:
139 case SkipScope:
140 case GetGlobalObject:
141 case GetGlobalThis:
142 case CreateActivation:
143 case PushWithScope:
144 case NewFunction:
145 case NewGeneratorFunction:
146 case NewAsyncFunction:
147 case NewAsyncGeneratorFunction:
148 case GetClosureVar:
149 case PutClosureVar:
150 case GetInternalField:
151 case PutInternalField:
152 case CreateDirectArguments:
153 case CreateScopedArguments:
154 case CreateClonedArguments:
155 case GetFromArguments:
156 case PutToArguments:
157 case GetArgument:
158 case InvalidationPoint:
159 case StringCharAt:
160 case CheckCell:
161 case CheckBadCell:
162 case CheckNotEmpty:
163 case AssertNotEmpty:
164 case CheckIdent:
165 case CheckTraps:
166 case StringCharCodeAt:
167 case StringCodePointAt:
168 case StringFromCharCode:
169 case AllocatePropertyStorage:
170 case ReallocatePropertyStorage:
171 case NukeStructureAndSetButterfly:
172 case GetTypedArrayByteOffset:
173 case GetPrototypeOf:
174 case NotifyWrite:
175 case StoreBarrier:
176 case FencedStoreBarrier:
177 case Call:
178 case DirectCall:
179 case TailCall:
180 case DirectTailCall:
181 case TailCallInlinedCaller:
182 case DirectTailCallInlinedCaller:
183 case Construct:
184 case DirectConstruct:
185 case CallVarargs:
186 case CallEval:
187 case TailCallVarargs:
188 case TailCallVarargsInlinedCaller:
189 case ConstructVarargs:
190 case CallForwardVarargs:
191 case TailCallForwardVarargs:
192 case TailCallForwardVarargsInlinedCaller:
193 case ConstructForwardVarargs:
194 case LoadVarargs:
195 case ValueToInt32:
196 case Branch:
197 case LogicalNot:
198 case CheckInBounds:
199 case ConstantStoragePointer:
200 case Check:
201 case CheckVarargs:
202 case CheckArray:
203 case CountExecution:
204 case SuperSamplerBegin:
205 case SuperSamplerEnd:
206 case GetExecutable:
207 case GetScope:
208 case GetCallee:
209 case SetCallee:
210 case GetArgumentCountIncludingThis:
211 case SetArgumentCountIncludingThis:
212 case ToNumber:
213 case ToNumeric:
214 case ToString:
215 case ToObject:
216 case CallObjectConstructor:
217 case CallStringConstructor:
218 case ObjectCreate:
219 case ObjectKeys:
220 case MakeRope:
221 case NewArrayWithSize:
222 case TryGetById:
223 case GetById:
224 case GetByIdFlush:
225 case GetByIdWithThis:
226 case GetByIdDirect:
227 case GetByIdDirectFlush:
228 case ToThis:
229 case MultiGetByOffset:
230 case MultiPutByOffset:
231 case ToPrimitive:
232 case Throw:
233 case ThrowStaticError:
234 case Unreachable:
235 case InByVal:
236 case InById:
237 case HasOwnProperty:
238 case IsCellWithType:
239 case MapHash:
240 case NormalizeMapKey:
241 case GetMapBucket:
242 case GetMapBucketHead:
243 case GetMapBucketNext:
244 case LoadKeyFromMapBucket:
245 case LoadValueFromMapBucket:
246 case ExtractValueFromWeakMapGet:
247 case SetAdd:
248 case MapSet:
249 case WeakMapGet:
250 case WeakSetAdd:
251 case WeakMapSet:
252 case IsEmpty:
253 case IsUndefined:
254 case IsUndefinedOrNull:
255 case IsBoolean:
256 case IsNumber:
257 case NumberIsInteger:
258 case IsObject:
259 case IsObjectOrNull:
260 case IsFunction:
261 case IsTypedArrayView:
262 case CheckTypeInfoFlags:
263 case OverridesHasInstance:
264 case InstanceOf:
265 case InstanceOfCustom:
266 case DoubleRep:
267 case ValueRep:
268 case Int52Rep:
269 case DoubleConstant:
270 case Int52Constant:
271 case BooleanToNumber:
272 case HasGenericProperty:
273 case HasStructureProperty:
274 case HasIndexedProperty:
275 case GetDirectPname:
276 case GetEnumerableLength:
277 case GetIndexedPropertyStorage:
278 case GetPropertyEnumerator:
279 case GetEnumeratorStructurePname:
280 case GetEnumeratorGenericPname:
281 case ToIndexString:
282 case BottomValue:
283 case PhantomNewObject:
284 case PhantomNewFunction:
285 case PhantomNewGeneratorFunction:
286 case PhantomNewAsyncGeneratorFunction:
287 case PhantomNewAsyncFunction:
288 case PhantomCreateActivation:
289 case PhantomNewRegexp:
290 case PutHint:
291 case CheckStructureImmediate:
292 case MaterializeNewObject:
293 case MaterializeCreateActivation:
294 case PhantomDirectArguments:
295 case PhantomCreateRest:
296 case PhantomSpread:
297 case PhantomNewArrayWithSpread:
298 case PhantomNewArrayBuffer:
299 case PhantomClonedArguments:
300 case GetMyArgumentByVal:
301 case GetMyArgumentByValOutOfBounds:
302 case ForwardVarargs:
303 case EntrySwitch:
304 case Switch:
305 case TypeOf:
306 case PutById:
307 case PutByIdDirect:
308 case PutByIdFlush:
309 case PutByIdWithThis:
310 case PutGetterById:
311 case PutSetterById:
312 case PutGetterSetterById:
313 case PutGetterByVal:
314 case PutSetterByVal:
315 case DeleteById:
316 case DeleteByVal:
317 case CreateRest:
318 case GetRestLength:
319 case RegExpExec:
320 case RegExpExecNonGlobalOrSticky:
321 case RegExpTest:
322 case RegExpMatchFast:
323 case RegExpMatchFastGlobal:
324 case NewRegexp:
325 case StringReplace:
326 case StringReplaceRegExp:
327 case GetRegExpObjectLastIndex:
328 case SetRegExpObjectLastIndex:
329 case RecordRegExpCachedResult:
330 case SetFunctionName:
331 case LogShadowChickenPrologue:
332 case LogShadowChickenTail:
333 case ResolveScope:
334 case ResolveScopeForHoistingFuncDeclInEval:
335 case GetDynamicVar:
336 case PutDynamicVar:
337 case CompareEq:
338 case CompareEqPtr:
339 case CompareLess:
340 case CompareLessEq:
341 case CompareGreater:
342 case CompareGreaterEq:
343 case CompareBelow:
344 case CompareBelowEq:
345 case CompareStrictEq:
346 case SameValue:
347 case DefineDataProperty:
348 case DefineAccessorProperty:
349 case StringValueOf:
350 case StringSlice:
351 case ToLowerCase:
352 case NumberToStringWithRadix:
353 case NumberToStringWithValidRadixConstant:
354 case CheckSubClass:
355 case CallDOM:
356 case CallDOMGetter:
357 case ArraySlice:
358 case ArrayIndexOf:
359 case ArrayPop:
360 case ArrayPush:
361 case ParseInt:
362 case AtomicsAdd:
363 case AtomicsAnd:
364 case AtomicsCompareExchange:
365 case AtomicsExchange:
366 case AtomicsLoad:
367 case AtomicsOr:
368 case AtomicsStore:
369 case AtomicsSub:
370 case AtomicsXor:
371 case AtomicsIsLockFree:
372 case InitializeEntrypointArguments:
373 case CPUIntrinsic:
374 case GetArrayLength:
375 case GetVectorLength:
376 case GetByVal:
377 case GetByValWithThis:
378 case PutByVal:
379 case PutByValAlias:
380 case PutByValDirect:
381 case PutByValWithThis:
382 case MatchStructure:
383 case FilterCallLinkStatus:
384 case FilterGetByStatus:
385 case FilterPutByIdStatus:
386 case FilterInByIdStatus:
387 case CreateThis:
388 case CreatePromise:
389 case CreateGenerator:
390 case CreateAsyncGenerator:
391 case DataViewGetInt:
392 case DataViewGetFloat:
393 case DataViewSet:
394 case DateGetInt32OrNaN:
395 case DateGetTime:
396 // These are OK.
397 break;
398
399 case Identity:
400 // No backend handles this because it will be optimized out. But we may check
401 // for capabilities before optimization. It would be a deep error to remove this
402 // case because it would prevent us from catching bugs where the FTL backend
403 // pipeline failed to optimize out an Identity.
404 break;
405
406 case IdentityWithProfile:
407 case CheckTierUpInLoop:
408 case CheckTierUpAndOSREnter:
409 case CheckTierUpAtReturn:
410 case FiatInt52:
411 case ArithIMul:
412 case ProfileType:
413 case ProfileControlFlow:
414 case LastNodeType:
415 return CannotCompile;
416 }
417 return CanCompileAndOSREnter;
418}
419
420CapabilityLevel canCompile(Graph& graph)
421{
422 if (graph.m_codeBlock->bytecodeCost() > Options::maximumFTLCandidateBytecodeCost()) {
423 if (verboseCapabilities())
424 dataLog("FTL rejecting ", *graph.m_codeBlock, " because it's too big.\n");
425 return CannotCompile;
426 }
427
428 if (UNLIKELY(graph.m_codeBlock->ownerExecutable()->neverFTLOptimize())) {
429 if (verboseCapabilities())
430 dataLog("FTL rejecting ", *graph.m_codeBlock, " because it is marked as never FTL compile.\n");
431 return CannotCompile;
432 }
433
434 CapabilityLevel result = CanCompileAndOSREnter;
435
436 for (BlockIndex blockIndex = graph.numBlocks(); blockIndex--;) {
437 BasicBlock* block = graph.block(blockIndex);
438 if (!block)
439 continue;
440
441 // We don't care if we can compile blocks that the CFA hasn't visited.
442 if (!block->cfaHasVisited)
443 continue;
444
445 for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
446 Node* node = block->at(nodeIndex);
447
448 for (unsigned childIndex = graph.numChildren(node); childIndex--;) {
449 Edge edge = graph.child(node, childIndex);
450 if (!edge)
451 continue;
452 switch (edge.useKind()) {
453 case UntypedUse:
454 case Int32Use:
455 case KnownInt32Use:
456 case Int52RepUse:
457 case NumberUse:
458 case RealNumberUse:
459 case DoubleRepUse:
460 case DoubleRepRealUse:
461 case BooleanUse:
462 case KnownBooleanUse:
463 case CellUse:
464 case KnownCellUse:
465 case CellOrOtherUse:
466 case ObjectUse:
467 case ArrayUse:
468 case FunctionUse:
469 case ObjectOrOtherUse:
470 case StringUse:
471 case StringOrOtherUse:
472 case KnownStringUse:
473 case KnownPrimitiveUse:
474 case StringObjectUse:
475 case StringOrStringObjectUse:
476 case SymbolUse:
477 case BigIntUse:
478 case DateObjectUse:
479 case MapObjectUse:
480 case SetObjectUse:
481 case WeakMapObjectUse:
482 case WeakSetObjectUse:
483 case DataViewObjectUse:
484 case FinalObjectUse:
485 case PromiseObjectUse:
486 case RegExpObjectUse:
487 case ProxyObjectUse:
488 case DerivedArrayUse:
489 case NotCellUse:
490 case OtherUse:
491 case KnownOtherUse:
492 case MiscUse:
493 case StringIdentUse:
494 case NotStringVarUse:
495 case NotSymbolUse:
496 case AnyIntUse:
497 case DoubleRepAnyIntUse:
498 // These are OK.
499 break;
500 default:
501 // Don't know how to handle anything else.
502 if (verboseCapabilities()) {
503 dataLog("FTL rejecting node in ", *graph.m_codeBlock, " because of bad use kind: ", edge.useKind(), " in node:\n");
504 graph.dump(WTF::dataFile(), " ", node);
505 }
506 return CannotCompile;
507 }
508 }
509
510 switch (canCompile(node)) {
511 case CannotCompile:
512 if (verboseCapabilities()) {
513 dataLog("FTL rejecting node in ", *graph.m_codeBlock, ":\n");
514 graph.dump(WTF::dataFile(), " ", node);
515 }
516 return CannotCompile;
517
518 case CanCompile:
519 if (result == CanCompileAndOSREnter && verboseCompilationEnabled()) {
520 dataLog("FTL disabling OSR entry because of node:\n");
521 graph.dump(WTF::dataFile(), " ", node);
522 }
523 result = CanCompile;
524 break;
525
526 case CanCompileAndOSREnter:
527 break;
528 }
529
530 if (node->op() == ForceOSRExit)
531 break;
532 }
533 }
534
535 return result;
536}
537
538} } // namespace JSC::FTL
539
540#endif // ENABLE(FTL_JIT)
541
542