1/*
2 * Copyright (C) 2008 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#ifndef JITStubCall_h
27#define JITStubCall_h
28
29#include "MacroAssemblerCodeRef.h"
30
31#if ENABLE(JIT)
32
33namespace JSC {
34
35    class JITStubCall {
36    public:
37        JITStubCall(JIT* jit, JSObject* (JIT_STUB *stub)(STUB_ARGS_DECLARATION))
38            : m_jit(jit)
39            , m_stub(stub)
40#if USE(JSVALUE32_64) || !ASSERT_DISABLED
41            , m_returnType(Cell)
42#endif
43            , m_stackIndex(JITSTACKFRAME_ARGS_INDEX)
44        {
45        }
46
47        JITStubCall(JIT* jit, JSPropertyNameIterator* (JIT_STUB *stub)(STUB_ARGS_DECLARATION))
48            : m_jit(jit)
49            , m_stub(stub)
50#if USE(JSVALUE32_64) || !ASSERT_DISABLED
51            , m_returnType(Cell)
52#endif
53            , m_stackIndex(JITSTACKFRAME_ARGS_INDEX)
54        {
55        }
56
57        JITStubCall(JIT* jit, void* (JIT_STUB *stub)(STUB_ARGS_DECLARATION))
58            : m_jit(jit)
59            , m_stub(stub)
60#if USE(JSVALUE32_64) || !ASSERT_DISABLED
61            , m_returnType(VoidPtr)
62#endif
63            , m_stackIndex(JITSTACKFRAME_ARGS_INDEX)
64        {
65        }
66
67        JITStubCall(JIT* jit, int (JIT_STUB *stub)(STUB_ARGS_DECLARATION))
68            : m_jit(jit)
69            , m_stub(stub)
70#if USE(JSVALUE32_64) || !ASSERT_DISABLED
71            , m_returnType(Int)
72#endif
73            , m_stackIndex(JITSTACKFRAME_ARGS_INDEX)
74        {
75        }
76
77        JITStubCall(JIT* jit, bool (JIT_STUB *stub)(STUB_ARGS_DECLARATION))
78            : m_jit(jit)
79            , m_stub(stub)
80#if USE(JSVALUE32_64) || !ASSERT_DISABLED
81            , m_returnType(Int)
82#endif
83            , m_stackIndex(JITSTACKFRAME_ARGS_INDEX)
84        {
85        }
86
87        JITStubCall(JIT* jit, void (JIT_STUB *stub)(STUB_ARGS_DECLARATION))
88            : m_jit(jit)
89            , m_stub(stub)
90#if USE(JSVALUE32_64) || !ASSERT_DISABLED
91            , m_returnType(Void)
92#endif
93            , m_stackIndex(JITSTACKFRAME_ARGS_INDEX)
94        {
95        }
96
97        JITStubCall(JIT* jit, EncodedJSValue (JIT_STUB *stub)(STUB_ARGS_DECLARATION))
98            : m_jit(jit)
99            , m_stub(stub)
100#if USE(JSVALUE32_64) || !ASSERT_DISABLED
101            , m_returnType(Value)
102#endif
103            , m_stackIndex(JITSTACKFRAME_ARGS_INDEX)
104        {
105        }
106
107        // Arguments are added first to last.
108
109        void skipArgument()
110        {
111            m_stackIndex += stackIndexStep;
112        }
113
114        void addArgument(JIT::TrustedImm32 argument)
115        {
116            m_jit->poke(argument, m_stackIndex);
117            m_stackIndex += stackIndexStep;
118        }
119
120        void addArgument(JIT::Imm32 argument)
121        {
122            m_jit->poke(argument, m_stackIndex);
123            m_stackIndex += stackIndexStep;
124        }
125
126        void addArgument(JIT::TrustedImmPtr argument)
127        {
128            m_jit->poke(argument, m_stackIndex);
129            m_stackIndex += stackIndexStep;
130        }
131
132        void addArgument(JIT::ImmPtr argument)
133        {
134            m_jit->poke(argument, m_stackIndex);
135            m_stackIndex += stackIndexStep;
136        }
137
138        void addArgument(JIT::RegisterID argument)
139        {
140#if USE(JSVALUE32_64)
141            m_jit->poke(argument, m_stackIndex);
142#else
143            m_jit->poke64(argument, m_stackIndex);
144#endif
145            m_stackIndex += stackIndexStep;
146        }
147
148#if USE(JSVALUE32_64)
149        void addArgument(const JSValue& value)
150        {
151            m_jit->poke(JIT::Imm32(value.payload()), m_stackIndex);
152            m_jit->poke(JIT::Imm32(value.tag()), m_stackIndex + 1);
153            m_stackIndex += stackIndexStep;
154        }
155#else
156        void addArgument(JIT::TrustedImm64 argument)
157        {
158            m_jit->poke(argument, m_stackIndex);
159            m_stackIndex += stackIndexStep;
160        }
161
162        void addArgument(JIT::Imm64 argument)
163        {
164            m_jit->poke(argument, m_stackIndex);
165            m_stackIndex += stackIndexStep;
166        }
167#endif
168
169        void addArgument(JIT::RegisterID tag, JIT::RegisterID payload)
170        {
171            m_jit->poke(payload, m_stackIndex);
172            m_jit->poke(tag, m_stackIndex + 1);
173            m_stackIndex += stackIndexStep;
174        }
175
176#if USE(JSVALUE32_64)
177        void addArgument(unsigned srcVirtualRegister)
178        {
179            if (m_jit->m_codeBlock->isConstantRegisterIndex(srcVirtualRegister)) {
180                addArgument(m_jit->getConstantOperand(srcVirtualRegister));
181                return;
182            }
183
184            m_jit->emitLoad(srcVirtualRegister, JIT::regT1, JIT::regT0);
185            addArgument(JIT::regT1, JIT::regT0);
186        }
187
188        void getArgument(size_t argumentNumber, JIT::RegisterID tag, JIT::RegisterID payload)
189        {
190            size_t stackIndex = JITSTACKFRAME_ARGS_INDEX + (argumentNumber * stackIndexStep);
191            m_jit->peek(payload, stackIndex);
192            m_jit->peek(tag, stackIndex + 1);
193        }
194#else
195        void addArgument(unsigned src, JIT::RegisterID scratchRegister) // src is a virtual register.
196        {
197            if (m_jit->m_codeBlock->isConstantRegisterIndex(src))
198                addArgument(JIT::Imm64(JSValue::encode(m_jit->m_codeBlock->getConstant(src))));
199            else {
200                m_jit->load64(JIT::Address(JIT::callFrameRegister, src * sizeof(Register)), scratchRegister);
201                addArgument(scratchRegister);
202            }
203            m_jit->killLastResultRegister();
204        }
205#endif
206
207        JIT::Call call()
208        {
209#if ENABLE(OPCODE_SAMPLING)
210            if (m_jit->m_bytecodeOffset != (unsigned)-1)
211                m_jit->sampleInstruction(m_jit->m_codeBlock->instructions().begin() + m_jit->m_bytecodeOffset, true);
212#endif
213
214            m_jit->restoreArgumentReference();
215            m_jit->updateTopCallFrame();
216            JIT::Call call = m_jit->call();
217            m_jit->m_calls.append(CallRecord(call, m_jit->m_bytecodeOffset, m_stub.value()));
218
219#if ENABLE(OPCODE_SAMPLING)
220            if (m_jit->m_bytecodeOffset != (unsigned)-1)
221                m_jit->sampleInstruction(m_jit->m_codeBlock->instructions().begin() + m_jit->m_bytecodeOffset, false);
222#endif
223
224#if USE(JSVALUE32_64)
225            m_jit->unmap();
226#else
227            m_jit->killLastResultRegister();
228#endif
229            return call;
230        }
231
232#if USE(JSVALUE32_64)
233        JIT::Call call(unsigned dst) // dst is a virtual register.
234        {
235            ASSERT(m_returnType == Value || m_returnType == Cell);
236            JIT::Call call = this->call();
237            if (m_returnType == Value)
238                m_jit->emitStore(dst, JIT::regT1, JIT::regT0);
239            else
240                m_jit->emitStoreCell(dst, JIT::returnValueRegister);
241            return call;
242        }
243
244        JIT::Call callWithValueProfiling(unsigned dst)
245        {
246            ASSERT(m_returnType == Value || m_returnType == Cell);
247            JIT::Call call = this->call();
248            ASSERT(JIT::returnValueRegister == JIT::regT0);
249            if (m_returnType == Cell)
250                m_jit->move(JIT::TrustedImm32(JSValue::CellTag), JIT::regT1);
251            m_jit->emitValueProfilingSite();
252            if (m_returnType == Value)
253                m_jit->emitStore(dst, JIT::regT1, JIT::regT0);
254            else
255                m_jit->emitStoreCell(dst, JIT::returnValueRegister);
256            return call;
257        }
258#else
259        JIT::Call call(unsigned dst) // dst is a virtual register.
260        {
261            ASSERT(m_returnType == Value || m_returnType == Cell);
262            JIT::Call call = this->call();
263            m_jit->emitPutVirtualRegister(dst);
264            return call;
265        }
266
267        JIT::Call callWithValueProfiling(unsigned dst)
268        {
269            ASSERT(m_returnType == Value || m_returnType == Cell);
270            JIT::Call call = this->call();
271            ASSERT(JIT::returnValueRegister == JIT::regT0);
272            m_jit->emitValueProfilingSite();
273            m_jit->emitPutVirtualRegister(dst);
274            return call;
275        }
276#endif
277
278        JIT::Call call(JIT::RegisterID dst) // dst is a machine register.
279        {
280#if USE(JSVALUE32_64) || !ASSERT_DISABLED
281            ASSERT(m_returnType == Value || m_returnType == VoidPtr || m_returnType == Int || m_returnType == Cell);
282#endif
283            JIT::Call call = this->call();
284            if (dst != JIT::returnValueRegister)
285                m_jit->move(JIT::returnValueRegister, dst);
286            return call;
287        }
288
289    private:
290        static const size_t stackIndexStep = sizeof(EncodedJSValue) == 2 * sizeof(void*) ? 2 : 1;
291
292        JIT* m_jit;
293        FunctionPtr m_stub;
294#if USE(JSVALUE32_64) || !ASSERT_DISABLED
295        enum { Void, VoidPtr, Int, Value, Cell } m_returnType;
296#endif
297        size_t m_stackIndex;
298    };
299}
300
301#endif // ENABLE(JIT)
302
303#endif // JITStubCall_h
304