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 {
44
struct ArgumentsAliasingData {
45
InlineCallFrame* callContext;
47
bool multipleCallContexts;
49
bool assignedFromArguments;
50
bool assignedFromManyThings;
54
ArgumentsAliasingData()
56
, callContextSet(false)
57
, multipleCallContexts(false)
58
, assignedFromArguments(false)
59
, assignedFromManyThings(false)
64
void mergeCallContext(InlineCallFrame* newCallContext)
66
if (multipleCallContexts)
69
if (!callContextSet) {
70
callContext = newCallContext;
71
callContextSet = true;
75
if (callContext == newCallContext)
78
multipleCallContexts = true;
81
bool callContextIsValid()
83
return callContextSet && !multipleCallContexts;
86
void mergeArgumentsAssignment()
88
assignedFromArguments = true;
91
void mergeNonArgumentsAssignment()
93
assignedFromManyThings = true;
96
bool argumentsAssignmentIsValid()
98
return assignedFromArguments && !assignedFromManyThings;
103
return callContextIsValid() && argumentsAssignmentIsValid() && !escapes;
107
} // end anonymous namespace
109
class ArgumentsSimplificationPhase : public Phase {
111
ArgumentsSimplificationPhase(Graph& graph)
112
: Phase(graph, "arguments simplification")
118
if (!m_graph.m_hasArguments)
121
bool changed = false;
123
// Record which arguments are known to escape no matter what.
124
for (unsigned i = codeBlock()->inlineCallFrames().size(); i--;) {
125
InlineCallFrame* inlineCallFrame = &codeBlock()->inlineCallFrames()[i];
126
if (m_graph.m_executablesWhoseArgumentsEscaped.contains(
127
m_graph.executableFor(inlineCallFrame)))
128
m_createsArguments.add(inlineCallFrame);
131
// Create data for variable access datas that we will want to analyze.
132
for (unsigned i = m_graph.m_variableAccessData.size(); i--;) {
133
VariableAccessData* variableAccessData = &m_graph.m_variableAccessData[i];
134
if (!variableAccessData->isRoot())
136
if (variableAccessData->isCaptured())
138
m_argumentsAliasing.add(variableAccessData, ArgumentsAliasingData());
141
// Figure out which variables alias the arguments and nothing else, and are
142
// used only for GetByVal and GetArrayLength accesses. At the same time,
143
// identify uses of CreateArguments that are not consistent with the arguments
144
// being aliased only to variables that satisfy these constraints.
145
for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
146
BasicBlock* block = m_graph.m_blocks[blockIndex].get();
149
for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
150
NodeIndex nodeIndex = block->at(indexInBlock);
151
Node& node = m_graph[nodeIndex];
152
if (!node.shouldGenerate())
155
case CreateArguments: {
156
// Ignore this op. If we see a lone CreateArguments then we want to
157
// completely ignore it because:
158
// 1) The default would be to see that the child is a GetLocal on the
159
// arguments register and conclude that we have an arguments escape.
160
// 2) The fact that a CreateArguments exists does not mean that it
161
// will continue to exist after we're done with this phase. As far
162
// as this phase is concerned, a CreateArguments only "exists" if it
163
// is used in a manner that necessitates its existance.
167
case TearOffArguments: {
168
// Ignore arguments tear off, because it's only relevant if we actually
169
// need to create the arguments.
174
Node& source = m_graph[node.child1()];
175
VariableAccessData* variableAccessData = node.variableAccessData();
176
int argumentsRegister =
177
m_graph.uncheckedArgumentsRegisterFor(node.codeOrigin);
178
if (source.op() != CreateArguments && source.op() != PhantomArguments) {
179
// Make sure that the source of the SetLocal knows that if it's
180
// a variable that we think is aliased to the arguments, then it
181
// may escape at this point. In future, we could track transitive
182
// aliasing. But not yet.
183
observeBadArgumentsUse(node.child1());
185
// If this is an assignment to the arguments register, then
186
// pretend as if the arguments were created. We don't want to
187
// optimize code that explicitly assigns to the arguments,
188
// because that seems too ugly.
190
// But, before getting rid of CreateArguments, we will have
191
// an assignment to the arguments registers with JSValue().
192
// That's because CSE will refuse to get rid of the
193
// init_lazy_reg since it treats CreateArguments as reading
194
// local variables. That could be fixed, but it's easier to
195
// work around this here.
196
if (source.op() == JSConstant
197
&& !source.valueOfJSConstant(codeBlock()))
200
if (argumentsRegister != InvalidVirtualRegister
201
&& (variableAccessData->local() == argumentsRegister
202
|| variableAccessData->local() == unmodifiedArgumentsRegister(argumentsRegister))) {
203
m_createsArguments.add(node.codeOrigin.inlineCallFrame);
207
if (variableAccessData->isCaptured())
210
// Make sure that if it's a variable that we think is aliased to
211
// the arguments, that we know that it might actually not be.
212
ArgumentsAliasingData& data =
213
m_argumentsAliasing.find(variableAccessData)->value;
214
data.mergeNonArgumentsAssignment();
215
data.mergeCallContext(node.codeOrigin.inlineCallFrame);
218
if (argumentsRegister != InvalidVirtualRegister
219
&& (variableAccessData->local() == argumentsRegister
220
|| variableAccessData->local() == unmodifiedArgumentsRegister(argumentsRegister))) {
221
if (node.codeOrigin.inlineCallFrame == source.codeOrigin.inlineCallFrame)
223
m_createsArguments.add(source.codeOrigin.inlineCallFrame);
226
if (variableAccessData->isCaptured()) {
227
m_createsArguments.add(source.codeOrigin.inlineCallFrame);
230
ArgumentsAliasingData& data =
231
m_argumentsAliasing.find(variableAccessData)->value;
232
data.mergeArgumentsAssignment();
233
// This ensures that the variable's uses are in the same context as
234
// the arguments it is aliasing.
235
data.mergeCallContext(node.codeOrigin.inlineCallFrame);
236
data.mergeCallContext(source.codeOrigin.inlineCallFrame);
242
VariableAccessData* variableAccessData = node.variableAccessData();
243
if (variableAccessData->isCaptured())
245
ArgumentsAliasingData& data =
246
m_argumentsAliasing.find(variableAccessData)->value;
247
data.mergeCallContext(node.codeOrigin.inlineCallFrame);
252
VariableAccessData* variableAccessData = node.variableAccessData();
253
if (variableAccessData->isCaptured())
255
ArgumentsAliasingData& data =
256
m_argumentsAliasing.find(variableAccessData)->value;
257
data.mergeCallContext(node.codeOrigin.inlineCallFrame);
259
// If a variable is used in a flush then by definition it escapes.
265
VariableAccessData* variableAccessData = node.variableAccessData();
266
if (variableAccessData->isCaptured())
268
ArgumentsAliasingData& data =
269
m_argumentsAliasing.find(variableAccessData)->value;
270
data.mergeNonArgumentsAssignment();
271
data.mergeCallContext(node.codeOrigin.inlineCallFrame);
276
if (node.arrayMode().type() != Array::Arguments) {
277
observeBadArgumentsUses(node);
281
// That's so awful and pretty much impossible since it would
282
// imply that the arguments were predicted integer, but it's
283
// good to be defensive and thorough.
284
observeBadArgumentsUse(node.child2());
285
observeProperArgumentsUse(node, node.child1());
289
case GetArrayLength: {
290
if (node.arrayMode().type() != Array::Arguments) {
291
observeBadArgumentsUses(node);
295
observeProperArgumentsUse(node, node.child1());
300
// We don't care about phantom uses, since phantom uses are all about
301
// just keeping things alive for OSR exit. If something - like the
302
// CreateArguments - is just being kept alive, then this transformation
303
// will not break this, since the Phantom will now just keep alive a
304
// PhantomArguments and OSR exit will still do the right things.
308
case ForwardCheckStructure:
309
case StructureTransitionWatchpoint:
310
case ForwardStructureTransitionWatchpoint:
312
// We don't care about these because if we get uses of the relevant
313
// variable then we can safely get rid of these, too. This of course
314
// relies on there not being any information transferred by the CFA
315
// from a CheckStructure on one variable to the information about the
316
// structures of another variable.
320
observeBadArgumentsUses(node);
326
// Now we know which variables are aliased to arguments. But if any of them are
327
// found to have escaped, or were otherwise invalidated, then we need to mark
328
// the arguments as requiring creation. This is a property of SetLocals to
329
// variables that are neither the correct arguments register nor are marked as
330
// being arguments-aliased.
331
for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
332
BasicBlock* block = m_graph.m_blocks[blockIndex].get();
335
for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
336
NodeIndex nodeIndex = block->at(indexInBlock);
337
Node& node = m_graph[nodeIndex];
338
if (!node.shouldGenerate())
340
if (node.op() != SetLocal)
342
Node& source = m_graph[node.child1()];
343
if (source.op() != CreateArguments)
345
VariableAccessData* variableAccessData = node.variableAccessData();
346
if (variableAccessData->isCaptured()) {
347
// The captured case would have already been taken care of in the
352
ArgumentsAliasingData& data =
353
m_argumentsAliasing.find(variableAccessData)->value;
357
m_createsArguments.add(source.codeOrigin.inlineCallFrame);
361
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
362
dataLogF("Arguments aliasing states:\n");
363
for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) {
364
VariableAccessData* variableAccessData = &m_graph.m_variableAccessData[i];
365
if (!variableAccessData->isRoot())
367
dataLogF(" r%d(%s): ", variableAccessData->local(), m_graph.nameOfVariableAccessData(variableAccessData));
368
if (variableAccessData->isCaptured())
369
dataLogF("Captured");
371
ArgumentsAliasingData& data =
372
m_argumentsAliasing.find(variableAccessData)->value;
374
if (data.callContextIsValid()) {
377
dataLogF("Have Call Context: %p", data.callContext);
379
if (!m_createsArguments.contains(data.callContext))
380
dataLogF(" (Does Not Create Arguments)");
382
if (data.argumentsAssignmentIsValid()) {
385
dataLogF("Arguments Assignment Is Valid");
391
dataLogF("Does Not Escape");
396
if (data.isValid()) {
397
if (m_createsArguments.contains(data.callContext))
400
dataLogF("INVALID (due to argument creation)");
402
dataLogF("INVALID (due to bad variable use)");
408
InsertionSet<NodeIndex> insertionSet;
410
for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
411
BasicBlock* block = m_graph.m_blocks[blockIndex].get();
414
for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
415
NodeIndex nodeIndex = block->at(indexInBlock);
416
Node& node = m_graph[nodeIndex];
417
if (!node.shouldGenerate())
422
Node& source = m_graph[node.child1()];
423
if (source.op() != CreateArguments)
426
if (m_createsArguments.contains(source.codeOrigin.inlineCallFrame))
429
VariableAccessData* variableAccessData = node.variableAccessData();
431
if (m_graph.argumentsRegisterFor(node.codeOrigin) == variableAccessData->local()
432
|| unmodifiedArgumentsRegister(m_graph.argumentsRegisterFor(node.codeOrigin)) == variableAccessData->local())
435
ASSERT(!variableAccessData->isCaptured());
437
// If this is a store into a VariableAccessData* that is marked as
438
// arguments aliasing for an InlineCallFrame* that does not create
439
// arguments, then flag the VariableAccessData as being an
440
// arguments-aliased. This'll let the OSR exit machinery do the right
441
// things. Note also that the SetLocal should become dead as soon as
442
// we replace all uses of this variable with GetMyArgumentsLength and
443
// GetMyArgumentByVal.
444
ASSERT(m_argumentsAliasing.find(variableAccessData)->value.isValid());
445
changed |= variableAccessData->mergeIsArgumentsAlias(true);
450
// It's highly likely that we will have a Phantom referencing either
451
// CreateArguments, or a local op for the arguments register, or a
452
// local op for an arguments-aliased variable. In any of those cases,
453
// we should remove the phantom reference, since:
454
// 1) Phantoms only exist to aid OSR exit. But arguments simplification
455
// has its own OSR exit story, which is to inform OSR exit to reify
456
// the arguments as necessary.
457
// 2) The Phantom may keep the CreateArguments node alive, which is
458
// precisely what we don't want.
459
for (unsigned i = 0; i < AdjacencyList::Size; ++i)
460
removeArgumentsReferencingPhantomChild(node, i);
465
case ForwardCheckStructure:
466
case StructureTransitionWatchpoint:
467
case ForwardStructureTransitionWatchpoint:
469
// We can just get rid of this node, if it references a phantom argument.
470
if (!isOKToOptimize(m_graph[node.child1()]))
472
m_graph.deref(node.child1());
473
node.setOpAndDefaultFlags(Phantom);
474
node.children.setChild1(Edge());
479
if (node.arrayMode().type() != Array::Arguments)
482
// This can be simplified to GetMyArgumentByVal if we know that
483
// it satisfies either condition (1) or (2):
484
// 1) Its first child is a valid ArgumentsAliasingData and the
485
// InlineCallFrame* is not marked as creating arguments.
486
// 2) Its first child is CreateArguments and its InlineCallFrame*
487
// is not marked as creating arguments.
489
if (!isOKToOptimize(m_graph[node.child1()]))
492
m_graph.deref(node.child1());
493
node.children.child1() = node.children.child2();
494
node.children.child2() = Edge();
495
node.setOpAndDefaultFlags(GetMyArgumentByVal);
497
--indexInBlock; // Force reconsideration of this op now that it's a GetMyArgumentByVal.
501
case GetArrayLength: {
502
if (node.arrayMode().type() != Array::Arguments)
505
if (!isOKToOptimize(m_graph[node.child1()]))
508
m_graph.deref(node.child1());
509
node.children.child1() = Edge();
510
node.setOpAndDefaultFlags(GetMyArgumentsLength);
512
--indexInBlock; // Force reconsideration of this op noew that it's a GetMyArgumentsLength.
516
case GetMyArgumentsLength:
517
case GetMyArgumentsLengthSafe: {
518
if (m_createsArguments.contains(node.codeOrigin.inlineCallFrame)) {
519
ASSERT(node.op() == GetMyArgumentsLengthSafe);
522
if (node.op() == GetMyArgumentsLengthSafe) {
523
node.setOp(GetMyArgumentsLength);
527
CodeOrigin codeOrigin = node.codeOrigin;
528
if (!codeOrigin.inlineCallFrame)
531
// We know exactly what this will return. But only after we have checked
532
// that nobody has escaped our arguments.
533
Node check(CheckArgumentsNotCreated, codeOrigin);
535
NodeIndex checkIndex = m_graph.size();
536
m_graph.append(check);
537
insertionSet.append(indexInBlock, checkIndex);
539
m_graph.convertToConstant(
540
nodeIndex, jsNumber(codeOrigin.inlineCallFrame->arguments.size() - 1));
545
case GetMyArgumentByVal:
546
case GetMyArgumentByValSafe: {
547
if (m_createsArguments.contains(node.codeOrigin.inlineCallFrame)) {
548
ASSERT(node.op() == GetMyArgumentByValSafe);
551
if (node.op() == GetMyArgumentByValSafe) {
552
node.setOp(GetMyArgumentByVal);
555
if (!node.codeOrigin.inlineCallFrame)
557
if (!m_graph[node.child1()].hasConstant())
559
JSValue value = m_graph[node.child1()].valueOfJSConstant(codeBlock());
560
if (!value.isInt32())
562
int32_t index = value.asInt32();
564
|| static_cast<size_t>(index + 1) >=
565
node.codeOrigin.inlineCallFrame->arguments.size())
568
// We know which argument this is accessing. But only after we have checked
569
// that nobody has escaped our arguments. We also need to ensure that the
570
// index is kept alive. That's somewhat pointless since it's a constant, but
571
// it's important because this is one of those invariants that we like to
572
// have in the DFG. Note finally that we use the GetLocalUnlinked opcode
573
// here, since this is being done _after_ the prediction propagation phase
574
// has run - therefore it makes little sense to link the GetLocal operation
575
// into the VariableAccessData and Phi graphs.
577
Node check(CheckArgumentsNotCreated, node.codeOrigin);
580
Node phantom(Phantom, node.codeOrigin);
582
phantom.children = node.children;
584
node.convertToGetLocalUnlinked(
585
static_cast<VirtualRegister>(
586
node.codeOrigin.inlineCallFrame->stackOffset +
587
m_graph.baselineCodeBlockFor(node.codeOrigin)->argumentIndexAfterCapture(index)));
589
NodeIndex checkNodeIndex = m_graph.size();
590
m_graph.append(check);
591
insertionSet.append(indexInBlock, checkNodeIndex);
592
NodeIndex phantomNodeIndex = m_graph.size();
593
m_graph.append(phantom);
594
insertionSet.append(indexInBlock, phantomNodeIndex);
600
case TearOffArguments: {
601
if (m_createsArguments.contains(node.codeOrigin.inlineCallFrame))
604
node.setOpAndDefaultFlags(Nop);
605
m_graph.clearAndDerefChild1(node);
606
m_graph.clearAndDerefChild2(node);
615
insertionSet.execute(*block);
618
for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
619
BasicBlock* block = m_graph.m_blocks[blockIndex].get();
622
for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
623
NodeIndex nodeIndex = block->at(indexInBlock);
624
Node& node = m_graph[nodeIndex];
625
if (node.op() != CreateArguments)
627
// If this is a CreateArguments for an InlineCallFrame* that does
628
// not create arguments, then replace it with a PhantomArguments.
629
// PhantomArguments is a non-executing node that just indicates
630
// that the node should be reified as an arguments object on OSR
632
if (m_createsArguments.contains(node.codeOrigin.inlineCallFrame))
634
if (node.shouldGenerate()) {
635
Node phantom(Phantom, node.codeOrigin);
636
phantom.children = node.children;
638
NodeIndex phantomNodeIndex = m_graph.size();
639
m_graph.append(phantom);
640
insertionSet.append(indexInBlock, phantomNodeIndex);
642
node.setOpAndDefaultFlags(PhantomArguments);
643
node.children.reset();
646
insertionSet.execute(*block);
650
m_graph.collectGarbage();
656
HashSet<InlineCallFrame*,
657
DefaultHash<InlineCallFrame*>::Hash,
658
NullableHashTraits<InlineCallFrame*> > m_createsArguments;
659
HashMap<VariableAccessData*, ArgumentsAliasingData,
660
DefaultHash<VariableAccessData*>::Hash,
661
NullableHashTraits<VariableAccessData*> > m_argumentsAliasing;
663
void observeBadArgumentsUse(Edge edge)
668
Node& child = m_graph[edge];
669
switch (child.op()) {
670
case CreateArguments: {
671
m_createsArguments.add(child.codeOrigin.inlineCallFrame);
676
int argumentsRegister = m_graph.uncheckedArgumentsRegisterFor(child.codeOrigin);
677
if (argumentsRegister != InvalidVirtualRegister
678
&& (child.local() == argumentsRegister
679
|| child.local() == unmodifiedArgumentsRegister(argumentsRegister))) {
680
m_createsArguments.add(child.codeOrigin.inlineCallFrame);
684
VariableAccessData* variableAccessData = child.variableAccessData();
685
if (variableAccessData->isCaptured())
688
ArgumentsAliasingData& data = m_argumentsAliasing.find(variableAccessData)->value;
698
void observeBadArgumentsUses(Node& node)
700
for (unsigned i = m_graph.numChildren(node); i--;)
701
observeBadArgumentsUse(m_graph.child(node, i));
704
void observeProperArgumentsUse(Node& node, Edge edge)
706
Node& child = m_graph[edge];
707
if (child.op() != GetLocal) {
708
// When can this happen? At least two cases that I can think
711
// 1) Aliased use of arguments in the same basic block,
714
// var a = arguments;
715
// var x = arguments[i];
717
// 2) If we're accessing arguments we got from the heap!
719
if (child.op() == CreateArguments
720
&& node.codeOrigin.inlineCallFrame
721
!= child.codeOrigin.inlineCallFrame)
722
m_createsArguments.add(child.codeOrigin.inlineCallFrame);
727
VariableAccessData* variableAccessData = child.variableAccessData();
728
if (child.local() == m_graph.uncheckedArgumentsRegisterFor(child.codeOrigin)
729
&& node.codeOrigin.inlineCallFrame != child.codeOrigin.inlineCallFrame) {
730
m_createsArguments.add(child.codeOrigin.inlineCallFrame);
734
if (variableAccessData->isCaptured())
737
ArgumentsAliasingData& data = m_argumentsAliasing.find(variableAccessData)->value;
738
data.mergeCallContext(node.codeOrigin.inlineCallFrame);
741
bool isOKToOptimize(Node& source)
743
if (m_createsArguments.contains(source.codeOrigin.inlineCallFrame))
746
switch (source.op()) {
748
VariableAccessData* variableAccessData = source.variableAccessData();
749
int argumentsRegister = m_graph.uncheckedArgumentsRegisterFor(source.codeOrigin);
750
if (argumentsRegister == InvalidVirtualRegister)
752
if (argumentsRegister == variableAccessData->local())
754
if (unmodifiedArgumentsRegister(argumentsRegister) == variableAccessData->local())
756
if (variableAccessData->isCaptured())
758
ArgumentsAliasingData& data =
759
m_argumentsAliasing.find(variableAccessData)->value;
766
case CreateArguments: {
777
void removeArgumentsReferencingPhantomChild(Node& node, unsigned edgeIndex)
779
Edge edge = node.children.child(edgeIndex);
783
Node& child = m_graph[edge];
784
switch (child.op()) {
785
case Phi: // Arises if we had CSE on a GetLocal of the arguments register.
786
case GetLocal: // Arises if we had CSE on an arguments access to a variable aliased to the arguments.
787
case SetLocal: { // Arises if we had CSE on a GetLocal of the arguments register.
788
VariableAccessData* variableAccessData = child.variableAccessData();
789
bool isDeadArgumentsRegister =
790
variableAccessData->local() ==
791
m_graph.uncheckedArgumentsRegisterFor(child.codeOrigin)
792
&& !m_createsArguments.contains(child.codeOrigin.inlineCallFrame);
793
bool isAliasedArgumentsRegister =
794
!variableAccessData->isCaptured()
795
&& m_argumentsAliasing.find(variableAccessData)->value.isValid()
796
&& !m_createsArguments.contains(child.codeOrigin.inlineCallFrame);
797
if (!isDeadArgumentsRegister && !isAliasedArgumentsRegister)
800
node.children.removeEdgeFromBag(edgeIndex);
804
case CreateArguments: { // Arises if we CSE two GetLocals to the arguments register and then CSE the second use of the GetLocal to the first.
805
if (m_createsArguments.contains(child.codeOrigin.inlineCallFrame))
808
node.children.removeEdgeFromBag(edgeIndex);
818
bool performArgumentsSimplification(Graph& graph)
820
SamplingRegion samplingRegion("DFG Arguments Simplification Phase");
821
return runPhase<ArgumentsSimplificationPhase>(graph);
824
} } // namespace JSC::DFG
826
#endif // ENABLE(DFG_JIT)