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