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 SetArgumentDefinitely:
454 case SetArgumentMaybe:
455 case Jump:
456 case Branch:
457 case Switch:
458 case EntrySwitch:
459 case ForceOSRExit:
460 case CPUIntrinsic:
461 case CheckBadCell:
462 case Return:
463 case Unreachable:
464 case CheckTierUpInLoop:
465 case CheckTierUpAtReturn:
466 case CheckTierUpAndOSREnter:
467 case LoopHint:
468 case ProfileType:
469 case ProfileControlFlow:
470 case PutHint:
471 case InitializeEntrypointArguments:
472 case FilterCallLinkStatus:
473 case FilterGetByIdStatus:
474 case FilterPutByIdStatus:
475 case FilterInByIdStatus:
476 write(SideState);
477 return;
478
479 case StoreBarrier:
480 read(JSCell_cellState);
481 write(JSCell_cellState);
482 return;
483
484 case FencedStoreBarrier:
485 read(Heap);
486 write(JSCell_cellState);
487 return;
488
489 case CheckTraps:
490 read(InternalState);
491 write(InternalState);
492 return;
493
494 case InvalidationPoint:
495 write(SideState);
496 def(HeapLocation(InvalidationPointLoc, Watchpoint_fire), LazyNode(node));
497 return;
498
499 case Flush:
500 read(AbstractHeap(Stack, node->local()));
501 write(SideState);
502 return;
503
504 case NotifyWrite:
505 write(Watchpoint_fire);
506 write(SideState);
507 return;
508
509 case PushWithScope: {
510 read(World);
511 write(HeapObjectCount);
512 return;
513 }
514
515 case CreateActivation: {
516 SymbolTable* table = node->castOperand<SymbolTable*>();
517 if (table->singletonScope()->isStillValid())
518 write(Watchpoint_fire);
519 read(HeapObjectCount);
520 write(HeapObjectCount);
521 return;
522 }
523
524 case CreateDirectArguments:
525 case CreateScopedArguments:
526 case CreateClonedArguments:
527 read(Stack);
528 read(HeapObjectCount);
529 write(HeapObjectCount);
530 return;
531
532 case PhantomDirectArguments:
533 case PhantomClonedArguments:
534 // DFG backend requires that the locals that this reads are flushed. FTL backend can handle those
535 // locals being promoted.
536 if (!graph.m_plan.isFTL())
537 read(Stack);
538
539 // Even though it's phantom, it still has the property that one can't be replaced with another.
540 read(HeapObjectCount);
541 write(HeapObjectCount);
542 return;
543
544 case PhantomSpread:
545 case PhantomNewArrayWithSpread:
546 case PhantomNewArrayBuffer:
547 case PhantomCreateRest:
548 // Even though it's phantom, it still has the property that one can't be replaced with another.
549 read(HeapObjectCount);
550 write(HeapObjectCount);
551 return;
552
553 case CallObjectConstructor:
554 read(HeapObjectCount);
555 write(HeapObjectCount);
556 return;
557
558 case ToThis:
559 read(MiscFields);
560 read(HeapObjectCount);
561 write(HeapObjectCount);
562 return;
563
564 case IsObjectOrNull:
565 read(MiscFields);
566 def(HeapLocation(IsObjectOrNullLoc, MiscFields, node->child1()), LazyNode(node));
567 return;
568
569 case IsFunction:
570 read(MiscFields);
571 def(HeapLocation(IsFunctionLoc, MiscFields, node->child1()), LazyNode(node));
572 return;
573
574 case MatchStructure:
575 read(JSCell_structureID);
576 return;
577
578 case ArraySlice:
579 read(MiscFields);
580 read(JSCell_indexingType);
581 read(JSCell_structureID);
582 read(JSObject_butterfly);
583 read(Butterfly_publicLength);
584 read(IndexedDoubleProperties);
585 read(IndexedInt32Properties);
586 read(IndexedContiguousProperties);
587 read(HeapObjectCount);
588 write(HeapObjectCount);
589 return;
590
591 case ArrayIndexOf: {
592 // FIXME: Should support a CSE rule.
593 // https://bugs.webkit.org/show_bug.cgi?id=173173
594 read(MiscFields);
595 read(JSCell_indexingType);
596 read(JSCell_structureID);
597 read(JSObject_butterfly);
598 read(Butterfly_publicLength);
599 switch (node->arrayMode().type()) {
600 case Array::Double:
601 read(IndexedDoubleProperties);
602 return;
603 case Array::Int32:
604 read(IndexedInt32Properties);
605 return;
606 case Array::Contiguous:
607 read(IndexedContiguousProperties);
608 return;
609 default:
610 RELEASE_ASSERT_NOT_REACHED();
611 return;
612 }
613 return;
614 }
615
616 case GetById:
617 case GetByIdFlush:
618 case GetByIdWithThis:
619 case GetByIdDirect:
620 case GetByIdDirectFlush:
621 case GetByValWithThis:
622 case PutById:
623 case PutByIdWithThis:
624 case PutByValWithThis:
625 case PutByIdFlush:
626 case PutByIdDirect:
627 case PutGetterById:
628 case PutSetterById:
629 case PutGetterSetterById:
630 case PutGetterByVal:
631 case PutSetterByVal:
632 case DefineDataProperty:
633 case DefineAccessorProperty:
634 case DeleteById:
635 case DeleteByVal:
636 case ArrayPush:
637 case ArrayPop:
638 case Call:
639 case DirectCall:
640 case TailCallInlinedCaller:
641 case DirectTailCallInlinedCaller:
642 case Construct:
643 case DirectConstruct:
644 case CallVarargs:
645 case CallForwardVarargs:
646 case TailCallVarargsInlinedCaller:
647 case TailCallForwardVarargsInlinedCaller:
648 case ConstructVarargs:
649 case ConstructForwardVarargs:
650 case ToPrimitive:
651 case InByVal:
652 case InById:
653 case HasOwnProperty:
654 case ValueNegate:
655 case SetFunctionName:
656 case GetDynamicVar:
657 case PutDynamicVar:
658 case ResolveScopeForHoistingFuncDeclInEval:
659 case ResolveScope:
660 case ToObject:
661 case HasGenericProperty:
662 case HasStructureProperty:
663 case GetPropertyEnumerator:
664 case GetDirectPname:
665 case InstanceOfCustom:
666 case ToNumber:
667 case NumberToStringWithRadix:
668 case CreateThis:
669 case InstanceOf:
670 case StringValueOf:
671 case ObjectKeys:
672 read(World);
673 write(Heap);
674 return;
675
676 case ValueBitAnd:
677 case ValueBitXor:
678 case ValueBitOr:
679 case ValueAdd:
680 case ValueSub:
681 case ValueMul:
682 case ValueDiv:
683 case ValueMod:
684 if (node->isBinaryUseKind(BigIntUse)) {
685 def(PureValue(node));
686 return;
687 }
688 read(World);
689 write(Heap);
690 return;
691
692 case AtomicsAdd:
693 case AtomicsAnd:
694 case AtomicsCompareExchange:
695 case AtomicsExchange:
696 case AtomicsLoad:
697 case AtomicsOr:
698 case AtomicsStore:
699 case AtomicsSub:
700 case AtomicsXor: {
701 unsigned numExtraArgs = numExtraAtomicsArgs(node->op());
702 Edge storageEdge = graph.child(node, 2 + numExtraArgs);
703 if (!storageEdge) {
704 read(World);
705 write(Heap);
706 return;
707 }
708 read(TypedArrayProperties);
709 read(MiscFields);
710 write(TypedArrayProperties);
711 return;
712 }
713
714 case CallEval:
715 ASSERT(!node->origin.semantic.inlineCallFrame());
716 read(AbstractHeap(Stack, graph.m_codeBlock->scopeRegister()));
717 read(AbstractHeap(Stack, virtualRegisterForArgument(0)));
718 read(World);
719 write(Heap);
720 return;
721
722 case Throw:
723 case ThrowStaticError:
724 case TailCall:
725 case DirectTailCall:
726 case TailCallVarargs:
727 case TailCallForwardVarargs:
728 read(World);
729 write(SideState);
730 return;
731
732 case GetGetter:
733 read(GetterSetter_getter);
734 def(HeapLocation(GetterLoc, GetterSetter_getter, node->child1()), LazyNode(node));
735 return;
736
737 case GetSetter:
738 read(GetterSetter_setter);
739 def(HeapLocation(SetterLoc, GetterSetter_setter, node->child1()), LazyNode(node));
740 return;
741
742 case GetCallee:
743 read(AbstractHeap(Stack, CallFrameSlot::callee));
744 def(HeapLocation(StackLoc, AbstractHeap(Stack, CallFrameSlot::callee)), LazyNode(node));
745 return;
746
747 case SetCallee:
748 write(AbstractHeap(Stack, CallFrameSlot::callee));
749 return;
750
751 case GetArgumentCountIncludingThis: {
752 auto heap = AbstractHeap(Stack, remapOperand(node->argumentsInlineCallFrame(), VirtualRegister(CallFrameSlot::argumentCount)));
753 read(heap);
754 def(HeapLocation(StackPayloadLoc, heap), LazyNode(node));
755 return;
756 }
757
758 case SetArgumentCountIncludingThis:
759 write(AbstractHeap(Stack, CallFrameSlot::argumentCount));
760 return;
761
762 case GetRestLength:
763 read(Stack);
764 return;
765
766 case GetLocal:
767 read(AbstractHeap(Stack, node->local()));
768 def(HeapLocation(StackLoc, AbstractHeap(Stack, node->local())), LazyNode(node));
769 return;
770
771 case SetLocal:
772 write(AbstractHeap(Stack, node->local()));
773 def(HeapLocation(StackLoc, AbstractHeap(Stack, node->local())), LazyNode(node->child1().node()));
774 return;
775
776 case GetStack: {
777 AbstractHeap heap(Stack, node->stackAccessData()->local);
778 read(heap);
779 def(HeapLocation(StackLoc, heap), LazyNode(node));
780 return;
781 }
782
783 case PutStack: {
784 AbstractHeap heap(Stack, node->stackAccessData()->local);
785 write(heap);
786 def(HeapLocation(StackLoc, heap), LazyNode(node->child1().node()));
787 return;
788 }
789
790 case LoadVarargs: {
791 read(World);
792 write(Heap);
793 LoadVarargsData* data = node->loadVarargsData();
794 write(AbstractHeap(Stack, data->count.offset()));
795 for (unsigned i = data->limit; i--;)
796 write(AbstractHeap(Stack, data->start.offset() + static_cast<int>(i)));
797 return;
798 }
799
800 case ForwardVarargs: {
801 // We could be way more precise here.
802 read(Stack);
803
804 LoadVarargsData* data = node->loadVarargsData();
805 write(AbstractHeap(Stack, data->count.offset()));
806 for (unsigned i = data->limit; i--;)
807 write(AbstractHeap(Stack, data->start.offset() + static_cast<int>(i)));
808 return;
809 }
810
811 case GetByVal: {
812 ArrayMode mode = node->arrayMode();
813 LocationKind indexedPropertyLoc = indexedPropertyLocForResultType(node->result());
814 switch (mode.type()) {
815 case Array::SelectUsingPredictions:
816 case Array::Unprofiled:
817 case Array::SelectUsingArguments:
818 // Assume the worst since we don't have profiling yet.
819 read(World);
820 write(Heap);
821 return;
822
823 case Array::ForceExit:
824 write(SideState);
825 return;
826
827 case Array::Generic:
828 read(World);
829 write(Heap);
830 return;
831
832 case Array::String:
833 if (mode.isOutOfBounds()) {
834 read(World);
835 write(Heap);
836 return;
837 }
838 // This appears to read nothing because it's only reading immutable data.
839 def(PureValue(graph, node, mode.asWord()));
840 return;
841
842 case Array::DirectArguments:
843 if (mode.isInBounds()) {
844 read(DirectArgumentsProperties);
845 def(HeapLocation(indexedPropertyLoc, DirectArgumentsProperties, graph.varArgChild(node, 0), graph.varArgChild(node, 1)), LazyNode(node));
846 return;
847 }
848 read(World);
849 write(Heap);
850 return;
851
852 case Array::ScopedArguments:
853 read(ScopeProperties);
854 def(HeapLocation(indexedPropertyLoc, ScopeProperties, graph.varArgChild(node, 0), graph.varArgChild(node, 1)), LazyNode(node));
855 return;
856
857 case Array::Int32:
858 if (mode.isInBounds()) {
859 read(Butterfly_publicLength);
860 read(IndexedInt32Properties);
861 def(HeapLocation(indexedPropertyLoc, IndexedInt32Properties, graph.varArgChild(node, 0), graph.varArgChild(node, 1)), LazyNode(node));
862 return;
863 }
864 read(World);
865 write(Heap);
866 return;
867
868 case Array::Double:
869 if (mode.isInBounds()) {
870 read(Butterfly_publicLength);
871 read(IndexedDoubleProperties);
872 LocationKind kind = mode.isSaneChain() ? IndexedPropertyDoubleSaneChainLoc : IndexedPropertyDoubleLoc;
873 def(HeapLocation(kind, IndexedDoubleProperties, graph.varArgChild(node, 0), graph.varArgChild(node, 1)), LazyNode(node));
874 return;
875 }
876 read(World);
877 write(Heap);
878 return;
879
880 case Array::Contiguous:
881 if (mode.isInBounds()) {
882 read(Butterfly_publicLength);
883 read(IndexedContiguousProperties);
884 def(HeapLocation(indexedPropertyLoc, IndexedContiguousProperties, graph.varArgChild(node, 0), graph.varArgChild(node, 1)), LazyNode(node));
885 return;
886 }
887 read(World);
888 write(Heap);
889 return;
890
891 case Array::Undecided:
892 def(PureValue(graph, node));
893 return;
894
895 case Array::ArrayStorage:
896 case Array::SlowPutArrayStorage:
897 if (mode.isInBounds()) {
898 read(Butterfly_vectorLength);
899 read(IndexedArrayStorageProperties);
900 return;
901 }
902 read(World);
903 write(Heap);
904 return;
905
906 case Array::Int8Array:
907 case Array::Int16Array:
908 case Array::Int32Array:
909 case Array::Uint8Array:
910 case Array::Uint8ClampedArray:
911 case Array::Uint16Array:
912 case Array::Uint32Array:
913 case Array::Float32Array:
914 case Array::Float64Array:
915 read(TypedArrayProperties);
916 read(MiscFields);
917 def(HeapLocation(indexedPropertyLoc, TypedArrayProperties, graph.varArgChild(node, 0), graph.varArgChild(node, 1)), LazyNode(node));
918 return;
919 // We should not get an AnyTypedArray in a GetByVal as AnyTypedArray is only created from intrinsics, which
920 // are only added from Inline Caching a GetById.
921 case Array::AnyTypedArray:
922 DFG_CRASH(graph, node, "impossible array mode for get");
923 return;
924 }
925 RELEASE_ASSERT_NOT_REACHED();
926 return;
927 }
928
929 case GetMyArgumentByVal:
930 case GetMyArgumentByValOutOfBounds: {
931 read(Stack);
932 // FIXME: It would be trivial to have a def here.
933 // https://bugs.webkit.org/show_bug.cgi?id=143077
934 return;
935 }
936
937 case PutByValDirect:
938 case PutByVal:
939 case PutByValAlias: {
940 ArrayMode mode = node->arrayMode();
941 Node* base = graph.varArgChild(node, 0).node();
942 Node* index = graph.varArgChild(node, 1).node();
943 Node* value = graph.varArgChild(node, 2).node();
944 LocationKind indexedPropertyLoc = indexedPropertyLocForResultType(node->result());
945
946 switch (mode.modeForPut().type()) {
947 case Array::SelectUsingPredictions:
948 case Array::SelectUsingArguments:
949 case Array::Unprofiled:
950 case Array::Undecided:
951 // Assume the worst since we don't have profiling yet.
952 read(World);
953 write(Heap);
954 return;
955
956 case Array::ForceExit:
957 write(SideState);
958 return;
959
960 case Array::Generic:
961 read(World);
962 write(Heap);
963 return;
964
965 case Array::Int32:
966 if (node->arrayMode().isOutOfBounds()) {
967 read(World);
968 write(Heap);
969 return;
970 }
971 read(Butterfly_publicLength);
972 read(Butterfly_vectorLength);
973 read(IndexedInt32Properties);
974 write(IndexedInt32Properties);
975 if (node->arrayMode().mayStoreToHole())
976 write(Butterfly_publicLength);
977 def(HeapLocation(indexedPropertyLoc, IndexedInt32Properties, base, index), LazyNode(value));
978 return;
979
980 case Array::Double:
981 if (node->arrayMode().isOutOfBounds()) {
982 read(World);
983 write(Heap);
984 return;
985 }
986 read(Butterfly_publicLength);
987 read(Butterfly_vectorLength);
988 read(IndexedDoubleProperties);
989 write(IndexedDoubleProperties);
990 if (node->arrayMode().mayStoreToHole())
991 write(Butterfly_publicLength);
992 def(HeapLocation(IndexedPropertyDoubleLoc, IndexedDoubleProperties, base, index), LazyNode(value));
993 def(HeapLocation(IndexedPropertyDoubleSaneChainLoc, IndexedDoubleProperties, base, index), LazyNode(value));
994 return;
995
996 case Array::Contiguous:
997 if (node->arrayMode().isOutOfBounds()) {
998 read(World);
999 write(Heap);
1000 return;
1001 }
1002 read(Butterfly_publicLength);
1003 read(Butterfly_vectorLength);
1004 read(IndexedContiguousProperties);
1005 write(IndexedContiguousProperties);
1006 if (node->arrayMode().mayStoreToHole())
1007 write(Butterfly_publicLength);
1008 def(HeapLocation(indexedPropertyLoc, IndexedContiguousProperties, base, index), LazyNode(value));
1009 return;
1010
1011 case Array::ArrayStorage:
1012 if (node->arrayMode().isOutOfBounds()) {
1013 read(World);
1014 write(Heap);
1015 return;
1016 }
1017 read(Butterfly_publicLength);
1018 read(Butterfly_vectorLength);
1019 read(ArrayStorageProperties);
1020 write(ArrayStorageProperties);
1021 if (node->arrayMode().mayStoreToHole())
1022 write(Butterfly_publicLength);
1023 return;
1024
1025 case Array::SlowPutArrayStorage:
1026 if (node->arrayMode().mayStoreToHole()) {
1027 read(World);
1028 write(Heap);
1029 return;
1030 }
1031 read(Butterfly_publicLength);
1032 read(Butterfly_vectorLength);
1033 read(ArrayStorageProperties);
1034 write(ArrayStorageProperties);
1035 return;
1036
1037 case Array::Int8Array:
1038 case Array::Int16Array:
1039 case Array::Int32Array:
1040 case Array::Uint8Array:
1041 case Array::Uint8ClampedArray:
1042 case Array::Uint16Array:
1043 case Array::Uint32Array:
1044 case Array::Float32Array:
1045 case Array::Float64Array:
1046 read(MiscFields);
1047 write(TypedArrayProperties);
1048 // FIXME: We can't def() anything here because these operations truncate their inputs.
1049 // https://bugs.webkit.org/show_bug.cgi?id=134737
1050 return;
1051 case Array::AnyTypedArray:
1052 case Array::String:
1053 case Array::DirectArguments:
1054 case Array::ScopedArguments:
1055 DFG_CRASH(graph, node, "impossible array mode for put");
1056 return;
1057 }
1058 RELEASE_ASSERT_NOT_REACHED();
1059 return;
1060 }
1061
1062 case CheckStructureOrEmpty:
1063 case CheckStructure:
1064 read(JSCell_structureID);
1065 return;
1066
1067 case CheckArray:
1068 read(JSCell_indexingType);
1069 read(JSCell_typeInfoType);
1070 read(JSCell_structureID);
1071 return;
1072
1073 case CheckTypeInfoFlags:
1074 read(JSCell_typeInfoFlags);
1075 def(HeapLocation(CheckTypeInfoFlagsLoc, JSCell_typeInfoFlags, node->child1()), LazyNode(node));
1076 return;
1077
1078 case ParseInt:
1079 // Note: We would have eliminated a ParseInt that has just a single child as an Int32Use inside fixup.
1080 if (node->child1().useKind() == StringUse && (!node->child2() || node->child2().useKind() == Int32Use)) {
1081 def(PureValue(node));
1082 return;
1083 }
1084
1085 read(World);
1086 write(Heap);
1087 return;
1088
1089 case OverridesHasInstance:
1090 read(JSCell_typeInfoFlags);
1091 def(HeapLocation(OverridesHasInstanceLoc, JSCell_typeInfoFlags, node->child1()), LazyNode(node));
1092 return;
1093
1094 case PutStructure:
1095 read(JSObject_butterfly);
1096 write(JSCell_structureID);
1097 write(JSCell_typeInfoType);
1098 write(JSCell_typeInfoFlags);
1099 write(JSCell_indexingType);
1100 return;
1101
1102 case AllocatePropertyStorage:
1103 case ReallocatePropertyStorage:
1104 read(HeapObjectCount);
1105 write(HeapObjectCount);
1106 return;
1107
1108 case NukeStructureAndSetButterfly:
1109 write(JSObject_butterfly);
1110 write(JSCell_structureID);
1111 def(HeapLocation(ButterflyLoc, JSObject_butterfly, node->child1()), LazyNode(node->child2().node()));
1112 return;
1113
1114 case GetButterfly:
1115 read(JSObject_butterfly);
1116 def(HeapLocation(ButterflyLoc, JSObject_butterfly, node->child1()), LazyNode(node));
1117 return;
1118
1119 case CheckSubClass:
1120 def(PureValue(node, node->classInfo()));
1121 return;
1122
1123 case CallDOMGetter: {
1124 DOMJIT::CallDOMGetterSnippet* snippet = node->callDOMGetterData()->snippet;
1125 if (!snippet) {
1126 read(World);
1127 write(Heap);
1128 return;
1129 }
1130 DOMJIT::Effect effect = snippet->effect;
1131 if (effect.reads) {
1132 if (effect.reads == DOMJIT::HeapRange::top())
1133 read(World);
1134 else
1135 read(AbstractHeap(DOMState, effect.reads.rawRepresentation()));
1136 }
1137 if (effect.writes) {
1138 if (effect.writes == DOMJIT::HeapRange::top())
1139 write(Heap);
1140 else
1141 write(AbstractHeap(DOMState, effect.writes.rawRepresentation()));
1142 }
1143 if (effect.def != DOMJIT::HeapRange::top()) {
1144 DOMJIT::HeapRange range = effect.def;
1145 if (range == DOMJIT::HeapRange::none())
1146 def(PureValue(node, bitwise_cast<uintptr_t>(node->callDOMGetterData()->customAccessorGetter)));
1147 else {
1148 // Def with heap location. We do not include "GlobalObject" for that since this information is included in the base node.
1149 // We only see the DOMJIT getter here. So just including "base" is ok.
1150 def(HeapLocation(DOMStateLoc, AbstractHeap(DOMState, range.rawRepresentation()), node->child1()), LazyNode(node));
1151 }
1152 }
1153 return;
1154 }
1155
1156 case CallDOM: {
1157 const DOMJIT::Signature* signature = node->signature();
1158 DOMJIT::Effect effect = signature->effect;
1159 if (effect.reads) {
1160 if (effect.reads == DOMJIT::HeapRange::top())
1161 read(World);
1162 else
1163 read(AbstractHeap(DOMState, effect.reads.rawRepresentation()));
1164 }
1165 if (effect.writes) {
1166 if (effect.writes == DOMJIT::HeapRange::top())
1167 write(Heap);
1168 else
1169 write(AbstractHeap(DOMState, effect.writes.rawRepresentation()));
1170 }
1171 ASSERT_WITH_MESSAGE(effect.def == DOMJIT::HeapRange::top(), "Currently, we do not accept any def for CallDOM.");
1172 return;
1173 }
1174
1175 case Arrayify:
1176 case ArrayifyToStructure:
1177 read(JSCell_structureID);
1178 read(JSCell_indexingType);
1179 read(JSObject_butterfly);
1180 write(JSCell_structureID);
1181 write(JSCell_indexingType);
1182 write(JSObject_butterfly);
1183 write(Watchpoint_fire);
1184 return;
1185
1186 case GetIndexedPropertyStorage:
1187 if (node->arrayMode().type() == Array::String) {
1188 def(PureValue(node, node->arrayMode().asWord()));
1189 return;
1190 }
1191 read(MiscFields);
1192 def(HeapLocation(IndexedPropertyStorageLoc, MiscFields, node->child1()), LazyNode(node));
1193 return;
1194
1195 case GetTypedArrayByteOffset:
1196 read(MiscFields);
1197 def(HeapLocation(TypedArrayByteOffsetLoc, MiscFields, node->child1()), LazyNode(node));
1198 return;
1199
1200 case GetPrototypeOf: {
1201 switch (node->child1().useKind()) {
1202 case ArrayUse:
1203 case FunctionUse:
1204 case FinalObjectUse:
1205 read(JSCell_structureID);
1206 read(JSObject_butterfly);
1207 read(NamedProperties); // Poly proto could load prototype from its slot.
1208 def(HeapLocation(PrototypeLoc, NamedProperties, node->child1()), LazyNode(node));
1209 return;
1210 default:
1211 read(World);
1212 write(Heap);
1213 return;
1214 }
1215 }
1216
1217 case GetByOffset:
1218 case GetGetterSetterByOffset: {
1219 unsigned identifierNumber = node->storageAccessData().identifierNumber;
1220 AbstractHeap heap(NamedProperties, identifierNumber);
1221 read(heap);
1222 def(HeapLocation(NamedPropertyLoc, heap, node->child2()), LazyNode(node));
1223 return;
1224 }
1225
1226 case TryGetById: {
1227 read(Heap);
1228 return;
1229 }
1230
1231 case MultiGetByOffset: {
1232 read(JSCell_structureID);
1233 read(JSObject_butterfly);
1234 AbstractHeap heap(NamedProperties, node->multiGetByOffsetData().identifierNumber);
1235 read(heap);
1236 def(HeapLocation(NamedPropertyLoc, heap, node->child1()), LazyNode(node));
1237 return;
1238 }
1239
1240 case MultiPutByOffset: {
1241 read(JSCell_structureID);
1242 read(JSObject_butterfly);
1243 AbstractHeap heap(NamedProperties, node->multiPutByOffsetData().identifierNumber);
1244 write(heap);
1245 if (node->multiPutByOffsetData().writesStructures())
1246 write(JSCell_structureID);
1247 if (node->multiPutByOffsetData().reallocatesStorage())
1248 write(JSObject_butterfly);
1249 def(HeapLocation(NamedPropertyLoc, heap, node->child1()), LazyNode(node->child2().node()));
1250 return;
1251 }
1252
1253 case PutByOffset: {
1254 unsigned identifierNumber = node->storageAccessData().identifierNumber;
1255 AbstractHeap heap(NamedProperties, identifierNumber);
1256 write(heap);
1257 def(HeapLocation(NamedPropertyLoc, heap, node->child2()), LazyNode(node->child3().node()));
1258 return;
1259 }
1260
1261 case GetArrayLength: {
1262 ArrayMode mode = node->arrayMode();
1263 switch (mode.type()) {
1264 case Array::Undecided:
1265 case Array::Int32:
1266 case Array::Double:
1267 case Array::Contiguous:
1268 case Array::ArrayStorage:
1269 case Array::SlowPutArrayStorage:
1270 read(Butterfly_publicLength);
1271 def(HeapLocation(ArrayLengthLoc, Butterfly_publicLength, node->child1()), LazyNode(node));
1272 return;
1273
1274 case Array::String:
1275 def(PureValue(node, mode.asWord()));
1276 return;
1277
1278 case Array::DirectArguments:
1279 case Array::ScopedArguments:
1280 read(MiscFields);
1281 def(HeapLocation(ArrayLengthLoc, MiscFields, node->child1()), LazyNode(node));
1282 return;
1283
1284 default:
1285 ASSERT(mode.isSomeTypedArrayView());
1286 read(MiscFields);
1287 def(HeapLocation(ArrayLengthLoc, MiscFields, node->child1()), LazyNode(node));
1288 return;
1289 }
1290 }
1291
1292 case GetVectorLength: {
1293 ArrayMode mode = node->arrayMode();
1294 switch (mode.type()) {
1295 case Array::ArrayStorage:
1296 case Array::SlowPutArrayStorage:
1297 read(Butterfly_vectorLength);
1298 def(HeapLocation(VectorLengthLoc, Butterfly_vectorLength, node->child1()), LazyNode(node));
1299 return;
1300
1301 default:
1302 RELEASE_ASSERT_NOT_REACHED();
1303 return;
1304 }
1305 }
1306
1307 case GetClosureVar:
1308 read(AbstractHeap(ScopeProperties, node->scopeOffset().offset()));
1309 def(HeapLocation(ClosureVariableLoc, AbstractHeap(ScopeProperties, node->scopeOffset().offset()), node->child1()), LazyNode(node));
1310 return;
1311
1312 case PutClosureVar:
1313 write(AbstractHeap(ScopeProperties, node->scopeOffset().offset()));
1314 def(HeapLocation(ClosureVariableLoc, AbstractHeap(ScopeProperties, node->scopeOffset().offset()), node->child1()), LazyNode(node->child2().node()));
1315 return;
1316
1317 case GetRegExpObjectLastIndex:
1318 read(RegExpObject_lastIndex);
1319 def(HeapLocation(RegExpObjectLastIndexLoc, RegExpObject_lastIndex, node->child1()), LazyNode(node));
1320 return;
1321
1322 case SetRegExpObjectLastIndex:
1323 write(RegExpObject_lastIndex);
1324 def(HeapLocation(RegExpObjectLastIndexLoc, RegExpObject_lastIndex, node->child1()), LazyNode(node->child2().node()));
1325 return;
1326
1327 case RecordRegExpCachedResult:
1328 write(RegExpState);
1329 return;
1330
1331 case GetFromArguments: {
1332 AbstractHeap heap(DirectArgumentsProperties, node->capturedArgumentsOffset().offset());
1333 read(heap);
1334 def(HeapLocation(DirectArgumentsLoc, heap, node->child1()), LazyNode(node));
1335 return;
1336 }
1337
1338 case PutToArguments: {
1339 AbstractHeap heap(DirectArgumentsProperties, node->capturedArgumentsOffset().offset());
1340 write(heap);
1341 def(HeapLocation(DirectArgumentsLoc, heap, node->child1()), LazyNode(node->child2().node()));
1342 return;
1343 }
1344
1345 case GetArgument: {
1346 read(Stack);
1347 // FIXME: It would be trivial to have a def here.
1348 // https://bugs.webkit.org/show_bug.cgi?id=143077
1349 return;
1350 }
1351
1352 case GetGlobalVar:
1353 case GetGlobalLexicalVariable:
1354 read(AbstractHeap(Absolute, node->variablePointer()));
1355 def(HeapLocation(GlobalVariableLoc, AbstractHeap(Absolute, node->variablePointer())), LazyNode(node));
1356 return;
1357
1358 case PutGlobalVariable:
1359 write(AbstractHeap(Absolute, node->variablePointer()));
1360 def(HeapLocation(GlobalVariableLoc, AbstractHeap(Absolute, node->variablePointer())), LazyNode(node->child2().node()));
1361 return;
1362
1363 case NewArrayWithSize:
1364 read(HeapObjectCount);
1365 write(HeapObjectCount);
1366 return;
1367
1368 case NewTypedArray:
1369 switch (node->child1().useKind()) {
1370 case Int32Use:
1371 read(HeapObjectCount);
1372 write(HeapObjectCount);
1373 return;
1374 case UntypedUse:
1375 read(World);
1376 write(Heap);
1377 return;
1378 default:
1379 DFG_CRASH(graph, node, "Bad use kind");
1380 }
1381 break;
1382
1383 case NewArrayWithSpread: {
1384 // This also reads from JSFixedArray's data store, but we don't have any way of describing that yet.
1385 read(HeapObjectCount);
1386 for (unsigned i = 0; i < node->numChildren(); i++) {
1387 Node* child = graph.varArgChild(node, i).node();
1388 if (child->op() == PhantomSpread) {
1389 read(Stack);
1390 break;
1391 }
1392 }
1393 write(HeapObjectCount);
1394 return;
1395 }
1396
1397 case Spread: {
1398 if (node->child1()->op() == PhantomNewArrayBuffer) {
1399 read(MiscFields);
1400 return;
1401 }
1402
1403 if (node->child1()->op() == PhantomCreateRest) {
1404 read(Stack);
1405 write(HeapObjectCount);
1406 return;
1407 }
1408
1409 read(World);
1410 write(Heap);
1411 return;
1412 }
1413
1414 case NewArray: {
1415 read(HeapObjectCount);
1416 write(HeapObjectCount);
1417
1418 unsigned numElements = node->numChildren();
1419
1420 def(HeapLocation(ArrayLengthLoc, Butterfly_publicLength, node),
1421 LazyNode(graph.freeze(jsNumber(numElements))));
1422
1423 if (!numElements)
1424 return;
1425
1426 AbstractHeap heap;
1427 LocationKind indexedPropertyLoc;
1428 switch (node->indexingType()) {
1429 case ALL_DOUBLE_INDEXING_TYPES:
1430 heap = IndexedDoubleProperties;
1431 indexedPropertyLoc = IndexedPropertyDoubleLoc;
1432 break;
1433
1434 case ALL_INT32_INDEXING_TYPES:
1435 heap = IndexedInt32Properties;
1436 indexedPropertyLoc = IndexedPropertyJSLoc;
1437 break;
1438
1439 case ALL_CONTIGUOUS_INDEXING_TYPES:
1440 heap = IndexedContiguousProperties;
1441 indexedPropertyLoc = IndexedPropertyJSLoc;
1442 break;
1443
1444 default:
1445 return;
1446 }
1447
1448 if (numElements < graph.m_uint32ValuesInUse.size()) {
1449 for (unsigned operandIdx = 0; operandIdx < numElements; ++operandIdx) {
1450 Edge use = graph.m_varArgChildren[node->firstChild() + operandIdx];
1451 def(HeapLocation(indexedPropertyLoc, heap, node, LazyNode(graph.freeze(jsNumber(operandIdx)))),
1452 LazyNode(use.node()));
1453 }
1454 } else {
1455 for (uint32_t operandIdx : graph.m_uint32ValuesInUse) {
1456 if (operandIdx >= numElements)
1457 continue;
1458 Edge use = graph.m_varArgChildren[node->firstChild() + operandIdx];
1459 // operandIdx comes from graph.m_uint32ValuesInUse and thus is guaranteed to be already frozen
1460 def(HeapLocation(indexedPropertyLoc, heap, node, LazyNode(graph.freeze(jsNumber(operandIdx)))),
1461 LazyNode(use.node()));
1462 }
1463 }
1464 return;
1465 }
1466
1467 case NewArrayBuffer: {
1468 read(HeapObjectCount);
1469 write(HeapObjectCount);
1470
1471 auto* array = node->castOperand<JSImmutableButterfly*>();
1472 unsigned numElements = array->length();
1473 def(HeapLocation(ArrayLengthLoc, Butterfly_publicLength, node),
1474 LazyNode(graph.freeze(jsNumber(numElements))));
1475
1476 AbstractHeap heap;
1477 LocationKind indexedPropertyLoc;
1478 NodeType op = JSConstant;
1479 switch (node->indexingType()) {
1480 case ALL_DOUBLE_INDEXING_TYPES:
1481 heap = IndexedDoubleProperties;
1482 indexedPropertyLoc = IndexedPropertyDoubleLoc;
1483 op = DoubleConstant;
1484 break;
1485
1486 case ALL_INT32_INDEXING_TYPES:
1487 heap = IndexedInt32Properties;
1488 indexedPropertyLoc = IndexedPropertyJSLoc;
1489 break;
1490
1491 case ALL_CONTIGUOUS_INDEXING_TYPES:
1492 heap = IndexedContiguousProperties;
1493 indexedPropertyLoc = IndexedPropertyJSLoc;
1494 break;
1495
1496 default:
1497 return;
1498 }
1499
1500 if (numElements < graph.m_uint32ValuesInUse.size()) {
1501 for (unsigned index = 0; index < numElements; ++index) {
1502 def(HeapLocation(indexedPropertyLoc, heap, node, LazyNode(graph.freeze(jsNumber(index)))),
1503 LazyNode(graph.freeze(array->get(index)), op));
1504 }
1505 } else {
1506 Vector<uint32_t> possibleIndices;
1507 for (uint32_t index : graph.m_uint32ValuesInUse) {
1508 if (index >= numElements)
1509 continue;
1510 possibleIndices.append(index);
1511 }
1512 for (uint32_t index : possibleIndices) {
1513 def(HeapLocation(indexedPropertyLoc, heap, node, LazyNode(graph.freeze(jsNumber(index)))),
1514 LazyNode(graph.freeze(array->get(index)), op));
1515 }
1516 }
1517 return;
1518 }
1519
1520 case CreateRest: {
1521 if (!graph.isWatchingHavingABadTimeWatchpoint(node)) {
1522 // This means we're already having a bad time.
1523 read(World);
1524 write(Heap);
1525 return;
1526 }
1527 read(Stack);
1528 read(HeapObjectCount);
1529 write(HeapObjectCount);
1530 return;
1531 }
1532
1533 case ObjectCreate: {
1534 switch (node->child1().useKind()) {
1535 case ObjectUse:
1536 read(HeapObjectCount);
1537 write(HeapObjectCount);
1538 return;
1539 case UntypedUse:
1540 read(World);
1541 write(Heap);
1542 return;
1543 default:
1544 RELEASE_ASSERT_NOT_REACHED();
1545 return;
1546 }
1547 }
1548
1549 case NewObject:
1550 case NewRegexp:
1551 case NewSymbol:
1552 case NewStringObject:
1553 case PhantomNewObject:
1554 case MaterializeNewObject:
1555 case PhantomNewFunction:
1556 case PhantomNewGeneratorFunction:
1557 case PhantomNewAsyncFunction:
1558 case PhantomNewAsyncGeneratorFunction:
1559 case PhantomCreateActivation:
1560 case MaterializeCreateActivation:
1561 case PhantomNewRegexp:
1562 read(HeapObjectCount);
1563 write(HeapObjectCount);
1564 return;
1565
1566 case NewFunction:
1567 case NewGeneratorFunction:
1568 case NewAsyncGeneratorFunction:
1569 case NewAsyncFunction:
1570 if (node->castOperand<FunctionExecutable*>()->singletonFunction()->isStillValid())
1571 write(Watchpoint_fire);
1572 read(HeapObjectCount);
1573 write(HeapObjectCount);
1574 return;
1575
1576 case RegExpExec:
1577 case RegExpTest:
1578 // Even if we've proven known input types as RegExpObject and String,
1579 // accessing lastIndex is effectful if it's a global regexp.
1580 read(World);
1581 write(Heap);
1582 return;
1583
1584 case RegExpMatchFast:
1585 read(RegExpState);
1586 read(RegExpObject_lastIndex);
1587 write(RegExpState);
1588 write(RegExpObject_lastIndex);
1589 return;
1590
1591 case RegExpExecNonGlobalOrSticky:
1592 case RegExpMatchFastGlobal:
1593 read(RegExpState);
1594 write(RegExpState);
1595 return;
1596
1597 case StringReplace:
1598 case StringReplaceRegExp:
1599 if (node->child1().useKind() == StringUse
1600 && node->child2().useKind() == RegExpObjectUse
1601 && node->child3().useKind() == StringUse) {
1602 read(RegExpState);
1603 read(RegExpObject_lastIndex);
1604 write(RegExpState);
1605 write(RegExpObject_lastIndex);
1606 return;
1607 }
1608 read(World);
1609 write(Heap);
1610 return;
1611
1612 case StringCharAt:
1613 if (node->arrayMode().isOutOfBounds()) {
1614 read(World);
1615 write(Heap);
1616 return;
1617 }
1618 def(PureValue(node));
1619 return;
1620
1621 case CompareBelow:
1622 case CompareBelowEq:
1623 def(PureValue(node));
1624 return;
1625
1626 case CompareEq:
1627 case CompareLess:
1628 case CompareLessEq:
1629 case CompareGreater:
1630 case CompareGreaterEq:
1631 if (node->isBinaryUseKind(StringUse)) {
1632 read(HeapObjectCount);
1633 write(HeapObjectCount);
1634 return;
1635 }
1636
1637 if (node->isBinaryUseKind(UntypedUse)) {
1638 read(World);
1639 write(Heap);
1640 return;
1641 }
1642
1643 def(PureValue(node));
1644 return;
1645
1646 case ToString:
1647 case CallStringConstructor:
1648 switch (node->child1().useKind()) {
1649 case CellUse:
1650 case UntypedUse:
1651 read(World);
1652 write(Heap);
1653 return;
1654
1655 case StringObjectUse:
1656 case StringOrStringObjectUse:
1657 // These two StringObjectUse's are pure because if we emit this node with either
1658 // of these UseKinds, we'll first emit a StructureCheck ensuring that we're the
1659 // original String or StringObject structure. Therefore, we don't have an overridden
1660 // valueOf, etc.
1661
1662 case Int32Use:
1663 case Int52RepUse:
1664 case DoubleRepUse:
1665 case NotCellUse:
1666 def(PureValue(node));
1667 return;
1668
1669 default:
1670 RELEASE_ASSERT_NOT_REACHED();
1671 return;
1672 }
1673
1674 case CountExecution:
1675 case SuperSamplerBegin:
1676 case SuperSamplerEnd:
1677 read(InternalState);
1678 write(InternalState);
1679 return;
1680
1681 case LogShadowChickenPrologue:
1682 case LogShadowChickenTail:
1683 write(SideState);
1684 return;
1685
1686 case MapHash:
1687 def(PureValue(node));
1688 return;
1689
1690 case NormalizeMapKey:
1691 def(PureValue(node));
1692 return;
1693
1694 case GetMapBucket: {
1695 Edge& mapEdge = node->child1();
1696 Edge& keyEdge = node->child2();
1697 AbstractHeapKind heap = (mapEdge.useKind() == MapObjectUse) ? JSMapFields : JSSetFields;
1698 read(heap);
1699 def(HeapLocation(MapBucketLoc, heap, mapEdge, keyEdge), LazyNode(node));
1700 return;
1701 }
1702
1703 case GetMapBucketHead: {
1704 Edge& mapEdge = node->child1();
1705 AbstractHeapKind heap = (mapEdge.useKind() == MapObjectUse) ? JSMapFields : JSSetFields;
1706 read(heap);
1707 def(HeapLocation(MapBucketHeadLoc, heap, mapEdge), LazyNode(node));
1708 return;
1709 }
1710
1711 case GetMapBucketNext: {
1712 AbstractHeapKind heap = (node->bucketOwnerType() == BucketOwnerType::Map) ? JSMapFields : JSSetFields;
1713 read(heap);
1714 Edge& bucketEdge = node->child1();
1715 def(HeapLocation(MapBucketNextLoc, heap, bucketEdge), LazyNode(node));
1716 return;
1717 }
1718
1719 case LoadKeyFromMapBucket: {
1720 AbstractHeapKind heap = (node->bucketOwnerType() == BucketOwnerType::Map) ? JSMapFields : JSSetFields;
1721 read(heap);
1722 Edge& bucketEdge = node->child1();
1723 def(HeapLocation(MapBucketKeyLoc, heap, bucketEdge), LazyNode(node));
1724 return;
1725 }
1726
1727 case LoadValueFromMapBucket: {
1728 AbstractHeapKind heap = (node->bucketOwnerType() == BucketOwnerType::Map) ? JSMapFields : JSSetFields;
1729 read(heap);
1730 Edge& bucketEdge = node->child1();
1731 def(HeapLocation(MapBucketValueLoc, heap, bucketEdge), LazyNode(node));
1732 return;
1733 }
1734
1735 case WeakMapGet: {
1736 Edge& mapEdge = node->child1();
1737 Edge& keyEdge = node->child2();
1738 AbstractHeapKind heap = (mapEdge.useKind() == WeakMapObjectUse) ? JSWeakMapFields : JSWeakSetFields;
1739 read(heap);
1740 def(HeapLocation(WeakMapGetLoc, heap, mapEdge, keyEdge), LazyNode(node));
1741 return;
1742 }
1743
1744 case SetAdd: {
1745 Edge& mapEdge = node->child1();
1746 Edge& keyEdge = node->child2();
1747 write(JSSetFields);
1748 def(HeapLocation(MapBucketLoc, JSSetFields, mapEdge, keyEdge), LazyNode(node));
1749 return;
1750 }
1751
1752 case MapSet: {
1753 Edge& mapEdge = graph.varArgChild(node, 0);
1754 Edge& keyEdge = graph.varArgChild(node, 1);
1755 write(JSMapFields);
1756 def(HeapLocation(MapBucketLoc, JSMapFields, mapEdge, keyEdge), LazyNode(node));
1757 return;
1758 }
1759
1760 case WeakSetAdd: {
1761 Edge& mapEdge = node->child1();
1762 Edge& keyEdge = node->child2();
1763 write(JSWeakSetFields);
1764 def(HeapLocation(WeakMapGetLoc, JSWeakSetFields, mapEdge, keyEdge), LazyNode(keyEdge.node()));
1765 return;
1766 }
1767
1768 case WeakMapSet: {
1769 Edge& mapEdge = graph.varArgChild(node, 0);
1770 Edge& keyEdge = graph.varArgChild(node, 1);
1771 Edge& valueEdge = graph.varArgChild(node, 2);
1772 write(JSWeakMapFields);
1773 def(HeapLocation(WeakMapGetLoc, JSWeakMapFields, mapEdge, keyEdge), LazyNode(valueEdge.node()));
1774 return;
1775 }
1776
1777 case ExtractValueFromWeakMapGet:
1778 def(PureValue(node));
1779 return;
1780
1781 case StringSlice:
1782 def(PureValue(node));
1783 return;
1784
1785 case ToLowerCase:
1786 def(PureValue(node));
1787 return;
1788
1789 case NumberToStringWithValidRadixConstant:
1790 def(PureValue(node, node->validRadixConstant()));
1791 return;
1792
1793 case DataViewGetFloat:
1794 case DataViewGetInt: {
1795 read(MiscFields);
1796 read(TypedArrayProperties);
1797 LocationKind indexedPropertyLoc = indexedPropertyLocForResultType(node->result());
1798 def(HeapLocation(indexedPropertyLoc, AbstractHeap(TypedArrayProperties, node->dataViewData().asQuadWord),
1799 node->child1(), node->child2(), node->child3()), LazyNode(node));
1800 return;
1801 }
1802
1803 case DataViewSet: {
1804 read(MiscFields);
1805 read(TypedArrayProperties);
1806 write(TypedArrayProperties);
1807 return;
1808 }
1809
1810 case LastNodeType:
1811 RELEASE_ASSERT_NOT_REACHED();
1812 return;
1813 }
1814
1815 DFG_CRASH(graph, node, toCString("Unrecognized node type: ", Graph::opName(node->op())).data());
1816}
1817
1818class NoOpClobberize {
1819public:
1820 NoOpClobberize() { }
1821 template<typename... T>
1822 void operator()(T...) const { }
1823};
1824
1825class CheckClobberize {
1826public:
1827 CheckClobberize()
1828 : m_result(false)
1829 {
1830 }
1831
1832 template<typename... T>
1833 void operator()(T...) const { m_result = true; }
1834
1835 bool result() const { return m_result; }
1836
1837private:
1838 mutable bool m_result;
1839};
1840
1841bool doesWrites(Graph&, Node*);
1842
1843class AbstractHeapOverlaps {
1844public:
1845 AbstractHeapOverlaps(AbstractHeap heap)
1846 : m_heap(heap)
1847 , m_result(false)
1848 {
1849 }
1850
1851 void operator()(AbstractHeap otherHeap) const
1852 {
1853 if (m_result)
1854 return;
1855 m_result = m_heap.overlaps(otherHeap);
1856 }
1857
1858 bool result() const { return m_result; }
1859
1860private:
1861 AbstractHeap m_heap;
1862 mutable bool m_result;
1863};
1864
1865bool accessesOverlap(Graph&, Node*, AbstractHeap);
1866bool writesOverlap(Graph&, Node*, AbstractHeap);
1867
1868bool clobbersHeap(Graph&, Node*);
1869
1870// We would have used bind() for these, but because of the overlaoding that we are doing,
1871// it's quite a bit of clearer to just write this out the traditional way.
1872
1873template<typename T>
1874class ReadMethodClobberize {
1875public:
1876 ReadMethodClobberize(T& value)
1877 : m_value(value)
1878 {
1879 }
1880
1881 void operator()(AbstractHeap heap) const
1882 {
1883 m_value.read(heap);
1884 }
1885private:
1886 T& m_value;
1887};
1888
1889template<typename T>
1890class WriteMethodClobberize {
1891public:
1892 WriteMethodClobberize(T& value)
1893 : m_value(value)
1894 {
1895 }
1896
1897 void operator()(AbstractHeap heap) const
1898 {
1899 m_value.write(heap);
1900 }
1901private:
1902 T& m_value;
1903};
1904
1905template<typename T>
1906class DefMethodClobberize {
1907public:
1908 DefMethodClobberize(T& value)
1909 : m_value(value)
1910 {
1911 }
1912
1913 void operator()(PureValue value) const
1914 {
1915 m_value.def(value);
1916 }
1917
1918 void operator()(HeapLocation location, LazyNode node) const
1919 {
1920 m_value.def(location, node);
1921 }
1922
1923private:
1924 T& m_value;
1925};
1926
1927template<typename Adaptor>
1928void clobberize(Graph& graph, Node* node, Adaptor& adaptor)
1929{
1930 ReadMethodClobberize<Adaptor> read(adaptor);
1931 WriteMethodClobberize<Adaptor> write(adaptor);
1932 DefMethodClobberize<Adaptor> def(adaptor);
1933 clobberize(graph, node, read, write, def);
1934}
1935
1936} } // namespace JSC::DFG
1937
1938#endif // ENABLE(DFG_JIT)
1939