1/*
2 * Copyright (C) 2013-2018 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#if ENABLE(DFG_JIT)
29
30#include "DFGAbstractHeap.h"
31#include "DFGGraph.h"
32#include "DFGHeapLocation.h"
33#include "DFGLazyNode.h"
34#include "DFGPureValue.h"
35#include "DOMJITCallDOMGetterSnippet.h"
36#include "DOMJITSignature.h"
37#include "InlineCallFrame.h"
38#include "JSFixedArray.h"
39#include "JSImmutableButterfly.h"
40
41namespace JSC { namespace DFG {
42
43template<typename ReadFunctor, typename WriteFunctor, typename DefFunctor>
44void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFunctor& write, const DefFunctor& def)
45{
46 // Some notes:
47 //
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.
53 //
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.
57 //
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
64 // of the soundness.
65 //
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.
69 //
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
74 // *doesn't* exit.
75 //
76 // - Broadly, we don't say that we're reading something if that something is
77 // immutable.
78 //
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
81 // OSR exit.
82 //
83 // - If you do read(Stack) or read(World), then make sure that readTop() in
84 // PreciseLocalClobberize is correct.
85
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:
92 //
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.
95 //
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
101 // is CSEable.
102 //
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.
108
109 // We allow the runtime to perform a stack scan at any time. We don't model which nodes get implemented
110 // by calls into the runtime. For debugging we might replace the implementation of any node with a call
111 // to the runtime, and that call may walk stack. Therefore, each node must read() anything that a stack
112 // scan would read. That's what this does.
113 for (InlineCallFrame* inlineCallFrame = node->origin.semantic.inlineCallFrame(); inlineCallFrame; inlineCallFrame = inlineCallFrame->directCaller.inlineCallFrame()) {
114 if (inlineCallFrame->isClosureCall)
115 read(AbstractHeap(Stack, inlineCallFrame->stackOffset + CallFrameSlot::callee));
116 if (inlineCallFrame->isVarargs())
117 read(AbstractHeap(Stack, inlineCallFrame->stackOffset + CallFrameSlot::argumentCount));
118 }
119
120 // We don't want to specifically account which nodes can read from the scope
121 // when the debugger is enabled. It's helpful to just claim all nodes do.
122 // Specifically, if a node allocates, this may call into the debugger's machinery.
123 // The debugger's machinery is free to take a stack trace and try to read from
124 // a scope which is expected to be flushed to the stack.
125 if (graph.hasDebuggerEnabled()) {
126 ASSERT(!node->origin.semantic.inlineCallFrame());
127 read(AbstractHeap(Stack, graph.m_codeBlock->scopeRegister()));
128 }
129
130 switch (node->op()) {
131 case JSConstant:
132 case DoubleConstant:
133 case Int52Constant:
134 def(PureValue(node, node->constant()));
135 return;
136
137 case Identity:
138 case IdentityWithProfile:
139 case Phantom:
140 case Check:
141 case CheckVarargs:
142 case ExtractOSREntryLocal:
143 case CheckStructureImmediate:
144 return;
145
146 case ExtractCatchLocal:
147 read(AbstractHeap(CatchLocals, node->catchOSREntryIndex()));
148 return;
149
150 case ClearCatchLocals:
151 write(CatchLocals);
152 return;
153
154 case LazyJSConstant:
155 // We should enable CSE of LazyJSConstant. It's a little annoying since LazyJSValue has
156 // more bits than we currently have in PureValue.
157 return;
158
159 case CompareEqPtr:
160 def(PureValue(node, node->cellOperand()->cell()));
161 return;
162
163 case ArithIMul:
164 case ArithMin:
165 case ArithMax:
166 case ArithPow:
167 case GetScope:
168 case SkipScope:
169 case GetGlobalObject:
170 case StringCharCodeAt:
171 case CompareStrictEq:
172 case SameValue:
173 case IsEmpty:
174 case IsUndefined:
175 case IsUndefinedOrNull:
176 case IsBoolean:
177 case IsNumber:
178 case NumberIsInteger:
179 case IsObject:
180 case IsTypedArrayView:
181 case LogicalNot:
182 case CheckInBounds:
183 case DoubleRep:
184 case ValueRep:
185 case Int52Rep:
186 case BooleanToNumber:
187 case FiatInt52:
188 case MakeRope:
189 case StrCat:
190 case ValueToInt32:
191 case GetExecutable:
192 case BottomValue:
193 case TypeOf:
194 def(PureValue(node));
195 return;
196
197 case GetGlobalThis:
198 read(World);
199 return;
200
201 case AtomicsIsLockFree:
202 if (node->child1().useKind() == Int32Use)
203 def(PureValue(node));
204 else {
205 read(World);
206 write(Heap);
207 }
208 return;
209
210 case ArithUnary:
211 if (node->child1().useKind() == DoubleRepUse)
212 def(PureValue(node, static_cast<std::underlying_type<Arith::UnaryType>::type>(node->arithUnaryType())));
213 else {
214 read(World);
215 write(Heap);
216 }
217 return;
218
219 case ArithFRound:
220 case ArithSqrt:
221 if (node->child1().useKind() == DoubleRepUse)
222 def(PureValue(node));
223 else {
224 read(World);
225 write(Heap);
226 }
227 return;
228
229 case ArithAbs:
230 if (node->child1().useKind() == Int32Use || node->child1().useKind() == DoubleRepUse)
231 def(PureValue(node));
232 else {
233 read(World);
234 write(Heap);
235 }
236 return;
237
238 case ArithClz32:
239 if (node->child1().useKind() == Int32Use || node->child1().useKind() == KnownInt32Use)
240 def(PureValue(node));
241 else {
242 read(World);
243 write(Heap);
244 }
245 return;
246
247 case ArithNegate:
248 if (node->child1().useKind() == Int32Use
249 || node->child1().useKind() == DoubleRepUse
250 || node->child1().useKind() == Int52RepUse)
251 def(PureValue(node));
252 else {
253 read(World);
254 write(Heap);
255 }
256 return;
257
258 case IsCellWithType:
259 def(PureValue(node, node->queriedType()));
260 return;
261
262 case ValueBitNot:
263 if (node->child1().useKind() == BigIntUse) {
264 def(PureValue(node));
265 return;
266 }
267 read(World);
268 write(Heap);
269 return;
270
271 case ArithBitNot:
272 if (node->child1().useKind() == UntypedUse) {
273 read(World);
274 write(Heap);
275 return;
276 }
277 def(PureValue(node));
278 return;
279
280 case ArithBitAnd:
281 case ArithBitOr:
282 case ArithBitXor:
283 case BitLShift:
284 case BitRShift:
285 case BitURShift:
286 if (node->child1().useKind() == UntypedUse || node->child2().useKind() == UntypedUse) {
287 read(World);
288 write(Heap);
289 return;
290 }
291 def(PureValue(node));
292 return;
293
294 case ArithRandom:
295 read(MathDotRandomState);
296 write(MathDotRandomState);
297 return;
298
299 case GetEnumerableLength: {
300 read(Heap);
301 write(SideState);
302 return;
303 }
304
305 case ToIndexString:
306 case GetEnumeratorStructurePname:
307 case GetEnumeratorGenericPname: {
308 def(PureValue(node));
309 return;
310 }
311
312 case HasIndexedProperty: {
313 read(JSObject_butterfly);
314 ArrayMode mode = node->arrayMode();
315 switch (mode.type()) {
316 case Array::ForceExit: {
317 write(SideState);
318 return;
319 }
320 case Array::Int32: {
321 if (mode.isInBounds()) {
322 read(Butterfly_publicLength);
323 read(IndexedInt32Properties);
324 def(HeapLocation(HasIndexedPropertyLoc, IndexedInt32Properties, graph.varArgChild(node, 0), graph.varArgChild(node, 1)), LazyNode(node));
325 return;
326 }
327 read(Heap);
328 return;
329 }
330
331 case Array::Double: {
332 if (mode.isInBounds()) {
333 read(Butterfly_publicLength);
334 read(IndexedDoubleProperties);
335 def(HeapLocation(HasIndexedPropertyLoc, IndexedDoubleProperties, graph.varArgChild(node, 0), graph.varArgChild(node, 1)), LazyNode(node));
336 return;
337 }
338 read(Heap);
339 return;
340 }
341
342 case Array::Contiguous: {
343 if (mode.isInBounds()) {
344 read(Butterfly_publicLength);
345 read(IndexedContiguousProperties);
346 def(HeapLocation(HasIndexedPropertyLoc, IndexedContiguousProperties, graph.varArgChild(node, 0), graph.varArgChild(node, 1)), LazyNode(node));
347 return;
348 }
349 read(Heap);
350 return;
351 }
352
353 case Array::ArrayStorage: {
354 if (mode.isInBounds()) {
355 read(Butterfly_vectorLength);
356 read(IndexedArrayStorageProperties);
357 return;
358 }
359 read(Heap);
360 return;
361 }
362
363 default: {
364 read(World);
365 write(Heap);
366 return;
367 }
368 }
369 RELEASE_ASSERT_NOT_REACHED();
370 return;
371 }
372
373 case StringFromCharCode:
374 switch (node->child1().useKind()) {
375 case Int32Use:
376 def(PureValue(node));
377 return;
378 case UntypedUse:
379 read(World);
380 write(Heap);
381 return;
382 default:
383 DFG_CRASH(graph, node, "Bad use kind");
384 }
385 return;
386
387 case ArithAdd:
388 case ArithMod:
389 case DoubleAsInt32:
390 case UInt32ToNumber:
391 def(PureValue(node, node->arithMode()));
392 return;
393
394 case ArithDiv:
395 case ArithMul:
396 case ArithSub:
397 switch (node->binaryUseKind()) {
398 case Int32Use:
399 case Int52RepUse:
400 case DoubleRepUse:
401 def(PureValue(node, node->arithMode()));
402 return;
403 case UntypedUse:
404 read(World);
405 write(Heap);
406 return;
407 default:
408 DFG_CRASH(graph, node, "Bad use kind");
409 }
410
411 case ArithRound:
412 case ArithFloor:
413 case ArithCeil:
414 case ArithTrunc:
415 if (node->child1().useKind() == DoubleRepUse)
416 def(PureValue(node, static_cast<uintptr_t>(node->arithRoundingMode())));
417 else {
418 read(World);
419 write(Heap);
420 }
421 return;
422
423 case CheckCell:
424 def(PureValue(CheckCell, AdjacencyList(AdjacencyList::Fixed, node->child1()), node->cellOperand()));
425 return;
426
427 case CheckNotEmpty:
428 def(PureValue(CheckNotEmpty, AdjacencyList(AdjacencyList::Fixed, node->child1())));
429 return;
430
431 case AssertNotEmpty:
432 write(SideState);
433 return;
434
435 case CheckStringIdent:
436 def(PureValue(CheckStringIdent, AdjacencyList(AdjacencyList::Fixed, node->child1()), node->uidOperand()));
437 return;
438
439 case ConstantStoragePointer:
440 def(PureValue(node, node->storagePointer()));
441 return;
442
443 case KillStack:
444 write(AbstractHeap(Stack, node->unlinkedLocal()));
445 return;
446
447 case MovHint:
448 case ZombieHint:
449 case ExitOK:
450 case Upsilon:
451 case Phi:
452 case PhantomLocal:
453 case SetArgument:
454 case Jump:
455 case Branch:
456 case Switch:
457 case EntrySwitch:
458 case ForceOSRExit:
459 case CPUIntrinsic:
460 case CheckBadCell:
461 case Return:
462 case Unreachable:
463 case CheckTierUpInLoop:
464 case CheckTierUpAtReturn:
465 case CheckTierUpAndOSREnter:
466 case LoopHint:
467 case ProfileType:
468 case ProfileControlFlow:
469 case PutHint:
470 case InitializeEntrypointArguments:
471 case FilterCallLinkStatus:
472 case FilterGetByIdStatus:
473 case FilterPutByIdStatus:
474 case FilterInByIdStatus:
475 write(SideState);
476 return;
477
478 case StoreBarrier:
479 read(JSCell_cellState);
480 write(JSCell_cellState);
481 return;
482
483 case FencedStoreBarrier:
484 read(Heap);
485 write(JSCell_cellState);
486 return;
487
488 case CheckTraps:
489 read(InternalState);
490 write(InternalState);
491 return;
492
493 case InvalidationPoint:
494 write(SideState);
495 def(HeapLocation(InvalidationPointLoc, Watchpoint_fire), LazyNode(node));
496 return;
497
498 case Flush:
499 read(AbstractHeap(Stack, node->local()));
500 write(SideState);
501 return;
502
503 case NotifyWrite:
504 write(Watchpoint_fire);
505 write(SideState);
506 return;
507
508 case PushWithScope: {
509 read(World);
510 write(HeapObjectCount);
511 return;
512 }
513
514 case CreateActivation: {
515 SymbolTable* table = node->castOperand<SymbolTable*>();
516 if (table->singletonScope()->isStillValid())
517 write(Watchpoint_fire);
518 read(HeapObjectCount);
519 write(HeapObjectCount);
520 return;
521 }
522
523 case CreateDirectArguments:
524 case CreateScopedArguments:
525 case CreateClonedArguments:
526 read(Stack);
527 read(HeapObjectCount);
528 write(HeapObjectCount);
529 return;
530
531 case PhantomDirectArguments:
532 case PhantomClonedArguments:
533 // DFG backend requires that the locals that this reads are flushed. FTL backend can handle those
534 // locals being promoted.
535 if (!graph.m_plan.isFTL())
536 read(Stack);
537
538 // Even though it's phantom, it still has the property that one can't be replaced with another.
539 read(HeapObjectCount);
540 write(HeapObjectCount);
541 return;
542
543 case PhantomSpread:
544 case PhantomNewArrayWithSpread:
545 case PhantomNewArrayBuffer:
546 case PhantomCreateRest:
547 // Even though it's phantom, it still has the property that one can't be replaced with another.
548 read(HeapObjectCount);
549 write(HeapObjectCount);
550 return;
551
552 case CallObjectConstructor:
553 read(HeapObjectCount);
554 write(HeapObjectCount);
555 return;
556
557 case ToThis:
558 read(MiscFields);
559 read(HeapObjectCount);
560 write(HeapObjectCount);
561 return;
562
563 case IsObjectOrNull:
564 read(MiscFields);
565 def(HeapLocation(IsObjectOrNullLoc, MiscFields, node->child1()), LazyNode(node));
566 return;
567
568 case IsFunction:
569 read(MiscFields);
570 def(HeapLocation(IsFunctionLoc, MiscFields, node->child1()), LazyNode(node));
571 return;
572
573 case MatchStructure:
574 read(JSCell_structureID);
575 return;
576
577 case ArraySlice:
578 read(MiscFields);
579 read(JSCell_indexingType);
580 read(JSCell_structureID);
581 read(JSObject_butterfly);
582 read(Butterfly_publicLength);
583 read(IndexedDoubleProperties);
584 read(IndexedInt32Properties);
585 read(IndexedContiguousProperties);
586 read(HeapObjectCount);
587 write(HeapObjectCount);
588 return;
589
590 case ArrayIndexOf: {
591 // FIXME: Should support a CSE rule.
592 // https://bugs.webkit.org/show_bug.cgi?id=173173
593 read(MiscFields);
594 read(JSCell_indexingType);
595 read(JSCell_structureID);
596 read(JSObject_butterfly);
597 read(Butterfly_publicLength);
598 switch (node->arrayMode().type()) {
599 case Array::Double:
600 read(IndexedDoubleProperties);
601 return;
602 case Array::Int32:
603 read(IndexedInt32Properties);
604 return;
605 case Array::Contiguous:
606 read(IndexedContiguousProperties);
607 return;
608 default:
609 RELEASE_ASSERT_NOT_REACHED();
610 return;
611 }
612 return;
613 }
614
615 case GetById:
616 case GetByIdFlush:
617 case GetByIdWithThis:
618 case GetByIdDirect:
619 case GetByIdDirectFlush:
620 case GetByValWithThis:
621 case PutById:
622 case PutByIdWithThis:
623 case PutByValWithThis:
624 case PutByIdFlush:
625 case PutByIdDirect:
626 case PutGetterById:
627 case PutSetterById:
628 case PutGetterSetterById:
629 case PutGetterByVal:
630 case PutSetterByVal:
631 case DefineDataProperty:
632 case DefineAccessorProperty:
633 case DeleteById:
634 case DeleteByVal:
635 case ArrayPush:
636 case ArrayPop:
637 case Call:
638 case DirectCall:
639 case TailCallInlinedCaller:
640 case DirectTailCallInlinedCaller:
641 case Construct:
642 case DirectConstruct:
643 case CallVarargs:
644 case CallForwardVarargs:
645 case TailCallVarargsInlinedCaller:
646 case TailCallForwardVarargsInlinedCaller:
647 case ConstructVarargs:
648 case ConstructForwardVarargs:
649 case ToPrimitive:
650 case InByVal:
651 case InById:
652 case HasOwnProperty:
653 case ValueNegate:
654 case SetFunctionName:
655 case GetDynamicVar:
656 case PutDynamicVar:
657 case ResolveScopeForHoistingFuncDeclInEval:
658 case ResolveScope:
659 case ToObject:
660 case HasGenericProperty:
661 case HasStructureProperty:
662 case GetPropertyEnumerator:
663 case GetDirectPname:
664 case InstanceOfCustom:
665 case ToNumber:
666 case NumberToStringWithRadix:
667 case CreateThis:
668 case InstanceOf:
669 case StringValueOf:
670 case ObjectKeys:
671 read(World);
672 write(Heap);
673 return;
674
675 case ValueBitAnd:
676 case ValueBitXor:
677 case ValueBitOr:
678 case ValueAdd:
679 case ValueSub:
680 case ValueMul:
681 case ValueDiv:
682 if (node->isBinaryUseKind(BigIntUse)) {
683 def(PureValue(node));
684 return;
685 }
686 read(World);
687 write(Heap);
688 return;
689
690 case AtomicsAdd:
691 case AtomicsAnd:
692 case AtomicsCompareExchange:
693 case AtomicsExchange:
694 case AtomicsLoad:
695 case AtomicsOr:
696 case AtomicsStore:
697 case AtomicsSub:
698 case AtomicsXor: {
699 unsigned numExtraArgs = numExtraAtomicsArgs(node->op());
700 Edge storageEdge = graph.child(node, 2 + numExtraArgs);
701 if (!storageEdge) {
702 read(World);
703 write(Heap);
704 return;
705 }
706 read(TypedArrayProperties);
707 read(MiscFields);
708 write(TypedArrayProperties);
709 return;
710 }
711
712 case CallEval:
713 ASSERT(!node->origin.semantic.inlineCallFrame());
714 read(AbstractHeap(Stack, graph.m_codeBlock->scopeRegister()));
715 read(AbstractHeap(Stack, virtualRegisterForArgument(0)));
716 read(World);
717 write(Heap);
718 return;
719
720 case Throw:
721 case ThrowStaticError:
722 case TailCall:
723 case DirectTailCall:
724 case TailCallVarargs:
725 case TailCallForwardVarargs:
726 read(World);
727 write(SideState);
728 return;
729
730 case GetGetter:
731 read(GetterSetter_getter);
732 def(HeapLocation(GetterLoc, GetterSetter_getter, node->child1()), LazyNode(node));
733 return;
734
735 case GetSetter:
736 read(GetterSetter_setter);
737 def(HeapLocation(SetterLoc, GetterSetter_setter, node->child1()), LazyNode(node));
738 return;
739
740 case GetCallee:
741 read(AbstractHeap(Stack, CallFrameSlot::callee));
742 def(HeapLocation(StackLoc, AbstractHeap(Stack, CallFrameSlot::callee)), LazyNode(node));
743 return;
744
745 case SetCallee:
746 write(AbstractHeap(Stack, CallFrameSlot::callee));
747 return;
748
749 case GetArgumentCountIncludingThis: {
750 auto heap = AbstractHeap(Stack, remapOperand(node->argumentsInlineCallFrame(), VirtualRegister(CallFrameSlot::argumentCount)));
751 read(heap);
752 def(HeapLocation(StackPayloadLoc, heap), LazyNode(node));
753 return;
754 }
755
756 case SetArgumentCountIncludingThis:
757 write(AbstractHeap(Stack, CallFrameSlot::argumentCount));
758 return;
759
760 case GetRestLength:
761 read(Stack);
762 return;
763
764 case GetLocal:
765 read(AbstractHeap(Stack, node->local()));
766 def(HeapLocation(StackLoc, AbstractHeap(Stack, node->local())), LazyNode(node));
767 return;
768
769 case SetLocal:
770 write(AbstractHeap(Stack, node->local()));
771 def(HeapLocation(StackLoc, AbstractHeap(Stack, node->local())), LazyNode(node->child1().node()));
772 return;
773
774 case GetStack: {
775 AbstractHeap heap(Stack, node->stackAccessData()->local);
776 read(heap);
777 def(HeapLocation(StackLoc, heap), LazyNode(node));
778 return;
779 }
780
781 case PutStack: {
782 AbstractHeap heap(Stack, node->stackAccessData()->local);
783 write(heap);
784 def(HeapLocation(StackLoc, heap), LazyNode(node->child1().node()));
785 return;
786 }
787
788 case LoadVarargs: {
789 read(World);
790 write(Heap);
791 LoadVarargsData* data = node->loadVarargsData();
792 write(AbstractHeap(Stack, data->count.offset()));
793 for (unsigned i = data->limit; i--;)
794 write(AbstractHeap(Stack, data->start.offset() + static_cast<int>(i)));
795 return;
796 }
797
798 case ForwardVarargs: {
799 // We could be way more precise here.
800 read(Stack);
801
802 LoadVarargsData* data = node->loadVarargsData();
803 write(AbstractHeap(Stack, data->count.offset()));
804 for (unsigned i = data->limit; i--;)
805 write(AbstractHeap(Stack, data->start.offset() + static_cast<int>(i)));
806 return;
807 }
808
809 case GetByVal: {
810 ArrayMode mode = node->arrayMode();
811 LocationKind indexedPropertyLoc = indexedPropertyLocForResultType(node->result());
812 switch (mode.type()) {
813 case Array::SelectUsingPredictions:
814 case Array::Unprofiled:
815 case Array::SelectUsingArguments:
816 // Assume the worst since we don't have profiling yet.
817 read(World);
818 write(Heap);
819 return;
820
821 case Array::ForceExit:
822 write(SideState);
823 return;
824
825 case Array::Generic:
826 read(World);
827 write(Heap);
828 return;
829
830 case Array::String:
831 if (mode.isOutOfBounds()) {
832 read(World);
833 write(Heap);
834 return;
835 }
836 // This appears to read nothing because it's only reading immutable data.
837 def(PureValue(graph, node, mode.asWord()));
838 return;
839
840 case Array::DirectArguments:
841 if (mode.isInBounds()) {
842 read(DirectArgumentsProperties);
843 def(HeapLocation(indexedPropertyLoc, DirectArgumentsProperties, graph.varArgChild(node, 0), graph.varArgChild(node, 1)), LazyNode(node));
844 return;
845 }
846 read(World);
847 write(Heap);
848 return;
849
850 case Array::ScopedArguments:
851 read(ScopeProperties);
852 def(HeapLocation(indexedPropertyLoc, ScopeProperties, graph.varArgChild(node, 0), graph.varArgChild(node, 1)), LazyNode(node));
853 return;
854
855 case Array::Int32:
856 if (mode.isInBounds()) {
857 read(Butterfly_publicLength);
858 read(IndexedInt32Properties);
859 def(HeapLocation(indexedPropertyLoc, IndexedInt32Properties, graph.varArgChild(node, 0), graph.varArgChild(node, 1)), LazyNode(node));
860 return;
861 }
862 read(World);
863 write(Heap);
864 return;
865
866 case Array::Double:
867 if (mode.isInBounds()) {
868 read(Butterfly_publicLength);
869 read(IndexedDoubleProperties);
870 LocationKind kind = mode.isSaneChain() ? IndexedPropertyDoubleSaneChainLoc : IndexedPropertyDoubleLoc;
871 def(HeapLocation(kind, IndexedDoubleProperties, graph.varArgChild(node, 0), graph.varArgChild(node, 1)), LazyNode(node));
872 return;
873 }
874 read(World);
875 write(Heap);
876 return;
877
878 case Array::Contiguous:
879 if (mode.isInBounds()) {
880 read(Butterfly_publicLength);
881 read(IndexedContiguousProperties);
882 def(HeapLocation(indexedPropertyLoc, IndexedContiguousProperties, graph.varArgChild(node, 0), graph.varArgChild(node, 1)), LazyNode(node));
883 return;
884 }
885 read(World);
886 write(Heap);
887 return;
888
889 case Array::Undecided:
890 def(PureValue(graph, node));
891 return;
892
893 case Array::ArrayStorage:
894 case Array::SlowPutArrayStorage:
895 if (mode.isInBounds()) {
896 read(Butterfly_vectorLength);
897 read(IndexedArrayStorageProperties);
898 return;
899 }
900 read(World);
901 write(Heap);
902 return;
903
904 case Array::Int8Array:
905 case Array::Int16Array:
906 case Array::Int32Array:
907 case Array::Uint8Array:
908 case Array::Uint8ClampedArray:
909 case Array::Uint16Array:
910 case Array::Uint32Array:
911 case Array::Float32Array:
912 case Array::Float64Array:
913 read(TypedArrayProperties);
914 read(MiscFields);
915 def(HeapLocation(indexedPropertyLoc, TypedArrayProperties, graph.varArgChild(node, 0), graph.varArgChild(node, 1)), LazyNode(node));
916 return;
917 // We should not get an AnyTypedArray in a GetByVal as AnyTypedArray is only created from intrinsics, which
918 // are only added from Inline Caching a GetById.
919 case Array::AnyTypedArray:
920 DFG_CRASH(graph, node, "impossible array mode for get");
921 return;
922 }
923 RELEASE_ASSERT_NOT_REACHED();
924 return;
925 }
926
927 case GetMyArgumentByVal:
928 case GetMyArgumentByValOutOfBounds: {
929 read(Stack);
930 // FIXME: It would be trivial to have a def here.
931 // https://bugs.webkit.org/show_bug.cgi?id=143077
932 return;
933 }
934
935 case PutByValDirect:
936 case PutByVal:
937 case PutByValAlias: {
938 ArrayMode mode = node->arrayMode();
939 Node* base = graph.varArgChild(node, 0).node();
940 Node* index = graph.varArgChild(node, 1).node();
941 Node* value = graph.varArgChild(node, 2).node();
942 LocationKind indexedPropertyLoc = indexedPropertyLocForResultType(node->result());
943
944 switch (mode.modeForPut().type()) {
945 case Array::SelectUsingPredictions:
946 case Array::SelectUsingArguments:
947 case Array::Unprofiled:
948 case Array::Undecided:
949 // Assume the worst since we don't have profiling yet.
950 read(World);
951 write(Heap);
952 return;
953
954 case Array::ForceExit:
955 write(SideState);
956 return;
957
958 case Array::Generic:
959 read(World);
960 write(Heap);
961 return;
962
963 case Array::Int32:
964 if (node->arrayMode().isOutOfBounds()) {
965 read(World);
966 write(Heap);
967 return;
968 }
969 read(Butterfly_publicLength);
970 read(Butterfly_vectorLength);
971 read(IndexedInt32Properties);
972 write(IndexedInt32Properties);
973 if (node->arrayMode().mayStoreToHole())
974 write(Butterfly_publicLength);
975 def(HeapLocation(indexedPropertyLoc, IndexedInt32Properties, base, index), LazyNode(value));
976 return;
977
978 case Array::Double:
979 if (node->arrayMode().isOutOfBounds()) {
980 read(World);
981 write(Heap);
982 return;
983 }
984 read(Butterfly_publicLength);
985 read(Butterfly_vectorLength);
986 read(IndexedDoubleProperties);
987 write(IndexedDoubleProperties);
988 if (node->arrayMode().mayStoreToHole())
989 write(Butterfly_publicLength);
990 def(HeapLocation(IndexedPropertyDoubleLoc, IndexedDoubleProperties, base, index), LazyNode(value));
991 def(HeapLocation(IndexedPropertyDoubleSaneChainLoc, IndexedDoubleProperties, base, index), LazyNode(value));
992 return;
993
994 case Array::Contiguous:
995 if (node->arrayMode().isOutOfBounds()) {
996 read(World);
997 write(Heap);
998 return;
999 }
1000 read(Butterfly_publicLength);
1001 read(Butterfly_vectorLength);
1002 read(IndexedContiguousProperties);
1003 write(IndexedContiguousProperties);
1004 if (node->arrayMode().mayStoreToHole())
1005 write(Butterfly_publicLength);
1006 def(HeapLocation(indexedPropertyLoc, IndexedContiguousProperties, base, index), LazyNode(value));
1007 return;
1008
1009 case Array::ArrayStorage:
1010 if (node->arrayMode().isOutOfBounds()) {
1011 read(World);
1012 write(Heap);
1013 return;
1014 }
1015 read(Butterfly_publicLength);
1016 read(Butterfly_vectorLength);
1017 read(ArrayStorageProperties);
1018 write(ArrayStorageProperties);
1019 if (node->arrayMode().mayStoreToHole())
1020 write(Butterfly_publicLength);
1021 return;
1022
1023 case Array::SlowPutArrayStorage:
1024 if (node->arrayMode().mayStoreToHole()) {
1025 read(World);
1026 write(Heap);
1027 return;
1028 }
1029 read(Butterfly_publicLength);
1030 read(Butterfly_vectorLength);
1031 read(ArrayStorageProperties);
1032 write(ArrayStorageProperties);
1033 return;
1034
1035 case Array::Int8Array:
1036 case Array::Int16Array:
1037 case Array::Int32Array:
1038 case Array::Uint8Array:
1039 case Array::Uint8ClampedArray:
1040 case Array::Uint16Array:
1041 case Array::Uint32Array:
1042 case Array::Float32Array:
1043 case Array::Float64Array:
1044 read(MiscFields);
1045 write(TypedArrayProperties);
1046 // FIXME: We can't def() anything here because these operations truncate their inputs.
1047 // https://bugs.webkit.org/show_bug.cgi?id=134737
1048 return;
1049 case Array::AnyTypedArray:
1050 case Array::String:
1051 case Array::DirectArguments:
1052 case Array::ScopedArguments:
1053 DFG_CRASH(graph, node, "impossible array mode for put");
1054 return;
1055 }
1056 RELEASE_ASSERT_NOT_REACHED();
1057 return;
1058 }
1059
1060 case CheckStructureOrEmpty:
1061 case CheckStructure:
1062 read(JSCell_structureID);
1063 return;
1064
1065 case CheckArray:
1066 read(JSCell_indexingType);
1067 read(JSCell_typeInfoType);
1068 read(JSCell_structureID);
1069 return;
1070
1071 case CheckTypeInfoFlags:
1072 read(JSCell_typeInfoFlags);
1073 def(HeapLocation(CheckTypeInfoFlagsLoc, JSCell_typeInfoFlags, node->child1()), LazyNode(node));
1074 return;
1075
1076 case ParseInt:
1077 // Note: We would have eliminated a ParseInt that has just a single child as an Int32Use inside fixup.
1078 if (node->child1().useKind() == StringUse && (!node->child2() || node->child2().useKind() == Int32Use)) {
1079 def(PureValue(node));
1080 return;
1081 }
1082
1083 read(World);
1084 write(Heap);
1085 return;
1086
1087 case OverridesHasInstance:
1088 read(JSCell_typeInfoFlags);
1089 def(HeapLocation(OverridesHasInstanceLoc, JSCell_typeInfoFlags, node->child1()), LazyNode(node));
1090 return;
1091
1092 case PutStructure:
1093 read(JSObject_butterfly);
1094 write(JSCell_structureID);
1095 write(JSCell_typeInfoType);
1096 write(JSCell_typeInfoFlags);
1097 write(JSCell_indexingType);
1098 return;
1099
1100 case AllocatePropertyStorage:
1101 case ReallocatePropertyStorage:
1102 read(HeapObjectCount);
1103 write(HeapObjectCount);
1104 return;
1105
1106 case NukeStructureAndSetButterfly:
1107 write(JSObject_butterfly);
1108 write(JSCell_structureID);
1109 def(HeapLocation(ButterflyLoc, JSObject_butterfly, node->child1()), LazyNode(node->child2().node()));
1110 return;
1111
1112 case GetButterfly:
1113 read(JSObject_butterfly);
1114 def(HeapLocation(ButterflyLoc, JSObject_butterfly, node->child1()), LazyNode(node));
1115 return;
1116
1117 case CheckSubClass:
1118 def(PureValue(node, node->classInfo()));
1119 return;
1120
1121 case CallDOMGetter: {
1122 DOMJIT::CallDOMGetterSnippet* snippet = node->callDOMGetterData()->snippet;
1123 if (!snippet) {
1124 read(World);
1125 write(Heap);
1126 return;
1127 }
1128 DOMJIT::Effect effect = snippet->effect;
1129 if (effect.reads) {
1130 if (effect.reads == DOMJIT::HeapRange::top())
1131 read(World);
1132 else
1133 read(AbstractHeap(DOMState, effect.reads.rawRepresentation()));
1134 }
1135 if (effect.writes) {
1136 if (effect.writes == DOMJIT::HeapRange::top())
1137 write(Heap);
1138 else
1139 write(AbstractHeap(DOMState, effect.writes.rawRepresentation()));
1140 }
1141 if (effect.def != DOMJIT::HeapRange::top()) {
1142 DOMJIT::HeapRange range = effect.def;
1143 if (range == DOMJIT::HeapRange::none())
1144 def(PureValue(node, bitwise_cast<uintptr_t>(node->callDOMGetterData()->customAccessorGetter)));
1145 else {
1146 // Def with heap location. We do not include "GlobalObject" for that since this information is included in the base node.
1147 // We only see the DOMJIT getter here. So just including "base" is ok.
1148 def(HeapLocation(DOMStateLoc, AbstractHeap(DOMState, range.rawRepresentation()), node->child1()), LazyNode(node));
1149 }
1150 }
1151 return;
1152 }
1153
1154 case CallDOM: {
1155 const DOMJIT::Signature* signature = node->signature();
1156 DOMJIT::Effect effect = signature->effect;
1157 if (effect.reads) {
1158 if (effect.reads == DOMJIT::HeapRange::top())
1159 read(World);
1160 else
1161 read(AbstractHeap(DOMState, effect.reads.rawRepresentation()));
1162 }
1163 if (effect.writes) {
1164 if (effect.writes == DOMJIT::HeapRange::top())
1165 write(Heap);
1166 else
1167 write(AbstractHeap(DOMState, effect.writes.rawRepresentation()));
1168 }
1169 ASSERT_WITH_MESSAGE(effect.def == DOMJIT::HeapRange::top(), "Currently, we do not accept any def for CallDOM.");
1170 return;
1171 }
1172
1173 case Arrayify:
1174 case ArrayifyToStructure:
1175 read(JSCell_structureID);
1176 read(JSCell_indexingType);
1177 read(JSObject_butterfly);
1178 write(JSCell_structureID);
1179 write(JSCell_indexingType);
1180 write(JSObject_butterfly);
1181 write(Watchpoint_fire);
1182 return;
1183
1184 case GetIndexedPropertyStorage:
1185 if (node->arrayMode().type() == Array::String) {
1186 def(PureValue(node, node->arrayMode().asWord()));
1187 return;
1188 }
1189 read(MiscFields);
1190 def(HeapLocation(IndexedPropertyStorageLoc, MiscFields, node->child1()), LazyNode(node));
1191 return;
1192
1193 case GetTypedArrayByteOffset:
1194 read(MiscFields);
1195 def(HeapLocation(TypedArrayByteOffsetLoc, MiscFields, node->child1()), LazyNode(node));
1196 return;
1197
1198 case GetPrototypeOf: {
1199 switch (node->child1().useKind()) {
1200 case ArrayUse:
1201 case FunctionUse:
1202 case FinalObjectUse:
1203 read(JSCell_structureID);
1204 read(JSObject_butterfly);
1205 read(NamedProperties); // Poly proto could load prototype from its slot.
1206 def(HeapLocation(PrototypeLoc, NamedProperties, node->child1()), LazyNode(node));
1207 return;
1208 default:
1209 read(World);
1210 write(Heap);
1211 return;
1212 }
1213 }
1214
1215 case GetByOffset:
1216 case GetGetterSetterByOffset: {
1217 unsigned identifierNumber = node->storageAccessData().identifierNumber;
1218 AbstractHeap heap(NamedProperties, identifierNumber);
1219 read(heap);
1220 def(HeapLocation(NamedPropertyLoc, heap, node->child2()), LazyNode(node));
1221 return;
1222 }
1223
1224 case TryGetById: {
1225 read(Heap);
1226 return;
1227 }
1228
1229 case MultiGetByOffset: {
1230 read(JSCell_structureID);
1231 read(JSObject_butterfly);
1232 AbstractHeap heap(NamedProperties, node->multiGetByOffsetData().identifierNumber);
1233 read(heap);
1234 def(HeapLocation(NamedPropertyLoc, heap, node->child1()), LazyNode(node));
1235 return;
1236 }
1237
1238 case MultiPutByOffset: {
1239 read(JSCell_structureID);
1240 read(JSObject_butterfly);
1241 AbstractHeap heap(NamedProperties, node->multiPutByOffsetData().identifierNumber);
1242 write(heap);
1243 if (node->multiPutByOffsetData().writesStructures())
1244 write(JSCell_structureID);
1245 if (node->multiPutByOffsetData().reallocatesStorage())
1246 write(JSObject_butterfly);
1247 def(HeapLocation(NamedPropertyLoc, heap, node->child1()), LazyNode(node->child2().node()));
1248 return;
1249 }
1250
1251 case PutByOffset: {
1252 unsigned identifierNumber = node->storageAccessData().identifierNumber;
1253 AbstractHeap heap(NamedProperties, identifierNumber);
1254 write(heap);
1255 def(HeapLocation(NamedPropertyLoc, heap, node->child2()), LazyNode(node->child3().node()));
1256 return;
1257 }
1258
1259 case GetArrayLength: {
1260 ArrayMode mode = node->arrayMode();
1261 switch (mode.type()) {
1262 case Array::Undecided:
1263 case Array::Int32:
1264 case Array::Double:
1265 case Array::Contiguous:
1266 case Array::ArrayStorage:
1267 case Array::SlowPutArrayStorage:
1268 read(Butterfly_publicLength);
1269 def(HeapLocation(ArrayLengthLoc, Butterfly_publicLength, node->child1()), LazyNode(node));
1270 return;
1271
1272 case Array::String:
1273 def(PureValue(node, mode.asWord()));
1274 return;
1275
1276 case Array::DirectArguments:
1277 case Array::ScopedArguments:
1278 read(MiscFields);
1279 def(HeapLocation(ArrayLengthLoc, MiscFields, node->child1()), LazyNode(node));
1280 return;
1281
1282 default:
1283 ASSERT(mode.isSomeTypedArrayView());
1284 read(MiscFields);
1285 def(HeapLocation(ArrayLengthLoc, MiscFields, node->child1()), LazyNode(node));
1286 return;
1287 }
1288 }
1289
1290 case GetVectorLength: {
1291 ArrayMode mode = node->arrayMode();
1292 switch (mode.type()) {
1293 case Array::ArrayStorage:
1294 case Array::SlowPutArrayStorage:
1295 read(Butterfly_vectorLength);
1296 def(HeapLocation(VectorLengthLoc, Butterfly_vectorLength, node->child1()), LazyNode(node));
1297 return;
1298
1299 default:
1300 RELEASE_ASSERT_NOT_REACHED();
1301 return;
1302 }
1303 }
1304
1305 case GetClosureVar:
1306 read(AbstractHeap(ScopeProperties, node->scopeOffset().offset()));
1307 def(HeapLocation(ClosureVariableLoc, AbstractHeap(ScopeProperties, node->scopeOffset().offset()), node->child1()), LazyNode(node));
1308 return;
1309
1310 case PutClosureVar:
1311 write(AbstractHeap(ScopeProperties, node->scopeOffset().offset()));
1312 def(HeapLocation(ClosureVariableLoc, AbstractHeap(ScopeProperties, node->scopeOffset().offset()), node->child1()), LazyNode(node->child2().node()));
1313 return;
1314
1315 case GetRegExpObjectLastIndex:
1316 read(RegExpObject_lastIndex);
1317 def(HeapLocation(RegExpObjectLastIndexLoc, RegExpObject_lastIndex, node->child1()), LazyNode(node));
1318 return;
1319
1320 case SetRegExpObjectLastIndex:
1321 write(RegExpObject_lastIndex);
1322 def(HeapLocation(RegExpObjectLastIndexLoc, RegExpObject_lastIndex, node->child1()), LazyNode(node->child2().node()));
1323 return;
1324
1325 case RecordRegExpCachedResult:
1326 write(RegExpState);
1327 return;
1328
1329 case GetFromArguments: {
1330 AbstractHeap heap(DirectArgumentsProperties, node->capturedArgumentsOffset().offset());
1331 read(heap);
1332 def(HeapLocation(DirectArgumentsLoc, heap, node->child1()), LazyNode(node));
1333 return;
1334 }
1335
1336 case PutToArguments: {
1337 AbstractHeap heap(DirectArgumentsProperties, node->capturedArgumentsOffset().offset());
1338 write(heap);
1339 def(HeapLocation(DirectArgumentsLoc, heap, node->child1()), LazyNode(node->child2().node()));
1340 return;
1341 }
1342
1343 case GetArgument: {
1344 read(Stack);
1345 // FIXME: It would be trivial to have a def here.
1346 // https://bugs.webkit.org/show_bug.cgi?id=143077
1347 return;
1348 }
1349
1350 case GetGlobalVar:
1351 case GetGlobalLexicalVariable:
1352 read(AbstractHeap(Absolute, node->variablePointer()));
1353 def(HeapLocation(GlobalVariableLoc, AbstractHeap(Absolute, node->variablePointer())), LazyNode(node));
1354 return;
1355
1356 case PutGlobalVariable:
1357 write(AbstractHeap(Absolute, node->variablePointer()));
1358 def(HeapLocation(GlobalVariableLoc, AbstractHeap(Absolute, node->variablePointer())), LazyNode(node->child2().node()));
1359 return;
1360
1361 case NewArrayWithSize:
1362 read(HeapObjectCount);
1363 write(HeapObjectCount);
1364 return;
1365
1366 case NewTypedArray:
1367 switch (node->child1().useKind()) {
1368 case Int32Use:
1369 read(HeapObjectCount);
1370 write(HeapObjectCount);
1371 return;
1372 case UntypedUse:
1373 read(World);
1374 write(Heap);
1375 return;
1376 default:
1377 DFG_CRASH(graph, node, "Bad use kind");
1378 }
1379 break;
1380
1381 case NewArrayWithSpread: {
1382 // This also reads from JSFixedArray's data store, but we don't have any way of describing that yet.
1383 read(HeapObjectCount);
1384 for (unsigned i = 0; i < node->numChildren(); i++) {
1385 Node* child = graph.varArgChild(node, i).node();
1386 if (child->op() == PhantomSpread) {
1387 read(Stack);
1388 break;
1389 }
1390 }
1391 write(HeapObjectCount);
1392 return;
1393 }
1394
1395 case Spread: {
1396 if (node->child1()->op() == PhantomNewArrayBuffer) {
1397 read(MiscFields);
1398 return;
1399 }
1400
1401 if (node->child1()->op() == PhantomCreateRest) {
1402 read(Stack);
1403 write(HeapObjectCount);
1404 return;
1405 }
1406
1407 read(World);
1408 write(Heap);
1409 return;
1410 }
1411
1412 case NewArray: {
1413 read(HeapObjectCount);
1414 write(HeapObjectCount);
1415
1416 unsigned numElements = node->numChildren();
1417
1418 def(HeapLocation(ArrayLengthLoc, Butterfly_publicLength, node),
1419 LazyNode(graph.freeze(jsNumber(numElements))));
1420
1421 if (!numElements)
1422 return;
1423
1424 AbstractHeap heap;
1425 LocationKind indexedPropertyLoc;
1426 switch (node->indexingType()) {
1427 case ALL_DOUBLE_INDEXING_TYPES:
1428 heap = IndexedDoubleProperties;
1429 indexedPropertyLoc = IndexedPropertyDoubleLoc;
1430 break;
1431
1432 case ALL_INT32_INDEXING_TYPES:
1433 heap = IndexedInt32Properties;
1434 indexedPropertyLoc = IndexedPropertyJSLoc;
1435 break;
1436
1437 case ALL_CONTIGUOUS_INDEXING_TYPES:
1438 heap = IndexedContiguousProperties;
1439 indexedPropertyLoc = IndexedPropertyJSLoc;
1440 break;
1441
1442 default:
1443 return;
1444 }
1445
1446 if (numElements < graph.m_uint32ValuesInUse.size()) {
1447 for (unsigned operandIdx = 0; operandIdx < numElements; ++operandIdx) {
1448 Edge use = graph.m_varArgChildren[node->firstChild() + operandIdx];
1449 def(HeapLocation(indexedPropertyLoc, heap, node, LazyNode(graph.freeze(jsNumber(operandIdx)))),
1450 LazyNode(use.node()));
1451 }
1452 } else {
1453 for (uint32_t operandIdx : graph.m_uint32ValuesInUse) {
1454 if (operandIdx >= numElements)
1455 continue;
1456 Edge use = graph.m_varArgChildren[node->firstChild() + operandIdx];
1457 // operandIdx comes from graph.m_uint32ValuesInUse and thus is guaranteed to be already frozen
1458 def(HeapLocation(indexedPropertyLoc, heap, node, LazyNode(graph.freeze(jsNumber(operandIdx)))),
1459 LazyNode(use.node()));
1460 }
1461 }
1462 return;
1463 }
1464
1465 case NewArrayBuffer: {
1466 read(HeapObjectCount);
1467 write(HeapObjectCount);
1468
1469 auto* array = node->castOperand<JSImmutableButterfly*>();
1470 unsigned numElements = array->length();
1471 def(HeapLocation(ArrayLengthLoc, Butterfly_publicLength, node),
1472 LazyNode(graph.freeze(jsNumber(numElements))));
1473
1474 AbstractHeap heap;
1475 LocationKind indexedPropertyLoc;
1476 NodeType op = JSConstant;
1477 switch (node->indexingType()) {
1478 case ALL_DOUBLE_INDEXING_TYPES:
1479 heap = IndexedDoubleProperties;
1480 indexedPropertyLoc = IndexedPropertyDoubleLoc;
1481 op = DoubleConstant;
1482 break;
1483
1484 case ALL_INT32_INDEXING_TYPES:
1485 heap = IndexedInt32Properties;
1486 indexedPropertyLoc = IndexedPropertyJSLoc;
1487 break;
1488
1489 case ALL_CONTIGUOUS_INDEXING_TYPES:
1490 heap = IndexedContiguousProperties;
1491 indexedPropertyLoc = IndexedPropertyJSLoc;
1492 break;
1493
1494 default:
1495 return;
1496 }
1497
1498 if (numElements < graph.m_uint32ValuesInUse.size()) {
1499 for (unsigned index = 0; index < numElements; ++index) {
1500 def(HeapLocation(indexedPropertyLoc, heap, node, LazyNode(graph.freeze(jsNumber(index)))),
1501 LazyNode(graph.freeze(array->get(index)), op));
1502 }
1503 } else {
1504 Vector<uint32_t> possibleIndices;
1505 for (uint32_t index : graph.m_uint32ValuesInUse) {
1506 if (index >= numElements)
1507 continue;
1508 possibleIndices.append(index);
1509 }
1510 for (uint32_t index : possibleIndices) {
1511 def(HeapLocation(indexedPropertyLoc, heap, node, LazyNode(graph.freeze(jsNumber(index)))),
1512 LazyNode(graph.freeze(array->get(index)), op));
1513 }
1514 }
1515 return;
1516 }
1517
1518 case CreateRest: {
1519 if (!graph.isWatchingHavingABadTimeWatchpoint(node)) {
1520 // This means we're already having a bad time.
1521 read(World);
1522 write(Heap);
1523 return;
1524 }
1525 read(Stack);
1526 read(HeapObjectCount);
1527 write(HeapObjectCount);
1528 return;
1529 }
1530
1531 case ObjectCreate: {
1532 switch (node->child1().useKind()) {
1533 case ObjectUse:
1534 read(HeapObjectCount);
1535 write(HeapObjectCount);
1536 return;
1537 case UntypedUse:
1538 read(World);
1539 write(Heap);
1540 return;
1541 default:
1542 RELEASE_ASSERT_NOT_REACHED();
1543 return;
1544 }
1545 }
1546
1547 case NewObject:
1548 case NewRegexp:
1549 case NewSymbol:
1550 case NewStringObject:
1551 case PhantomNewObject:
1552 case MaterializeNewObject:
1553 case PhantomNewFunction:
1554 case PhantomNewGeneratorFunction:
1555 case PhantomNewAsyncFunction:
1556 case PhantomNewAsyncGeneratorFunction:
1557 case PhantomCreateActivation:
1558 case MaterializeCreateActivation:
1559 case PhantomNewRegexp:
1560 read(HeapObjectCount);
1561 write(HeapObjectCount);
1562 return;
1563
1564 case NewFunction:
1565 case NewGeneratorFunction:
1566 case NewAsyncGeneratorFunction:
1567 case NewAsyncFunction:
1568 if (node->castOperand<FunctionExecutable*>()->singletonFunction()->isStillValid())
1569 write(Watchpoint_fire);
1570 read(HeapObjectCount);
1571 write(HeapObjectCount);
1572 return;
1573
1574 case RegExpExec:
1575 case RegExpTest:
1576 // Even if we've proven known input types as RegExpObject and String,
1577 // accessing lastIndex is effectful if it's a global regexp.
1578 read(World);
1579 write(Heap);
1580 return;
1581
1582 case RegExpMatchFast:
1583 read(RegExpState);
1584 read(RegExpObject_lastIndex);
1585 write(RegExpState);
1586 write(RegExpObject_lastIndex);
1587 return;
1588
1589 case RegExpExecNonGlobalOrSticky:
1590 case RegExpMatchFastGlobal:
1591 read(RegExpState);
1592 write(RegExpState);
1593 return;
1594
1595 case StringReplace:
1596 case StringReplaceRegExp:
1597 if (node->child1().useKind() == StringUse
1598 && node->child2().useKind() == RegExpObjectUse
1599 && node->child3().useKind() == StringUse) {
1600 read(RegExpState);
1601 read(RegExpObject_lastIndex);
1602 write(RegExpState);
1603 write(RegExpObject_lastIndex);
1604 return;
1605 }
1606 read(World);
1607 write(Heap);
1608 return;
1609
1610 case StringCharAt:
1611 if (node->arrayMode().isOutOfBounds()) {
1612 read(World);
1613 write(Heap);
1614 return;
1615 }
1616 def(PureValue(node));
1617 return;
1618
1619 case CompareBelow:
1620 case CompareBelowEq:
1621 def(PureValue(node));
1622 return;
1623
1624 case CompareEq:
1625 case CompareLess:
1626 case CompareLessEq:
1627 case CompareGreater:
1628 case CompareGreaterEq:
1629 if (node->isBinaryUseKind(StringUse)) {
1630 read(HeapObjectCount);
1631 write(HeapObjectCount);
1632 return;
1633 }
1634
1635 if (node->isBinaryUseKind(UntypedUse)) {
1636 read(World);
1637 write(Heap);
1638 return;
1639 }
1640
1641 def(PureValue(node));
1642 return;
1643
1644 case ToString:
1645 case CallStringConstructor:
1646 switch (node->child1().useKind()) {
1647 case CellUse:
1648 case UntypedUse:
1649 read(World);
1650 write(Heap);
1651 return;
1652
1653 case StringObjectUse:
1654 case StringOrStringObjectUse:
1655 // These two StringObjectUse's are pure because if we emit this node with either
1656 // of these UseKinds, we'll first emit a StructureCheck ensuring that we're the
1657 // original String or StringObject structure. Therefore, we don't have an overridden
1658 // valueOf, etc.
1659
1660 case Int32Use:
1661 case Int52RepUse:
1662 case DoubleRepUse:
1663 case NotCellUse:
1664 def(PureValue(node));
1665 return;
1666
1667 default:
1668 RELEASE_ASSERT_NOT_REACHED();
1669 return;
1670 }
1671
1672 case CountExecution:
1673 case SuperSamplerBegin:
1674 case SuperSamplerEnd:
1675 read(InternalState);
1676 write(InternalState);
1677 return;
1678
1679 case LogShadowChickenPrologue:
1680 case LogShadowChickenTail:
1681 write(SideState);
1682 return;
1683
1684 case MapHash:
1685 def(PureValue(node));
1686 return;
1687
1688 case NormalizeMapKey:
1689 def(PureValue(node));
1690 return;
1691
1692 case GetMapBucket: {
1693 Edge& mapEdge = node->child1();
1694 Edge& keyEdge = node->child2();
1695 AbstractHeapKind heap = (mapEdge.useKind() == MapObjectUse) ? JSMapFields : JSSetFields;
1696 read(heap);
1697 def(HeapLocation(MapBucketLoc, heap, mapEdge, keyEdge), LazyNode(node));
1698 return;
1699 }
1700
1701 case GetMapBucketHead: {
1702 Edge& mapEdge = node->child1();
1703 AbstractHeapKind heap = (mapEdge.useKind() == MapObjectUse) ? JSMapFields : JSSetFields;
1704 read(heap);
1705 def(HeapLocation(MapBucketHeadLoc, heap, mapEdge), LazyNode(node));
1706 return;
1707 }
1708
1709 case GetMapBucketNext: {
1710 AbstractHeapKind heap = (node->bucketOwnerType() == BucketOwnerType::Map) ? JSMapFields : JSSetFields;
1711 read(heap);
1712 Edge& bucketEdge = node->child1();
1713 def(HeapLocation(MapBucketNextLoc, heap, bucketEdge), LazyNode(node));
1714 return;
1715 }
1716
1717 case LoadKeyFromMapBucket: {
1718 AbstractHeapKind heap = (node->bucketOwnerType() == BucketOwnerType::Map) ? JSMapFields : JSSetFields;
1719 read(heap);
1720 Edge& bucketEdge = node->child1();
1721 def(HeapLocation(MapBucketKeyLoc, heap, bucketEdge), LazyNode(node));
1722 return;
1723 }
1724
1725 case LoadValueFromMapBucket: {
1726 AbstractHeapKind heap = (node->bucketOwnerType() == BucketOwnerType::Map) ? JSMapFields : JSSetFields;
1727 read(heap);
1728 Edge& bucketEdge = node->child1();
1729 def(HeapLocation(MapBucketValueLoc, heap, bucketEdge), LazyNode(node));
1730 return;
1731 }
1732
1733 case WeakMapGet: {
1734 Edge& mapEdge = node->child1();
1735 Edge& keyEdge = node->child2();
1736 AbstractHeapKind heap = (mapEdge.useKind() == WeakMapObjectUse) ? JSWeakMapFields : JSWeakSetFields;
1737 read(heap);
1738 def(HeapLocation(WeakMapGetLoc, heap, mapEdge, keyEdge), LazyNode(node));
1739 return;
1740 }
1741
1742 case SetAdd: {
1743 Edge& mapEdge = node->child1();
1744 Edge& keyEdge = node->child2();
1745 write(JSSetFields);
1746 def(HeapLocation(MapBucketLoc, JSSetFields, mapEdge, keyEdge), LazyNode(node));
1747 return;
1748 }
1749
1750 case MapSet: {
1751 Edge& mapEdge = graph.varArgChild(node, 0);
1752 Edge& keyEdge = graph.varArgChild(node, 1);
1753 write(JSMapFields);
1754 def(HeapLocation(MapBucketLoc, JSMapFields, mapEdge, keyEdge), LazyNode(node));
1755 return;
1756 }
1757
1758 case WeakSetAdd: {
1759 Edge& mapEdge = node->child1();
1760 Edge& keyEdge = node->child2();
1761 write(JSWeakSetFields);
1762 def(HeapLocation(WeakMapGetLoc, JSWeakSetFields, mapEdge, keyEdge), LazyNode(keyEdge.node()));
1763 return;
1764 }
1765
1766 case WeakMapSet: {
1767 Edge& mapEdge = graph.varArgChild(node, 0);
1768 Edge& keyEdge = graph.varArgChild(node, 1);
1769 Edge& valueEdge = graph.varArgChild(node, 2);
1770 write(JSWeakMapFields);
1771 def(HeapLocation(WeakMapGetLoc, JSWeakMapFields, mapEdge, keyEdge), LazyNode(valueEdge.node()));
1772 return;
1773 }
1774
1775 case ExtractValueFromWeakMapGet:
1776 def(PureValue(node));
1777 return;
1778
1779 case StringSlice:
1780 def(PureValue(node));
1781 return;
1782
1783 case ToLowerCase:
1784 def(PureValue(node));
1785 return;
1786
1787 case NumberToStringWithValidRadixConstant:
1788 def(PureValue(node, node->validRadixConstant()));
1789 return;
1790
1791 case DataViewGetFloat:
1792 case DataViewGetInt: {
1793 read(MiscFields);
1794 read(TypedArrayProperties);
1795 LocationKind indexedPropertyLoc = indexedPropertyLocForResultType(node->result());
1796 def(HeapLocation(indexedPropertyLoc, AbstractHeap(TypedArrayProperties, node->dataViewData().asQuadWord),
1797 node->child1(), node->child2(), node->child3()), LazyNode(node));
1798 return;
1799 }
1800
1801 case DataViewSet: {
1802 read(MiscFields);
1803 read(TypedArrayProperties);
1804 write(TypedArrayProperties);
1805 return;
1806 }
1807
1808 case LastNodeType:
1809 RELEASE_ASSERT_NOT_REACHED();
1810 return;
1811 }
1812
1813 DFG_CRASH(graph, node, toCString("Unrecognized node type: ", Graph::opName(node->op())).data());
1814}
1815
1816class NoOpClobberize {
1817public:
1818 NoOpClobberize() { }
1819 template<typename... T>
1820 void operator()(T...) const { }
1821};
1822
1823class CheckClobberize {
1824public:
1825 CheckClobberize()
1826 : m_result(false)
1827 {
1828 }
1829
1830 template<typename... T>
1831 void operator()(T...) const { m_result = true; }
1832
1833 bool result() const { return m_result; }
1834
1835private:
1836 mutable bool m_result;
1837};
1838
1839bool doesWrites(Graph&, Node*);
1840
1841class AbstractHeapOverlaps {
1842public:
1843 AbstractHeapOverlaps(AbstractHeap heap)
1844 : m_heap(heap)
1845 , m_result(false)
1846 {
1847 }
1848
1849 void operator()(AbstractHeap otherHeap) const
1850 {
1851 if (m_result)
1852 return;
1853 m_result = m_heap.overlaps(otherHeap);
1854 }
1855
1856 bool result() const { return m_result; }
1857
1858private:
1859 AbstractHeap m_heap;
1860 mutable bool m_result;
1861};
1862
1863bool accessesOverlap(Graph&, Node*, AbstractHeap);
1864bool writesOverlap(Graph&, Node*, AbstractHeap);
1865
1866bool clobbersHeap(Graph&, Node*);
1867
1868// We would have used bind() for these, but because of the overlaoding that we are doing,
1869// it's quite a bit of clearer to just write this out the traditional way.
1870
1871template<typename T>
1872class ReadMethodClobberize {
1873public:
1874 ReadMethodClobberize(T& value)
1875 : m_value(value)
1876 {
1877 }
1878
1879 void operator()(AbstractHeap heap) const
1880 {
1881 m_value.read(heap);
1882 }
1883private:
1884 T& m_value;
1885};
1886
1887template<typename T>
1888class WriteMethodClobberize {
1889public:
1890 WriteMethodClobberize(T& value)
1891 : m_value(value)
1892 {
1893 }
1894
1895 void operator()(AbstractHeap heap) const
1896 {
1897 m_value.write(heap);
1898 }
1899private:
1900 T& m_value;
1901};
1902
1903template<typename T>
1904class DefMethodClobberize {
1905public:
1906 DefMethodClobberize(T& value)
1907 : m_value(value)
1908 {
1909 }
1910
1911 void operator()(PureValue value) const
1912 {
1913 m_value.def(value);
1914 }
1915
1916 void operator()(HeapLocation location, LazyNode node) const
1917 {
1918 m_value.def(location, node);
1919 }
1920
1921private:
1922 T& m_value;
1923};
1924
1925template<typename Adaptor>
1926void clobberize(Graph& graph, Node* node, Adaptor& adaptor)
1927{
1928 ReadMethodClobberize<Adaptor> read(adaptor);
1929 WriteMethodClobberize<Adaptor> write(adaptor);
1930 DefMethodClobberize<Adaptor> def(adaptor);
1931 clobberize(graph, node, read, write, def);
1932}
1933
1934} } // namespace JSC::DFG
1935
1936#endif // ENABLE(DFG_JIT)
1937