1/*
2 * Copyright (C) 2015 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#include "config.h"
27#include "DFGArgumentsUtilities.h"
28
29#if ENABLE(DFG_JIT)
30
31#include "JSCInlines.h"
32
33namespace JSC { namespace DFG {
34
35bool argumentsInvolveStackSlot(InlineCallFrame* inlineCallFrame, VirtualRegister reg)
36{
37 if (!inlineCallFrame)
38 return (reg.isArgument() && reg.toArgument()) || reg.isHeader();
39
40 if (inlineCallFrame->isClosureCall
41 && reg == VirtualRegister(inlineCallFrame->stackOffset + CallFrameSlot::callee))
42 return true;
43
44 if (inlineCallFrame->isVarargs()
45 && reg == VirtualRegister(inlineCallFrame->stackOffset + CallFrameSlot::argumentCount))
46 return true;
47
48 // We do not include fixups here since it is not related to |arguments|, rest parameters, and varargs.
49 unsigned numArguments = inlineCallFrame->argumentCountIncludingThis - 1;
50 VirtualRegister argumentStart =
51 VirtualRegister(inlineCallFrame->stackOffset) + CallFrame::argumentOffset(0);
52 return reg >= argumentStart && reg < argumentStart + numArguments;
53}
54
55bool argumentsInvolveStackSlot(Node* candidate, VirtualRegister reg)
56{
57 return argumentsInvolveStackSlot(candidate->origin.semantic.inlineCallFrame(), reg);
58}
59
60Node* emitCodeToGetArgumentsArrayLength(
61 InsertionSet& insertionSet, Node* arguments, unsigned nodeIndex, NodeOrigin origin)
62{
63 Graph& graph = insertionSet.graph();
64
65 DFG_ASSERT(
66 graph, arguments,
67 arguments->op() == CreateDirectArguments || arguments->op() == CreateScopedArguments
68 || arguments->op() == CreateClonedArguments || arguments->op() == CreateRest
69 || arguments->op() == NewArrayBuffer
70 || arguments->op() == PhantomDirectArguments || arguments->op() == PhantomClonedArguments
71 || arguments->op() == PhantomCreateRest || arguments->op() == PhantomNewArrayBuffer
72 || arguments->op() == PhantomNewArrayWithSpread,
73 arguments->op());
74
75 if (arguments->op() == PhantomNewArrayWithSpread) {
76 unsigned numberOfNonSpreadArguments = 0;
77 BitVector* bitVector = arguments->bitVector();
78 Node* currentSum = nullptr;
79 for (unsigned i = 0; i < arguments->numChildren(); i++) {
80 if (bitVector->get(i)) {
81 Node* child = graph.varArgChild(arguments, i).node();
82 DFG_ASSERT(graph, child, child->op() == PhantomSpread, child->op());
83 DFG_ASSERT(graph, child->child1().node(),
84 child->child1()->op() == PhantomCreateRest || child->child1()->op() == PhantomNewArrayBuffer,
85 child->child1()->op());
86 Node* lengthOfChild = emitCodeToGetArgumentsArrayLength(insertionSet, child->child1().node(), nodeIndex, origin);
87 if (currentSum)
88 currentSum = insertionSet.insertNode(nodeIndex, SpecInt32Only, ArithAdd, origin, OpInfo(Arith::CheckOverflow), Edge(currentSum, Int32Use), Edge(lengthOfChild, Int32Use));
89 else
90 currentSum = lengthOfChild;
91 } else
92 numberOfNonSpreadArguments++;
93 }
94 if (currentSum) {
95 if (!numberOfNonSpreadArguments)
96 return currentSum;
97 return insertionSet.insertNode(
98 nodeIndex, SpecInt32Only, ArithAdd, origin, OpInfo(Arith::CheckOverflow), Edge(currentSum, Int32Use),
99 insertionSet.insertConstantForUse(nodeIndex, origin, jsNumber(numberOfNonSpreadArguments), Int32Use));
100 }
101 return insertionSet.insertConstant(nodeIndex, origin, jsNumber(numberOfNonSpreadArguments));
102 }
103
104 if (arguments->op() == NewArrayBuffer || arguments->op() == PhantomNewArrayBuffer) {
105 return insertionSet.insertConstant(
106 nodeIndex, origin, jsNumber(arguments->castOperand<JSImmutableButterfly*>()->length()));
107 }
108
109 InlineCallFrame* inlineCallFrame = arguments->origin.semantic.inlineCallFrame();
110
111 unsigned numberOfArgumentsToSkip = 0;
112 if (arguments->op() == CreateRest || arguments->op() == PhantomCreateRest)
113 numberOfArgumentsToSkip = arguments->numberOfArgumentsToSkip();
114
115 if (inlineCallFrame && !inlineCallFrame->isVarargs()) {
116 unsigned argumentsSize = inlineCallFrame->argumentCountIncludingThis - 1;
117 if (argumentsSize >= numberOfArgumentsToSkip)
118 argumentsSize -= numberOfArgumentsToSkip;
119 else
120 argumentsSize = 0;
121 return insertionSet.insertConstant(
122 nodeIndex, origin, jsNumber(argumentsSize));
123 }
124
125 Node* argumentCount = insertionSet.insertNode(nodeIndex,
126 SpecInt32Only, GetArgumentCountIncludingThis, origin, OpInfo(inlineCallFrame));
127
128 Node* result = insertionSet.insertNode(
129 nodeIndex, SpecInt32Only, ArithSub, origin, OpInfo(Arith::Unchecked),
130 Edge(argumentCount, Int32Use),
131 insertionSet.insertConstantForUse(
132 nodeIndex, origin, jsNumber(1 + numberOfArgumentsToSkip), Int32Use));
133
134 if (numberOfArgumentsToSkip) {
135 // The above subtraction may produce a negative number if this number is non-zero. We correct that here.
136 result = insertionSet.insertNode(
137 nodeIndex, SpecInt32Only, ArithMax, origin,
138 Edge(result, Int32Use),
139 insertionSet.insertConstantForUse(nodeIndex, origin, jsNumber(0), Int32Use));
140 result->setResult(NodeResultInt32);
141 }
142
143 return result;
144}
145
146} } // namespace JSC::DFG
147
148#endif // ENABLE(DFG_JIT)
149
150