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 "InlineCallFrame.h"
39 #include "JSFixedArray.h"
41 namespace JSC { namespace DFG {
43 template<typename ReadFunctor, typename WriteFunctor, typename DefFunctor>
44 void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFunctor& write, const DefFunctor& def)
48 // - The canonical way of clobbering the world is to read world and write
49 // heap. This is because World subsumes Heap and Stack, and Stack can be
50 // read by anyone but only written to by explicit stack writing operations.
51 // Of course, claiming to also write World is not wrong; it'll just
52 // pessimise some important optimizations.
54 // - We cannot hoist, or sink, anything that has effects. This means that the
55 // easiest way of indicating that something cannot be hoisted is to claim
56 // that it side-effects some miscellaneous thing.
58 // - We cannot hoist forward-exiting nodes without some additional effort. I
59 // believe that what it comes down to is that forward-exiting generally have
60 // their NodeExitsForward cleared upon hoist, except for forward-exiting
61 // nodes that take bogus state as their input. Those are substantially
62 // harder. We disable it for now. In the future we could enable it by having
63 // versions of those nodes that backward-exit instead, but I'm not convinced
66 // - Some nodes lie, and claim that they do not read the JSCell_structureID,
67 // JSCell_typeInfoFlags, etc. These are nodes that use the structure in a way
68 // that does not depend on things that change under structure transitions.
70 // - It's implicitly understood that OSR exits read the world. This is why we
71 // generally don't move or eliminate stores. Every node can exit, so the
72 // read set does not reflect things that would be read if we exited.
73 // Instead, the read set reflects what the node will have to read if it
76 // - Broadly, we don't say that we're reading something if that something is
79 // - This must be sound even prior to type inference. We use this as early as
80 // bytecode parsing to determine at which points in the program it's legal to
83 // - If you do read(Stack) or read(World), then make sure that readTop() in
84 // PreciseLocalClobberize is correct.
86 // While read() and write() are fairly self-explanatory - they track what sorts of things the
87 // node may read or write - the def() functor is more tricky. It tells you the heap locations
88 // (not just abstract heaps) that are defined by a node. A heap location comprises an abstract
89 // heap, some nodes, and a LocationKind. Briefly, a location defined by a node is a location
90 // whose value can be deduced from looking at the node itself. The locations returned must obey
91 // the following properties:
93 // - If someone wants to CSE a load from the heap, then a HeapLocation object should be
94 // sufficient to find a single matching node.
96 // - The abstract heap is the only abstract heap that could be clobbered to invalidate any such
97 // CSE attempt. I.e. if clobberize() reports that on every path between some node and a node
98 // that defines a HeapLocation that it wanted, there were no writes to any abstract heap that
99 // overlap the location's heap, then we have a sound match. Effectively, the semantics of
100 // write() and def() are intertwined such that for them to be sound they must agree on what
103 // read(), write(), and def() for heap locations is enough to do GCSE on effectful things. To
104 // keep things simple, this code will also def() pure things. def() must be overloaded to also
105 // accept PureValue. This way, a client of clobberize() can implement GCSE entirely using the
106 // information that clobberize() passes to write() and def(). Other clients of clobberize() can
107 // just ignore def() by using a NoOpClobberize functor.
109 if (edgesUseStructure(graph, node))
110 read(JSCell_structureID);
112 // We allow the runtime to perform a stack scan at any time. We don't model which nodes get implemented
113 // by calls into the runtime. For debugging we might replace the implementation of any node with a call
114 // to the runtime, and that call may walk stack. Therefore, each node must read() anything that a stack
115 // scan would read. That's what this does.
116 for (InlineCallFrame* inlineCallFrame = node->origin.semantic.inlineCallFrame; inlineCallFrame; inlineCallFrame = inlineCallFrame->directCaller.inlineCallFrame) {
117 if (inlineCallFrame->isClosureCall)
118 read(AbstractHeap(Stack, inlineCallFrame->stackOffset + CallFrameSlot::callee));
119 if (inlineCallFrame->isVarargs())
120 read(AbstractHeap(Stack, inlineCallFrame->stackOffset + CallFrameSlot::argumentCount));
123 // We don't want to specifically account which nodes can read from the scope
124 // when the debugger is enabled. It's helpful to just claim all nodes do.
125 // Specifically, if a node allocates, this may call into the debugger's machinery.
126 // The debugger's machinery is free to take a stack trace and try to read from
127 // a scope which is expected to be flushed to the stack.
128 if (graph.hasDebuggerEnabled()) {
129 ASSERT(!node->origin.semantic.inlineCallFrame);
130 read(AbstractHeap(Stack, graph.m_codeBlock->scopeRegister()));
133 switch (node->op()) {
137 def(PureValue(node, node->constant()));
141 case IdentityWithProfile:
145 case ExtractOSREntryLocal:
146 case ExtractCatchLocal:
147 case CheckStructureImmediate:
151 // We should enable CSE of LazyJSConstant. It's a little annoying since LazyJSValue has
152 // more bits than we currently have in PureValue.
156 def(PureValue(node, node->cellOperand()->cell()));
165 case GetGlobalObject:
166 case StringCharCodeAt:
167 case CompareStrictEq:
172 case NumberIsInteger:
174 case IsTypedArrayView:
180 case BooleanToNumber:
188 def(PureValue(node));
195 case AtomicsIsLockFree:
196 if (node->child1().useKind() == Int32Use)
197 def(PureValue(node));
205 if (node->child1().useKind() == DoubleRepUse)
206 def(PureValue(node, static_cast<std::underlying_type<Arith::UnaryType>::type>(node->arithUnaryType())));
215 if (node->child1().useKind() == DoubleRepUse)
216 def(PureValue(node));
224 if (node->child1().useKind() == Int32Use || node->child1().useKind() == DoubleRepUse)
225 def(PureValue(node));
233 if (node->child1().useKind() == Int32Use || node->child1().useKind() == KnownInt32Use)
234 def(PureValue(node));
242 if (node->child1().useKind() == Int32Use
243 || node->child1().useKind() == DoubleRepUse
244 || node->child1().useKind() == Int52RepUse)
245 def(PureValue(node));
253 def(PureValue(node, node->queriedType()));
262 if (node->child1().useKind() == UntypedUse || node->child2().useKind() == UntypedUse) {
267 def(PureValue(node));
271 read(MathDotRandomState);
272 write(MathDotRandomState);
275 case HasGenericProperty:
276 case HasStructureProperty:
277 case GetPropertyEnumerator: {
283 case GetEnumerableLength: {
289 case GetDirectPname: {
290 // This reads and writes heap because it can end up calling a generic getByVal
291 // if the Structure changed, which could in turn end up calling a getter.
298 case GetEnumeratorStructurePname:
299 case GetEnumeratorGenericPname: {
300 def(PureValue(node));
304 case HasIndexedProperty: {
305 read(JSObject_butterfly);
306 ArrayMode mode = node->arrayMode();
307 switch (mode.type()) {
308 case Array::ForceExit: {
313 if (mode.isInBounds()) {
314 read(Butterfly_publicLength);
315 read(IndexedInt32Properties);
316 def(HeapLocation(HasIndexedPropertyLoc, IndexedInt32Properties, node->child1(), node->child2()), LazyNode(node));
323 case Array::Double: {
324 if (mode.isInBounds()) {
325 read(Butterfly_publicLength);
326 read(IndexedDoubleProperties);
327 def(HeapLocation(HasIndexedPropertyLoc, IndexedDoubleProperties, node->child1(), node->child2()), LazyNode(node));
334 case Array::Contiguous: {
335 if (mode.isInBounds()) {
336 read(Butterfly_publicLength);
337 read(IndexedContiguousProperties);
338 def(HeapLocation(HasIndexedPropertyLoc, IndexedContiguousProperties, node->child1(), node->child2()), LazyNode(node));
345 case Array::ArrayStorage: {
346 if (mode.isInBounds()) {
347 read(Butterfly_vectorLength);
348 read(IndexedArrayStorageProperties);
361 RELEASE_ASSERT_NOT_REACHED();
365 case StringFromCharCode:
366 switch (node->child1().useKind()) {
368 def(PureValue(node));
375 DFG_CRASH(graph, node, "Bad use kind");
383 def(PureValue(node, node->arithMode()));
389 switch (node->binaryUseKind()) {
393 def(PureValue(node, node->arithMode()));
400 DFG_CRASH(graph, node, "Bad use kind");
407 if (node->child1().useKind() == DoubleRepUse)
408 def(PureValue(node, static_cast<uintptr_t>(node->arithRoundingMode())));
416 def(PureValue(CheckCell, AdjacencyList(AdjacencyList::Fixed, node->child1()), node->cellOperand()));
420 def(PureValue(CheckNotEmpty, AdjacencyList(AdjacencyList::Fixed, node->child1())));
427 case CheckStringIdent:
428 def(PureValue(CheckStringIdent, AdjacencyList(AdjacencyList::Fixed, node->child1()), node->uidOperand()));
431 case ConstantStoragePointer:
432 def(PureValue(node, node->storagePointer()));
452 case CheckTierUpInLoop:
453 case CheckTierUpAtReturn:
454 case CheckTierUpAndOSREnter:
457 case ProfileControlFlow:
459 case InitializeEntrypointArguments:
464 read(JSCell_cellState);
465 write(JSCell_cellState);
468 case FencedStoreBarrier:
470 write(JSCell_cellState);
474 if (Options::usePollingTraps()) {
476 write(InternalState);
478 write(Watchpoint_fire);
481 case InvalidationPoint:
483 def(HeapLocation(InvalidationPointLoc, Watchpoint_fire), LazyNode(node));
487 read(AbstractHeap(Stack, node->local()));
492 write(Watchpoint_fire);
496 case PushWithScope: {
498 write(HeapObjectCount);
502 case CreateActivation: {
503 SymbolTable* table = node->castOperand<SymbolTable*>();
504 if (table->singletonScope()->isStillValid())
505 write(Watchpoint_fire);
506 read(HeapObjectCount);
507 write(HeapObjectCount);
511 case CreateDirectArguments:
512 case CreateScopedArguments:
513 case CreateClonedArguments:
515 read(HeapObjectCount);
516 write(HeapObjectCount);
519 case PhantomDirectArguments:
520 case PhantomClonedArguments:
521 // DFG backend requires that the locals that this reads are flushed. FTL backend can handle those
522 // locals being promoted.
523 if (!isFTL(graph.m_plan.mode))
526 // Even though it's phantom, it still has the property that one can't be replaced with another.
527 read(HeapObjectCount);
528 write(HeapObjectCount);
532 case PhantomNewArrayWithSpread:
533 case PhantomNewArrayBuffer:
534 case PhantomCreateRest:
535 // Even though it's phantom, it still has the property that one can't be replaced with another.
536 read(HeapObjectCount);
537 write(HeapObjectCount);
545 case CallObjectConstructor:
546 read(HeapObjectCount);
547 write(HeapObjectCount);
553 read(HeapObjectCount);
554 write(HeapObjectCount);
559 def(HeapLocation(IsObjectOrNullLoc, MiscFields, node->child1()), LazyNode(node));
564 def(HeapLocation(IsFunctionLoc, MiscFields, node->child1()), LazyNode(node));
569 read(JSCell_indexingType);
570 read(JSCell_structureID);
571 read(JSObject_butterfly);
572 read(JSObject_butterflyMask);
573 read(Butterfly_publicLength);
574 read(IndexedDoubleProperties);
575 read(IndexedInt32Properties);
576 read(IndexedContiguousProperties);
577 read(HeapObjectCount);
578 write(HeapObjectCount);
582 // FIXME: Should support a CSE rule.
583 // https://bugs.webkit.org/show_bug.cgi?id=173173
585 read(JSCell_indexingType);
586 read(JSCell_structureID);
587 read(JSObject_butterfly);
588 read(JSObject_butterflyMask);
589 read(Butterfly_publicLength);
590 switch (node->arrayMode().type()) {
592 read(IndexedDoubleProperties);
595 read(IndexedInt32Properties);
597 case Array::Contiguous:
598 read(IndexedContiguousProperties);
601 RELEASE_ASSERT_NOT_REACHED();
609 case GetByIdWithThis:
610 case GetByValWithThis:
612 case PutByIdWithThis:
613 case PutByValWithThis:
618 case PutGetterSetterById:
621 case DefineDataProperty:
622 case DefineAccessorProperty:
629 case TailCallInlinedCaller:
630 case DirectTailCallInlinedCaller:
632 case DirectConstruct:
634 case CallForwardVarargs:
635 case TailCallVarargsInlinedCaller:
636 case TailCallForwardVarargsInlinedCaller:
637 case ConstructVarargs:
638 case ConstructForwardVarargs:
643 case SetFunctionName:
646 case ResolveScopeForHoistingFuncDeclInEval:
654 case AtomicsCompareExchange:
655 case AtomicsExchange:
661 unsigned numExtraArgs = numExtraAtomicsArgs(node->op());
662 Edge storageEdge = graph.child(node, 2 + numExtraArgs);
668 read(TypedArrayProperties);
670 write(TypedArrayProperties);
675 ASSERT(!node->origin.semantic.inlineCallFrame);
676 read(AbstractHeap(Stack, graph.m_codeBlock->scopeRegister()));
677 read(AbstractHeap(Stack, virtualRegisterForArgument(0)));
683 case ThrowStaticError:
686 case TailCallVarargs:
687 case TailCallForwardVarargs:
693 read(GetterSetter_getter);
694 def(HeapLocation(GetterLoc, GetterSetter_getter, node->child1()), LazyNode(node));
698 read(GetterSetter_setter);
699 def(HeapLocation(SetterLoc, GetterSetter_setter, node->child1()), LazyNode(node));
703 read(AbstractHeap(Stack, CallFrameSlot::callee));
704 def(HeapLocation(StackLoc, AbstractHeap(Stack, CallFrameSlot::callee)), LazyNode(node));
707 case GetArgumentCountIncludingThis: {
708 auto heap = AbstractHeap(Stack, remapOperand(node->argumentsInlineCallFrame(), VirtualRegister(CallFrameSlot::argumentCount)));
710 def(HeapLocation(StackPayloadLoc, heap), LazyNode(node));
714 case SetArgumentCountIncludingThis:
715 write(AbstractHeap(Stack, CallFrameSlot::argumentCount));
723 read(AbstractHeap(Stack, node->local()));
724 def(HeapLocation(StackLoc, AbstractHeap(Stack, node->local())), LazyNode(node));
728 write(AbstractHeap(Stack, node->local()));
729 def(HeapLocation(StackLoc, AbstractHeap(Stack, node->local())), LazyNode(node->child1().node()));
733 AbstractHeap heap(Stack, node->stackAccessData()->local);
735 def(HeapLocation(StackLoc, heap), LazyNode(node));
740 AbstractHeap heap(Stack, node->stackAccessData()->local);
742 def(HeapLocation(StackLoc, heap), LazyNode(node->child1().node()));
749 LoadVarargsData* data = node->loadVarargsData();
750 write(AbstractHeap(Stack, data->count.offset()));
751 for (unsigned i = data->limit; i--;)
752 write(AbstractHeap(Stack, data->start.offset() + static_cast<int>(i)));
756 case ForwardVarargs: {
757 // We could be way more precise here.
760 LoadVarargsData* data = node->loadVarargsData();
761 write(AbstractHeap(Stack, data->count.offset()));
762 for (unsigned i = data->limit; i--;)
763 write(AbstractHeap(Stack, data->start.offset() + static_cast<int>(i)));
768 ArrayMode mode = node->arrayMode();
769 LocationKind indexedPropertyLoc = indexedPropertyLocForResultType(node->result());
770 switch (mode.type()) {
771 case Array::SelectUsingPredictions:
772 case Array::Unprofiled:
773 case Array::SelectUsingArguments:
774 // Assume the worst since we don't have profiling yet.
779 case Array::ForceExit:
789 if (mode.isOutOfBounds()) {
794 // This appears to read nothing because it's only reading immutable data.
795 def(PureValue(graph, node, mode.asWord()));
798 case Array::DirectArguments:
799 if (mode.isInBounds()) {
800 read(DirectArgumentsProperties);
801 def(HeapLocation(indexedPropertyLoc, DirectArgumentsProperties, graph.varArgChild(node, 0), graph.varArgChild(node, 1)), LazyNode(node));
808 case Array::ScopedArguments:
809 read(ScopeProperties);
810 def(HeapLocation(indexedPropertyLoc, ScopeProperties, graph.varArgChild(node, 0), graph.varArgChild(node, 1)), LazyNode(node));
814 if (mode.isInBounds()) {
815 read(Butterfly_publicLength);
816 read(IndexedInt32Properties);
817 def(HeapLocation(indexedPropertyLoc, IndexedInt32Properties, graph.varArgChild(node, 0), graph.varArgChild(node, 1)), LazyNode(node));
825 if (mode.isInBounds()) {
826 read(Butterfly_publicLength);
827 read(IndexedDoubleProperties);
828 def(HeapLocation(indexedPropertyLoc, IndexedDoubleProperties, graph.varArgChild(node, 0), graph.varArgChild(node, 1)), LazyNode(node));
835 case Array::Contiguous:
836 if (mode.isInBounds()) {
837 read(Butterfly_publicLength);
838 read(IndexedContiguousProperties);
839 def(HeapLocation(indexedPropertyLoc, IndexedContiguousProperties, graph.varArgChild(node, 0), graph.varArgChild(node, 1)), LazyNode(node));
846 case Array::Undecided:
847 def(PureValue(graph, node));
850 case Array::ArrayStorage:
851 case Array::SlowPutArrayStorage:
852 if (mode.isInBounds()) {
853 read(Butterfly_vectorLength);
854 read(IndexedArrayStorageProperties);
861 case Array::Int8Array:
862 case Array::Int16Array:
863 case Array::Int32Array:
864 case Array::Uint8Array:
865 case Array::Uint8ClampedArray:
866 case Array::Uint16Array:
867 case Array::Uint32Array:
868 case Array::Float32Array:
869 case Array::Float64Array:
870 read(TypedArrayProperties);
872 def(HeapLocation(indexedPropertyLoc, TypedArrayProperties, graph.varArgChild(node, 0), graph.varArgChild(node, 1)), LazyNode(node));
874 // We should not get an AnyTypedArray in a GetByVal as AnyTypedArray is only created from intrinsics, which
875 // are only added from Inline Caching a GetById.
876 case Array::AnyTypedArray:
877 DFG_CRASH(graph, node, "impossible array mode for get");
880 RELEASE_ASSERT_NOT_REACHED();
884 case GetMyArgumentByVal:
885 case GetMyArgumentByValOutOfBounds: {
887 // FIXME: It would be trivial to have a def here.
888 // https://bugs.webkit.org/show_bug.cgi?id=143077
894 case PutByValAlias: {
895 ArrayMode mode = node->arrayMode();
896 Node* base = graph.varArgChild(node, 0).node();
897 Node* index = graph.varArgChild(node, 1).node();
898 Node* value = graph.varArgChild(node, 2).node();
899 LocationKind indexedPropertyLoc = indexedPropertyLocForResultType(node->result());
901 switch (mode.modeForPut().type()) {
902 case Array::SelectUsingPredictions:
903 case Array::SelectUsingArguments:
904 case Array::Unprofiled:
905 case Array::Undecided:
906 // Assume the worst since we don't have profiling yet.
911 case Array::ForceExit:
921 if (node->arrayMode().isOutOfBounds()) {
926 read(Butterfly_publicLength);
927 read(Butterfly_vectorLength);
928 read(IndexedInt32Properties);
929 write(IndexedInt32Properties);
930 if (node->arrayMode().mayStoreToHole())
931 write(Butterfly_publicLength);
932 def(HeapLocation(indexedPropertyLoc, IndexedInt32Properties, base, index), LazyNode(value));
936 if (node->arrayMode().isOutOfBounds()) {
941 read(Butterfly_publicLength);
942 read(Butterfly_vectorLength);
943 read(IndexedDoubleProperties);
944 write(IndexedDoubleProperties);
945 if (node->arrayMode().mayStoreToHole())
946 write(Butterfly_publicLength);
947 def(HeapLocation(indexedPropertyLoc, IndexedDoubleProperties, base, index), LazyNode(value));
950 case Array::Contiguous:
951 if (node->arrayMode().isOutOfBounds()) {
956 read(Butterfly_publicLength);
957 read(Butterfly_vectorLength);
958 read(IndexedContiguousProperties);
959 write(IndexedContiguousProperties);
960 if (node->arrayMode().mayStoreToHole())
961 write(Butterfly_publicLength);
962 def(HeapLocation(indexedPropertyLoc, IndexedContiguousProperties, base, index), LazyNode(value));
965 case Array::ArrayStorage:
966 case Array::SlowPutArrayStorage:
967 // Give up on life for now.
972 case Array::Int8Array:
973 case Array::Int16Array:
974 case Array::Int32Array:
975 case Array::Uint8Array:
976 case Array::Uint8ClampedArray:
977 case Array::Uint16Array:
978 case Array::Uint32Array:
979 case Array::Float32Array:
980 case Array::Float64Array:
982 write(TypedArrayProperties);
983 // FIXME: We can't def() anything here because these operations truncate their inputs.
984 // https://bugs.webkit.org/show_bug.cgi?id=134737
986 case Array::AnyTypedArray:
988 case Array::DirectArguments:
989 case Array::ScopedArguments:
990 DFG_CRASH(graph, node, "impossible array mode for put");
993 RELEASE_ASSERT_NOT_REACHED();
997 case CheckStructureOrEmpty:
999 read(JSCell_structureID);
1003 read(JSCell_indexingType);
1004 read(JSCell_typeInfoType);
1005 read(JSCell_structureID);
1008 case CheckTypeInfoFlags:
1009 read(JSCell_typeInfoFlags);
1010 def(HeapLocation(CheckTypeInfoFlagsLoc, JSCell_typeInfoFlags, node->child1()), LazyNode(node));
1014 // Note: We would have eliminated a ParseInt that has just a single child as an Int32Use inside fixup.
1015 if (node->child1().useKind() == StringUse && (!node->child2() || node->child2().useKind() == Int32Use)) {
1016 def(PureValue(node));
1024 case OverridesHasInstance:
1025 read(JSCell_typeInfoFlags);
1026 def(HeapLocation(OverridesHasInstanceLoc, JSCell_typeInfoFlags, node->child1()), LazyNode(node));
1030 read(JSCell_structureID);
1031 def(HeapLocation(InstanceOfLoc, JSCell_structureID, node->child1(), node->child2()), LazyNode(node));
1034 case InstanceOfCustom:
1040 read(JSObject_butterfly);
1041 write(JSCell_structureID);
1042 write(JSCell_typeInfoType);
1043 write(JSCell_typeInfoFlags);
1044 write(JSCell_indexingType);
1047 case AllocatePropertyStorage:
1048 case ReallocatePropertyStorage:
1049 read(HeapObjectCount);
1050 write(HeapObjectCount);
1053 case NukeStructureAndSetButterfly:
1054 write(JSObject_butterfly);
1055 write(JSCell_structureID);
1056 def(HeapLocation(ButterflyLoc, JSObject_butterfly, node->child1()), LazyNode(node->child2().node()));
1060 read(JSObject_butterfly);
1061 def(HeapLocation(ButterflyLoc, JSObject_butterfly, node->child1()), LazyNode(node));
1065 def(PureValue(node, node->classInfo()));
1068 case CallDOMGetter: {
1069 DOMJIT::CallDOMGetterSnippet* snippet = node->callDOMGetterData()->snippet;
1075 DOMJIT::Effect effect = snippet->effect;
1077 if (effect.reads == DOMJIT::HeapRange::top())
1080 read(AbstractHeap(DOMState, effect.reads.rawRepresentation()));
1082 if (effect.writes) {
1083 if (effect.writes == DOMJIT::HeapRange::top())
1086 write(AbstractHeap(DOMState, effect.writes.rawRepresentation()));
1088 if (effect.def != DOMJIT::HeapRange::top()) {
1089 DOMJIT::HeapRange range = effect.def;
1090 if (range == DOMJIT::HeapRange::none())
1091 def(PureValue(node, bitwise_cast<uintptr_t>(node->callDOMGetterData()->customAccessorGetter)));
1093 // Def with heap location. We do not include "GlobalObject" for that since this information is included in the base node.
1094 // We only see the DOMJIT getter here. So just including "base" is ok.
1095 def(HeapLocation(DOMStateLoc, AbstractHeap(DOMState, range.rawRepresentation()), node->child1()), LazyNode(node));
1102 const DOMJIT::Signature* signature = node->signature();
1103 DOMJIT::Effect effect = signature->effect;
1105 if (effect.reads == DOMJIT::HeapRange::top())
1108 read(AbstractHeap(DOMState, effect.reads.rawRepresentation()));
1110 if (effect.writes) {
1111 if (effect.writes == DOMJIT::HeapRange::top())
1114 write(AbstractHeap(DOMState, effect.writes.rawRepresentation()));
1116 ASSERT_WITH_MESSAGE(effect.def == DOMJIT::HeapRange::top(), "Currently, we do not accept any def for CallDOM.");
1121 case ArrayifyToStructure:
1122 read(JSCell_structureID);
1123 read(JSCell_indexingType);
1124 read(JSObject_butterfly);
1125 write(JSCell_structureID);
1126 write(JSCell_indexingType);
1127 write(JSObject_butterfly);
1128 write(JSObject_butterflyMask);
1129 write(Watchpoint_fire);
1132 case GetIndexedPropertyStorage:
1133 if (node->arrayMode().type() == Array::String) {
1134 def(PureValue(node, node->arrayMode().asWord()));
1138 def(HeapLocation(IndexedPropertyStorageLoc, MiscFields, node->child1()), LazyNode(node));
1141 case GetTypedArrayByteOffset:
1143 def(HeapLocation(TypedArrayByteOffsetLoc, MiscFields, node->child1()), LazyNode(node));
1146 case GetPrototypeOf: {
1147 switch (node->child1().useKind()) {
1150 case FinalObjectUse:
1151 read(JSCell_structureID);
1152 read(JSObject_butterfly);
1153 read(NamedProperties); // Poly proto could load prototype from its slot.
1154 def(HeapLocation(PrototypeLoc, NamedProperties, node->child1()), LazyNode(node));
1164 case GetGetterSetterByOffset: {
1165 unsigned identifierNumber = node->storageAccessData().identifierNumber;
1166 AbstractHeap heap(NamedProperties, identifierNumber);
1168 def(HeapLocation(NamedPropertyLoc, heap, node->child2()), LazyNode(node));
1177 case MultiGetByOffset: {
1178 read(JSCell_structureID);
1179 read(JSObject_butterfly);
1180 read(JSObject_butterflyMask);
1181 AbstractHeap heap(NamedProperties, node->multiGetByOffsetData().identifierNumber);
1183 // FIXME: We cannot def() for MultiGetByOffset because CSE is not smart enough to decay it
1184 // to a CheckStructure.
1185 // https://bugs.webkit.org/show_bug.cgi?id=159859
1189 case MultiPutByOffset: {
1190 read(JSCell_structureID);
1191 read(JSObject_butterfly);
1192 AbstractHeap heap(NamedProperties, node->multiPutByOffsetData().identifierNumber);
1194 if (node->multiPutByOffsetData().writesStructures())
1195 write(JSCell_structureID);
1196 if (node->multiPutByOffsetData().reallocatesStorage())
1197 write(JSObject_butterfly);
1198 def(HeapLocation(NamedPropertyLoc, heap, node->child1()), LazyNode(node->child2().node()));
1203 unsigned identifierNumber = node->storageAccessData().identifierNumber;
1204 AbstractHeap heap(NamedProperties, identifierNumber);
1206 def(HeapLocation(NamedPropertyLoc, heap, node->child2()), LazyNode(node->child3().node()));
1211 read(JSObject_butterflyMask);
1212 def(HeapLocation(ArrayMaskLoc, JSObject_butterflyMask, node->child1()), LazyNode(node));
1215 case GetArrayLength: {
1216 ArrayMode mode = node->arrayMode();
1217 switch (mode.type()) {
1218 case Array::Undecided:
1221 case Array::Contiguous:
1222 case Array::ArrayStorage:
1223 case Array::SlowPutArrayStorage:
1224 read(Butterfly_publicLength);
1225 def(HeapLocation(ArrayLengthLoc, Butterfly_publicLength, node->child1()), LazyNode(node));
1229 def(PureValue(node, mode.asWord()));
1232 case Array::DirectArguments:
1233 case Array::ScopedArguments:
1235 def(HeapLocation(ArrayLengthLoc, MiscFields, node->child1()), LazyNode(node));
1239 ASSERT(mode.isSomeTypedArrayView());
1241 def(HeapLocation(ArrayLengthLoc, MiscFields, node->child1()), LazyNode(node));
1246 case GetVectorLength: {
1247 ArrayMode mode = node->arrayMode();
1248 switch (mode.type()) {
1249 case Array::ArrayStorage:
1250 case Array::SlowPutArrayStorage:
1251 read(Butterfly_vectorLength);
1252 def(HeapLocation(VectorLengthLoc, Butterfly_vectorLength, node->child1()), LazyNode(node));
1256 RELEASE_ASSERT_NOT_REACHED();
1262 read(AbstractHeap(ScopeProperties, node->scopeOffset().offset()));
1263 def(HeapLocation(ClosureVariableLoc, AbstractHeap(ScopeProperties, node->scopeOffset().offset()), node->child1()), LazyNode(node));
1267 write(AbstractHeap(ScopeProperties, node->scopeOffset().offset()));
1268 def(HeapLocation(ClosureVariableLoc, AbstractHeap(ScopeProperties, node->scopeOffset().offset()), node->child1()), LazyNode(node->child2().node()));
1271 case GetRegExpObjectLastIndex:
1272 read(RegExpObject_lastIndex);
1273 def(HeapLocation(RegExpObjectLastIndexLoc, RegExpObject_lastIndex, node->child1()), LazyNode(node));
1276 case SetRegExpObjectLastIndex:
1277 write(RegExpObject_lastIndex);
1278 def(HeapLocation(RegExpObjectLastIndexLoc, RegExpObject_lastIndex, node->child1()), LazyNode(node->child2().node()));
1281 case RecordRegExpCachedResult:
1285 case GetFromArguments: {
1286 AbstractHeap heap(DirectArgumentsProperties, node->capturedArgumentsOffset().offset());
1288 def(HeapLocation(DirectArgumentsLoc, heap, node->child1()), LazyNode(node));
1292 case PutToArguments: {
1293 AbstractHeap heap(DirectArgumentsProperties, node->capturedArgumentsOffset().offset());
1295 def(HeapLocation(DirectArgumentsLoc, heap, node->child1()), LazyNode(node->child2().node()));
1301 // FIXME: It would be trivial to have a def here.
1302 // https://bugs.webkit.org/show_bug.cgi?id=143077
1307 case GetGlobalLexicalVariable:
1308 read(AbstractHeap(Absolute, node->variablePointer()));
1309 def(HeapLocation(GlobalVariableLoc, AbstractHeap(Absolute, node->variablePointer())), LazyNode(node));
1312 case PutGlobalVariable:
1313 write(AbstractHeap(Absolute, node->variablePointer()));
1314 def(HeapLocation(GlobalVariableLoc, AbstractHeap(Absolute, node->variablePointer())), LazyNode(node->child2().node()));
1317 case NewArrayWithSize:
1319 read(HeapObjectCount);
1320 write(HeapObjectCount);
1323 case NewArrayWithSpread: {
1324 // This also reads from JSFixedArray's data store, but we don't have any way of describing that yet.
1325 read(HeapObjectCount);
1326 for (unsigned i = 0; i < node->numChildren(); i++) {
1327 Node* child = graph.varArgChild(node, i).node();
1328 if (child->op() == PhantomSpread) {
1333 write(HeapObjectCount);
1338 if (node->child1()->op() == PhantomNewArrayBuffer) {
1343 if (node->child1()->op() == PhantomCreateRest) {
1345 write(HeapObjectCount);
1355 read(HeapObjectCount);
1356 write(HeapObjectCount);
1358 unsigned numElements = node->numChildren();
1360 def(HeapLocation(ArrayLengthLoc, Butterfly_publicLength, node),
1361 LazyNode(graph.freeze(jsNumber(numElements))));
1367 LocationKind indexedPropertyLoc;
1368 switch (node->indexingType()) {
1369 case ALL_DOUBLE_INDEXING_TYPES:
1370 heap = IndexedDoubleProperties;
1371 indexedPropertyLoc = IndexedPropertyDoubleLoc;
1374 case ALL_INT32_INDEXING_TYPES:
1375 heap = IndexedInt32Properties;
1376 indexedPropertyLoc = IndexedPropertyJSLoc;
1379 case ALL_CONTIGUOUS_INDEXING_TYPES:
1380 heap = IndexedContiguousProperties;
1381 indexedPropertyLoc = IndexedPropertyJSLoc;
1388 if (numElements < graph.m_uint32ValuesInUse.size()) {
1389 for (unsigned operandIdx = 0; operandIdx < numElements; ++operandIdx) {
1390 Edge use = graph.m_varArgChildren[node->firstChild() + operandIdx];
1391 def(HeapLocation(indexedPropertyLoc, heap, node, LazyNode(graph.freeze(jsNumber(operandIdx)))),
1392 LazyNode(use.node()));
1395 for (uint32_t operandIdx : graph.m_uint32ValuesInUse) {
1396 if (operandIdx >= numElements)
1398 Edge use = graph.m_varArgChildren[node->firstChild() + operandIdx];
1399 // operandIdx comes from graph.m_uint32ValuesInUse and thus is guaranteed to be already frozen
1400 def(HeapLocation(indexedPropertyLoc, heap, node, LazyNode(graph.freeze(jsNumber(operandIdx)))),
1401 LazyNode(use.node()));
1407 case NewArrayBuffer: {
1408 read(HeapObjectCount);
1409 write(HeapObjectCount);
1411 JSFixedArray* array = node->castOperand<JSFixedArray*>();
1412 unsigned numElements = array->length();
1413 def(HeapLocation(ArrayLengthLoc, Butterfly_publicLength, node),
1414 LazyNode(graph.freeze(jsNumber(numElements))));
1417 LocationKind indexedPropertyLoc;
1418 NodeType op = JSConstant;
1419 switch (node->indexingType()) {
1420 case ALL_DOUBLE_INDEXING_TYPES:
1421 heap = IndexedDoubleProperties;
1422 indexedPropertyLoc = IndexedPropertyDoubleLoc;
1423 op = DoubleConstant;
1426 case ALL_INT32_INDEXING_TYPES:
1427 heap = IndexedInt32Properties;
1428 indexedPropertyLoc = IndexedPropertyJSLoc;
1431 case ALL_CONTIGUOUS_INDEXING_TYPES:
1432 heap = IndexedContiguousProperties;
1433 indexedPropertyLoc = IndexedPropertyJSLoc;
1440 if (numElements < graph.m_uint32ValuesInUse.size()) {
1441 for (unsigned index = 0; index < numElements; ++index) {
1442 def(HeapLocation(indexedPropertyLoc, heap, node, LazyNode(graph.freeze(jsNumber(index)))),
1443 LazyNode(graph.freeze(array->get(index)), op));
1446 Vector<uint32_t> possibleIndices;
1447 for (uint32_t index : graph.m_uint32ValuesInUse) {
1448 if (index >= numElements)
1450 possibleIndices.append(index);
1452 for (uint32_t index : possibleIndices) {
1453 def(HeapLocation(indexedPropertyLoc, heap, node, LazyNode(graph.freeze(jsNumber(index)))),
1454 LazyNode(graph.freeze(array->get(index)), op));
1461 if (!graph.isWatchingHavingABadTimeWatchpoint(node)) {
1462 // This means we're already having a bad time.
1468 read(HeapObjectCount);
1469 write(HeapObjectCount);
1475 case NewStringObject:
1476 case PhantomNewObject:
1477 case MaterializeNewObject:
1478 case PhantomNewFunction:
1479 case PhantomNewGeneratorFunction:
1480 case PhantomNewAsyncFunction:
1481 case PhantomNewAsyncGeneratorFunction:
1482 case PhantomCreateActivation:
1483 case MaterializeCreateActivation:
1484 case PhantomNewRegexp:
1485 read(HeapObjectCount);
1486 write(HeapObjectCount);
1490 case NewGeneratorFunction:
1491 case NewAsyncGeneratorFunction:
1492 case NewAsyncFunction:
1493 if (node->castOperand<FunctionExecutable*>()->singletonFunction()->isStillValid())
1494 write(Watchpoint_fire);
1495 read(HeapObjectCount);
1496 write(HeapObjectCount);
1501 case RegExpMatchFast:
1502 if (node->child2().useKind() == RegExpObjectUse
1503 && node->child3().useKind() == StringUse) {
1505 read(RegExpObject_lastIndex);
1507 write(RegExpObject_lastIndex);
1514 case RegExpExecNonGlobalOrSticky:
1515 case RegExpMatchFastGlobal:
1521 case StringReplaceRegExp:
1522 if (node->child1().useKind() == StringUse
1523 && node->child2().useKind() == RegExpObjectUse
1524 && node->child3().useKind() == StringUse) {
1526 read(RegExpObject_lastIndex);
1528 write(RegExpObject_lastIndex);
1536 if (node->arrayMode().isOutOfBounds()) {
1541 def(PureValue(node));
1545 case CompareBelowEq:
1546 def(PureValue(node));
1552 case CompareGreater:
1553 case CompareGreaterEq:
1554 if (node->isBinaryUseKind(StringUse)) {
1555 read(HeapObjectCount);
1556 write(HeapObjectCount);
1560 if (node->op() == CompareEq && node->isBinaryUseKind(ObjectUse)) {
1561 def(PureValue(node));
1564 if (node->child1().useKind() == UntypedUse || node->child1().useKind() == ObjectUse
1565 || node->child2().useKind() == UntypedUse || node->child2().useKind() == ObjectUse) {
1571 def(PureValue(node));
1581 case CallStringConstructor:
1582 switch (node->child1().useKind()) {
1583 case StringObjectUse:
1584 case StringOrStringObjectUse:
1585 // These don't def a pure value, unfortunately. I'll avoid load-eliminating these for
1599 def(PureValue(node));
1603 RELEASE_ASSERT_NOT_REACHED();
1607 case CountExecution:
1608 case SuperSamplerBegin:
1609 case SuperSamplerEnd:
1610 read(InternalState);
1611 write(InternalState);
1614 case LogShadowChickenPrologue:
1615 case LogShadowChickenTail:
1620 def(PureValue(node));
1623 case NormalizeMapKey:
1624 def(PureValue(node));
1627 case GetMapBucket: {
1628 Edge& mapEdge = node->child1();
1629 Edge& keyEdge = node->child2();
1630 AbstractHeapKind heap = (mapEdge.useKind() == MapObjectUse) ? JSMapFields : JSSetFields;
1632 def(HeapLocation(MapBucketLoc, heap, mapEdge, keyEdge), LazyNode(node));
1636 case GetMapBucketHead: {
1637 Edge& mapEdge = node->child1();
1638 AbstractHeapKind heap = (mapEdge.useKind() == MapObjectUse) ? JSMapFields : JSSetFields;
1640 def(HeapLocation(MapBucketHeadLoc, heap, mapEdge), LazyNode(node));
1644 case GetMapBucketNext: {
1645 AbstractHeapKind heap = (node->bucketOwnerType() == BucketOwnerType::Map) ? JSMapFields : JSSetFields;
1647 Edge& bucketEdge = node->child1();
1648 def(HeapLocation(MapBucketNextLoc, heap, bucketEdge), LazyNode(node));
1652 case LoadKeyFromMapBucket: {
1653 AbstractHeapKind heap = (node->bucketOwnerType() == BucketOwnerType::Map) ? JSMapFields : JSSetFields;
1655 Edge& bucketEdge = node->child1();
1656 def(HeapLocation(MapBucketKeyLoc, heap, bucketEdge), LazyNode(node));
1660 case LoadValueFromMapBucket: {
1661 AbstractHeapKind heap = (node->bucketOwnerType() == BucketOwnerType::Map) ? JSMapFields : JSSetFields;
1663 Edge& bucketEdge = node->child1();
1664 def(HeapLocation(MapBucketValueLoc, heap, bucketEdge), LazyNode(node));
1669 Edge& mapEdge = node->child1();
1670 Edge& keyEdge = node->child2();
1671 AbstractHeapKind heap = (mapEdge.useKind() == WeakMapObjectUse) ? JSWeakMapFields : JSWeakSetFields;
1673 def(HeapLocation(WeakMapGetLoc, heap, mapEdge, keyEdge), LazyNode(node));
1678 Edge& mapEdge = node->child1();
1679 Edge& keyEdge = node->child2();
1681 def(HeapLocation(MapBucketLoc, JSSetFields, mapEdge, keyEdge), LazyNode(node));
1686 Edge& mapEdge = graph.varArgChild(node, 0);
1687 Edge& keyEdge = graph.varArgChild(node, 1);
1689 def(HeapLocation(MapBucketLoc, JSMapFields, mapEdge, keyEdge), LazyNode(node));
1694 Edge& mapEdge = node->child1();
1695 Edge& keyEdge = node->child2();
1696 write(JSWeakSetFields);
1697 def(HeapLocation(WeakMapGetLoc, JSWeakSetFields, mapEdge, keyEdge), LazyNode(keyEdge.node()));
1702 Edge& mapEdge = graph.varArgChild(node, 0);
1703 Edge& keyEdge = graph.varArgChild(node, 1);
1704 Edge& valueEdge = graph.varArgChild(node, 2);
1705 write(JSWeakMapFields);
1706 def(HeapLocation(WeakMapGetLoc, JSWeakMapFields, mapEdge, keyEdge), LazyNode(valueEdge.node()));
1710 case ExtractValueFromWeakMapGet:
1711 def(PureValue(node));
1715 def(PureValue(node));
1719 def(PureValue(node));
1722 case NumberToStringWithRadix:
1723 // If the radix is invalid, NumberToStringWithRadix can throw an error.
1728 case NumberToStringWithValidRadixConstant:
1729 def(PureValue(node, node->validRadixConstant()));
1733 RELEASE_ASSERT_NOT_REACHED();
1737 DFG_CRASH(graph, node, toCString("Unrecognized node type: ", Graph::opName(node->op())).data());
1740 class NoOpClobberize {
1742 NoOpClobberize() { }
1743 template<typename... T>
1744 void operator()(T...) const { }
1747 class CheckClobberize {
1754 template<typename... T>
1755 void operator()(T...) const { m_result = true; }
1757 bool result() const { return m_result; }
1760 mutable bool m_result;
1763 bool doesWrites(Graph&, Node*);
1765 class AbstractHeapOverlaps {
1767 AbstractHeapOverlaps(AbstractHeap heap)
1773 void operator()(AbstractHeap otherHeap) const
1777 m_result = m_heap.overlaps(otherHeap);
1780 bool result() const { return m_result; }
1783 AbstractHeap m_heap;
1784 mutable bool m_result;
1787 bool accessesOverlap(Graph&, Node*, AbstractHeap);
1788 bool writesOverlap(Graph&, Node*, AbstractHeap);
1790 bool clobbersHeap(Graph&, Node*);
1792 // We would have used bind() for these, but because of the overlaoding that we are doing,
1793 // it's quite a bit of clearer to just write this out the traditional way.
1795 template<typename T>
1796 class ReadMethodClobberize {
1798 ReadMethodClobberize(T& value)
1803 void operator()(AbstractHeap heap) const
1811 template<typename T>
1812 class WriteMethodClobberize {
1814 WriteMethodClobberize(T& value)
1819 void operator()(AbstractHeap heap) const
1821 m_value.write(heap);
1827 template<typename T>
1828 class DefMethodClobberize {
1830 DefMethodClobberize(T& value)
1835 void operator()(PureValue value) const
1840 void operator()(HeapLocation location, LazyNode node) const
1842 m_value.def(location, node);
1849 template<typename Adaptor>
1850 void clobberize(Graph& graph, Node* node, Adaptor& adaptor)
1852 ReadMethodClobberize<Adaptor> read(adaptor);
1853 WriteMethodClobberize<Adaptor> write(adaptor);
1854 DefMethodClobberize<Adaptor> def(adaptor);
1855 clobberize(graph, node, read, write, def);
1858 } } // namespace JSC::DFG
1860 #endif // ENABLE(DFG_JIT)