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 ValuePow:
384 case ValueBitNot:
385 case ValueNegate:
386#else
387 // See comment at the top for why be default for all nodes should be to
388 // return true.
389 default:
390#endif
391 return true;
392
393 case CallStringConstructor:
394 case ToString:
395 switch (node->child1().useKind()) {
396 case StringObjectUse:
397 case StringOrStringObjectUse:
398 return false;
399 default:
400 break;
401 }
402 return true;
403
404 case CheckTraps:
405 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=194323
406 ASSERT(Options::usePollingTraps());
407 return true;
408
409 case CompareEq:
410 case CompareLess:
411 case CompareLessEq:
412 case CompareGreater:
413 case CompareGreaterEq:
414 if (node->isBinaryUseKind(Int32Use)
415#if USE(JSVALUE64)
416 || node->isBinaryUseKind(Int52RepUse)
417#endif
418 || node->isBinaryUseKind(DoubleRepUse)
419 || node->isBinaryUseKind(StringIdentUse)
420 )
421 return false;
422 if (node->op() == CompareEq) {
423 if (node->isBinaryUseKind(BooleanUse)
424 || node->isBinaryUseKind(SymbolUse)
425 || node->isBinaryUseKind(ObjectUse)
426 || node->isBinaryUseKind(ObjectUse, ObjectOrOtherUse) || node->isBinaryUseKind(ObjectOrOtherUse, ObjectUse))
427 return false;
428 }
429 return true;
430
431 case CompareStrictEq:
432 if (node->isBinaryUseKind(BooleanUse)
433 || node->isBinaryUseKind(Int32Use)
434#if USE(JSVALUE64)
435 || node->isBinaryUseKind(Int52RepUse)
436#endif
437 || node->isBinaryUseKind(DoubleRepUse)
438 || node->isBinaryUseKind(SymbolUse)
439 || node->isBinaryUseKind(SymbolUse, UntypedUse)
440 || node->isBinaryUseKind(UntypedUse, SymbolUse)
441 || node->isBinaryUseKind(StringIdentUse)
442 || node->isBinaryUseKind(ObjectUse, UntypedUse) || node->isBinaryUseKind(UntypedUse, ObjectUse)
443 || node->isBinaryUseKind(ObjectUse)
444 || node->isBinaryUseKind(MiscUse, UntypedUse) || node->isBinaryUseKind(UntypedUse, MiscUse)
445 || node->isBinaryUseKind(StringIdentUse, NotStringVarUse) || node->isBinaryUseKind(NotStringVarUse, StringIdentUse))
446 return false;
447 return true;
448
449 case GetIndexedPropertyStorage:
450 case GetByVal:
451 if (node->arrayMode().type() == Array::String)
452 return true;
453 return false;
454
455 case PutByValDirect:
456 case PutByVal:
457 case PutByValAlias:
458 if (!graph.m_plan.isFTL()) {
459 switch (node->arrayMode().modeForPut().type()) {
460 case Array::Int8Array:
461 case Array::Int16Array:
462 case Array::Int32Array:
463 case Array::Uint8Array:
464 case Array::Uint8ClampedArray:
465 case Array::Uint16Array:
466 case Array::Uint32Array:
467 return true;
468 default:
469 break;
470 }
471 }
472 return false;
473
474 case MapHash:
475 switch (node->child1().useKind()) {
476 case BooleanUse:
477 case Int32Use:
478 case SymbolUse:
479 case ObjectUse:
480 return false;
481 default:
482 // We might resolve a rope.
483 return true;
484 }
485
486 case MultiPutByOffset:
487 return node->multiPutByOffsetData().reallocatesStorage();
488
489 case SameValue:
490 if (node->isBinaryUseKind(DoubleRepUse))
491 return false;
492 return true;
493
494 case StringFromCharCode:
495 // FIXME: Should we constant fold this case?
496 // https://bugs.webkit.org/show_bug.cgi?id=194308
497 if (node->child1()->isInt32Constant() && (node->child1()->asUInt32() <= maxSingleCharacterString))
498 return false;
499 return true;
500
501 case Switch:
502 switch (node->switchData()->kind) {
503 case SwitchCell:
504 ASSERT(graph.m_plan.isFTL());
505 FALLTHROUGH;
506 case SwitchImm:
507 return false;
508 case SwitchChar:
509 return true;
510 case SwitchString:
511 if (node->child1().useKind() == StringIdentUse)
512 return false;
513 ASSERT(node->child1().useKind() == StringUse || node->child1().useKind() == UntypedUse);
514 return true;
515 }
516 RELEASE_ASSERT_NOT_REACHED();
517
518 case LastNodeType:
519 RELEASE_ASSERT_NOT_REACHED();
520 }
521
522 RELEASE_ASSERT_NOT_REACHED();
523}
524
525} } // namespace JSC::DFG
526
527#endif // ENABLE(DFG_JIT)
528