1/*
2 * Copyright (C) 2014-2019 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 "DFGDoesGC.h"
28
29#if ENABLE(DFG_JIT)
30
31#include "DFGClobberize.h"
32#include "DFGGraph.h"
33#include "DFGNode.h"
34#include "Operations.h"
35
36namespace JSC { namespace DFG {
37
38bool doesGC(Graph& graph, Node* node)
39{
40 if (clobbersHeap(graph, node))
41 return true;
42
43 // Now consider nodes that don't clobber the world but that still may GC. This includes all
44 // nodes. By default, we should assume every node can GC and return true. This includes the
45 // world-clobbering nodes. We should only return false if we have proven that the node cannot
46 // GC. Typical examples of how a node can GC is if the code emitted for the node does any of the
47 // following:
48 // 1. Allocates any objects.
49 // 2. Resolves a rope string, which allocates a string.
50 // 3. Produces a string (which allocates the string) except when we can prove that
51 // the string will always be one of the pre-allcoated SmallStrings.
52 // 4. Triggers a structure transition (which can allocate a new structure)
53 // unless it is a known transition between previously allocated structures
54 // such as between Array types.
55 // 5. Calls to a JS function, which can execute arbitrary code including allocating objects.
56 // 6. Calls operations that uses DeferGC, because it may GC in its destructor.
57
58 switch (node->op()) {
59 case JSConstant:
60 case DoubleConstant:
61 case Int52Constant:
62 case LazyJSConstant:
63 case Identity:
64 case IdentityWithProfile:
65 case GetCallee:
66 case SetCallee:
67 case GetArgumentCountIncludingThis:
68 case SetArgumentCountIncludingThis:
69 case GetRestLength:
70 case GetLocal:
71 case SetLocal:
72 case MovHint:
73 case InitializeEntrypointArguments:
74 case ZombieHint:
75 case ExitOK:
76 case Phantom:
77 case Upsilon:
78 case Phi:
79 case Flush:
80 case PhantomLocal:
81 case SetArgumentDefinitely:
82 case SetArgumentMaybe:
83 case ArithBitNot:
84 case ArithBitAnd:
85 case ArithBitOr:
86 case ArithBitXor:
87 case BitLShift:
88 case BitRShift:
89 case BitURShift:
90 case ValueToInt32:
91 case UInt32ToNumber:
92 case DoubleAsInt32:
93 case ArithAdd:
94 case ArithClz32:
95 case ArithSub:
96 case ArithNegate:
97 case ArithMul:
98 case ArithIMul:
99 case ArithDiv:
100 case ArithMod:
101 case ArithAbs:
102 case ArithMin:
103 case ArithMax:
104 case ArithPow:
105 case ArithSqrt:
106 case ArithRandom:
107 case ArithRound:
108 case ArithFloor:
109 case ArithCeil:
110 case ArithTrunc:
111 case ArithFRound:
112 case ArithUnary:
113 case CheckStructure:
114 case CheckStructureOrEmpty:
115 case CheckStructureImmediate:
116 case GetExecutable:
117 case GetButterfly:
118 case CheckSubClass:
119 case CheckArray:
120 case GetScope:
121 case SkipScope:
122 case GetGlobalObject:
123 case GetGlobalThis:
124 case GetClosureVar:
125 case PutClosureVar:
126 case GetRegExpObjectLastIndex:
127 case SetRegExpObjectLastIndex:
128 case RecordRegExpCachedResult:
129 case GetGlobalVar:
130 case GetGlobalLexicalVariable:
131 case PutGlobalVariable:
132 case CheckCell:
133 case CheckNotEmpty:
134 case AssertNotEmpty:
135 case CheckStringIdent:
136 case CompareBelow:
137 case CompareBelowEq:
138 case CompareEqPtr:
139 case ProfileControlFlow:
140 case OverridesHasInstance:
141 case IsEmpty:
142 case IsUndefined:
143 case IsUndefinedOrNull:
144 case IsBoolean:
145 case IsNumber:
146 case NumberIsInteger:
147 case IsObject:
148 case IsObjectOrNull:
149 case IsFunction:
150 case IsCellWithType:
151 case IsTypedArrayView:
152 case TypeOf:
153 case LogicalNot:
154 case Jump:
155 case Branch:
156 case EntrySwitch:
157 case CountExecution:
158 case SuperSamplerBegin:
159 case SuperSamplerEnd:
160 case CPUIntrinsic:
161 case NormalizeMapKey:
162 case GetMapBucketHead:
163 case GetMapBucketNext:
164 case LoadKeyFromMapBucket:
165 case LoadValueFromMapBucket:
166 case ExtractValueFromWeakMapGet:
167 case WeakMapGet:
168 case WeakSetAdd:
169 case WeakMapSet:
170 case Unreachable:
171 case ExtractOSREntryLocal:
172 case ExtractCatchLocal:
173 case ClearCatchLocals:
174 case LoopHint:
175 case StoreBarrier:
176 case FencedStoreBarrier:
177 case InvalidationPoint:
178 case NotifyWrite:
179 case CheckInBounds:
180 case ConstantStoragePointer:
181 case Check:
182 case CheckVarargs:
183 case CheckTypeInfoFlags:
184 case MultiGetByOffset:
185 case ValueRep:
186 case DoubleRep:
187 case Int52Rep:
188 case GetGetter:
189 case GetSetter:
190 case GetArrayLength:
191 case GetVectorLength:
192 case StringCharCodeAt:
193 case GetTypedArrayByteOffset:
194 case GetPrototypeOf:
195 case PutStructure:
196 case GetByOffset:
197 case GetGetterSetterByOffset:
198 case GetEnumerableLength:
199 case FiatInt52:
200 case BooleanToNumber:
201 case CheckBadCell:
202 case BottomValue:
203 case PhantomNewObject:
204 case PhantomNewFunction:
205 case PhantomNewGeneratorFunction:
206 case PhantomNewAsyncFunction:
207 case PhantomNewAsyncGeneratorFunction:
208 case PhantomCreateActivation:
209 case PhantomDirectArguments:
210 case PhantomCreateRest:
211 case PhantomNewArrayWithSpread:
212 case PhantomNewArrayBuffer:
213 case PhantomSpread:
214 case PhantomClonedArguments:
215 case PhantomNewRegexp:
216 case GetMyArgumentByVal:
217 case GetMyArgumentByValOutOfBounds:
218 case ForwardVarargs:
219 case PutHint:
220 case KillStack:
221 case GetStack:
222 case GetFromArguments:
223 case GetArgument:
224 case LogShadowChickenPrologue:
225 case LogShadowChickenTail:
226 case NukeStructureAndSetButterfly:
227 case AtomicsAdd:
228 case AtomicsAnd:
229 case AtomicsCompareExchange:
230 case AtomicsExchange:
231 case AtomicsLoad:
232 case AtomicsOr:
233 case AtomicsStore:
234 case AtomicsSub:
235 case AtomicsXor:
236 case AtomicsIsLockFree:
237 case MatchStructure:
238 case FilterCallLinkStatus:
239 case FilterGetByIdStatus:
240 case FilterPutByIdStatus:
241 case FilterInByIdStatus:
242 case DataViewGetInt:
243 case DataViewGetFloat:
244 case DataViewSet:
245 return false;
246
247#if !ASSERT_DISABLED
248 case ArrayPush:
249 case ArrayPop:
250 case PushWithScope:
251 case CreateActivation:
252 case CreateDirectArguments:
253 case CreateScopedArguments:
254 case CreateClonedArguments:
255 case Call:
256 case CallEval:
257 case CallForwardVarargs:
258 case CallObjectConstructor:
259 case CallVarargs:
260 case CheckTierUpAndOSREnter:
261 case CheckTierUpAtReturn:
262 case CheckTierUpInLoop:
263 case Construct:
264 case ConstructForwardVarargs:
265 case ConstructVarargs:
266 case DefineDataProperty:
267 case DefineAccessorProperty:
268 case DeleteById:
269 case DeleteByVal:
270 case DirectCall:
271 case DirectConstruct:
272 case DirectTailCall:
273 case DirectTailCallInlinedCaller:
274 case ForceOSRExit:
275 case GetById:
276 case GetByIdDirect:
277 case GetByIdDirectFlush:
278 case GetByIdFlush:
279 case GetByIdWithThis:
280 case GetByValWithThis:
281 case GetDirectPname:
282 case GetDynamicVar:
283 case GetMapBucket:
284 case HasGenericProperty:
285 case HasIndexedProperty:
286 case HasOwnProperty:
287 case HasStructureProperty:
288 case InById:
289 case InByVal:
290 case InstanceOf:
291 case InstanceOfCustom:
292 case LoadVarargs:
293 case NumberToStringWithRadix:
294 case NumberToStringWithValidRadixConstant:
295 case ProfileType:
296 case PutById:
297 case PutByIdDirect:
298 case PutByIdFlush:
299 case PutByIdWithThis:
300 case PutByOffset:
301 case PutByValWithThis:
302 case PutDynamicVar:
303 case PutGetterById:
304 case PutGetterByVal:
305 case PutGetterSetterById:
306 case PutSetterById:
307 case PutSetterByVal:
308 case PutStack:
309 case PutToArguments:
310 case RegExpExec:
311 case RegExpExecNonGlobalOrSticky:
312 case RegExpMatchFast:
313 case RegExpMatchFastGlobal:
314 case RegExpTest:
315 case ResolveScope:
316 case ResolveScopeForHoistingFuncDeclInEval:
317 case Return:
318 case StringCharAt:
319 case TailCall:
320 case TailCallForwardVarargs:
321 case TailCallForwardVarargsInlinedCaller:
322 case TailCallInlinedCaller:
323 case TailCallVarargs:
324 case TailCallVarargsInlinedCaller:
325 case Throw:
326 case ToNumber:
327 case ToObject:
328 case ToPrimitive:
329 case ToThis:
330 case TryGetById:
331 case CreateThis:
332 case ObjectCreate:
333 case ObjectKeys:
334 case AllocatePropertyStorage:
335 case ReallocatePropertyStorage:
336 case Arrayify:
337 case ArrayifyToStructure:
338 case NewObject:
339 case NewArray:
340 case NewArrayWithSpread:
341 case Spread:
342 case NewArrayWithSize:
343 case NewArrayBuffer:
344 case NewRegexp:
345 case NewStringObject:
346 case NewSymbol:
347 case MakeRope:
348 case NewFunction:
349 case NewGeneratorFunction:
350 case NewAsyncGeneratorFunction:
351 case NewAsyncFunction:
352 case NewTypedArray:
353 case ThrowStaticError:
354 case GetPropertyEnumerator:
355 case GetEnumeratorStructurePname:
356 case GetEnumeratorGenericPname:
357 case ToIndexString:
358 case MaterializeNewObject:
359 case MaterializeCreateActivation:
360 case SetFunctionName:
361 case StrCat:
362 case StringReplace:
363 case StringReplaceRegExp:
364 case StringSlice:
365 case StringValueOf:
366 case CreateRest:
367 case ToLowerCase:
368 case CallDOMGetter:
369 case CallDOM:
370 case ArraySlice:
371 case ArrayIndexOf:
372 case ParseInt: // We might resolve a rope even though we don't clobber anything.
373 case SetAdd:
374 case MapSet:
375 case ValueBitAnd:
376 case ValueBitOr:
377 case ValueBitXor:
378 case ValueAdd:
379 case ValueSub:
380 case ValueMul:
381 case ValueDiv:
382 case ValueMod:
383 case ValueBitNot:
384 case ValueNegate:
385#else
386 // See comment at the top for why be default for all nodes should be to
387 // return true.
388 default:
389#endif
390 return true;
391
392 case CallStringConstructor:
393 case ToString:
394 switch (node->child1().useKind()) {
395 case StringObjectUse:
396 case StringOrStringObjectUse:
397 return false;
398 default:
399 break;
400 }
401 return true;
402
403 case CheckTraps:
404 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=194323
405 ASSERT(Options::usePollingTraps());
406 return true;
407
408 case CompareEq:
409 case CompareLess:
410 case CompareLessEq:
411 case CompareGreater:
412 case CompareGreaterEq:
413 if (node->isBinaryUseKind(Int32Use)
414#if USE(JSVALUE64)
415 || node->isBinaryUseKind(Int52RepUse)
416#endif
417 || node->isBinaryUseKind(DoubleRepUse)
418 || node->isBinaryUseKind(StringIdentUse)
419 )
420 return false;
421 if (node->op() == CompareEq) {
422 if (node->isBinaryUseKind(BooleanUse)
423 || node->isBinaryUseKind(SymbolUse)
424 || node->isBinaryUseKind(ObjectUse)
425 || node->isBinaryUseKind(ObjectUse, ObjectOrOtherUse) || node->isBinaryUseKind(ObjectOrOtherUse, ObjectUse))
426 return false;
427 }
428 return true;
429
430 case CompareStrictEq:
431 if (node->isBinaryUseKind(BooleanUse)
432 || node->isBinaryUseKind(Int32Use)
433#if USE(JSVALUE64)
434 || node->isBinaryUseKind(Int52RepUse)
435#endif
436 || node->isBinaryUseKind(DoubleRepUse)
437 || node->isBinaryUseKind(SymbolUse)
438 || node->isBinaryUseKind(SymbolUse, UntypedUse)
439 || node->isBinaryUseKind(UntypedUse, SymbolUse)
440 || node->isBinaryUseKind(StringIdentUse)
441 || node->isBinaryUseKind(ObjectUse, UntypedUse) || node->isBinaryUseKind(UntypedUse, ObjectUse)
442 || node->isBinaryUseKind(ObjectUse)
443 || node->isBinaryUseKind(MiscUse, UntypedUse) || node->isBinaryUseKind(UntypedUse, MiscUse)
444 || node->isBinaryUseKind(StringIdentUse, NotStringVarUse) || node->isBinaryUseKind(NotStringVarUse, StringIdentUse))
445 return false;
446 return true;
447
448 case GetIndexedPropertyStorage:
449 case GetByVal:
450 if (node->arrayMode().type() == Array::String)
451 return true;
452 return false;
453
454 case PutByValDirect:
455 case PutByVal:
456 case PutByValAlias:
457 if (!graph.m_plan.isFTL()) {
458 switch (node->arrayMode().modeForPut().type()) {
459 case Array::Int8Array:
460 case Array::Int16Array:
461 case Array::Int32Array:
462 case Array::Uint8Array:
463 case Array::Uint8ClampedArray:
464 case Array::Uint16Array:
465 case Array::Uint32Array:
466 return true;
467 default:
468 break;
469 }
470 }
471 return false;
472
473 case MapHash:
474 switch (node->child1().useKind()) {
475 case BooleanUse:
476 case Int32Use:
477 case SymbolUse:
478 case ObjectUse:
479 return false;
480 default:
481 // We might resolve a rope.
482 return true;
483 }
484
485 case MultiPutByOffset:
486 return node->multiPutByOffsetData().reallocatesStorage();
487
488 case SameValue:
489 if (node->isBinaryUseKind(DoubleRepUse))
490 return false;
491 return true;
492
493 case StringFromCharCode:
494 // FIXME: Should we constant fold this case?
495 // https://bugs.webkit.org/show_bug.cgi?id=194308
496 if (node->child1()->isInt32Constant() && (node->child1()->asUInt32() <= maxSingleCharacterString))
497 return false;
498 return true;
499
500 case Switch:
501 switch (node->switchData()->kind) {
502 case SwitchCell:
503 ASSERT(graph.m_plan.isFTL());
504 FALLTHROUGH;
505 case SwitchImm:
506 return false;
507 case SwitchChar:
508 return true;
509 case SwitchString:
510 if (node->child1().useKind() == StringIdentUse)
511 return false;
512 ASSERT(node->child1().useKind() == StringUse || node->child1().useKind() == UntypedUse);
513 return true;
514 }
515 RELEASE_ASSERT_NOT_REACHED();
516
517 case LastNodeType:
518 RELEASE_ASSERT_NOT_REACHED();
519 }
520
521 RELEASE_ASSERT_NOT_REACHED();
522}
523
524} } // namespace JSC::DFG
525
526#endif // ENABLE(DFG_JIT)
527