2 * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
26 #ifndef DFGClobberize_h
27 #define DFGClobberize_h
31 #include "DFGAbstractHeap.h"
32 #include "DFGEdgeUsesStructure.h"
34 #include "DFGHeapLocation.h"
35 #include "DFGLazyNode.h"
36 #include "DFGPureValue.h"
38 namespace JSC { namespace DFG {
40 template<typename ReadFunctor, typename WriteFunctor, typename DefFunctor>
41 void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFunctor& write, const DefFunctor& def)
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.
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.
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
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.
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
73 // - Broadly, we don't say that we're reading something if that something is
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
81 // - If you do read(Stack) or read(World), then make sure that readTop() in
82 // PreciseLocalClobberize is correct.
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:
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.
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
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.
107 if (edgesUseStructure(graph, node))
108 read(JSCell_structureID);
110 switch (node->op()) {
114 def(PureValue(node, node->constant()));
120 case ExtractOSREntryLocal:
121 case CheckStructureImmediate:
125 // We should enable CSE of LazyJSConstant. It's a little annoying since LazyJSValue has
126 // more bits than we currently have in PureValue.
142 case GetGlobalObject:
143 case StringCharCodeAt:
144 case CompareStrictEq:
155 case BooleanToNumber:
163 def(PureValue(node));
172 if (node->child1().useKind() == UntypedUse || node->child2().useKind() == UntypedUse) {
177 def(PureValue(node));
181 read(MathDotRandomState);
182 write(MathDotRandomState);
185 case HasGenericProperty:
186 case HasStructureProperty:
187 case GetEnumerableLength:
188 case GetPropertyEnumerator: {
194 case GetDirectPname: {
195 // This reads and writes heap because it can end up calling a generic getByVal
196 // if the Structure changed, which could in turn end up calling a getter.
203 case GetEnumeratorStructurePname:
204 case GetEnumeratorGenericPname: {
205 def(PureValue(node));
209 case HasIndexedProperty: {
210 read(JSObject_butterfly);
211 ArrayMode mode = node->arrayMode();
212 switch (mode.type()) {
214 if (mode.isInBounds()) {
215 read(Butterfly_publicLength);
216 read(IndexedInt32Properties);
217 def(HeapLocation(HasIndexedPropertyLoc, IndexedInt32Properties, node->child1(), node->child2()), LazyNode(node));
224 case Array::Double: {
225 if (mode.isInBounds()) {
226 read(Butterfly_publicLength);
227 read(IndexedDoubleProperties);
228 def(HeapLocation(HasIndexedPropertyLoc, IndexedDoubleProperties, node->child1(), node->child2()), LazyNode(node));
235 case Array::Contiguous: {
236 if (mode.isInBounds()) {
237 read(Butterfly_publicLength);
238 read(IndexedContiguousProperties);
239 def(HeapLocation(HasIndexedPropertyLoc, IndexedContiguousProperties, node->child1(), node->child2()), LazyNode(node));
246 case Array::ArrayStorage: {
247 if (mode.isInBounds()) {
248 read(Butterfly_vectorLength);
249 read(IndexedArrayStorageProperties);
262 RELEASE_ASSERT_NOT_REACHED();
266 case StringFromCharCode:
267 switch (node->child1().useKind()) {
269 def(PureValue(node));
276 DFG_CRASH(graph, node, "Bad use kind");
285 def(PureValue(node, node->arithMode()));
291 switch (node->binaryUseKind()) {
295 def(PureValue(node, node->arithMode()));
302 DFG_CRASH(graph, node, "Bad use kind");
308 def(PureValue(node, static_cast<uintptr_t>(node->arithRoundingMode())));
312 def(PureValue(CheckCell, AdjacencyList(AdjacencyList::Fixed, node->child1()), node->cellOperand()));
316 def(PureValue(CheckNotEmpty, AdjacencyList(AdjacencyList::Fixed, node->child1())));
320 def(PureValue(CheckIdent, AdjacencyList(AdjacencyList::Fixed, node->child1()), node->uidOperand()));
323 case ConstantStoragePointer:
324 def(PureValue(node, node->storagePointer()));
343 case CheckTierUpInLoop:
344 case CheckTierUpAtReturn:
345 case CheckTierUpAndOSREnter:
348 case ProfileWillCall:
351 case ProfileControlFlow:
357 case InvalidationPoint:
359 def(HeapLocation(InvalidationPointLoc, Watchpoint_fire), LazyNode(node));
363 read(AbstractHeap(Stack, node->local()));
368 write(Watchpoint_fire);
372 case CreateActivation: {
373 SymbolTable* table = node->castOperand<SymbolTable*>();
374 if (table->singletonScope()->isStillValid())
375 write(Watchpoint_fire);
376 read(HeapObjectCount);
377 write(HeapObjectCount);
381 case CreateDirectArguments:
382 case CreateScopedArguments:
383 case CreateClonedArguments:
385 read(HeapObjectCount);
386 write(HeapObjectCount);
389 case PhantomDirectArguments:
390 case PhantomClonedArguments:
391 // DFG backend requires that the locals that this reads are flushed. FTL backend can handle those
392 // locals being promoted.
393 if (!isFTL(graph.m_plan.mode))
396 // Even though it's phantom, it still has the property that one can't be replaced with another.
397 read(HeapObjectCount);
398 write(HeapObjectCount);
404 read(HeapObjectCount);
405 write(HeapObjectCount);
408 case VarInjectionWatchpoint:
410 def(HeapLocation(VarInjectionWatchpointLoc, MiscFields), LazyNode(node));
415 def(HeapLocation(IsObjectOrNullLoc, MiscFields, node->child1()), LazyNode(node));
420 def(HeapLocation(IsFunctionLoc, MiscFields, node->child1()), LazyNode(node));
430 case PutGetterSetterById:
436 case TailCallInlinedCaller:
439 case CallForwardVarargs:
440 case TailCallVarargsInlinedCaller:
441 case TailCallForwardVarargsInlinedCaller:
442 case ConstructVarargs:
443 case ConstructForwardVarargs:
452 case TailCallVarargs:
453 case TailCallForwardVarargs:
459 read(GetterSetter_getter);
460 def(HeapLocation(GetterLoc, GetterSetter_getter, node->child1()), LazyNode(node));
464 read(GetterSetter_setter);
465 def(HeapLocation(SetterLoc, GetterSetter_setter, node->child1()), LazyNode(node));
469 read(AbstractHeap(Stack, JSStack::Callee));
470 def(HeapLocation(StackLoc, AbstractHeap(Stack, JSStack::Callee)), LazyNode(node));
473 case GetArgumentCount:
474 read(AbstractHeap(Stack, JSStack::ArgumentCount));
475 def(HeapLocation(StackPayloadLoc, AbstractHeap(Stack, JSStack::ArgumentCount)), LazyNode(node));
483 read(AbstractHeap(Stack, node->local()));
484 def(HeapLocation(StackLoc, AbstractHeap(Stack, node->local())), LazyNode(node));
488 write(AbstractHeap(Stack, node->local()));
489 def(HeapLocation(StackLoc, AbstractHeap(Stack, node->local())), LazyNode(node->child1().node()));
493 AbstractHeap heap(Stack, node->stackAccessData()->local);
495 def(HeapLocation(StackLoc, heap), LazyNode(node));
500 AbstractHeap heap(Stack, node->stackAccessData()->local);
502 def(HeapLocation(StackLoc, heap), LazyNode(node->child1().node()));
509 LoadVarargsData* data = node->loadVarargsData();
510 write(AbstractHeap(Stack, data->count.offset()));
511 for (unsigned i = data->limit; i--;)
512 write(AbstractHeap(Stack, data->start.offset() + static_cast<int>(i)));
516 case ForwardVarargs: {
517 // We could be way more precise here.
520 LoadVarargsData* data = node->loadVarargsData();
521 write(AbstractHeap(Stack, data->count.offset()));
522 for (unsigned i = data->limit; i--;)
523 write(AbstractHeap(Stack, data->start.offset() + static_cast<int>(i)));
527 case GetLocalUnlinked:
528 read(AbstractHeap(Stack, node->unlinkedLocal()));
529 def(HeapLocation(StackLoc, AbstractHeap(Stack, node->unlinkedLocal())), LazyNode(node));
533 ArrayMode mode = node->arrayMode();
534 switch (mode.type()) {
535 case Array::SelectUsingPredictions:
536 case Array::Unprofiled:
537 case Array::SelectUsingArguments:
538 // Assume the worst since we don't have profiling yet.
543 case Array::ForceExit:
553 if (mode.isOutOfBounds()) {
558 // This appears to read nothing because it's only reading immutable data.
559 def(PureValue(node, mode.asWord()));
562 case Array::DirectArguments:
563 read(DirectArgumentsProperties);
564 def(HeapLocation(IndexedPropertyLoc, DirectArgumentsProperties, node->child1(), node->child2()), LazyNode(node));
567 case Array::ScopedArguments:
568 read(ScopeProperties);
569 def(HeapLocation(IndexedPropertyLoc, ScopeProperties, node->child1(), node->child2()), LazyNode(node));
573 if (mode.isInBounds()) {
574 read(Butterfly_publicLength);
575 read(IndexedInt32Properties);
576 def(HeapLocation(IndexedPropertyLoc, IndexedInt32Properties, node->child1(), node->child2()), LazyNode(node));
584 if (mode.isInBounds()) {
585 read(Butterfly_publicLength);
586 read(IndexedDoubleProperties);
587 def(HeapLocation(IndexedPropertyLoc, IndexedDoubleProperties, node->child1(), node->child2()), LazyNode(node));
594 case Array::Contiguous:
595 if (mode.isInBounds()) {
596 read(Butterfly_publicLength);
597 read(IndexedContiguousProperties);
598 def(HeapLocation(IndexedPropertyLoc, IndexedContiguousProperties, node->child1(), node->child2()), LazyNode(node));
605 case Array::Undecided:
606 def(PureValue(node));
609 case Array::ArrayStorage:
610 case Array::SlowPutArrayStorage:
611 if (mode.isInBounds()) {
612 read(Butterfly_vectorLength);
613 read(IndexedArrayStorageProperties);
620 case Array::Int8Array:
621 case Array::Int16Array:
622 case Array::Int32Array:
623 case Array::Uint8Array:
624 case Array::Uint8ClampedArray:
625 case Array::Uint16Array:
626 case Array::Uint32Array:
627 case Array::Float32Array:
628 case Array::Float64Array:
629 read(TypedArrayProperties);
631 def(HeapLocation(IndexedPropertyLoc, TypedArrayProperties, node->child1(), node->child2()), LazyNode(node));
633 // We should not get an AnyTypedArray in a GetByVal as AnyTypedArray is only created from intrinsics, which
634 // are only added from Inline Caching a GetById.
635 case Array::AnyTypedArray:
636 DFG_CRASH(graph, node, "impossible array mode for get");
639 RELEASE_ASSERT_NOT_REACHED();
643 case GetMyArgumentByVal: {
645 // FIXME: It would be trivial to have a def here.
646 // https://bugs.webkit.org/show_bug.cgi?id=143077
652 case PutByValAlias: {
653 ArrayMode mode = node->arrayMode();
654 Node* base = graph.varArgChild(node, 0).node();
655 Node* index = graph.varArgChild(node, 1).node();
656 Node* value = graph.varArgChild(node, 2).node();
657 switch (mode.modeForPut().type()) {
658 case Array::SelectUsingPredictions:
659 case Array::SelectUsingArguments:
660 case Array::Unprofiled:
661 case Array::Undecided:
662 // Assume the worst since we don't have profiling yet.
667 case Array::ForceExit:
677 if (node->arrayMode().isOutOfBounds()) {
682 read(Butterfly_publicLength);
683 read(Butterfly_vectorLength);
684 read(IndexedInt32Properties);
685 write(IndexedInt32Properties);
686 if (node->arrayMode().mayStoreToHole())
687 write(Butterfly_publicLength);
688 def(HeapLocation(IndexedPropertyLoc, IndexedInt32Properties, base, index), LazyNode(value));
692 if (node->arrayMode().isOutOfBounds()) {
697 read(Butterfly_publicLength);
698 read(Butterfly_vectorLength);
699 read(IndexedDoubleProperties);
700 write(IndexedDoubleProperties);
701 if (node->arrayMode().mayStoreToHole())
702 write(Butterfly_publicLength);
703 def(HeapLocation(IndexedPropertyLoc, IndexedDoubleProperties, base, index), LazyNode(value));
706 case Array::Contiguous:
707 if (node->arrayMode().isOutOfBounds()) {
712 read(Butterfly_publicLength);
713 read(Butterfly_vectorLength);
714 read(IndexedContiguousProperties);
715 write(IndexedContiguousProperties);
716 if (node->arrayMode().mayStoreToHole())
717 write(Butterfly_publicLength);
718 def(HeapLocation(IndexedPropertyLoc, IndexedContiguousProperties, base, index), LazyNode(value));
721 case Array::ArrayStorage:
722 case Array::SlowPutArrayStorage:
723 // Give up on life for now.
728 case Array::Int8Array:
729 case Array::Int16Array:
730 case Array::Int32Array:
731 case Array::Uint8Array:
732 case Array::Uint8ClampedArray:
733 case Array::Uint16Array:
734 case Array::Uint32Array:
735 case Array::Float32Array:
736 case Array::Float64Array:
738 write(TypedArrayProperties);
739 // FIXME: We can't def() anything here because these operations truncate their inputs.
740 // https://bugs.webkit.org/show_bug.cgi?id=134737
742 case Array::AnyTypedArray:
744 case Array::DirectArguments:
745 case Array::ScopedArguments:
746 DFG_CRASH(graph, node, "impossible array mode for put");
749 RELEASE_ASSERT_NOT_REACHED();
754 read(JSCell_structureID);
758 read(JSCell_indexingType);
759 read(JSCell_typeInfoType);
760 read(JSCell_structureID);
763 case CheckTypeInfoFlags:
764 read(JSCell_typeInfoFlags);
765 def(HeapLocation(CheckTypeInfoFlagsLoc, JSCell_typeInfoFlags, node->child1()), LazyNode(node));
768 case OverridesHasInstance:
769 read(JSCell_typeInfoFlags);
770 def(HeapLocation(OverridesHasInstanceLoc, JSCell_typeInfoFlags, node->child1()), LazyNode(node));
774 read(JSCell_structureID);
775 def(HeapLocation(InstanceOfLoc, JSCell_structureID, node->child1(), node->child2()), LazyNode(node));
778 case InstanceOfCustom:
784 write(JSCell_structureID);
785 write(JSCell_typeInfoType);
786 write(JSCell_typeInfoFlags);
787 write(JSCell_indexingType);
790 case AllocatePropertyStorage:
791 write(JSObject_butterfly);
792 def(HeapLocation(ButterflyLoc, JSObject_butterfly, node->child1()), LazyNode(node));
795 case ReallocatePropertyStorage:
796 read(JSObject_butterfly);
797 write(JSObject_butterfly);
798 def(HeapLocation(ButterflyLoc, JSObject_butterfly, node->child1()), LazyNode(node));
802 read(JSObject_butterfly);
803 def(HeapLocation(ButterflyLoc, JSObject_butterfly, node->child1()), LazyNode(node));
806 case GetButterflyReadOnly:
807 // This rule is separate to prevent CSE of GetButterfly with GetButterflyReadOnly. But in reality,
808 // this works because we don't introduce GetButterflyReadOnly until the bitter end of compilation.
809 read(JSObject_butterfly);
810 def(HeapLocation(ButterflyReadOnlyLoc, JSObject_butterfly, node->child1()), LazyNode(node));
814 case ArrayifyToStructure:
815 read(JSCell_structureID);
816 read(JSCell_indexingType);
817 read(JSObject_butterfly);
818 write(JSCell_structureID);
819 write(JSCell_indexingType);
820 write(JSObject_butterfly);
821 write(Watchpoint_fire);
824 case GetIndexedPropertyStorage:
825 if (node->arrayMode().type() == Array::String) {
826 def(PureValue(node, node->arrayMode().asWord()));
830 def(HeapLocation(IndexedPropertyStorageLoc, MiscFields, node->child1()), LazyNode(node));
833 case GetTypedArrayByteOffset:
835 def(HeapLocation(TypedArrayByteOffsetLoc, MiscFields, node->child1()), LazyNode(node));
839 case GetGetterSetterByOffset: {
840 unsigned identifierNumber = node->storageAccessData().identifierNumber;
841 AbstractHeap heap(NamedProperties, identifierNumber);
843 def(HeapLocation(NamedPropertyLoc, heap, node->child2()), LazyNode(node));
847 case MultiGetByOffset: {
848 read(JSCell_structureID);
849 read(JSObject_butterfly);
850 AbstractHeap heap(NamedProperties, node->multiGetByOffsetData().identifierNumber);
852 def(HeapLocation(NamedPropertyLoc, heap, node->child1()), LazyNode(node));
856 case MultiPutByOffset: {
857 read(JSCell_structureID);
858 read(JSObject_butterfly);
859 AbstractHeap heap(NamedProperties, node->multiPutByOffsetData().identifierNumber);
861 if (node->multiPutByOffsetData().writesStructures())
862 write(JSCell_structureID);
863 if (node->multiPutByOffsetData().reallocatesStorage())
864 write(JSObject_butterfly);
865 def(HeapLocation(NamedPropertyLoc, heap, node->child1()), LazyNode(node->child2().node()));
870 unsigned identifierNumber = node->storageAccessData().identifierNumber;
871 AbstractHeap heap(NamedProperties, identifierNumber);
873 def(HeapLocation(NamedPropertyLoc, heap, node->child2()), LazyNode(node->child3().node()));
877 case GetArrayLength: {
878 ArrayMode mode = node->arrayMode();
879 switch (mode.type()) {
882 case Array::Contiguous:
883 case Array::ArrayStorage:
884 case Array::SlowPutArrayStorage:
885 read(Butterfly_publicLength);
886 def(HeapLocation(ArrayLengthLoc, Butterfly_publicLength, node->child1()), LazyNode(node));
890 def(PureValue(node, mode.asWord()));
893 case Array::DirectArguments:
894 case Array::ScopedArguments:
896 def(HeapLocation(ArrayLengthLoc, MiscFields, node->child1()), LazyNode(node));
900 ASSERT(mode.isSomeTypedArrayView());
902 def(HeapLocation(ArrayLengthLoc, MiscFields, node->child1()), LazyNode(node));
908 read(AbstractHeap(ScopeProperties, node->scopeOffset().offset()));
909 def(HeapLocation(ClosureVariableLoc, AbstractHeap(ScopeProperties, node->scopeOffset().offset()), node->child1()), LazyNode(node));
913 write(AbstractHeap(ScopeProperties, node->scopeOffset().offset()));
914 def(HeapLocation(ClosureVariableLoc, AbstractHeap(ScopeProperties, node->scopeOffset().offset()), node->child1()), LazyNode(node->child2().node()));
917 case GetRegExpObjectLastIndex:
918 read(RegExpObject_lastIndex);
919 def(HeapLocation(RegExpObjectLastIndexLoc, RegExpObject_lastIndex, node->child1()), LazyNode(node));
922 case SetRegExpObjectLastIndex:
923 write(RegExpObject_lastIndex);
924 def(HeapLocation(RegExpObjectLastIndexLoc, RegExpObject_lastIndex, node->child1()), LazyNode(node->child2().node()));
927 case GetFromArguments: {
928 AbstractHeap heap(DirectArgumentsProperties, node->capturedArgumentsOffset().offset());
930 def(HeapLocation(DirectArgumentsLoc, heap, node->child1()), LazyNode(node));
934 case PutToArguments: {
935 AbstractHeap heap(DirectArgumentsProperties, node->capturedArgumentsOffset().offset());
937 def(HeapLocation(DirectArgumentsLoc, heap, node->child1()), LazyNode(node->child2().node()));
942 case GetGlobalLexicalVariable:
943 read(AbstractHeap(Absolute, node->variablePointer()));
944 def(HeapLocation(GlobalVariableLoc, AbstractHeap(Absolute, node->variablePointer())), LazyNode(node));
947 case PutGlobalVariable:
948 write(AbstractHeap(Absolute, node->variablePointer()));
949 def(HeapLocation(GlobalVariableLoc, AbstractHeap(Absolute, node->variablePointer())), LazyNode(node->child2().node()));
952 case NewArrayWithSize:
954 read(HeapObjectCount);
955 write(HeapObjectCount);
959 read(HeapObjectCount);
960 write(HeapObjectCount);
962 unsigned numElements = node->numChildren();
964 def(HeapLocation(ArrayLengthLoc, Butterfly_publicLength, node),
965 LazyNode(graph.freeze(jsNumber(numElements))));
971 switch (node->indexingType()) {
972 case ALL_DOUBLE_INDEXING_TYPES:
973 heap = IndexedDoubleProperties;
976 case ALL_INT32_INDEXING_TYPES:
977 heap = IndexedInt32Properties;
980 case ALL_CONTIGUOUS_INDEXING_TYPES:
981 heap = IndexedContiguousProperties;
988 if (numElements < graph.m_uint32ValuesInUse.size()) {
989 for (unsigned operandIdx = 0; operandIdx < numElements; ++operandIdx) {
990 Edge use = graph.m_varArgChildren[node->firstChild() + operandIdx];
991 def(HeapLocation(IndexedPropertyLoc, heap, node, LazyNode(graph.freeze(jsNumber(operandIdx)))),
992 LazyNode(use.node()));
995 for (uint32_t operandIdx : graph.m_uint32ValuesInUse) {
996 if (operandIdx >= numElements)
998 Edge use = graph.m_varArgChildren[node->firstChild() + operandIdx];
999 // operandIdx comes from graph.m_uint32ValuesInUse and thus is guaranteed to be already frozen
1000 def(HeapLocation(IndexedPropertyLoc, heap, node, LazyNode(graph.freeze(jsNumber(operandIdx)))),
1001 LazyNode(use.node()));
1007 case NewArrayBuffer: {
1008 read(HeapObjectCount);
1009 write(HeapObjectCount);
1011 unsigned numElements = node->numConstants();
1012 def(HeapLocation(ArrayLengthLoc, Butterfly_publicLength, node),
1013 LazyNode(graph.freeze(jsNumber(numElements))));
1016 NodeType op = JSConstant;
1017 switch (node->indexingType()) {
1018 case ALL_DOUBLE_INDEXING_TYPES:
1019 heap = IndexedDoubleProperties;
1020 op = DoubleConstant;
1023 case ALL_INT32_INDEXING_TYPES:
1024 heap = IndexedInt32Properties;
1027 case ALL_CONTIGUOUS_INDEXING_TYPES:
1028 heap = IndexedContiguousProperties;
1035 JSValue* data = graph.m_codeBlock->constantBuffer(node->startConstant());
1036 if (numElements < graph.m_uint32ValuesInUse.size()) {
1037 for (unsigned index = 0; index < numElements; ++index) {
1038 def(HeapLocation(IndexedPropertyLoc, heap, node, LazyNode(graph.freeze(jsNumber(index)))),
1039 LazyNode(graph.freeze(data[index]), op));
1042 Vector<uint32_t> possibleIndices;
1043 for (uint32_t index : graph.m_uint32ValuesInUse) {
1044 if (index >= numElements)
1046 possibleIndices.append(index);
1048 for (uint32_t index : possibleIndices) {
1049 def(HeapLocation(IndexedPropertyLoc, heap, node, LazyNode(graph.freeze(jsNumber(index)))),
1050 LazyNode(graph.freeze(data[index]), op));
1064 case NewStringObject:
1065 case PhantomNewObject:
1066 case MaterializeNewObject:
1067 case PhantomNewFunction:
1068 case PhantomNewGeneratorFunction:
1069 case PhantomCreateActivation:
1070 case MaterializeCreateActivation:
1071 read(HeapObjectCount);
1072 write(HeapObjectCount);
1075 case NewArrowFunction:
1077 case NewGeneratorFunction:
1078 if (node->castOperand<FunctionExecutable*>()->singletonFunction()->isStillValid())
1079 write(Watchpoint_fire);
1080 read(HeapObjectCount);
1081 write(HeapObjectCount);
1086 if (node->child2().useKind() == RegExpObjectUse
1087 && node->child3().useKind() == StringUse) {
1097 if (node->child1().useKind() == StringUse
1098 && node->child2().useKind() == RegExpObjectUse
1099 && node->child3().useKind() == StringUse) {
1109 if (node->arrayMode().isOutOfBounds()) {
1114 def(PureValue(node));
1120 case CompareGreater:
1121 case CompareGreaterEq:
1122 if (!node->isBinaryUseKind(UntypedUse)) {
1123 def(PureValue(node));
1131 case CallStringConstructor:
1132 switch (node->child1().useKind()) {
1133 case StringObjectUse:
1134 case StringOrStringObjectUse:
1135 // These don't def a pure value, unfortunately. I'll avoid load-eliminating these for
1146 RELEASE_ASSERT_NOT_REACHED();
1150 case ThrowReferenceError:
1154 case CountExecution:
1155 case CheckWatchdogTimer:
1156 read(InternalState);
1157 write(InternalState);
1161 RELEASE_ASSERT_NOT_REACHED();
1165 DFG_CRASH(graph, node, toCString("Unrecognized node type: ", Graph::opName(node->op())).data());
1168 class NoOpClobberize {
1170 NoOpClobberize() { }
1171 template<typename... T>
1172 void operator()(T...) const { }
1175 class CheckClobberize {
1182 template<typename... T>
1183 void operator()(T...) const { m_result = true; }
1185 bool result() const { return m_result; }
1188 mutable bool m_result;
1191 bool doesWrites(Graph&, Node*);
1193 class AbstractHeapOverlaps {
1195 AbstractHeapOverlaps(AbstractHeap heap)
1201 void operator()(AbstractHeap otherHeap) const
1205 m_result = m_heap.overlaps(otherHeap);
1208 bool result() const { return m_result; }
1211 AbstractHeap m_heap;
1212 mutable bool m_result;
1215 bool accessesOverlap(Graph&, Node*, AbstractHeap);
1216 bool writesOverlap(Graph&, Node*, AbstractHeap);
1218 bool clobbersHeap(Graph&, Node*);
1220 // We would have used bind() for these, but because of the overlaoding that we are doing,
1221 // it's quite a bit of clearer to just write this out the traditional way.
1223 template<typename T>
1224 class ReadMethodClobberize {
1226 ReadMethodClobberize(T& value)
1231 void operator()(AbstractHeap heap) const
1239 template<typename T>
1240 class WriteMethodClobberize {
1242 WriteMethodClobberize(T& value)
1247 void operator()(AbstractHeap heap) const
1249 m_value.write(heap);
1255 template<typename T>
1256 class DefMethodClobberize {
1258 DefMethodClobberize(T& value)
1263 void operator()(PureValue value) const
1268 void operator()(HeapLocation location, LazyNode node) const
1270 m_value.def(location, node);
1277 template<typename Adaptor>
1278 void clobberize(Graph& graph, Node* node, Adaptor& adaptor)
1280 ReadMethodClobberize<Adaptor> read(adaptor);
1281 WriteMethodClobberize<Adaptor> write(adaptor);
1282 DefMethodClobberize<Adaptor> def(adaptor);
1283 clobberize(graph, node, read, write, def);
1286 } } // namespace JSC::DFG
1288 #endif // ENABLE(DFG_JIT)
1290 #endif // DFGClobberize_h