2 * Copyright (C) 2012 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "DFGArgumentsSimplificationPhase.h"
31 #include "DFGAbstractState.h"
32 #include "DFGBasicBlock.h"
34 #include "DFGInsertionSet.h"
36 #include "DFGValidate.h"
37 #include <wtf/HashSet.h>
38 #include <wtf/HashMap.h>
40 namespace JSC { namespace DFG {
45 struct NullableHashTraits : public HashTraits<T> {
46 static const bool emptyValueIsZero = false;
47 static T emptyValue() { return reinterpret_cast<T>(1); }
50 struct ArgumentsAliasingData {
51 InlineCallFrame* callContext;
53 bool multipleCallContexts;
55 bool assignedFromArguments;
56 bool assignedFromManyThings;
60 ArgumentsAliasingData()
62 , callContextSet(false)
63 , multipleCallContexts(false)
64 , assignedFromArguments(false)
65 , assignedFromManyThings(false)
70 void mergeCallContext(InlineCallFrame* newCallContext)
72 if (multipleCallContexts)
75 if (!callContextSet) {
76 callContext = newCallContext;
77 callContextSet = true;
81 if (callContext == newCallContext)
84 multipleCallContexts = true;
87 bool callContextIsValid()
89 return callContextSet && !multipleCallContexts;
92 void mergeArgumentsAssignment()
94 assignedFromArguments = true;
97 void mergeNonArgumentsAssignment()
99 assignedFromManyThings = true;
102 bool argumentsAssignmentIsValid()
104 return assignedFromArguments && !assignedFromManyThings;
109 return callContextIsValid() && argumentsAssignmentIsValid() && !escapes;
113 } // end anonymous namespace
115 class ArgumentsSimplificationPhase : public Phase {
117 ArgumentsSimplificationPhase(Graph& graph)
118 : Phase(graph, "arguments simplification")
124 if (!m_graph.m_hasArguments)
127 bool changed = false;
129 // Record which arguments are known to escape no matter what.
130 for (unsigned i = codeBlock()->inlineCallFrames().size(); i--;) {
131 InlineCallFrame* inlineCallFrame = &codeBlock()->inlineCallFrames()[i];
132 if (m_graph.m_executablesWhoseArgumentsEscaped.contains(
133 m_graph.executableFor(inlineCallFrame)))
134 m_createsArguments.add(inlineCallFrame);
137 // Create data for variable access datas that we will want to analyze.
138 for (unsigned i = m_graph.m_variableAccessData.size(); i--;) {
139 VariableAccessData* variableAccessData = &m_graph.m_variableAccessData[i];
140 if (!variableAccessData->isRoot())
142 if (variableAccessData->isCaptured())
144 m_argumentsAliasing.add(variableAccessData, ArgumentsAliasingData());
147 // Figure out which variables alias the arguments and nothing else, and are
148 // used only for GetByVal and GetArgumentsLength accesses. At the same time,
149 // identify uses of CreateArguments that are not consistent with the arguments
150 // being aliased only to variables that satisfy these constraints.
151 for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
152 BasicBlock* block = m_graph.m_blocks[blockIndex].get();
155 for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
156 NodeIndex nodeIndex = block->at(indexInBlock);
157 Node& node = m_graph[nodeIndex];
158 if (!node.shouldGenerate())
161 case CreateArguments: {
162 // Ignore this op. If we see a lone CreateArguments then we want to
163 // completely ignore it because:
164 // 1) The default would be to see that the child is a GetLocal on the
165 // arguments register and conclude that we have an arguments escape.
166 // 2) The fact that a CreateArguments exists does not mean that it
167 // will continue to exist after we're done with this phase. As far
168 // as this phase is concerned, a CreateArguments only "exists" if it
169 // is used in a manner that necessitates its existance.
173 case TearOffArguments: {
174 // Ignore arguments tear off, because it's only relevant if we actually
175 // need to create the arguments.
180 Node& source = m_graph[node.child1()];
181 VariableAccessData* variableAccessData = node.variableAccessData();
182 int argumentsRegister =
183 m_graph.uncheckedArgumentsRegisterFor(node.codeOrigin);
184 if (source.op() != CreateArguments) {
185 // Make sure that the source of the SetLocal knows that if it's
186 // a variable that we think is aliased to the arguments, then it
187 // may escape at this point. In future, we could track transitive
188 // aliasing. But not yet.
189 observeBadArgumentsUse(node.child1());
191 if (variableAccessData->isCaptured()) {
192 // If this is an assignment to the arguments register, then
193 // pretend as if the arguments were created. We don't want to
194 // optimize code that explicitly assigns to the arguments,
195 // because that seems too ugly.
197 // But, before getting rid of CreateArguments, we will have
198 // an assignment to the arguments registers with JSValue().
199 // That's because CSE will refuse to get rid of the
200 // init_lazy_reg since it treats CreateArguments as reading
201 // local variables. That could be fixed, but it's easier to
202 // work around this here.
203 if (source.op() == JSConstant
204 && !source.valueOfJSConstant(codeBlock()))
207 if (argumentsRegister != InvalidVirtualRegister
208 && (variableAccessData->local() == argumentsRegister
209 || variableAccessData->local() == unmodifiedArgumentsRegister(argumentsRegister)))
210 m_createsArguments.add(node.codeOrigin.inlineCallFrame);
214 // Make sure that if it's a variable that we think is aliased to
215 // the arguments, that we know that it might actually not be.
216 ArgumentsAliasingData& data =
217 m_argumentsAliasing.find(variableAccessData)->second;
218 data.mergeNonArgumentsAssignment();
219 data.mergeCallContext(node.codeOrigin.inlineCallFrame);
222 if (argumentsRegister != InvalidVirtualRegister
223 && (variableAccessData->local() == argumentsRegister
224 || variableAccessData->local() == unmodifiedArgumentsRegister(argumentsRegister))) {
225 if (node.codeOrigin.inlineCallFrame == source.codeOrigin.inlineCallFrame)
227 m_createsArguments.add(source.codeOrigin.inlineCallFrame);
230 if (variableAccessData->isCaptured()) {
231 m_createsArguments.add(source.codeOrigin.inlineCallFrame);
234 ArgumentsAliasingData& data =
235 m_argumentsAliasing.find(variableAccessData)->second;
236 data.mergeArgumentsAssignment();
237 // This ensures that the variable's uses are in the same context as
238 // the arguments it is aliasing.
239 data.mergeCallContext(node.codeOrigin.inlineCallFrame);
240 data.mergeCallContext(source.codeOrigin.inlineCallFrame);
246 VariableAccessData* variableAccessData = node.variableAccessData();
247 if (variableAccessData->isCaptured())
249 ArgumentsAliasingData& data =
250 m_argumentsAliasing.find(variableAccessData)->second;
251 data.mergeCallContext(node.codeOrigin.inlineCallFrame);
256 VariableAccessData* variableAccessData = node.variableAccessData();
257 if (variableAccessData->isCaptured())
259 ArgumentsAliasingData& data =
260 m_argumentsAliasing.find(variableAccessData)->second;
261 data.mergeCallContext(node.codeOrigin.inlineCallFrame);
263 // If a variable is used in a flush then by definition it escapes.
269 VariableAccessData* variableAccessData = node.variableAccessData();
270 if (variableAccessData->isCaptured())
272 ArgumentsAliasingData& data =
273 m_argumentsAliasing.find(variableAccessData)->second;
274 data.mergeNonArgumentsAssignment();
275 data.mergeCallContext(node.codeOrigin.inlineCallFrame);
280 if (!node.prediction()
281 || !m_graph[node.child1()].prediction()
282 || !m_graph[node.child2()].prediction()) {
283 observeBadArgumentsUses(node);
287 if (!isActionableArraySpeculation(m_graph[node.child1()].prediction())
288 || !m_graph[node.child2()].shouldSpeculateInteger()) {
289 observeBadArgumentsUses(node);
293 if (m_graph[node.child1()].shouldSpeculateArguments()) {
294 // If arguments is used as an index, then it's an escaping use.
295 // That's so awful and pretty much impossible since it would
296 // imply that the arguments were predicted integer, but it's
297 // good to be defensive and thorough.
298 observeBadArgumentsUse(node.child2());
299 observeProperArgumentsUse(node, node.child1());
303 observeBadArgumentsUses(node);
307 case GetArgumentsLength: {
308 observeProperArgumentsUse(node, node.child1());
313 // We don't care about phantom uses, since phantom uses are all about
314 // just keeping things alive for OSR exit. If something - like the
315 // CreateArguments - is just being kept alive, then this transformation
316 // will not break this, since the Phantom will now just keep alive a
317 // PhantomArguments and OSR exit will still do the right things.
321 observeBadArgumentsUses(node);
327 // Now we know which variables are aliased to arguments. But if any of them are
328 // found to have escaped, or were otherwise invalidated, then we need to mark
329 // the arguments as requiring creation. This is a property of SetLocals to
330 // variables that are neither the correct arguments register nor are marked as
331 // being arguments-aliased.
332 for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
333 BasicBlock* block = m_graph.m_blocks[blockIndex].get();
336 for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
337 NodeIndex nodeIndex = block->at(indexInBlock);
338 Node& node = m_graph[nodeIndex];
339 if (!node.shouldGenerate())
341 if (node.op() != SetLocal)
343 Node& source = m_graph[node.child1()];
344 if (source.op() != CreateArguments)
346 VariableAccessData* variableAccessData = node.variableAccessData();
347 if (variableAccessData->isCaptured()) {
348 // The captured case would have already been taken care of in the
353 ArgumentsAliasingData& data =
354 m_argumentsAliasing.find(variableAccessData)->second;
358 m_createsArguments.add(source.codeOrigin.inlineCallFrame);
362 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
363 dataLog("Arguments aliasing states:\n");
364 for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) {
365 VariableAccessData* variableAccessData = &m_graph.m_variableAccessData[i];
366 if (!variableAccessData->isRoot())
368 dataLog(" r%d(%s): ", variableAccessData->local(), m_graph.nameOfVariableAccessData(variableAccessData));
369 if (variableAccessData->isCaptured())
372 ArgumentsAliasingData& data =
373 m_argumentsAliasing.find(variableAccessData)->second;
375 if (data.callContextIsValid()) {
378 dataLog("Have Call Context: %p", data.callContext);
380 if (!m_createsArguments.contains(data.callContext))
381 dataLog(" (Does Not Create Arguments)");
383 if (data.argumentsAssignmentIsValid()) {
386 dataLog("Arguments Assignment Is Valid");
392 dataLog("Does Not Escape");
397 if (data.isValid()) {
398 if (m_createsArguments.contains(data.callContext))
401 dataLog("INVALID (due to argument creation)");
403 dataLog("INVALID (due to bad variable use)");
409 InsertionSet<NodeIndex> insertionSet;
411 for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
412 BasicBlock* block = m_graph.m_blocks[blockIndex].get();
415 for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
416 NodeIndex nodeIndex = block->at(indexInBlock);
417 Node& node = m_graph[nodeIndex];
418 if (!node.shouldGenerate())
423 Node& source = m_graph[node.child1()];
424 if (source.op() != CreateArguments)
427 if (m_createsArguments.contains(source.codeOrigin.inlineCallFrame))
430 VariableAccessData* variableAccessData = node.variableAccessData();
432 if (variableAccessData->isCaptured()) {
433 ASSERT(m_graph.argumentsRegisterFor(node.codeOrigin) == variableAccessData->local()
434 || unmodifiedArgumentsRegister(m_graph.argumentsRegisterFor(node.codeOrigin)) == variableAccessData->local());
435 // The child of this store should really be the empty value.
436 Node emptyJSValue(JSConstant, node.codeOrigin, OpInfo(codeBlock()->addOrFindConstant(JSValue())));
438 NodeIndex emptyJSValueIndex = m_graph.size();
439 m_graph.deref(node.child1());
440 node.children.child1() = Edge(emptyJSValueIndex);
441 m_graph.append(emptyJSValue);
442 insertionSet.append(indexInBlock, emptyJSValueIndex);
447 // If this is a store into a VariableAccessData* that is marked as
448 // arguments aliasing for an InlineCallFrame* that does not create
449 // arguments, then flag the VariableAccessData as being an
450 // arguments-aliased. This'll let the OSR exit machinery do the right
451 // things. Note also that the SetLocal should become dead as soon as
452 // we replace all uses of this variable with GetMyArgumentsLength and
453 // GetMyArgumentByVal.
454 ASSERT(m_argumentsAliasing.find(variableAccessData)->second.isValid());
455 changed |= variableAccessData->mergeIsArgumentsAlias(true);
460 // It's highly likely that we will have a Phantom referencing either
461 // CreateArguments, or a local op for the arguments register, or a
462 // local op for an arguments-aliased variable. In any of those cases,
463 // we should remove the phantom reference, since:
464 // 1) Phantoms only exist to aid OSR exit. But arguments simplification
465 // has its own OSR exit story, which is to inform OSR exit to reify
466 // the arguments as necessary.
467 // 2) The Phantom may keep the CreateArguments node alive, which is
468 // precisely what we don't want.
469 for (unsigned i = 0; i < AdjacencyList::Size; ++i)
470 removeArgumentsReferencingPhantomChild(node, i);
475 if (!node.prediction()
476 || !m_graph[node.child1()].prediction()
477 || !m_graph[node.child2()].prediction())
480 if (!isActionableArraySpeculation(m_graph[node.child1()].prediction())
481 || !m_graph[node.child2()].shouldSpeculateInteger())
484 if (m_graph[node.child1()].shouldSpeculateArguments()) {
485 // This can be simplified to GetMyArgumentByVal if we know that
486 // it satisfies either condition (1) or (2):
487 // 1) Its first child is a valid ArgumentsAliasingData and the
488 // InlineCallFrame* is not marked as creating arguments.
489 // 2) Its first child is CreateArguments and its InlineCallFrame*
490 // is not marked as creating arguments.
492 if (!isOKToOptimize(m_graph[node.child1()]))
495 m_graph.deref(node.child1());
496 node.children.child1() = node.children.child2();
497 node.children.child2() = Edge();
498 node.setOpAndDefaultFlags(GetMyArgumentByVal);
500 --indexInBlock; // Force reconsideration of this op now that it's a GetMyArgumentByVal.
506 case GetArgumentsLength: {
507 if (!isOKToOptimize(m_graph[node.child1()]))
510 m_graph.deref(node.child1());
511 node.children.child1() = Edge();
512 node.setOpAndDefaultFlags(GetMyArgumentsLength);
514 --indexInBlock; // Force reconsideration of this op noew that it's a GetMyArgumentsLength.
518 case GetMyArgumentsLength:
519 case GetMyArgumentsLengthSafe: {
520 if (m_createsArguments.contains(node.codeOrigin.inlineCallFrame)) {
521 ASSERT(node.op() == GetMyArgumentsLengthSafe);
524 if (node.op() == GetMyArgumentsLengthSafe) {
525 node.setOp(GetMyArgumentsLength);
529 CodeOrigin codeOrigin = node.codeOrigin;
530 if (!codeOrigin.inlineCallFrame)
533 // We know exactly what this will return. But only after we have checked
534 // that nobody has escaped our arguments.
535 Node check(CheckArgumentsNotCreated, codeOrigin);
537 NodeIndex checkIndex = m_graph.size();
538 m_graph.append(check);
539 insertionSet.append(indexInBlock, checkIndex);
541 m_graph.convertToConstant(
542 nodeIndex, jsNumber(codeOrigin.inlineCallFrame->arguments.size() - 1));
547 case GetMyArgumentByVal:
548 case GetMyArgumentByValSafe: {
549 if (m_createsArguments.contains(node.codeOrigin.inlineCallFrame)) {
550 ASSERT(node.op() == GetMyArgumentByValSafe);
553 if (node.op() == GetMyArgumentByValSafe) {
554 node.setOp(GetMyArgumentByVal);
557 if (!node.codeOrigin.inlineCallFrame)
559 if (!m_graph[node.child1()].hasConstant())
561 JSValue value = m_graph[node.child1()].valueOfJSConstant(codeBlock());
562 if (!value.isInt32())
564 int32_t index = value.asInt32();
566 || static_cast<size_t>(index + 1) >=
567 node.codeOrigin.inlineCallFrame->arguments.size())
570 // We know which argument this is accessing. But only after we have checked
571 // that nobody has escaped our arguments. We also need to ensure that the
572 // index is kept alive. That's somewhat pointless since it's a constant, but
573 // it's important because this is one of those invariants that we like to
574 // have in the DFG. Note finally that we use the GetLocalUnlinked opcode
575 // here, since this is being done _after_ the prediction propagation phase
576 // has run - therefore it makes little sense to link the GetLocal operation
577 // into the VariableAccessData and Phi graphs.
579 Node check(CheckArgumentsNotCreated, node.codeOrigin);
582 Node phantom(Phantom, node.codeOrigin);
584 phantom.children = node.children;
586 node.convertToGetLocalUnlinked(
587 static_cast<VirtualRegister>(
588 node.codeOrigin.inlineCallFrame->stackOffset +
589 argumentToOperand(index + 1)));
591 NodeIndex checkNodeIndex = m_graph.size();
592 m_graph.append(check);
593 insertionSet.append(indexInBlock, checkNodeIndex);
594 NodeIndex phantomNodeIndex = m_graph.size();
595 m_graph.append(phantom);
596 insertionSet.append(indexInBlock, phantomNodeIndex);
602 case TearOffArguments: {
603 if (m_createsArguments.contains(node.codeOrigin.inlineCallFrame))
606 node.setOpAndDefaultFlags(Nop);
607 m_graph.clearAndDerefChild1(node);
616 insertionSet.execute(*block);
619 for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
620 BasicBlock* block = m_graph.m_blocks[blockIndex].get();
623 for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
624 NodeIndex nodeIndex = block->at(indexInBlock);
625 Node& node = m_graph[nodeIndex];
626 if (node.op() != CreateArguments)
628 // If this is a CreateArguments for an InlineCallFrame* that does
629 // not create arguments, then replace it with a PhantomArguments.
630 // PhantomArguments is a non-executing node that just indicates
631 // that the node should be reified as an arguments object on OSR
633 if (m_createsArguments.contains(node.codeOrigin.inlineCallFrame))
635 if (node.shouldGenerate()) {
636 Node phantom(Phantom, node.codeOrigin);
637 phantom.children = node.children;
639 NodeIndex phantomNodeIndex = m_graph.size();
640 m_graph.append(phantom);
641 insertionSet.append(indexInBlock, phantomNodeIndex);
643 node.setOpAndDefaultFlags(PhantomArguments);
644 node.children.reset();
647 insertionSet.execute(*block);
651 m_graph.collectGarbage();
653 // Verify that PhantomArguments nodes are not shouldGenerate().
655 for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
656 BasicBlock* block = m_graph.m_blocks[blockIndex].get();
659 for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
660 NodeIndex nodeIndex = block->at(indexInBlock);
661 Node& node = m_graph[nodeIndex];
662 if (node.op() != PhantomArguments)
664 ASSERT(!node.shouldGenerate());
674 HashSet<InlineCallFrame*,
675 DefaultHash<InlineCallFrame*>::Hash,
676 NullableHashTraits<InlineCallFrame*> > m_createsArguments;
677 HashMap<VariableAccessData*, ArgumentsAliasingData,
678 DefaultHash<VariableAccessData*>::Hash,
679 NullableHashTraits<VariableAccessData*> > m_argumentsAliasing;
681 void observeBadArgumentsUse(Edge edge)
686 Node& child = m_graph[edge];
687 switch (child.op()) {
688 case CreateArguments: {
689 m_createsArguments.add(child.codeOrigin.inlineCallFrame);
694 int argumentsRegister = m_graph.uncheckedArgumentsRegisterFor(child.codeOrigin);
695 if (argumentsRegister != InvalidVirtualRegister
696 && (child.local() == argumentsRegister
697 || child.local() == unmodifiedArgumentsRegister(argumentsRegister))) {
698 m_createsArguments.add(child.codeOrigin.inlineCallFrame);
702 VariableAccessData* variableAccessData = child.variableAccessData();
703 if (variableAccessData->isCaptured())
706 ArgumentsAliasingData& data = m_argumentsAliasing.find(variableAccessData)->second;
716 void observeBadArgumentsUses(Node& node)
718 for (unsigned i = m_graph.numChildren(node); i--;)
719 observeBadArgumentsUse(m_graph.child(node, i));
722 void observeProperArgumentsUse(Node& node, Edge edge)
724 Node& child = m_graph[edge];
725 if (child.op() != GetLocal) {
726 // When can this happen? At least two cases that I can think
729 // 1) Aliased use of arguments in the same basic block,
732 // var a = arguments;
733 // var x = arguments[i];
735 // 2) If we're accessing arguments we got from the heap!
737 if (child.op() == CreateArguments
738 && node.codeOrigin.inlineCallFrame
739 != child.codeOrigin.inlineCallFrame)
740 m_createsArguments.add(child.codeOrigin.inlineCallFrame);
745 VariableAccessData* variableAccessData = child.variableAccessData();
746 if (variableAccessData->isCaptured()) {
747 if (child.local() == m_graph.uncheckedArgumentsRegisterFor(child.codeOrigin)
748 && node.codeOrigin.inlineCallFrame != child.codeOrigin.inlineCallFrame)
749 m_createsArguments.add(child.codeOrigin.inlineCallFrame);
753 ArgumentsAliasingData& data = m_argumentsAliasing.find(variableAccessData)->second;
754 data.mergeCallContext(node.codeOrigin.inlineCallFrame);
757 bool isOKToOptimize(Node& source)
759 if (m_createsArguments.contains(source.codeOrigin.inlineCallFrame))
762 switch (source.op()) {
764 VariableAccessData* variableAccessData = source.variableAccessData();
765 if (variableAccessData->isCaptured()) {
766 int argumentsRegister = m_graph.uncheckedArgumentsRegisterFor(source.codeOrigin);
767 if (argumentsRegister == InvalidVirtualRegister)
769 if (argumentsRegister == variableAccessData->local())
771 if (unmodifiedArgumentsRegister(argumentsRegister) == variableAccessData->local())
775 ArgumentsAliasingData& data =
776 m_argumentsAliasing.find(variableAccessData)->second;
783 case CreateArguments: {
794 void removeArgumentsReferencingPhantomChild(Node& node, unsigned edgeIndex)
796 Edge edge = node.children.child(edgeIndex);
800 Node& child = m_graph[edge];
801 switch (child.op()) {
802 case Phi: // Arises if we had CSE on a GetLocal of the arguments register.
803 case GetLocal: // Arises if we had CSE on an arguments access to a variable aliased to the arguments.
804 case SetLocal: { // Arises if we had CSE on a GetLocal of the arguments register.
805 VariableAccessData* variableAccessData = child.variableAccessData();
806 bool isDeadArgumentsRegister =
807 variableAccessData->local() ==
808 m_graph.uncheckedArgumentsRegisterFor(child.codeOrigin)
809 && !m_createsArguments.contains(child.codeOrigin.inlineCallFrame);
810 bool isAliasedArgumentsRegister =
811 !variableAccessData->isCaptured()
812 && m_argumentsAliasing.find(variableAccessData)->second.isValid()
813 && !m_createsArguments.contains(child.codeOrigin.inlineCallFrame);
814 if (!isDeadArgumentsRegister && !isAliasedArgumentsRegister)
817 node.children.removeEdgeFromBag(edgeIndex);
821 case CreateArguments: { // Arises if we CSE two GetLocals to the arguments register and then CSE the second use of the GetLocal to the first.
822 if (m_createsArguments.contains(child.codeOrigin.inlineCallFrame))
825 node.children.removeEdgeFromBag(edgeIndex);
835 bool performArgumentsSimplification(Graph& graph)
837 return runPhase<ArgumentsSimplificationPhase>(graph);
840 } } // namespace JSC::DFG
842 #endif // ENABLE(DFG_JIT)