2 * Copyright (C) 2015 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 "SetupVarargsFrame.h"
31 #include "Interpreter.h"
32 #include "JSCInlines.h"
33 #include "StackAlignment.h"
37 void emitSetVarargsFrame(CCallHelpers
& jit
, GPRReg lengthGPR
, bool lengthIncludesThis
, GPRReg numUsedSlotsGPR
, GPRReg resultGPR
)
39 jit
.move(numUsedSlotsGPR
, resultGPR
);
40 jit
.addPtr(lengthGPR
, resultGPR
);
41 jit
.addPtr(CCallHelpers::TrustedImm32(JSStack::CallFrameHeaderSize
+ (lengthIncludesThis
? 0 : 1)), resultGPR
);
43 // resultGPR now has the required frame size in Register units
44 // Round resultGPR to next multiple of stackAlignmentRegisters()
45 jit
.addPtr(CCallHelpers::TrustedImm32(stackAlignmentRegisters() - 1), resultGPR
);
46 jit
.andPtr(CCallHelpers::TrustedImm32(~(stackAlignmentRegisters() - 1)), resultGPR
);
48 // Now resultGPR has the right stack frame offset in Register units.
49 jit
.negPtr(resultGPR
);
50 jit
.lshiftPtr(CCallHelpers::Imm32(3), resultGPR
);
51 jit
.addPtr(GPRInfo::callFrameRegister
, resultGPR
);
54 void emitSetupVarargsFrameFastCase(CCallHelpers
& jit
, GPRReg numUsedSlotsGPR
, GPRReg scratchGPR1
, GPRReg scratchGPR2
, GPRReg scratchGPR3
, ValueRecovery argCountRecovery
, VirtualRegister firstArgumentReg
, unsigned firstVarArgOffset
, CCallHelpers::JumpList
& slowCase
)
56 CCallHelpers::JumpList end
;
58 if (argCountRecovery
.isConstant()) {
59 // FIXME: We could constant-fold a lot of the computation below in this case.
60 // https://bugs.webkit.org/show_bug.cgi?id=141486
61 jit
.move(CCallHelpers::TrustedImm32(argCountRecovery
.constant().asInt32()), scratchGPR1
);
63 jit
.load32(CCallHelpers::payloadFor(argCountRecovery
.virtualRegister()), scratchGPR1
);
64 if (firstVarArgOffset
) {
65 CCallHelpers::Jump sufficientArguments
= jit
.branch32(CCallHelpers::GreaterThan
, scratchGPR1
, CCallHelpers::TrustedImm32(firstVarArgOffset
+ 1));
66 jit
.move(CCallHelpers::TrustedImm32(1), scratchGPR1
);
67 CCallHelpers::Jump endVarArgs
= jit
.jump();
68 sufficientArguments
.link(&jit
);
69 jit
.sub32(CCallHelpers::TrustedImm32(firstVarArgOffset
), scratchGPR1
);
70 endVarArgs
.link(&jit
);
72 slowCase
.append(jit
.branch32(CCallHelpers::Above
, scratchGPR1
, CCallHelpers::TrustedImm32(maxArguments
+ 1)));
74 emitSetVarargsFrame(jit
, scratchGPR1
, true, numUsedSlotsGPR
, scratchGPR2
);
76 slowCase
.append(jit
.branchPtr(CCallHelpers::Above
, CCallHelpers::AbsoluteAddress(jit
.vm()->addressOfStackLimit()), scratchGPR2
));
78 // Initialize ArgumentCount.
79 jit
.store32(scratchGPR1
, CCallHelpers::Address(scratchGPR2
, JSStack::ArgumentCount
* static_cast<int>(sizeof(Register
)) + PayloadOffset
));
82 jit
.signExtend32ToPtr(scratchGPR1
, scratchGPR1
);
83 CCallHelpers::Jump done
= jit
.branchSubPtr(CCallHelpers::Zero
, CCallHelpers::TrustedImm32(1), scratchGPR1
);
84 // scratchGPR1: argumentCount
86 CCallHelpers::Label copyLoop
= jit
.label();
87 int argOffset
= (firstArgumentReg
.offset() - 1 + firstVarArgOffset
) * static_cast<int>(sizeof(Register
));
89 jit
.load64(CCallHelpers::BaseIndex(GPRInfo::callFrameRegister
, scratchGPR1
, CCallHelpers::TimesEight
, argOffset
), scratchGPR3
);
90 jit
.store64(scratchGPR3
, CCallHelpers::BaseIndex(scratchGPR2
, scratchGPR1
, CCallHelpers::TimesEight
, CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register
))));
91 #else // USE(JSVALUE64), so this begins the 32-bit case
92 jit
.load32(CCallHelpers::BaseIndex(GPRInfo::callFrameRegister
, scratchGPR1
, CCallHelpers::TimesEight
, argOffset
+ TagOffset
), scratchGPR3
);
93 jit
.store32(scratchGPR3
, CCallHelpers::BaseIndex(scratchGPR2
, scratchGPR1
, CCallHelpers::TimesEight
, CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register
)) + TagOffset
));
94 jit
.load32(CCallHelpers::BaseIndex(GPRInfo::callFrameRegister
, scratchGPR1
, CCallHelpers::TimesEight
, argOffset
+ PayloadOffset
), scratchGPR3
);
95 jit
.store32(scratchGPR3
, CCallHelpers::BaseIndex(scratchGPR2
, scratchGPR1
, CCallHelpers::TimesEight
, CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register
)) + PayloadOffset
));
96 #endif // USE(JSVALUE64), end of 32-bit case
97 jit
.branchSubPtr(CCallHelpers::NonZero
, CCallHelpers::TrustedImm32(1), scratchGPR1
).linkTo(copyLoop
, &jit
);
102 void emitSetupVarargsFrameFastCase(CCallHelpers
& jit
, GPRReg numUsedSlotsGPR
, GPRReg scratchGPR1
, GPRReg scratchGPR2
, GPRReg scratchGPR3
, unsigned firstVarArgOffset
, CCallHelpers::JumpList
& slowCase
)
104 emitSetupVarargsFrameFastCase(jit
, numUsedSlotsGPR
, scratchGPR1
, scratchGPR2
, scratchGPR3
, nullptr, firstVarArgOffset
, slowCase
);
107 void emitSetupVarargsFrameFastCase(CCallHelpers
& jit
, GPRReg numUsedSlotsGPR
, GPRReg scratchGPR1
, GPRReg scratchGPR2
, GPRReg scratchGPR3
, InlineCallFrame
* inlineCallFrame
, unsigned firstVarArgOffset
, CCallHelpers::JumpList
& slowCase
)
109 ValueRecovery argumentCountRecovery
;
110 VirtualRegister firstArgumentReg
;
111 if (inlineCallFrame
) {
112 if (inlineCallFrame
->isVarargs()) {
113 argumentCountRecovery
= ValueRecovery::displacedInJSStack(
114 inlineCallFrame
->argumentCountRegister
, DataFormatInt32
);
116 argumentCountRecovery
= ValueRecovery::constant(
117 jsNumber(inlineCallFrame
->arguments
.size()));
119 if (inlineCallFrame
->arguments
.size() > 1)
120 firstArgumentReg
= inlineCallFrame
->arguments
[1].virtualRegister();
122 firstArgumentReg
= VirtualRegister(0);
124 argumentCountRecovery
= ValueRecovery::displacedInJSStack(
125 VirtualRegister(JSStack::ArgumentCount
), DataFormatInt32
);
126 firstArgumentReg
= VirtualRegister(CallFrame::argumentOffset(0));
128 emitSetupVarargsFrameFastCase(jit
, numUsedSlotsGPR
, scratchGPR1
, scratchGPR2
, scratchGPR3
, argumentCountRecovery
, firstArgumentReg
, firstVarArgOffset
, slowCase
);
133 #endif // ENABLE(JIT)