8d8d6cd06f7947e42caebf950c6294cb74c8b785
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGDoesGC.cpp
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
36 namespace JSC { namespace DFG {
37
38 bool 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)