2 * Copyright (C) 2013-2017 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.
30 #include "DFGAbstractHeap.h"
31 #include "DFGEdgeUsesStructure.h"
33 #include "DFGHeapLocation.h"
34 #include "DFGLazyNode.h"
35 #include "DFGPureValue.h"
36 #include "DOMJITCallDOMGetterSnippet.h"
37 #include "DOMJITSignature.h"
38 #include "JSFixedArray.h"
40 namespace JSC { namespace DFG {
42 template<typename ReadFunctor, typename WriteFunctor, typename DefFunctor>
43 void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFunctor& write, const DefFunctor& def)
47 // - The canonical way of clobbering the world is to read world and write
48 // heap. This is because World subsumes Heap and Stack, and Stack can be
49 // read by anyone but only written to by explicit stack writing operations.
50 // Of course, claiming to also write World is not wrong; it'll just
51 // pessimise some important optimizations.
53 // - We cannot hoist, or sink, anything that has effects. This means that the
54 // easiest way of indicating that something cannot be hoisted is to claim
55 // that it side-effects some miscellaneous thing.
57 // - We cannot hoist forward-exiting nodes without some additional effort. I
58 // believe that what it comes down to is that forward-exiting generally have
59 // their NodeExitsForward cleared upon hoist, except for forward-exiting
60 // nodes that take bogus state as their input. Those are substantially
61 // harder. We disable it for now. In the future we could enable it by having
62 // versions of those nodes that backward-exit instead, but I'm not convinced
65 // - Some nodes lie, and claim that they do not read the JSCell_structureID,
66 // JSCell_typeInfoFlags, etc. These are nodes that use the structure in a way
67 // that does not depend on things that change under structure transitions.
69 // - It's implicitly understood that OSR exits read the world. This is why we
70 // generally don't move or eliminate stores. Every node can exit, so the
71 // read set does not reflect things that would be read if we exited.
72 // Instead, the read set reflects what the node will have to read if it
75 // - Broadly, we don't say that we're reading something if that something is
78 // - This must be sound even prior to type inference. We use this as early as
79 // bytecode parsing to determine at which points in the program it's legal to
82 // - If you do read(Stack) or read(World), then make sure that readTop() in
83 // PreciseLocalClobberize is correct.
85 // While read() and write() are fairly self-explanatory - they track what sorts of things the
86 // node may read or write - the def() functor is more tricky. It tells you the heap locations
87 // (not just abstract heaps) that are defined by a node. A heap location comprises an abstract
88 // heap, some nodes, and a LocationKind. Briefly, a location defined by a node is a location
89 // whose value can be deduced from looking at the node itself. The locations returned must obey
90 // the following properties:
92 // - If someone wants to CSE a load from the heap, then a HeapLocation object should be
93 // sufficient to find a single matching node.
95 // - The abstract heap is the only abstract heap that could be clobbered to invalidate any such
96 // CSE attempt. I.e. if clobberize() reports that on every path between some node and a node
97 // that defines a HeapLocation that it wanted, there were no writes to any abstract heap that
98 // overlap the location's heap, then we have a sound match. Effectively, the semantics of
99 // write() and def() are intertwined such that for them to be sound they must agree on what
102 // read(), write(), and def() for heap locations is enough to do GCSE on effectful things. To
103 // keep things simple, this code will also def() pure things. def() must be overloaded to also
104 // accept PureValue. This way, a client of clobberize() can implement GCSE entirely using the
105 // information that clobberize() passes to write() and def(). Other clients of clobberize() can
106 // just ignore def() by using a NoOpClobberize functor.
108 if (edgesUseStructure(graph, node))
109 read(JSCell_structureID);
111 // We allow the runtime to perform a stack scan at any time. We don't model which nodes get implemented
112 // by calls into the runtime. For debugging we might replace the implementation of any node with a call
113 // to the runtime, and that call may walk stack. Therefore, each node must read() anything that a stack
114 // scan would read. That's what this does.
115 for (InlineCallFrame* inlineCallFrame = node->origin.semantic.inlineCallFrame; inlineCallFrame; inlineCallFrame = inlineCallFrame->directCaller.inlineCallFrame) {
116 if (inlineCallFrame->isClosureCall)
117 read(AbstractHeap(Stack, inlineCallFrame->stackOffset + CallFrameSlot::callee));
118 if (inlineCallFrame->isVarargs())
119 read(AbstractHeap(Stack, inlineCallFrame->stackOffset + CallFrameSlot::argumentCount));
122 // We don't want to specifically account which nodes can read from the scope
123 // when the debugger is enabled. It's helpful to just claim all nodes do.
124 // Specifically, if a node allocates, this may call into the debugger's machinery.
125 // The debugger's machinery is free to take a stack trace and try to read from
126 // a scope which is expected to be flushed to the stack.
127 if (graph.hasDebuggerEnabled()) {
128 ASSERT(!node->origin.semantic.inlineCallFrame);
129 read(AbstractHeap(Stack, graph.m_codeBlock->scopeRegister()));
132 switch (node->op()) {
136 def(PureValue(node, node->constant()));
140 case IdentityWithProfile:
143 case ExtractOSREntryLocal:
144 case ExtractCatchLocal:
145 case CheckStructureImmediate:
149 // We should enable CSE of LazyJSConstant. It's a little annoying since LazyJSValue has
150 // more bits than we currently have in PureValue.
154 def(PureValue(node, node->cellOperand()->cell()));
163 case GetGlobalObject:
164 case StringCharCodeAt:
165 case CompareStrictEq:
171 case IsTypedArrayView:
177 case BooleanToNumber:
185 def(PureValue(node));
192 case AtomicsIsLockFree:
193 if (node->child1().useKind() == Int32Use)
194 def(PureValue(node));
202 if (node->child1().useKind() == DoubleRepUse)
203 def(PureValue(node, static_cast<std::underlying_type<Arith::UnaryType>::type>(node->arithUnaryType())));
212 if (node->child1().useKind() == DoubleRepUse)
213 def(PureValue(node));
221 if (node->child1().useKind() == Int32Use || node->child1().useKind() == DoubleRepUse)
222 def(PureValue(node));
230 if (node->child1().useKind() == Int32Use || node->child1().useKind() == KnownInt32Use)
231 def(PureValue(node));
239 if (node->child1().useKind() == Int32Use
240 || node->child1().useKind() == DoubleRepUse
241 || node->child1().useKind() == Int52RepUse)
242 def(PureValue(node));
250 def(PureValue(node, node->queriedType()));
259 if (node->child1().useKind() == UntypedUse || node->child2().useKind() == UntypedUse) {
264 def(PureValue(node));
268 read(MathDotRandomState);
269 write(MathDotRandomState);
272 case HasGenericProperty:
273 case HasStructureProperty:
274 case GetPropertyEnumerator: {
280 case GetEnumerableLength: {
286 case GetDirectPname: {
287 // This reads and writes heap because it can end up calling a generic getByVal
288 // if the Structure changed, which could in turn end up calling a getter.
295 case GetEnumeratorStructurePname:
296 case GetEnumeratorGenericPname: {
297 def(PureValue(node));
301 case HasIndexedProperty: {
302 read(JSObject_butterfly);
303 ArrayMode mode = node->arrayMode();
304 switch (mode.type()) {
305 case Array::ForceExit: {
310 if (mode.isInBounds()) {
311 read(Butterfly_publicLength);
312 read(IndexedInt32Properties);
313 def(HeapLocation(HasIndexedPropertyLoc, IndexedInt32Properties, node->child1(), node->child2()), LazyNode(node));
320 case Array::Double: {
321 if (mode.isInBounds()) {
322 read(Butterfly_publicLength);
323 read(IndexedDoubleProperties);
324 def(HeapLocation(HasIndexedPropertyLoc, IndexedDoubleProperties, node->child1(), node->child2()), LazyNode(node));
331 case Array::Contiguous: {
332 if (mode.isInBounds()) {
333 read(Butterfly_publicLength);
334 read(IndexedContiguousProperties);
335 def(HeapLocation(HasIndexedPropertyLoc, IndexedContiguousProperties, node->child1(), node->child2()), LazyNode(node));
342 case Array::ArrayStorage: {
343 if (mode.isInBounds()) {
344 read(Butterfly_vectorLength);
345 read(IndexedArrayStorageProperties);
358 RELEASE_ASSERT_NOT_REACHED();
362 case StringFromCharCode:
363 switch (node->child1().useKind()) {
365 def(PureValue(node));
372 DFG_CRASH(graph, node, "Bad use kind");
380 def(PureValue(node, node->arithMode()));
386 switch (node->binaryUseKind()) {
390 def(PureValue(node, node->arithMode()));
397 DFG_CRASH(graph, node, "Bad use kind");
404 if (node->child1().useKind() == DoubleRepUse)
405 def(PureValue(node, static_cast<uintptr_t>(node->arithRoundingMode())));
413 def(PureValue(CheckCell, AdjacencyList(AdjacencyList::Fixed, node->child1()), node->cellOperand()));
417 def(PureValue(CheckNotEmpty, AdjacencyList(AdjacencyList::Fixed, node->child1())));
420 case CheckStringIdent:
421 def(PureValue(CheckStringIdent, AdjacencyList(AdjacencyList::Fixed, node->child1()), node->uidOperand()));
424 case ConstantStoragePointer:
425 def(PureValue(node, node->storagePointer()));
445 case CheckTierUpInLoop:
446 case CheckTierUpAtReturn:
447 case CheckTierUpAndOSREnter:
450 case ProfileControlFlow:
452 case InitializeEntrypointArguments:
457 read(JSCell_cellState);
458 write(JSCell_cellState);
461 case FencedStoreBarrier:
463 write(JSCell_cellState);
467 if (Options::usePollingTraps()) {
469 write(InternalState);
471 write(Watchpoint_fire);
474 case InvalidationPoint:
476 def(HeapLocation(InvalidationPointLoc, Watchpoint_fire), LazyNode(node));
480 read(AbstractHeap(Stack, node->local()));
485 write(Watchpoint_fire);
489 case PushWithScope: {
491 write(HeapObjectCount);
495 case CreateActivation: {
496 SymbolTable* table = node->castOperand<SymbolTable*>();
497 if (table->singletonScope()->isStillValid())
498 write(Watchpoint_fire);
499 read(HeapObjectCount);
500 write(HeapObjectCount);
504 case CreateDirectArguments:
505 case CreateScopedArguments:
506 case CreateClonedArguments:
508 read(HeapObjectCount);
509 write(HeapObjectCount);
512 case PhantomDirectArguments:
513 case PhantomClonedArguments:
514 // DFG backend requires that the locals that this reads are flushed. FTL backend can handle those
515 // locals being promoted.
516 if (!isFTL(graph.m_plan.mode))
519 // Even though it's phantom, it still has the property that one can't be replaced with another.
520 read(HeapObjectCount);
521 write(HeapObjectCount);
525 case PhantomNewArrayWithSpread:
526 case PhantomNewArrayBuffer:
527 case PhantomCreateRest:
528 // Even though it's phantom, it still has the property that one can't be replaced with another.
529 read(HeapObjectCount);
530 write(HeapObjectCount);
538 case CallObjectConstructor:
539 read(HeapObjectCount);
540 write(HeapObjectCount);
546 read(HeapObjectCount);
547 write(HeapObjectCount);
552 def(HeapLocation(IsObjectOrNullLoc, MiscFields, node->child1()), LazyNode(node));
557 def(HeapLocation(IsFunctionLoc, MiscFields, node->child1()), LazyNode(node));
562 read(JSCell_indexingType);
563 read(JSCell_structureID);
564 read(JSObject_butterfly);
565 read(JSObject_butterflyMask);
566 read(Butterfly_publicLength);
567 read(IndexedDoubleProperties);
568 read(IndexedInt32Properties);
569 read(IndexedContiguousProperties);
570 read(HeapObjectCount);
571 write(HeapObjectCount);
575 // FIXME: Should support a CSE rule.
576 // https://bugs.webkit.org/show_bug.cgi?id=173173
578 read(JSCell_indexingType);
579 read(JSCell_structureID);
580 read(JSObject_butterfly);
581 read(JSObject_butterflyMask);
582 read(Butterfly_publicLength);
583 switch (node->arrayMode().type()) {
585 read(IndexedDoubleProperties);
588 read(IndexedInt32Properties);
590 case Array::Contiguous:
591 read(IndexedContiguousProperties);
594 RELEASE_ASSERT_NOT_REACHED();
602 case GetByIdWithThis:
603 case GetByValWithThis:
605 case PutByIdWithThis:
606 case PutByValWithThis:
611 case PutGetterSetterById:
614 case DefineDataProperty:
615 case DefineAccessorProperty:
622 case TailCallInlinedCaller:
623 case DirectTailCallInlinedCaller:
625 case DirectConstruct:
627 case CallForwardVarargs:
628 case TailCallVarargsInlinedCaller:
629 case TailCallForwardVarargsInlinedCaller:
630 case ConstructVarargs:
631 case ConstructForwardVarargs:
636 case SetFunctionName:
639 case ResolveScopeForHoistingFuncDeclInEval:
647 case AtomicsCompareExchange:
648 case AtomicsExchange:
654 unsigned numExtraArgs = numExtraAtomicsArgs(node->op());
655 Edge storageEdge = graph.child(node, 2 + numExtraArgs);
661 read(TypedArrayProperties);
663 write(TypedArrayProperties);
668 ASSERT(!node->origin.semantic.inlineCallFrame);
669 read(AbstractHeap(Stack, graph.m_codeBlock->scopeRegister()));
670 read(AbstractHeap(Stack, virtualRegisterForArgument(0)));
676 case ThrowStaticError:
679 case TailCallVarargs:
680 case TailCallForwardVarargs:
686 read(GetterSetter_getter);
687 def(HeapLocation(GetterLoc, GetterSetter_getter, node->child1()), LazyNode(node));
691 read(GetterSetter_setter);
692 def(HeapLocation(SetterLoc, GetterSetter_setter, node->child1()), LazyNode(node));
696 read(AbstractHeap(Stack, CallFrameSlot::callee));
697 def(HeapLocation(StackLoc, AbstractHeap(Stack, CallFrameSlot::callee)), LazyNode(node));
700 case GetArgumentCountIncludingThis:
701 read(AbstractHeap(Stack, CallFrameSlot::argumentCount));
702 def(HeapLocation(StackPayloadLoc, AbstractHeap(Stack, CallFrameSlot::argumentCount)), LazyNode(node));
710 read(AbstractHeap(Stack, node->local()));
711 def(HeapLocation(StackLoc, AbstractHeap(Stack, node->local())), LazyNode(node));
715 write(AbstractHeap(Stack, node->local()));
716 def(HeapLocation(StackLoc, AbstractHeap(Stack, node->local())), LazyNode(node->child1().node()));
720 AbstractHeap heap(Stack, node->stackAccessData()->local);
722 def(HeapLocation(StackLoc, heap), LazyNode(node));
727 AbstractHeap heap(Stack, node->stackAccessData()->local);
729 def(HeapLocation(StackLoc, heap), LazyNode(node->child1().node()));
736 LoadVarargsData* data = node->loadVarargsData();
737 write(AbstractHeap(Stack, data->count.offset()));
738 for (unsigned i = data->limit; i--;)
739 write(AbstractHeap(Stack, data->start.offset() + static_cast<int>(i)));
743 case ForwardVarargs: {
744 // We could be way more precise here.
747 LoadVarargsData* data = node->loadVarargsData();
748 write(AbstractHeap(Stack, data->count.offset()));
749 for (unsigned i = data->limit; i--;)
750 write(AbstractHeap(Stack, data->start.offset() + static_cast<int>(i)));
755 ArrayMode mode = node->arrayMode();
756 LocationKind indexedPropertyLoc = indexedPropertyLocForResultType(node->result());
757 switch (mode.type()) {
758 case Array::SelectUsingPredictions:
759 case Array::Unprofiled:
760 case Array::SelectUsingArguments:
761 // Assume the worst since we don't have profiling yet.
766 case Array::ForceExit:
776 if (mode.isOutOfBounds()) {
781 // This appears to read nothing because it's only reading immutable data.
782 def(PureValue(node, mode.asWord()));
785 case Array::DirectArguments:
786 if (mode.isInBounds()) {
787 read(DirectArgumentsProperties);
788 def(HeapLocation(indexedPropertyLoc, DirectArgumentsProperties, node->child1(), node->child2()), LazyNode(node));
795 case Array::ScopedArguments:
796 read(ScopeProperties);
797 def(HeapLocation(indexedPropertyLoc, ScopeProperties, node->child1(), node->child2()), LazyNode(node));
801 if (mode.isInBounds()) {
802 read(Butterfly_publicLength);
803 read(IndexedInt32Properties);
804 def(HeapLocation(indexedPropertyLoc, IndexedInt32Properties, node->child1(), node->child2()), LazyNode(node));
812 if (mode.isInBounds()) {
813 read(Butterfly_publicLength);
814 read(IndexedDoubleProperties);
815 def(HeapLocation(indexedPropertyLoc, IndexedDoubleProperties, node->child1(), node->child2()), LazyNode(node));
822 case Array::Contiguous:
823 if (mode.isInBounds()) {
824 read(Butterfly_publicLength);
825 read(IndexedContiguousProperties);
826 def(HeapLocation(indexedPropertyLoc, IndexedContiguousProperties, node->child1(), node->child2()), LazyNode(node));
833 case Array::Undecided:
834 def(PureValue(node));
837 case Array::ArrayStorage:
838 case Array::SlowPutArrayStorage:
839 if (mode.isInBounds()) {
840 read(Butterfly_vectorLength);
841 read(IndexedArrayStorageProperties);
848 case Array::Int8Array:
849 case Array::Int16Array:
850 case Array::Int32Array:
851 case Array::Uint8Array:
852 case Array::Uint8ClampedArray:
853 case Array::Uint16Array:
854 case Array::Uint32Array:
855 case Array::Float32Array:
856 case Array::Float64Array:
857 read(TypedArrayProperties);
859 def(HeapLocation(indexedPropertyLoc, TypedArrayProperties, node->child1(), node->child2()), LazyNode(node));
861 // We should not get an AnyTypedArray in a GetByVal as AnyTypedArray is only created from intrinsics, which
862 // are only added from Inline Caching a GetById.
863 case Array::AnyTypedArray:
864 DFG_CRASH(graph, node, "impossible array mode for get");
867 RELEASE_ASSERT_NOT_REACHED();
871 case GetMyArgumentByVal:
872 case GetMyArgumentByValOutOfBounds: {
874 // FIXME: It would be trivial to have a def here.
875 // https://bugs.webkit.org/show_bug.cgi?id=143077
881 case PutByValAlias: {
882 ArrayMode mode = node->arrayMode();
883 Node* base = graph.varArgChild(node, 0).node();
884 Node* index = graph.varArgChild(node, 1).node();
885 Node* value = graph.varArgChild(node, 2).node();
886 LocationKind indexedPropertyLoc = indexedPropertyLocForResultType(node->result());
888 switch (mode.modeForPut().type()) {
889 case Array::SelectUsingPredictions:
890 case Array::SelectUsingArguments:
891 case Array::Unprofiled:
892 case Array::Undecided:
893 // Assume the worst since we don't have profiling yet.
898 case Array::ForceExit:
908 if (node->arrayMode().isOutOfBounds()) {
913 read(Butterfly_publicLength);
914 read(Butterfly_vectorLength);
915 read(IndexedInt32Properties);
916 write(IndexedInt32Properties);
917 if (node->arrayMode().mayStoreToHole())
918 write(Butterfly_publicLength);
919 def(HeapLocation(indexedPropertyLoc, IndexedInt32Properties, base, index), LazyNode(value));
923 if (node->arrayMode().isOutOfBounds()) {
928 read(Butterfly_publicLength);
929 read(Butterfly_vectorLength);
930 read(IndexedDoubleProperties);
931 write(IndexedDoubleProperties);
932 if (node->arrayMode().mayStoreToHole())
933 write(Butterfly_publicLength);
934 def(HeapLocation(indexedPropertyLoc, IndexedDoubleProperties, base, index), LazyNode(value));
937 case Array::Contiguous:
938 if (node->arrayMode().isOutOfBounds()) {
943 read(Butterfly_publicLength);
944 read(Butterfly_vectorLength);
945 read(IndexedContiguousProperties);
946 write(IndexedContiguousProperties);
947 if (node->arrayMode().mayStoreToHole())
948 write(Butterfly_publicLength);
949 def(HeapLocation(indexedPropertyLoc, IndexedContiguousProperties, base, index), LazyNode(value));
952 case Array::ArrayStorage:
953 case Array::SlowPutArrayStorage:
954 // Give up on life for now.
959 case Array::Int8Array:
960 case Array::Int16Array:
961 case Array::Int32Array:
962 case Array::Uint8Array:
963 case Array::Uint8ClampedArray:
964 case Array::Uint16Array:
965 case Array::Uint32Array:
966 case Array::Float32Array:
967 case Array::Float64Array:
969 write(TypedArrayProperties);
970 // FIXME: We can't def() anything here because these operations truncate their inputs.
971 // https://bugs.webkit.org/show_bug.cgi?id=134737
973 case Array::AnyTypedArray:
975 case Array::DirectArguments:
976 case Array::ScopedArguments:
977 DFG_CRASH(graph, node, "impossible array mode for put");
980 RELEASE_ASSERT_NOT_REACHED();
984 case CheckStructureOrEmpty:
986 read(JSCell_structureID);
990 read(JSCell_indexingType);
991 read(JSCell_typeInfoType);
992 read(JSCell_structureID);
995 case CheckTypeInfoFlags:
996 read(JSCell_typeInfoFlags);
997 def(HeapLocation(CheckTypeInfoFlagsLoc, JSCell_typeInfoFlags, node->child1()), LazyNode(node));
1001 // Note: We would have eliminated a ParseInt that has just a single child as an Int32Use inside fixup.
1002 if (node->child1().useKind() == StringUse && (!node->child2() || node->child2().useKind() == Int32Use)) {
1003 def(PureValue(node));
1011 case OverridesHasInstance:
1012 read(JSCell_typeInfoFlags);
1013 def(HeapLocation(OverridesHasInstanceLoc, JSCell_typeInfoFlags, node->child1()), LazyNode(node));
1017 read(JSCell_structureID);
1018 def(HeapLocation(InstanceOfLoc, JSCell_structureID, node->child1(), node->child2()), LazyNode(node));
1021 case InstanceOfCustom:
1027 read(JSObject_butterfly);
1028 write(JSCell_structureID);
1029 write(JSCell_typeInfoType);
1030 write(JSCell_typeInfoFlags);
1031 write(JSCell_indexingType);
1034 case AllocatePropertyStorage:
1035 case ReallocatePropertyStorage:
1036 read(HeapObjectCount);
1037 write(HeapObjectCount);
1040 case NukeStructureAndSetButterfly:
1041 write(JSObject_butterfly);
1042 write(JSCell_structureID);
1043 def(HeapLocation(ButterflyLoc, JSObject_butterfly, node->child1()), LazyNode(node->child2().node()));
1047 read(JSObject_butterfly);
1048 def(HeapLocation(ButterflyLoc, JSObject_butterfly, node->child1()), LazyNode(node));
1052 def(PureValue(node, node->classInfo()));
1055 case CallDOMGetter: {
1056 DOMJIT::CallDOMGetterSnippet* snippet = node->callDOMGetterData()->snippet;
1062 DOMJIT::Effect effect = snippet->effect;
1064 if (effect.reads == DOMJIT::HeapRange::top())
1067 read(AbstractHeap(DOMState, effect.reads.rawRepresentation()));
1069 if (effect.writes) {
1070 if (effect.writes == DOMJIT::HeapRange::top())
1073 write(AbstractHeap(DOMState, effect.writes.rawRepresentation()));
1075 if (effect.def != DOMJIT::HeapRange::top()) {
1076 DOMJIT::HeapRange range = effect.def;
1077 if (range == DOMJIT::HeapRange::none())
1078 def(PureValue(node, bitwise_cast<uintptr_t>(node->callDOMGetterData()->customAccessorGetter)));
1080 // Def with heap location. We do not include "GlobalObject" for that since this information is included in the base node.
1081 // We only see the DOMJIT getter here. So just including "base" is ok.
1082 def(HeapLocation(DOMStateLoc, AbstractHeap(DOMState, range.rawRepresentation()), node->child1()), LazyNode(node));
1089 const DOMJIT::Signature* signature = node->signature();
1090 DOMJIT::Effect effect = signature->effect;
1092 if (effect.reads == DOMJIT::HeapRange::top())
1095 read(AbstractHeap(DOMState, effect.reads.rawRepresentation()));
1097 if (effect.writes) {
1098 if (effect.writes == DOMJIT::HeapRange::top())
1101 write(AbstractHeap(DOMState, effect.writes.rawRepresentation()));
1103 ASSERT_WITH_MESSAGE(effect.def == DOMJIT::HeapRange::top(), "Currently, we do not accept any def for CallDOM.");
1108 case ArrayifyToStructure:
1109 read(JSCell_structureID);
1110 read(JSCell_indexingType);
1111 read(JSObject_butterfly);
1112 write(JSCell_structureID);
1113 write(JSCell_indexingType);
1114 write(JSObject_butterfly);
1115 write(JSObject_butterflyMask);
1116 write(Watchpoint_fire);
1119 case GetIndexedPropertyStorage:
1120 if (node->arrayMode().type() == Array::String) {
1121 def(PureValue(node, node->arrayMode().asWord()));
1125 def(HeapLocation(IndexedPropertyStorageLoc, MiscFields, node->child1()), LazyNode(node));
1128 case GetTypedArrayByteOffset:
1130 def(HeapLocation(TypedArrayByteOffsetLoc, MiscFields, node->child1()), LazyNode(node));
1133 case GetPrototypeOf: {
1134 switch (node->child1().useKind()) {
1137 case FinalObjectUse:
1138 read(JSCell_structureID);
1139 read(JSObject_butterfly);
1140 read(NamedProperties); // Poly proto could load prototype from its slot.
1141 def(HeapLocation(PrototypeLoc, NamedProperties, node->child1()), LazyNode(node));
1151 case GetGetterSetterByOffset: {
1152 unsigned identifierNumber = node->storageAccessData().identifierNumber;
1153 AbstractHeap heap(NamedProperties, identifierNumber);
1155 def(HeapLocation(NamedPropertyLoc, heap, node->child2()), LazyNode(node));
1164 case MultiGetByOffset: {
1165 read(JSCell_structureID);
1166 read(JSObject_butterfly);
1167 read(JSObject_butterflyMask);
1168 AbstractHeap heap(NamedProperties, node->multiGetByOffsetData().identifierNumber);
1170 // FIXME: We cannot def() for MultiGetByOffset because CSE is not smart enough to decay it
1171 // to a CheckStructure.
1172 // https://bugs.webkit.org/show_bug.cgi?id=159859
1176 case MultiPutByOffset: {
1177 read(JSCell_structureID);
1178 read(JSObject_butterfly);
1179 AbstractHeap heap(NamedProperties, node->multiPutByOffsetData().identifierNumber);
1181 if (node->multiPutByOffsetData().writesStructures())
1182 write(JSCell_structureID);
1183 if (node->multiPutByOffsetData().reallocatesStorage())
1184 write(JSObject_butterfly);
1185 def(HeapLocation(NamedPropertyLoc, heap, node->child1()), LazyNode(node->child2().node()));
1190 unsigned identifierNumber = node->storageAccessData().identifierNumber;
1191 AbstractHeap heap(NamedProperties, identifierNumber);
1193 def(HeapLocation(NamedPropertyLoc, heap, node->child2()), LazyNode(node->child3().node()));
1197 case GetArrayLength: {
1198 ArrayMode mode = node->arrayMode();
1199 switch (mode.type()) {
1200 case Array::Undecided:
1203 case Array::Contiguous:
1204 case Array::ArrayStorage:
1205 case Array::SlowPutArrayStorage:
1206 read(Butterfly_publicLength);
1207 def(HeapLocation(ArrayLengthLoc, Butterfly_publicLength, node->child1()), LazyNode(node));
1211 def(PureValue(node, mode.asWord()));
1214 case Array::DirectArguments:
1215 case Array::ScopedArguments:
1217 def(HeapLocation(ArrayLengthLoc, MiscFields, node->child1()), LazyNode(node));
1221 ASSERT(mode.isSomeTypedArrayView());
1223 def(HeapLocation(ArrayLengthLoc, MiscFields, node->child1()), LazyNode(node));
1228 case GetVectorLength: {
1229 ArrayMode mode = node->arrayMode();
1230 switch (mode.type()) {
1231 case Array::ArrayStorage:
1232 case Array::SlowPutArrayStorage:
1233 read(Butterfly_vectorLength);
1234 def(HeapLocation(VectorLengthLoc, Butterfly_vectorLength, node->child1()), LazyNode(node));
1238 RELEASE_ASSERT_NOT_REACHED();
1244 read(AbstractHeap(ScopeProperties, node->scopeOffset().offset()));
1245 def(HeapLocation(ClosureVariableLoc, AbstractHeap(ScopeProperties, node->scopeOffset().offset()), node->child1()), LazyNode(node));
1249 write(AbstractHeap(ScopeProperties, node->scopeOffset().offset()));
1250 def(HeapLocation(ClosureVariableLoc, AbstractHeap(ScopeProperties, node->scopeOffset().offset()), node->child1()), LazyNode(node->child2().node()));
1253 case GetRegExpObjectLastIndex:
1254 read(RegExpObject_lastIndex);
1255 def(HeapLocation(RegExpObjectLastIndexLoc, RegExpObject_lastIndex, node->child1()), LazyNode(node));
1258 case SetRegExpObjectLastIndex:
1259 write(RegExpObject_lastIndex);
1260 def(HeapLocation(RegExpObjectLastIndexLoc, RegExpObject_lastIndex, node->child1()), LazyNode(node->child2().node()));
1263 case RecordRegExpCachedResult:
1267 case GetFromArguments: {
1268 AbstractHeap heap(DirectArgumentsProperties, node->capturedArgumentsOffset().offset());
1270 def(HeapLocation(DirectArgumentsLoc, heap, node->child1()), LazyNode(node));
1274 case PutToArguments: {
1275 AbstractHeap heap(DirectArgumentsProperties, node->capturedArgumentsOffset().offset());
1277 def(HeapLocation(DirectArgumentsLoc, heap, node->child1()), LazyNode(node->child2().node()));
1283 // FIXME: It would be trivial to have a def here.
1284 // https://bugs.webkit.org/show_bug.cgi?id=143077
1289 case GetGlobalLexicalVariable:
1290 read(AbstractHeap(Absolute, node->variablePointer()));
1291 def(HeapLocation(GlobalVariableLoc, AbstractHeap(Absolute, node->variablePointer())), LazyNode(node));
1294 case PutGlobalVariable:
1295 write(AbstractHeap(Absolute, node->variablePointer()));
1296 def(HeapLocation(GlobalVariableLoc, AbstractHeap(Absolute, node->variablePointer())), LazyNode(node->child2().node()));
1299 case NewArrayWithSize:
1301 read(HeapObjectCount);
1302 write(HeapObjectCount);
1305 case NewArrayWithSpread: {
1306 // This also reads from JSFixedArray's data store, but we don't have any way of describing that yet.
1307 read(HeapObjectCount);
1308 for (unsigned i = 0; i < node->numChildren(); i++) {
1309 Node* child = graph.varArgChild(node, i).node();
1310 if (child->op() == PhantomSpread) {
1315 write(HeapObjectCount);
1320 if (node->child1()->op() == PhantomCreateRest)
1323 if (node->child1().useKind() == ArrayUse) {
1324 // FIXME: We can probably CSE these together, but we need to construct the right rules
1325 // to prove that nobody writes to child1() in between two Spreads: https://bugs.webkit.org/show_bug.cgi?id=164531
1326 read(HeapObjectCount);
1327 read(JSCell_indexingType);
1328 read(JSObject_butterfly);
1329 read(Butterfly_publicLength);
1330 read(IndexedDoubleProperties);
1331 read(IndexedInt32Properties);
1332 read(IndexedContiguousProperties);
1333 read(IndexedArrayStorageProperties);
1335 write(HeapObjectCount);
1345 read(HeapObjectCount);
1346 write(HeapObjectCount);
1348 unsigned numElements = node->numChildren();
1350 def(HeapLocation(ArrayLengthLoc, Butterfly_publicLength, node),
1351 LazyNode(graph.freeze(jsNumber(numElements))));
1357 LocationKind indexedPropertyLoc;
1358 switch (node->indexingType()) {
1359 case ALL_DOUBLE_INDEXING_TYPES:
1360 heap = IndexedDoubleProperties;
1361 indexedPropertyLoc = IndexedPropertyDoubleLoc;
1364 case ALL_INT32_INDEXING_TYPES:
1365 heap = IndexedInt32Properties;
1366 indexedPropertyLoc = IndexedPropertyJSLoc;
1369 case ALL_CONTIGUOUS_INDEXING_TYPES:
1370 heap = IndexedContiguousProperties;
1371 indexedPropertyLoc = IndexedPropertyJSLoc;
1378 if (numElements < graph.m_uint32ValuesInUse.size()) {
1379 for (unsigned operandIdx = 0; operandIdx < numElements; ++operandIdx) {
1380 Edge use = graph.m_varArgChildren[node->firstChild() + operandIdx];
1381 def(HeapLocation(indexedPropertyLoc, heap, node, LazyNode(graph.freeze(jsNumber(operandIdx)))),
1382 LazyNode(use.node()));
1385 for (uint32_t operandIdx : graph.m_uint32ValuesInUse) {
1386 if (operandIdx >= numElements)
1388 Edge use = graph.m_varArgChildren[node->firstChild() + operandIdx];
1389 // operandIdx comes from graph.m_uint32ValuesInUse and thus is guaranteed to be already frozen
1390 def(HeapLocation(indexedPropertyLoc, heap, node, LazyNode(graph.freeze(jsNumber(operandIdx)))),
1391 LazyNode(use.node()));
1397 case NewArrayBuffer: {
1398 read(HeapObjectCount);
1399 write(HeapObjectCount);
1401 JSFixedArray* array = node->castOperand<JSFixedArray*>();
1402 unsigned numElements = array->length();
1403 def(HeapLocation(ArrayLengthLoc, Butterfly_publicLength, node),
1404 LazyNode(graph.freeze(jsNumber(numElements))));
1407 LocationKind indexedPropertyLoc;
1408 NodeType op = JSConstant;
1409 switch (node->indexingType()) {
1410 case ALL_DOUBLE_INDEXING_TYPES:
1411 heap = IndexedDoubleProperties;
1412 indexedPropertyLoc = IndexedPropertyDoubleLoc;
1413 op = DoubleConstant;
1416 case ALL_INT32_INDEXING_TYPES:
1417 heap = IndexedInt32Properties;
1418 indexedPropertyLoc = IndexedPropertyJSLoc;
1421 case ALL_CONTIGUOUS_INDEXING_TYPES:
1422 heap = IndexedContiguousProperties;
1423 indexedPropertyLoc = IndexedPropertyJSLoc;
1430 if (numElements < graph.m_uint32ValuesInUse.size()) {
1431 for (unsigned index = 0; index < numElements; ++index) {
1432 def(HeapLocation(indexedPropertyLoc, heap, node, LazyNode(graph.freeze(jsNumber(index)))),
1433 LazyNode(graph.freeze(array->get(index)), op));
1436 Vector<uint32_t> possibleIndices;
1437 for (uint32_t index : graph.m_uint32ValuesInUse) {
1438 if (index >= numElements)
1440 possibleIndices.append(index);
1442 for (uint32_t index : possibleIndices) {
1443 def(HeapLocation(indexedPropertyLoc, heap, node, LazyNode(graph.freeze(jsNumber(index)))),
1444 LazyNode(graph.freeze(array->get(index)), op));
1451 if (!graph.isWatchingHavingABadTimeWatchpoint(node)) {
1452 // This means we're already having a bad time.
1458 read(HeapObjectCount);
1459 write(HeapObjectCount);
1465 case NewStringObject:
1466 case PhantomNewObject:
1467 case MaterializeNewObject:
1468 case PhantomNewFunction:
1469 case PhantomNewGeneratorFunction:
1470 case PhantomNewAsyncFunction:
1471 case PhantomNewAsyncGeneratorFunction:
1472 case PhantomCreateActivation:
1473 case MaterializeCreateActivation:
1474 read(HeapObjectCount);
1475 write(HeapObjectCount);
1479 case NewGeneratorFunction:
1480 case NewAsyncGeneratorFunction:
1481 case NewAsyncFunction:
1482 if (node->castOperand<FunctionExecutable*>()->singletonFunction()->isStillValid())
1483 write(Watchpoint_fire);
1484 read(HeapObjectCount);
1485 write(HeapObjectCount);
1490 if (node->child2().useKind() == RegExpObjectUse
1491 && node->child3().useKind() == StringUse) {
1493 read(RegExpObject_lastIndex);
1495 write(RegExpObject_lastIndex);
1503 case StringReplaceRegExp:
1504 if (node->child1().useKind() == StringUse
1505 && node->child2().useKind() == RegExpObjectUse
1506 && node->child3().useKind() == StringUse) {
1508 read(RegExpObject_lastIndex);
1510 write(RegExpObject_lastIndex);
1518 if (node->arrayMode().isOutOfBounds()) {
1523 def(PureValue(node));
1527 case CompareBelowEq:
1528 def(PureValue(node));
1534 case CompareGreater:
1535 case CompareGreaterEq:
1536 if (node->isBinaryUseKind(StringUse)) {
1537 read(HeapObjectCount);
1538 write(HeapObjectCount);
1541 if (!node->isBinaryUseKind(UntypedUse)) {
1542 def(PureValue(node));
1556 case CallStringConstructor:
1557 switch (node->child1().useKind()) {
1558 case StringObjectUse:
1559 case StringOrStringObjectUse:
1560 // These don't def a pure value, unfortunately. I'll avoid load-eliminating these for
1574 def(PureValue(node));
1578 RELEASE_ASSERT_NOT_REACHED();
1582 case CountExecution:
1583 case SuperSamplerBegin:
1584 case SuperSamplerEnd:
1585 read(InternalState);
1586 write(InternalState);
1589 case LogShadowChickenPrologue:
1590 case LogShadowChickenTail:
1595 def(PureValue(node));
1598 case NormalizeMapKey:
1599 def(PureValue(node));
1602 case GetMapBucket: {
1603 Edge& mapEdge = node->child1();
1604 Edge& keyEdge = node->child2();
1605 AbstractHeapKind heap = (mapEdge.useKind() == MapObjectUse) ? JSMapFields : JSSetFields;
1607 def(HeapLocation(MapBucketLoc, heap, mapEdge, keyEdge), LazyNode(node));
1611 case GetMapBucketHead: {
1612 Edge& mapEdge = node->child1();
1613 AbstractHeapKind heap = (mapEdge.useKind() == MapObjectUse) ? JSMapFields : JSSetFields;
1615 def(HeapLocation(MapBucketHeadLoc, heap, mapEdge), LazyNode(node));
1619 case GetMapBucketNext: {
1620 AbstractHeapKind heap = (node->bucketOwnerType() == BucketOwnerType::Map) ? JSMapFields : JSSetFields;
1622 Edge& bucketEdge = node->child1();
1623 def(HeapLocation(MapBucketNextLoc, heap, bucketEdge), LazyNode(node));
1627 case LoadKeyFromMapBucket: {
1628 AbstractHeapKind heap = (node->bucketOwnerType() == BucketOwnerType::Map) ? JSMapFields : JSSetFields;
1630 Edge& bucketEdge = node->child1();
1631 def(HeapLocation(MapBucketKeyLoc, heap, bucketEdge), LazyNode(node));
1635 case LoadValueFromMapBucket: {
1636 AbstractHeapKind heap = (node->bucketOwnerType() == BucketOwnerType::Map) ? JSMapFields : JSSetFields;
1638 Edge& bucketEdge = node->child1();
1639 def(HeapLocation(MapBucketValueLoc, heap, bucketEdge), LazyNode(node));
1644 Edge& mapEdge = node->child1();
1645 Edge& keyEdge = node->child2();
1646 AbstractHeapKind heap = (mapEdge.useKind() == WeakMapObjectUse) ? JSWeakMapFields : JSWeakSetFields;
1648 def(HeapLocation(WeakMapGetLoc, heap, mapEdge, keyEdge), LazyNode(node));
1653 Edge& mapEdge = node->child1();
1654 Edge& keyEdge = node->child2();
1656 def(HeapLocation(MapBucketLoc, JSSetFields, mapEdge, keyEdge), LazyNode(node));
1661 Edge& mapEdge = graph.varArgChild(node, 0);
1662 Edge& keyEdge = graph.varArgChild(node, 1);
1664 def(HeapLocation(MapBucketLoc, JSMapFields, mapEdge, keyEdge), LazyNode(node));
1668 case ExtractValueFromWeakMapGet:
1669 def(PureValue(node));
1673 def(PureValue(node));
1677 def(PureValue(node));
1680 case NumberToStringWithRadix:
1681 // If the radix is invalid, NumberToStringWithRadix can throw an error.
1686 case NumberToStringWithValidRadixConstant:
1687 def(PureValue(node, node->validRadixConstant()));
1691 RELEASE_ASSERT_NOT_REACHED();
1695 DFG_CRASH(graph, node, toCString("Unrecognized node type: ", Graph::opName(node->op())).data());
1698 class NoOpClobberize {
1700 NoOpClobberize() { }
1701 template<typename... T>
1702 void operator()(T...) const { }
1705 class CheckClobberize {
1712 template<typename... T>
1713 void operator()(T...) const { m_result = true; }
1715 bool result() const { return m_result; }
1718 mutable bool m_result;
1721 bool doesWrites(Graph&, Node*);
1723 class AbstractHeapOverlaps {
1725 AbstractHeapOverlaps(AbstractHeap heap)
1731 void operator()(AbstractHeap otherHeap) const
1735 m_result = m_heap.overlaps(otherHeap);
1738 bool result() const { return m_result; }
1741 AbstractHeap m_heap;
1742 mutable bool m_result;
1745 bool accessesOverlap(Graph&, Node*, AbstractHeap);
1746 bool writesOverlap(Graph&, Node*, AbstractHeap);
1748 bool clobbersHeap(Graph&, Node*);
1750 // We would have used bind() for these, but because of the overlaoding that we are doing,
1751 // it's quite a bit of clearer to just write this out the traditional way.
1753 template<typename T>
1754 class ReadMethodClobberize {
1756 ReadMethodClobberize(T& value)
1761 void operator()(AbstractHeap heap) const
1769 template<typename T>
1770 class WriteMethodClobberize {
1772 WriteMethodClobberize(T& value)
1777 void operator()(AbstractHeap heap) const
1779 m_value.write(heap);
1785 template<typename T>
1786 class DefMethodClobberize {
1788 DefMethodClobberize(T& value)
1793 void operator()(PureValue value) const
1798 void operator()(HeapLocation location, LazyNode node) const
1800 m_value.def(location, node);
1807 template<typename Adaptor>
1808 void clobberize(Graph& graph, Node* node, Adaptor& adaptor)
1810 ReadMethodClobberize<Adaptor> read(adaptor);
1811 WriteMethodClobberize<Adaptor> write(adaptor);
1812 DefMethodClobberize<Adaptor> def(adaptor);
1813 clobberize(graph, node, read, write, def);
1816 } } // namespace JSC::DFG
1818 #endif // ENABLE(DFG_JIT)