Rollout r200426 since it causes PLT regressions.
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGClobberize.h
1 /*
2  * Copyright (C) 2013-2016 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 #ifndef DFGClobberize_h
27 #define DFGClobberize_h
28
29 #if ENABLE(DFG_JIT)
30
31 #include "DFGAbstractHeap.h"
32 #include "DFGEdgeUsesStructure.h"
33 #include "DFGGraph.h"
34 #include "DFGHeapLocation.h"
35 #include "DFGLazyNode.h"
36 #include "DFGPureValue.h"
37
38 namespace JSC { namespace DFG {
39
40 template<typename ReadFunctor, typename WriteFunctor, typename DefFunctor>
41 void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFunctor& write, const DefFunctor& def)
42 {
43     // Some notes:
44     //
45     // - The canonical way of clobbering the world is to read world and write
46     //   heap. This is because World subsumes Heap and Stack, and Stack can be
47     //   read by anyone but only written to by explicit stack writing operations.
48     //   Of course, claiming to also write World is not wrong; it'll just
49     //   pessimise some important optimizations.
50     //
51     // - We cannot hoist, or sink, anything that has effects. This means that the
52     //   easiest way of indicating that something cannot be hoisted is to claim
53     //   that it side-effects some miscellaneous thing.
54     //
55     // - We cannot hoist forward-exiting nodes without some additional effort. I
56     //   believe that what it comes down to is that forward-exiting generally have
57     //   their NodeExitsForward cleared upon hoist, except for forward-exiting
58     //   nodes that take bogus state as their input. Those are substantially
59     //   harder. We disable it for now. In the future we could enable it by having
60     //   versions of those nodes that backward-exit instead, but I'm not convinced
61     //   of the soundness.
62     //
63     // - Some nodes lie, and claim that they do not read the JSCell_structureID,
64     //   JSCell_typeInfoFlags, etc. These are nodes that use the structure in a way
65     //   that does not depend on things that change under structure transitions.
66     //
67     // - It's implicitly understood that OSR exits read the world. This is why we
68     //   generally don't move or eliminate stores. Every node can exit, so the
69     //   read set does not reflect things that would be read if we exited.
70     //   Instead, the read set reflects what the node will have to read if it
71     //   *doesn't* exit.
72     //
73     // - Broadly, we don't say that we're reading something if that something is
74     //   immutable.
75     //
76     // - We try to make this work even prior to type inference, just so that we
77     //   can use it for IR dumps. No promises on whether the answers are sound
78     //   prior to type inference - though they probably could be if we did some
79     //   small hacking.
80     //
81     // - If you do read(Stack) or read(World), then make sure that readTop() in
82     //   PreciseLocalClobberize is correct.
83     
84     // While read() and write() are fairly self-explanatory - they track what sorts of things the
85     // node may read or write - the def() functor is more tricky. It tells you the heap locations
86     // (not just abstract heaps) that are defined by a node. A heap location comprises an abstract
87     // heap, some nodes, and a LocationKind. Briefly, a location defined by a node is a location
88     // whose value can be deduced from looking at the node itself. The locations returned must obey
89     // the following properties:
90     //
91     // - If someone wants to CSE a load from the heap, then a HeapLocation object should be
92     //   sufficient to find a single matching node.
93     //
94     // - The abstract heap is the only abstract heap that could be clobbered to invalidate any such
95     //   CSE attempt. I.e. if clobberize() reports that on every path between some node and a node
96     //   that defines a HeapLocation that it wanted, there were no writes to any abstract heap that
97     //   overlap the location's heap, then we have a sound match. Effectively, the semantics of
98     //   write() and def() are intertwined such that for them to be sound they must agree on what
99     //   is CSEable.
100     //
101     // read(), write(), and def() for heap locations is enough to do GCSE on effectful things. To
102     // keep things simple, this code will also def() pure things. def() must be overloaded to also
103     // accept PureValue. This way, a client of clobberize() can implement GCSE entirely using the
104     // information that clobberize() passes to write() and def(). Other clients of clobberize() can
105     // just ignore def() by using a NoOpClobberize functor.
106
107     if (edgesUseStructure(graph, node))
108         read(JSCell_structureID);
109     
110     // We allow the runtime to perform a stack scan at any time. We don't model which nodes get implemented
111     // by calls into the runtime. For debugging we might replace the implementation of any node with a call
112     // to the runtime, and that call may walk stack. Therefore, each node must read() anything that a stack
113     // scan would read. That's what this does.
114     for (InlineCallFrame* inlineCallFrame = node->origin.semantic.inlineCallFrame; inlineCallFrame; inlineCallFrame = inlineCallFrame->directCaller.inlineCallFrame) {
115         if (inlineCallFrame->isClosureCall)
116             read(AbstractHeap(Stack, inlineCallFrame->stackOffset + JSStack::Callee));
117         if (inlineCallFrame->isVarargs())
118             read(AbstractHeap(Stack, inlineCallFrame->stackOffset + JSStack::ArgumentCount));
119     }
120
121     // We don't want to specifically account which nodes can read from the scope
122     // when the debugger is enabled. It's helpful to just claim all nodes do.
123     // Specifically, if a node allocates, this may call into the debugger's machinery.
124     // The debugger's machinery is free to take a stack trace and try to read from
125     // a scope which is expected to be flushed to the stack.
126     if (graph.hasDebuggerEnabled()) {
127         ASSERT(!node->origin.semantic.inlineCallFrame);
128         read(AbstractHeap(Stack, graph.m_codeBlock->scopeRegister()));
129     }
130         
131     
132     switch (node->op()) {
133     case JSConstant:
134     case DoubleConstant:
135     case Int52Constant:
136         def(PureValue(node, node->constant()));
137         return;
138
139     case Identity:
140     case Phantom:
141     case Check:
142     case ExtractOSREntryLocal:
143     case CheckStructureImmediate:
144         return;
145         
146     case LazyJSConstant:
147         // We should enable CSE of LazyJSConstant. It's a little annoying since LazyJSValue has
148         // more bits than we currently have in PureValue.
149         return;
150         
151     case ArithIMul:
152     case ArithAbs:
153     case ArithClz32:
154     case ArithMin:
155     case ArithMax:
156     case ArithPow:
157     case ArithSqrt:
158     case ArithFRound:
159     case ArithSin:
160     case ArithCos:
161     case ArithLog:
162     case GetScope:
163     case SkipScope:
164     case GetGlobalObject:
165     case StringCharCodeAt:
166     case CompareStrictEq:
167     case IsEmpty:
168     case IsUndefined:
169     case IsBoolean:
170     case IsNumber:
171     case IsString:
172     case IsObject:
173     case IsRegExpObject:
174     case LogicalNot:
175     case CheckInBounds:
176     case DoubleRep:
177     case ValueRep:
178     case Int52Rep:
179     case BooleanToNumber:
180     case FiatInt52:
181     case MakeRope:
182     case StrCat:
183     case ValueToInt32:
184     case GetExecutable:
185     case BottomValue:
186     case TypeOf:
187         def(PureValue(node));
188         return;
189
190     case BitAnd:
191     case BitOr:
192     case BitXor:
193     case BitLShift:
194     case BitRShift:
195     case BitURShift:
196         if (node->child1().useKind() == UntypedUse || node->child2().useKind() == UntypedUse) {
197             read(World);
198             write(Heap);
199             return;
200         }
201         def(PureValue(node));
202         return;
203
204     case ArithRandom:
205         read(MathDotRandomState);
206         write(MathDotRandomState);
207         return;
208         
209     case HasGenericProperty:
210     case HasStructureProperty:
211     case GetEnumerableLength:
212     case GetPropertyEnumerator: {
213         read(Heap);
214         write(SideState);
215         return;
216     }
217
218     case GetDirectPname: {
219         // This reads and writes heap because it can end up calling a generic getByVal 
220         // if the Structure changed, which could in turn end up calling a getter.
221         read(World);
222         write(Heap);
223         return;
224     }
225
226     case ToIndexString:
227     case GetEnumeratorStructurePname:
228     case GetEnumeratorGenericPname: {
229         def(PureValue(node));
230         return;
231     }
232
233     case HasIndexedProperty: {
234         read(JSObject_butterfly);
235         ArrayMode mode = node->arrayMode();
236         switch (mode.type()) {
237         case Array::Int32: {
238             if (mode.isInBounds()) {
239                 read(Butterfly_publicLength);
240                 read(IndexedInt32Properties);
241                 def(HeapLocation(HasIndexedPropertyLoc, IndexedInt32Properties, node->child1(), node->child2()), LazyNode(node));
242                 return;
243             }
244             read(Heap);
245             return;
246         }
247             
248         case Array::Double: {
249             if (mode.isInBounds()) {
250                 read(Butterfly_publicLength);
251                 read(IndexedDoubleProperties);
252                 def(HeapLocation(HasIndexedPropertyLoc, IndexedDoubleProperties, node->child1(), node->child2()), LazyNode(node));
253                 return;
254             }
255             read(Heap);
256             return;
257         }
258             
259         case Array::Contiguous: {
260             if (mode.isInBounds()) {
261                 read(Butterfly_publicLength);
262                 read(IndexedContiguousProperties);
263                 def(HeapLocation(HasIndexedPropertyLoc, IndexedContiguousProperties, node->child1(), node->child2()), LazyNode(node));
264                 return;
265             }
266             read(Heap);
267             return;
268         }
269
270         case Array::ArrayStorage: {
271             if (mode.isInBounds()) {
272                 read(Butterfly_vectorLength);
273                 read(IndexedArrayStorageProperties);
274                 return;
275             }
276             read(Heap);
277             return;
278         }
279
280         default: {
281             read(World);
282             write(Heap);
283             return;
284         }
285         }
286         RELEASE_ASSERT_NOT_REACHED();
287         return;
288     }
289
290     case StringFromCharCode:
291         switch (node->child1().useKind()) {
292         case Int32Use:
293             def(PureValue(node));
294             return;
295         case UntypedUse:
296             read(World);
297             write(Heap);
298             return;
299         default:
300             DFG_CRASH(graph, node, "Bad use kind");
301         }
302         return;
303
304     case ArithAdd:
305     case ArithNegate:
306     case ArithMod:
307     case DoubleAsInt32:
308     case UInt32ToNumber:
309         def(PureValue(node, node->arithMode()));
310         return;
311
312     case ArithDiv:
313     case ArithMul:
314     case ArithSub:
315         switch (node->binaryUseKind()) {
316         case Int32Use:
317         case Int52RepUse:
318         case DoubleRepUse:
319             def(PureValue(node, node->arithMode()));
320             return;
321         case UntypedUse:
322             read(World);
323             write(Heap);
324             return;
325         default:
326             DFG_CRASH(graph, node, "Bad use kind");
327         }
328
329     case ArithRound:
330     case ArithFloor:
331     case ArithCeil:
332     case ArithTrunc:
333         def(PureValue(node, static_cast<uintptr_t>(node->arithRoundingMode())));
334         return;
335
336     case CheckCell:
337         def(PureValue(CheckCell, AdjacencyList(AdjacencyList::Fixed, node->child1()), node->cellOperand()));
338         return;
339
340     case CheckNotEmpty:
341         def(PureValue(CheckNotEmpty, AdjacencyList(AdjacencyList::Fixed, node->child1())));
342         return;
343
344     case CheckIdent:
345         def(PureValue(CheckIdent, AdjacencyList(AdjacencyList::Fixed, node->child1()), node->uidOperand()));
346         return;
347
348     case ConstantStoragePointer:
349         def(PureValue(node, node->storagePointer()));
350         return;
351          
352     case MovHint:
353     case ZombieHint:
354     case ExitOK:
355     case KillStack:
356     case Upsilon:
357     case Phi:
358     case PhantomLocal:
359     case SetArgument:
360     case Jump:
361     case Branch:
362     case Switch:
363     case Throw:
364     case ForceOSRExit:
365     case CheckBadCell:
366     case Return:
367     case Unreachable:
368     case CheckTierUpInLoop:
369     case CheckTierUpAtReturn:
370     case CheckTierUpAndOSREnter:
371     case LoopHint:
372     case ProfileWillCall:
373     case ProfileDidCall:
374     case ProfileType:
375     case ProfileControlFlow:
376     case StoreBarrier:
377     case PutHint:
378         write(SideState);
379         return;
380         
381     case InvalidationPoint:
382         write(SideState);
383         def(HeapLocation(InvalidationPointLoc, Watchpoint_fire), LazyNode(node));
384         return;
385
386     case Flush:
387         read(AbstractHeap(Stack, node->local()));
388         write(SideState);
389         return;
390
391     case NotifyWrite:
392         write(Watchpoint_fire);
393         write(SideState);
394         return;
395
396     case CreateActivation: {
397         SymbolTable* table = node->castOperand<SymbolTable*>();
398         if (table->singletonScope()->isStillValid())
399             write(Watchpoint_fire);
400         read(HeapObjectCount);
401         write(HeapObjectCount);
402         return;
403     }
404         
405     case CreateDirectArguments:
406     case CreateScopedArguments:
407     case CreateClonedArguments:
408         read(Stack);
409         read(HeapObjectCount);
410         write(HeapObjectCount);
411         return;
412
413     case PhantomDirectArguments:
414     case PhantomClonedArguments:
415         // DFG backend requires that the locals that this reads are flushed. FTL backend can handle those
416         // locals being promoted.
417         if (!isFTL(graph.m_plan.mode))
418             read(Stack);
419         
420         // Even though it's phantom, it still has the property that one can't be replaced with another.
421         read(HeapObjectCount);
422         write(HeapObjectCount);
423         return;
424
425     case ToThis:
426     case CreateThis:
427         read(MiscFields);
428         read(HeapObjectCount);
429         write(HeapObjectCount);
430         return;
431
432     case VarInjectionWatchpoint:
433         read(MiscFields);
434         def(HeapLocation(VarInjectionWatchpointLoc, MiscFields), LazyNode(node));
435         return;
436
437     case IsObjectOrNull:
438         read(MiscFields);
439         def(HeapLocation(IsObjectOrNullLoc, MiscFields, node->child1()), LazyNode(node));
440         return;
441         
442     case IsFunction:
443         read(MiscFields);
444         def(HeapLocation(IsFunctionLoc, MiscFields, node->child1()), LazyNode(node));
445         return;
446         
447     case GetById:
448     case GetByIdFlush:
449     case GetByIdWithThis:
450     case GetByValWithThis:
451     case PutById:
452     case PutByIdWithThis:
453     case PutByValWithThis:
454     case PutByIdFlush:
455     case PutByIdDirect:
456     case PutGetterById:
457     case PutSetterById:
458     case PutGetterSetterById:
459     case PutGetterByVal:
460     case PutSetterByVal:
461     case DeleteById:
462     case DeleteByVal:
463     case ArrayPush:
464     case ArrayPop:
465     case Call:
466     case TailCallInlinedCaller:
467     case Construct:
468     case CallVarargs:
469     case CallForwardVarargs:
470     case TailCallVarargsInlinedCaller:
471     case TailCallForwardVarargsInlinedCaller:
472     case ConstructVarargs:
473     case ConstructForwardVarargs:
474     case ToPrimitive:
475     case In:
476     case ValueAdd:
477     case SetFunctionName:
478     case GetDynamicVar:
479     case PutDynamicVar:
480     case ResolveScope:
481         read(World);
482         write(Heap);
483         return;
484
485     case TailCall:
486     case TailCallVarargs:
487     case TailCallForwardVarargs:
488         read(World);
489         write(SideState);
490         return;
491         
492     case GetGetter:
493         read(GetterSetter_getter);
494         def(HeapLocation(GetterLoc, GetterSetter_getter, node->child1()), LazyNode(node));
495         return;
496         
497     case GetSetter:
498         read(GetterSetter_setter);
499         def(HeapLocation(SetterLoc, GetterSetter_setter, node->child1()), LazyNode(node));
500         return;
501         
502     case GetCallee:
503         read(AbstractHeap(Stack, JSStack::Callee));
504         def(HeapLocation(StackLoc, AbstractHeap(Stack, JSStack::Callee)), LazyNode(node));
505         return;
506         
507     case GetArgumentCount:
508         read(AbstractHeap(Stack, JSStack::ArgumentCount));
509         def(HeapLocation(StackPayloadLoc, AbstractHeap(Stack, JSStack::ArgumentCount)), LazyNode(node));
510         return;
511
512     case GetRestLength:
513         read(Stack);
514         return;
515         
516     case GetLocal:
517         read(AbstractHeap(Stack, node->local()));
518         def(HeapLocation(StackLoc, AbstractHeap(Stack, node->local())), LazyNode(node));
519         return;
520         
521     case SetLocal:
522         write(AbstractHeap(Stack, node->local()));
523         def(HeapLocation(StackLoc, AbstractHeap(Stack, node->local())), LazyNode(node->child1().node()));
524         return;
525         
526     case GetStack: {
527         AbstractHeap heap(Stack, node->stackAccessData()->local);
528         read(heap);
529         def(HeapLocation(StackLoc, heap), LazyNode(node));
530         return;
531     }
532         
533     case PutStack: {
534         AbstractHeap heap(Stack, node->stackAccessData()->local);
535         write(heap);
536         def(HeapLocation(StackLoc, heap), LazyNode(node->child1().node()));
537         return;
538     }
539         
540     case LoadVarargs: {
541         read(World);
542         write(Heap);
543         LoadVarargsData* data = node->loadVarargsData();
544         write(AbstractHeap(Stack, data->count.offset()));
545         for (unsigned i = data->limit; i--;)
546             write(AbstractHeap(Stack, data->start.offset() + static_cast<int>(i)));
547         return;
548     }
549         
550     case ForwardVarargs: {
551         // We could be way more precise here.
552         read(Stack);
553         
554         LoadVarargsData* data = node->loadVarargsData();
555         write(AbstractHeap(Stack, data->count.offset()));
556         for (unsigned i = data->limit; i--;)
557             write(AbstractHeap(Stack, data->start.offset() + static_cast<int>(i)));
558         return;
559     }
560         
561     case GetLocalUnlinked:
562         read(AbstractHeap(Stack, node->unlinkedLocal()));
563         def(HeapLocation(StackLoc, AbstractHeap(Stack, node->unlinkedLocal())), LazyNode(node));
564         return;
565         
566     case GetByVal: {
567         ArrayMode mode = node->arrayMode();
568         switch (mode.type()) {
569         case Array::SelectUsingPredictions:
570         case Array::Unprofiled:
571         case Array::SelectUsingArguments:
572             // Assume the worst since we don't have profiling yet.
573             read(World);
574             write(Heap);
575             return;
576             
577         case Array::ForceExit:
578             write(SideState);
579             return;
580             
581         case Array::Generic:
582             read(World);
583             write(Heap);
584             return;
585             
586         case Array::String:
587             if (mode.isOutOfBounds()) {
588                 read(World);
589                 write(Heap);
590                 return;
591             }
592             // This appears to read nothing because it's only reading immutable data.
593             def(PureValue(node, mode.asWord()));
594             return;
595             
596         case Array::DirectArguments:
597             read(DirectArgumentsProperties);
598             def(HeapLocation(IndexedPropertyLoc, DirectArgumentsProperties, node->child1(), node->child2()), LazyNode(node));
599             return;
600             
601         case Array::ScopedArguments:
602             read(ScopeProperties);
603             def(HeapLocation(IndexedPropertyLoc, ScopeProperties, node->child1(), node->child2()), LazyNode(node));
604             return;
605             
606         case Array::Int32:
607             if (mode.isInBounds()) {
608                 read(Butterfly_publicLength);
609                 read(IndexedInt32Properties);
610                 def(HeapLocation(IndexedPropertyLoc, IndexedInt32Properties, node->child1(), node->child2()), LazyNode(node));
611                 return;
612             }
613             read(World);
614             write(Heap);
615             return;
616             
617         case Array::Double:
618             if (mode.isInBounds()) {
619                 read(Butterfly_publicLength);
620                 read(IndexedDoubleProperties);
621                 def(HeapLocation(IndexedPropertyLoc, IndexedDoubleProperties, node->child1(), node->child2()), LazyNode(node));
622                 return;
623             }
624             read(World);
625             write(Heap);
626             return;
627             
628         case Array::Contiguous:
629             if (mode.isInBounds()) {
630                 read(Butterfly_publicLength);
631                 read(IndexedContiguousProperties);
632                 def(HeapLocation(IndexedPropertyLoc, IndexedContiguousProperties, node->child1(), node->child2()), LazyNode(node));
633                 return;
634             }
635             read(World);
636             write(Heap);
637             return;
638
639         case Array::Undecided:
640             def(PureValue(node));
641             return;
642             
643         case Array::ArrayStorage:
644         case Array::SlowPutArrayStorage:
645             if (mode.isInBounds()) {
646                 read(Butterfly_vectorLength);
647                 read(IndexedArrayStorageProperties);
648                 return;
649             }
650             read(World);
651             write(Heap);
652             return;
653             
654         case Array::Int8Array:
655         case Array::Int16Array:
656         case Array::Int32Array:
657         case Array::Uint8Array:
658         case Array::Uint8ClampedArray:
659         case Array::Uint16Array:
660         case Array::Uint32Array:
661         case Array::Float32Array:
662         case Array::Float64Array:
663             read(TypedArrayProperties);
664             read(MiscFields);
665             def(HeapLocation(IndexedPropertyLoc, TypedArrayProperties, node->child1(), node->child2()), LazyNode(node));
666             return;
667         // We should not get an AnyTypedArray in a GetByVal as AnyTypedArray is only created from intrinsics, which
668         // are only added from Inline Caching a GetById.
669         case Array::AnyTypedArray:
670             DFG_CRASH(graph, node, "impossible array mode for get");
671             return;
672         }
673         RELEASE_ASSERT_NOT_REACHED();
674         return;
675     }
676         
677     case GetMyArgumentByVal:
678     case GetMyArgumentByValOutOfBounds: {
679         read(Stack);
680         // FIXME: It would be trivial to have a def here.
681         // https://bugs.webkit.org/show_bug.cgi?id=143077
682         return;
683     }
684
685     case PutByValDirect:
686     case PutByVal:
687     case PutByValAlias: {
688         ArrayMode mode = node->arrayMode();
689         Node* base = graph.varArgChild(node, 0).node();
690         Node* index = graph.varArgChild(node, 1).node();
691         Node* value = graph.varArgChild(node, 2).node();
692         switch (mode.modeForPut().type()) {
693         case Array::SelectUsingPredictions:
694         case Array::SelectUsingArguments:
695         case Array::Unprofiled:
696         case Array::Undecided:
697             // Assume the worst since we don't have profiling yet.
698             read(World);
699             write(Heap);
700             return;
701             
702         case Array::ForceExit:
703             write(SideState);
704             return;
705             
706         case Array::Generic:
707             read(World);
708             write(Heap);
709             return;
710             
711         case Array::Int32:
712             if (node->arrayMode().isOutOfBounds()) {
713                 read(World);
714                 write(Heap);
715                 return;
716             }
717             read(Butterfly_publicLength);
718             read(Butterfly_vectorLength);
719             read(IndexedInt32Properties);
720             write(IndexedInt32Properties);
721             if (node->arrayMode().mayStoreToHole())
722                 write(Butterfly_publicLength);
723             def(HeapLocation(IndexedPropertyLoc, IndexedInt32Properties, base, index), LazyNode(value));
724             return;
725             
726         case Array::Double:
727             if (node->arrayMode().isOutOfBounds()) {
728                 read(World);
729                 write(Heap);
730                 return;
731             }
732             read(Butterfly_publicLength);
733             read(Butterfly_vectorLength);
734             read(IndexedDoubleProperties);
735             write(IndexedDoubleProperties);
736             if (node->arrayMode().mayStoreToHole())
737                 write(Butterfly_publicLength);
738             def(HeapLocation(IndexedPropertyLoc, IndexedDoubleProperties, base, index), LazyNode(value));
739             return;
740             
741         case Array::Contiguous:
742             if (node->arrayMode().isOutOfBounds()) {
743                 read(World);
744                 write(Heap);
745                 return;
746             }
747             read(Butterfly_publicLength);
748             read(Butterfly_vectorLength);
749             read(IndexedContiguousProperties);
750             write(IndexedContiguousProperties);
751             if (node->arrayMode().mayStoreToHole())
752                 write(Butterfly_publicLength);
753             def(HeapLocation(IndexedPropertyLoc, IndexedContiguousProperties, base, index), LazyNode(value));
754             return;
755             
756         case Array::ArrayStorage:
757         case Array::SlowPutArrayStorage:
758             // Give up on life for now.
759             read(World);
760             write(Heap);
761             return;
762
763         case Array::Int8Array:
764         case Array::Int16Array:
765         case Array::Int32Array:
766         case Array::Uint8Array:
767         case Array::Uint8ClampedArray:
768         case Array::Uint16Array:
769         case Array::Uint32Array:
770         case Array::Float32Array:
771         case Array::Float64Array:
772             read(MiscFields);
773             write(TypedArrayProperties);
774             // FIXME: We can't def() anything here because these operations truncate their inputs.
775             // https://bugs.webkit.org/show_bug.cgi?id=134737
776             return;
777         case Array::AnyTypedArray:
778         case Array::String:
779         case Array::DirectArguments:
780         case Array::ScopedArguments:
781             DFG_CRASH(graph, node, "impossible array mode for put");
782             return;
783         }
784         RELEASE_ASSERT_NOT_REACHED();
785         return;
786     }
787         
788     case CheckStructure:
789         read(JSCell_structureID);
790         return;
791
792     case CheckArray:
793         read(JSCell_indexingType);
794         read(JSCell_typeInfoType);
795         read(JSCell_structureID);
796         return;
797
798     case CheckTypeInfoFlags:
799         read(JSCell_typeInfoFlags);
800         def(HeapLocation(CheckTypeInfoFlagsLoc, JSCell_typeInfoFlags, node->child1()), LazyNode(node));
801         return;
802
803     case OverridesHasInstance:
804         read(JSCell_typeInfoFlags);
805         def(HeapLocation(OverridesHasInstanceLoc, JSCell_typeInfoFlags, node->child1()), LazyNode(node));
806         return;
807
808     case InstanceOf:
809         read(JSCell_structureID);
810         def(HeapLocation(InstanceOfLoc, JSCell_structureID, node->child1(), node->child2()), LazyNode(node));
811         return;
812
813     case InstanceOfCustom:
814         read(World);
815         write(Heap);
816         return;
817
818     case PutStructure:
819         write(JSCell_structureID);
820         write(JSCell_typeInfoType);
821         write(JSCell_typeInfoFlags);
822         write(JSCell_indexingType);
823         return;
824         
825     case AllocatePropertyStorage:
826         write(JSObject_butterfly);
827         def(HeapLocation(ButterflyLoc, JSObject_butterfly, node->child1()), LazyNode(node));
828         return;
829         
830     case ReallocatePropertyStorage:
831         read(JSObject_butterfly);
832         write(JSObject_butterfly);
833         def(HeapLocation(ButterflyLoc, JSObject_butterfly, node->child1()), LazyNode(node));
834         return;
835         
836     case GetButterfly:
837         read(JSObject_butterfly);
838         def(HeapLocation(ButterflyLoc, JSObject_butterfly, node->child1()), LazyNode(node));
839         return;
840
841     case Arrayify:
842     case ArrayifyToStructure:
843         read(JSCell_structureID);
844         read(JSCell_indexingType);
845         read(JSObject_butterfly);
846         write(JSCell_structureID);
847         write(JSCell_indexingType);
848         write(JSObject_butterfly);
849         write(Watchpoint_fire);
850         return;
851         
852     case GetIndexedPropertyStorage:
853         if (node->arrayMode().type() == Array::String) {
854             def(PureValue(node, node->arrayMode().asWord()));
855             return;
856         }
857         read(MiscFields);
858         def(HeapLocation(IndexedPropertyStorageLoc, MiscFields, node->child1()), LazyNode(node));
859         return;
860         
861     case GetTypedArrayByteOffset:
862         read(MiscFields);
863         def(HeapLocation(TypedArrayByteOffsetLoc, MiscFields, node->child1()), LazyNode(node));
864         return;
865         
866     case GetByOffset:
867     case GetGetterSetterByOffset: {
868         unsigned identifierNumber = node->storageAccessData().identifierNumber;
869         AbstractHeap heap(NamedProperties, identifierNumber);
870         read(heap);
871         def(HeapLocation(NamedPropertyLoc, heap, node->child2()), LazyNode(node));
872         return;
873     }
874
875     case TryGetById: {
876         read(Heap);
877         return;
878     }
879
880     case MultiGetByOffset: {
881         read(JSCell_structureID);
882         read(JSObject_butterfly);
883         AbstractHeap heap(NamedProperties, node->multiGetByOffsetData().identifierNumber);
884         read(heap);
885         def(HeapLocation(NamedPropertyLoc, heap, node->child1()), LazyNode(node));
886         return;
887     }
888         
889     case MultiPutByOffset: {
890         read(JSCell_structureID);
891         read(JSObject_butterfly);
892         AbstractHeap heap(NamedProperties, node->multiPutByOffsetData().identifierNumber);
893         write(heap);
894         if (node->multiPutByOffsetData().writesStructures())
895             write(JSCell_structureID);
896         if (node->multiPutByOffsetData().reallocatesStorage())
897             write(JSObject_butterfly);
898         def(HeapLocation(NamedPropertyLoc, heap, node->child1()), LazyNode(node->child2().node()));
899         return;
900     }
901         
902     case PutByOffset: {
903         unsigned identifierNumber = node->storageAccessData().identifierNumber;
904         AbstractHeap heap(NamedProperties, identifierNumber);
905         write(heap);
906         def(HeapLocation(NamedPropertyLoc, heap, node->child2()), LazyNode(node->child3().node()));
907         return;
908     }
909         
910     case GetArrayLength: {
911         ArrayMode mode = node->arrayMode();
912         switch (mode.type()) {
913         case Array::Int32:
914         case Array::Double:
915         case Array::Contiguous:
916         case Array::ArrayStorage:
917         case Array::SlowPutArrayStorage:
918             read(Butterfly_publicLength);
919             def(HeapLocation(ArrayLengthLoc, Butterfly_publicLength, node->child1()), LazyNode(node));
920             return;
921             
922         case Array::String:
923             def(PureValue(node, mode.asWord()));
924             return;
925
926         case Array::DirectArguments:
927         case Array::ScopedArguments:
928             read(MiscFields);
929             def(HeapLocation(ArrayLengthLoc, MiscFields, node->child1()), LazyNode(node));
930             return;
931
932         default:
933             ASSERT(mode.isSomeTypedArrayView());
934             read(MiscFields);
935             def(HeapLocation(ArrayLengthLoc, MiscFields, node->child1()), LazyNode(node));
936             return;
937         }
938     }
939         
940     case GetClosureVar:
941         read(AbstractHeap(ScopeProperties, node->scopeOffset().offset()));
942         def(HeapLocation(ClosureVariableLoc, AbstractHeap(ScopeProperties, node->scopeOffset().offset()), node->child1()), LazyNode(node));
943         return;
944         
945     case PutClosureVar:
946         write(AbstractHeap(ScopeProperties, node->scopeOffset().offset()));
947         def(HeapLocation(ClosureVariableLoc, AbstractHeap(ScopeProperties, node->scopeOffset().offset()), node->child1()), LazyNode(node->child2().node()));
948         return;
949
950     case GetRegExpObjectLastIndex:
951         read(RegExpObject_lastIndex);
952         def(HeapLocation(RegExpObjectLastIndexLoc, RegExpObject_lastIndex, node->child1()), LazyNode(node));
953         return;
954
955     case SetRegExpObjectLastIndex:
956         write(RegExpObject_lastIndex);
957         def(HeapLocation(RegExpObjectLastIndexLoc, RegExpObject_lastIndex, node->child1()), LazyNode(node->child2().node()));
958         return;
959
960     case RecordRegExpCachedResult:
961         write(RegExpState);
962         return;
963         
964     case GetFromArguments: {
965         AbstractHeap heap(DirectArgumentsProperties, node->capturedArgumentsOffset().offset());
966         read(heap);
967         def(HeapLocation(DirectArgumentsLoc, heap, node->child1()), LazyNode(node));
968         return;
969     }
970         
971     case PutToArguments: {
972         AbstractHeap heap(DirectArgumentsProperties, node->capturedArgumentsOffset().offset());
973         write(heap);
974         def(HeapLocation(DirectArgumentsLoc, heap, node->child1()), LazyNode(node->child2().node()));
975         return;
976     }
977         
978     case GetGlobalVar:
979     case GetGlobalLexicalVariable:
980         read(AbstractHeap(Absolute, node->variablePointer()));
981         def(HeapLocation(GlobalVariableLoc, AbstractHeap(Absolute, node->variablePointer())), LazyNode(node));
982         return;
983         
984     case PutGlobalVariable:
985         write(AbstractHeap(Absolute, node->variablePointer()));
986         def(HeapLocation(GlobalVariableLoc, AbstractHeap(Absolute, node->variablePointer())), LazyNode(node->child2().node()));
987         return;
988
989     case NewArrayWithSize:
990     case NewTypedArray:
991         read(HeapObjectCount);
992         write(HeapObjectCount);
993         return;
994
995     case NewArray: {
996         read(HeapObjectCount);
997         write(HeapObjectCount);
998
999         unsigned numElements = node->numChildren();
1000
1001         def(HeapLocation(ArrayLengthLoc, Butterfly_publicLength, node),
1002             LazyNode(graph.freeze(jsNumber(numElements))));
1003
1004         if (!numElements)
1005             return;
1006
1007         AbstractHeap heap;
1008         switch (node->indexingType()) {
1009         case ALL_DOUBLE_INDEXING_TYPES:
1010             heap = IndexedDoubleProperties;
1011             break;
1012
1013         case ALL_INT32_INDEXING_TYPES:
1014             heap = IndexedInt32Properties;
1015             break;
1016
1017         case ALL_CONTIGUOUS_INDEXING_TYPES:
1018             heap = IndexedContiguousProperties;
1019             break;
1020
1021         default:
1022             return;
1023         }
1024
1025         if (numElements < graph.m_uint32ValuesInUse.size()) {
1026             for (unsigned operandIdx = 0; operandIdx < numElements; ++operandIdx) {
1027                 Edge use = graph.m_varArgChildren[node->firstChild() + operandIdx];
1028                 def(HeapLocation(IndexedPropertyLoc, heap, node, LazyNode(graph.freeze(jsNumber(operandIdx)))),
1029                     LazyNode(use.node()));
1030             }
1031         } else {
1032             for (uint32_t operandIdx : graph.m_uint32ValuesInUse) {
1033                 if (operandIdx >= numElements)
1034                     continue;
1035                 Edge use = graph.m_varArgChildren[node->firstChild() + operandIdx];
1036                 // operandIdx comes from graph.m_uint32ValuesInUse and thus is guaranteed to be already frozen
1037                 def(HeapLocation(IndexedPropertyLoc, heap, node, LazyNode(graph.freeze(jsNumber(operandIdx)))),
1038                     LazyNode(use.node()));
1039             }
1040         }
1041         return;
1042     }
1043
1044     case NewArrayBuffer: {
1045         read(HeapObjectCount);
1046         write(HeapObjectCount);
1047
1048         unsigned numElements = node->numConstants();
1049         def(HeapLocation(ArrayLengthLoc, Butterfly_publicLength, node),
1050             LazyNode(graph.freeze(jsNumber(numElements))));
1051
1052         AbstractHeap heap;
1053         NodeType op = JSConstant;
1054         switch (node->indexingType()) {
1055         case ALL_DOUBLE_INDEXING_TYPES:
1056             heap = IndexedDoubleProperties;
1057             op = DoubleConstant;
1058             break;
1059
1060         case ALL_INT32_INDEXING_TYPES:
1061             heap = IndexedInt32Properties;
1062             break;
1063
1064         case ALL_CONTIGUOUS_INDEXING_TYPES:
1065             heap = IndexedContiguousProperties;
1066             break;
1067
1068         default:
1069             return;
1070         }
1071
1072         JSValue* data = graph.m_codeBlock->constantBuffer(node->startConstant());
1073         if (numElements < graph.m_uint32ValuesInUse.size()) {
1074             for (unsigned index = 0; index < numElements; ++index) {
1075                 def(HeapLocation(IndexedPropertyLoc, heap, node, LazyNode(graph.freeze(jsNumber(index)))),
1076                     LazyNode(graph.freeze(data[index]), op));
1077             }
1078         } else {
1079             Vector<uint32_t> possibleIndices;
1080             for (uint32_t index : graph.m_uint32ValuesInUse) {
1081                 if (index >= numElements)
1082                     continue;
1083                 possibleIndices.append(index);
1084             }
1085             for (uint32_t index : possibleIndices) {
1086                 def(HeapLocation(IndexedPropertyLoc, heap, node, LazyNode(graph.freeze(jsNumber(index)))),
1087                     LazyNode(graph.freeze(data[index]), op));
1088             }
1089         }
1090         return;
1091     }
1092
1093     case CopyRest: {
1094         read(Stack);
1095         write(Heap);
1096         return;
1097     }
1098
1099     case NewObject:
1100     case NewRegexp:
1101     case NewStringObject:
1102     case PhantomNewObject:
1103     case MaterializeNewObject:
1104     case PhantomNewFunction:
1105     case PhantomNewGeneratorFunction:
1106     case PhantomCreateActivation:
1107     case MaterializeCreateActivation:
1108         read(HeapObjectCount);
1109         write(HeapObjectCount);
1110         return;
1111
1112     case NewFunction:
1113     case NewGeneratorFunction:
1114         if (node->castOperand<FunctionExecutable*>()->singletonFunction()->isStillValid())
1115             write(Watchpoint_fire);
1116         read(HeapObjectCount);
1117         write(HeapObjectCount);
1118         return;
1119
1120     case RegExpExec:
1121     case RegExpTest:
1122         if (node->child2().useKind() == RegExpObjectUse
1123             && node->child3().useKind() == StringUse) {
1124             read(RegExpState);
1125             read(RegExpObject_lastIndex);
1126             write(RegExpState);
1127             write(RegExpObject_lastIndex);
1128             return;
1129         }
1130         read(World);
1131         write(Heap);
1132         return;
1133
1134     case StringReplace:
1135     case StringReplaceRegExp:
1136         if (node->child1().useKind() == StringUse
1137             && node->child2().useKind() == RegExpObjectUse
1138             && node->child3().useKind() == StringUse) {
1139             read(RegExpState);
1140             read(RegExpObject_lastIndex);
1141             write(RegExpState);
1142             write(RegExpObject_lastIndex);
1143             return;
1144         }
1145         read(World);
1146         write(Heap);
1147         return;
1148
1149     case StringCharAt:
1150         if (node->arrayMode().isOutOfBounds()) {
1151             read(World);
1152             write(Heap);
1153             return;
1154         }
1155         def(PureValue(node));
1156         return;
1157         
1158     case CompareEq:
1159     case CompareLess:
1160     case CompareLessEq:
1161     case CompareGreater:
1162     case CompareGreaterEq:
1163         if (node->isBinaryUseKind(StringUse)) {
1164             read(HeapObjectCount);
1165             write(HeapObjectCount);
1166             return;
1167         }
1168         if (!node->isBinaryUseKind(UntypedUse)) {
1169             def(PureValue(node));
1170             return;
1171         }
1172         read(World);
1173         write(Heap);
1174         return;
1175         
1176     case ToString:
1177     case CallStringConstructor:
1178         switch (node->child1().useKind()) {
1179         case StringObjectUse:
1180         case StringOrStringObjectUse:
1181             // These don't def a pure value, unfortunately. I'll avoid load-eliminating these for
1182             // now.
1183             return;
1184             
1185         case CellUse:
1186         case UntypedUse:
1187             read(World);
1188             write(Heap);
1189             return;
1190             
1191         default:
1192             RELEASE_ASSERT_NOT_REACHED();
1193             return;
1194         }
1195         
1196     case ThrowReferenceError:
1197         write(SideState);
1198         return;
1199         
1200     case CountExecution:
1201     case CheckWatchdogTimer:
1202         read(InternalState);
1203         write(InternalState);
1204         return;
1205         
1206     case LogShadowChickenPrologue:
1207     case LogShadowChickenTail:
1208         write(SideState);
1209         return;
1210         
1211     case LastNodeType:
1212         RELEASE_ASSERT_NOT_REACHED();
1213         return;
1214     }
1215     
1216     DFG_CRASH(graph, node, toCString("Unrecognized node type: ", Graph::opName(node->op())).data());
1217 }
1218
1219 class NoOpClobberize {
1220 public:
1221     NoOpClobberize() { }
1222     template<typename... T>
1223     void operator()(T...) const { }
1224 };
1225
1226 class CheckClobberize {
1227 public:
1228     CheckClobberize()
1229         : m_result(false)
1230     {
1231     }
1232     
1233     template<typename... T>
1234     void operator()(T...) const { m_result = true; }
1235     
1236     bool result() const { return m_result; }
1237     
1238 private:
1239     mutable bool m_result;
1240 };
1241
1242 bool doesWrites(Graph&, Node*);
1243
1244 class AbstractHeapOverlaps {
1245 public:
1246     AbstractHeapOverlaps(AbstractHeap heap)
1247         : m_heap(heap)
1248         , m_result(false)
1249     {
1250     }
1251     
1252     void operator()(AbstractHeap otherHeap) const
1253     {
1254         if (m_result)
1255             return;
1256         m_result = m_heap.overlaps(otherHeap);
1257     }
1258     
1259     bool result() const { return m_result; }
1260
1261 private:
1262     AbstractHeap m_heap;
1263     mutable bool m_result;
1264 };
1265
1266 bool accessesOverlap(Graph&, Node*, AbstractHeap);
1267 bool writesOverlap(Graph&, Node*, AbstractHeap);
1268
1269 bool clobbersHeap(Graph&, Node*);
1270
1271 // We would have used bind() for these, but because of the overlaoding that we are doing,
1272 // it's quite a bit of clearer to just write this out the traditional way.
1273
1274 template<typename T>
1275 class ReadMethodClobberize {
1276 public:
1277     ReadMethodClobberize(T& value)
1278         : m_value(value)
1279     {
1280     }
1281     
1282     void operator()(AbstractHeap heap) const
1283     {
1284         m_value.read(heap);
1285     }
1286 private:
1287     T& m_value;
1288 };
1289
1290 template<typename T>
1291 class WriteMethodClobberize {
1292 public:
1293     WriteMethodClobberize(T& value)
1294         : m_value(value)
1295     {
1296     }
1297     
1298     void operator()(AbstractHeap heap) const
1299     {
1300         m_value.write(heap);
1301     }
1302 private:
1303     T& m_value;
1304 };
1305
1306 template<typename T>
1307 class DefMethodClobberize {
1308 public:
1309     DefMethodClobberize(T& value)
1310         : m_value(value)
1311     {
1312     }
1313     
1314     void operator()(PureValue value) const
1315     {
1316         m_value.def(value);
1317     }
1318     
1319     void operator()(HeapLocation location, LazyNode node) const
1320     {
1321         m_value.def(location, node);
1322     }
1323
1324 private:
1325     T& m_value;
1326 };
1327
1328 template<typename Adaptor>
1329 void clobberize(Graph& graph, Node* node, Adaptor& adaptor)
1330 {
1331     ReadMethodClobberize<Adaptor> read(adaptor);
1332     WriteMethodClobberize<Adaptor> write(adaptor);
1333     DefMethodClobberize<Adaptor> def(adaptor);
1334     clobberize(graph, node, read, write, def);
1335 }
1336
1337 } } // namespace JSC::DFG
1338
1339 #endif // ENABLE(DFG_JIT)
1340
1341 #endif // DFGClobberize_h
1342