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            , m_returnType(Cell)
41            , m_stackIndex(JITSTACKFRAME_ARGS_INDEX)
42        {
43        }
44
45        JITStubCall(JIT* jit, JSPropertyNameIterator* (JIT_STUB *stub)(STUB_ARGS_DECLARATION))
46            : m_jit(jit)
47            , m_stub(stub)
48            , m_returnType(Cell)
49            , m_stackIndex(JITSTACKFRAME_ARGS_INDEX)
50        {
51        }
52
53        JITStubCall(JIT* jit, void* (JIT_STUB *stub)(STUB_ARGS_DECLARATION))
54            : m_jit(jit)
55            , m_stub(stub)
56            , m_returnType(VoidPtr)
57            , m_stackIndex(JITSTACKFRAME_ARGS_INDEX)
58        {
59        }
60
61        JITStubCall(JIT* jit, int (JIT_STUB *stub)(STUB_ARGS_DECLARATION))
62            : m_jit(jit)
63            , m_stub(stub)
64            , m_returnType(Int)
65            , m_stackIndex(JITSTACKFRAME_ARGS_INDEX)
66        {
67        }
68
69        JITStubCall(JIT* jit, bool (JIT_STUB *stub)(STUB_ARGS_DECLARATION))
70            : m_jit(jit)
71            , m_stub(stub)
72            , m_returnType(Int)
73            , m_stackIndex(JITSTACKFRAME_ARGS_INDEX)
74        {
75        }
76
77        JITStubCall(JIT* jit, void (JIT_STUB *stub)(STUB_ARGS_DECLARATION))
78            : m_jit(jit)
79            , m_stub(stub)
80            , m_returnType(Void)
81            , m_stackIndex(JITSTACKFRAME_ARGS_INDEX)
82        {
83        }
84
85#if USE(JSVALUE32_64)
86        JITStubCall(JIT* jit, EncodedJSValue (JIT_STUB *stub)(STUB_ARGS_DECLARATION))
87            : m_jit(jit)
88            , m_stub(stub)
89            , m_returnType(Value)
90            , m_stackIndex(JITSTACKFRAME_ARGS_INDEX)
91        {
92        }
93#endif
94
95        // Arguments are added first to last.
96
97        void skipArgument()
98        {
99            m_stackIndex += stackIndexStep;
100        }
101
102        void addArgument(JIT::TrustedImm32 argument)
103        {
104            m_jit->poke(argument, m_stackIndex);
105            m_stackIndex += stackIndexStep;
106        }
107
108        void addArgument(JIT::TrustedImmPtr argument)
109        {
110            m_jit->poke(argument, m_stackIndex);
111            m_stackIndex += stackIndexStep;
112        }
113
114        void addArgument(JIT::RegisterID argument)
115        {
116            m_jit->poke(argument, m_stackIndex);
117            m_stackIndex += stackIndexStep;
118        }
119
120#if USE(JSVALUE32_64)
121        void addArgument(const JSValue& value)
122        {
123            m_jit->poke(JIT::Imm32(value.payload()), m_stackIndex);
124            m_jit->poke(JIT::Imm32(value.tag()), m_stackIndex + 1);
125            m_stackIndex += stackIndexStep;
126        }
127#endif
128
129        void addArgument(JIT::RegisterID tag, JIT::RegisterID payload)
130        {
131            m_jit->poke(payload, m_stackIndex);
132            m_jit->poke(tag, m_stackIndex + 1);
133            m_stackIndex += stackIndexStep;
134        }
135
136#if USE(JSVALUE32_64)
137        void addArgument(unsigned srcVirtualRegister)
138        {
139            if (m_jit->m_codeBlock->isConstantRegisterIndex(srcVirtualRegister)) {
140                addArgument(m_jit->getConstantOperand(srcVirtualRegister));
141                return;
142            }
143
144            m_jit->emitLoad(srcVirtualRegister, JIT::regT1, JIT::regT0);
145            addArgument(JIT::regT1, JIT::regT0);
146        }
147
148        void getArgument(size_t argumentNumber, JIT::RegisterID tag, JIT::RegisterID payload)
149        {
150            size_t stackIndex = JITSTACKFRAME_ARGS_INDEX + (argumentNumber * stackIndexStep);
151            m_jit->peek(payload, stackIndex);
152            m_jit->peek(tag, stackIndex + 1);
153        }
154#else
155        void addArgument(unsigned src, JIT::RegisterID scratchRegister) // src is a virtual register.
156        {
157            if (m_jit->m_codeBlock->isConstantRegisterIndex(src))
158                addArgument(JIT::ImmPtr(JSValue::encode(m_jit->m_codeBlock->getConstant(src))));
159            else {
160                m_jit->loadPtr(JIT::Address(JIT::callFrameRegister, src * sizeof(Register)), scratchRegister);
161                addArgument(scratchRegister);
162            }
163            m_jit->killLastResultRegister();
164        }
165#endif
166
167        JIT::Call call()
168        {
169#if ENABLE(OPCODE_SAMPLING)
170            if (m_jit->m_bytecodeOffset != (unsigned)-1)
171                m_jit->sampleInstruction(m_jit->m_codeBlock->instructions().begin() + m_jit->m_bytecodeOffset, true);
172#endif
173
174            m_jit->restoreArgumentReference();
175            JIT::Call call = m_jit->call();
176            m_jit->m_calls.append(CallRecord(call, m_jit->m_bytecodeOffset, m_stub.value()));
177
178#if ENABLE(OPCODE_SAMPLING)
179            if (m_jit->m_bytecodeOffset != (unsigned)-1)
180                m_jit->sampleInstruction(m_jit->m_codeBlock->instructions().begin() + m_jit->m_bytecodeOffset, false);
181#endif
182
183#if USE(JSVALUE32_64)
184            m_jit->unmap();
185#else
186            m_jit->killLastResultRegister();
187#endif
188            return call;
189        }
190
191#if USE(JSVALUE32_64)
192        JIT::Call call(unsigned dst) // dst is a virtual register.
193        {
194            ASSERT(m_returnType == Value || m_returnType == Cell);
195            JIT::Call call = this->call();
196            if (m_returnType == Value)
197                m_jit->emitStore(dst, JIT::regT1, JIT::regT0);
198            else
199                m_jit->emitStoreCell(dst, JIT::returnValueRegister);
200            return call;
201        }
202#else
203        JIT::Call call(unsigned dst) // dst is a virtual register.
204        {
205            ASSERT(m_returnType == VoidPtr || m_returnType == Cell);
206            JIT::Call call = this->call();
207            m_jit->emitPutVirtualRegister(dst);
208            return call;
209        }
210#endif
211
212        JIT::Call call(JIT::RegisterID dst) // dst is a machine register.
213        {
214#if USE(JSVALUE32_64)
215            ASSERT(m_returnType == Value || m_returnType == VoidPtr || m_returnType == Int || m_returnType == Cell);
216#else
217            ASSERT(m_returnType == VoidPtr || m_returnType == Int || m_returnType == Cell);
218#endif
219            JIT::Call call = this->call();
220            if (dst != JIT::returnValueRegister)
221                m_jit->move(JIT::returnValueRegister, dst);
222            return call;
223        }
224
225    private:
226        static const size_t stackIndexStep = sizeof(EncodedJSValue) == 2 * sizeof(void*) ? 2 : 1;
227
228        JIT* m_jit;
229        FunctionPtr m_stub;
230        enum { Void, VoidPtr, Int, Value, Cell } m_returnType;
231        size_t m_stackIndex;
232    };
233}
234
235#endif // ENABLE(JIT)
236
237#endif // JITStubCall_h
238