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