| /* |
| * Copyright (C) 2015 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "DFGArgumentsUtilities.h" |
| |
| #if ENABLE(DFG_JIT) |
| |
| #include "JSCInlines.h" |
| |
| namespace JSC { namespace DFG { |
| |
| bool argumentsInvolveStackSlot(InlineCallFrame* inlineCallFrame, Operand operand) |
| { |
| if (operand.isTmp()) |
| return false; |
| |
| VirtualRegister reg = operand.virtualRegister(); |
| if (!inlineCallFrame) |
| return (reg.isArgument() && reg.toArgument()) || reg.isHeader(); |
| |
| if (inlineCallFrame->isClosureCall |
| && reg == VirtualRegister(inlineCallFrame->stackOffset + CallFrameSlot::callee)) |
| return true; |
| |
| if (inlineCallFrame->isVarargs() |
| && reg == VirtualRegister(inlineCallFrame->stackOffset + CallFrameSlot::argumentCountIncludingThis)) |
| return true; |
| |
| // We do not include fixups here since it is not related to |arguments|, rest parameters, and varargs. |
| unsigned numArguments = static_cast<unsigned>(inlineCallFrame->argumentCountIncludingThis - 1); |
| VirtualRegister argumentStart = |
| VirtualRegister(inlineCallFrame->stackOffset) + CallFrame::argumentOffset(0); |
| return reg >= argumentStart && reg < argumentStart + numArguments; |
| } |
| |
| bool argumentsInvolveStackSlot(Node* candidate, Operand operand) |
| { |
| return argumentsInvolveStackSlot(candidate->origin.semantic.inlineCallFrame(), operand); |
| } |
| |
| Node* emitCodeToGetArgumentsArrayLength( |
| InsertionSet& insertionSet, Node* arguments, unsigned nodeIndex, NodeOrigin origin, bool addThis) |
| { |
| Graph& graph = insertionSet.graph(); |
| |
| DFG_ASSERT( |
| graph, arguments, |
| arguments->op() == CreateDirectArguments || arguments->op() == CreateScopedArguments |
| || arguments->op() == CreateClonedArguments || arguments->op() == CreateRest |
| || arguments->op() == NewArrayBuffer |
| || arguments->op() == PhantomDirectArguments || arguments->op() == PhantomClonedArguments |
| || arguments->op() == PhantomCreateRest || arguments->op() == PhantomNewArrayBuffer |
| || arguments->op() == PhantomNewArrayWithSpread || arguments->op() == PhantomSpread, |
| arguments->op()); |
| |
| if (arguments->op() == PhantomSpread) |
| return emitCodeToGetArgumentsArrayLength(insertionSet, arguments->child1().node(), nodeIndex, origin, addThis); |
| |
| if (arguments->op() == PhantomNewArrayWithSpread) { |
| unsigned numberOfNonSpreadArguments = addThis; |
| BitVector* bitVector = arguments->bitVector(); |
| Node* currentSum = nullptr; |
| for (unsigned i = 0; i < arguments->numChildren(); i++) { |
| if (bitVector->get(i)) { |
| Node* child = graph.varArgChild(arguments, i).node(); |
| DFG_ASSERT(graph, child, child->op() == PhantomSpread, child->op()); |
| DFG_ASSERT(graph, child->child1().node(), |
| child->child1()->op() == PhantomCreateRest || child->child1()->op() == PhantomNewArrayBuffer, |
| child->child1()->op()); |
| Node* lengthOfChild = emitCodeToGetArgumentsArrayLength(insertionSet, child->child1().node(), nodeIndex, origin); |
| if (currentSum) |
| currentSum = insertionSet.insertNode(nodeIndex, SpecInt32Only, ArithAdd, origin, OpInfo(Arith::CheckOverflow), Edge(currentSum, Int32Use), Edge(lengthOfChild, Int32Use)); |
| else |
| currentSum = lengthOfChild; |
| } else |
| numberOfNonSpreadArguments++; |
| } |
| if (currentSum) { |
| if (!numberOfNonSpreadArguments) |
| return currentSum; |
| return insertionSet.insertNode( |
| nodeIndex, SpecInt32Only, ArithAdd, origin, OpInfo(Arith::CheckOverflow), Edge(currentSum, Int32Use), |
| insertionSet.insertConstantForUse(nodeIndex, origin, jsNumber(numberOfNonSpreadArguments), Int32Use)); |
| } |
| return insertionSet.insertConstant(nodeIndex, origin, jsNumber(numberOfNonSpreadArguments)); |
| } |
| |
| if (arguments->op() == NewArrayBuffer || arguments->op() == PhantomNewArrayBuffer) { |
| return insertionSet.insertConstant( |
| nodeIndex, origin, jsNumber(arguments->castOperand<JSImmutableButterfly*>()->length() + addThis)); |
| } |
| |
| InlineCallFrame* inlineCallFrame = arguments->origin.semantic.inlineCallFrame(); |
| |
| unsigned numberOfArgumentsToSkip = 0; |
| if (arguments->op() == CreateRest || arguments->op() == PhantomCreateRest) |
| numberOfArgumentsToSkip = arguments->numberOfArgumentsToSkip(); |
| |
| if (inlineCallFrame && !inlineCallFrame->isVarargs()) { |
| unsigned argumentsSize = inlineCallFrame->argumentCountIncludingThis - !addThis; |
| if (argumentsSize >= numberOfArgumentsToSkip) |
| argumentsSize -= numberOfArgumentsToSkip; |
| else |
| argumentsSize = 0; |
| return insertionSet.insertConstant( |
| nodeIndex, origin, jsNumber(argumentsSize)); |
| } |
| |
| Node* argumentCount = insertionSet.insertNode(nodeIndex, |
| SpecInt32Only, GetArgumentCountIncludingThis, origin, OpInfo(inlineCallFrame)); |
| |
| Node* result = insertionSet.insertNode( |
| nodeIndex, SpecInt32Only, ArithSub, origin, OpInfo(Arith::Unchecked), |
| Edge(argumentCount, Int32Use), |
| insertionSet.insertConstantForUse( |
| nodeIndex, origin, jsNumber(numberOfArgumentsToSkip + !addThis), Int32Use)); |
| |
| if (numberOfArgumentsToSkip) { |
| // The above subtraction may produce a negative number if this number is non-zero. We correct that here. |
| result = insertionSet.insertNode( |
| nodeIndex, SpecInt32Only, ArithMax, origin, |
| Edge(result, Int32Use), |
| insertionSet.insertConstantForUse(nodeIndex, origin, jsNumber(static_cast<unsigned>(addThis)), Int32Use)); |
| result->setResult(NodeResultInt32); |
| } |
| |
| return result; |
| } |
| |
| } } // namespace JSC::DFG |
| |
| #endif // ENABLE(DFG_JIT) |
| |