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