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