1/*
2 * Copyright (C) 2010 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. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef SpecializedThunkJIT_h
27#define SpecializedThunkJIT_h
28
29#if ENABLE(JIT)
30
31#include "Executable.h"
32#include "JSInterfaceJIT.h"
33#include "LinkBuffer.h"
34
35namespace JSC {
36
37    class SpecializedThunkJIT : public JSInterfaceJIT {
38    public:
39        static const int ThisArgument = -1;
40        SpecializedThunkJIT(int expectedArgCount, JSGlobalData* globalData, ExecutablePool* pool)
41            : m_expectedArgCount(expectedArgCount)
42            , m_globalData(globalData)
43            , m_pool(pool)
44        {
45            // Check that we have the expected number of arguments
46            m_failures.append(branch32(NotEqual, Address(callFrameRegister, RegisterFile::ArgumentCount * (int)sizeof(Register)), TrustedImm32(expectedArgCount + 1)));
47        }
48
49        void loadDoubleArgument(int argument, FPRegisterID dst, RegisterID scratch)
50        {
51            unsigned src = argumentToVirtualRegister(argument);
52            m_failures.append(emitLoadDouble(src, dst, scratch));
53        }
54
55        void loadCellArgument(int argument, RegisterID dst)
56        {
57            unsigned src = argumentToVirtualRegister(argument);
58            m_failures.append(emitLoadJSCell(src, dst));
59        }
60
61        void loadJSStringArgument(int argument, RegisterID dst)
62        {
63            loadCellArgument(argument, dst);
64            m_failures.append(branchPtr(NotEqual, Address(dst, 0), TrustedImmPtr(m_globalData->jsStringVPtr)));
65            m_failures.append(branchTest32(NonZero, Address(dst, OBJECT_OFFSETOF(JSString, m_fiberCount))));
66        }
67
68        void loadInt32Argument(int argument, RegisterID dst, Jump& failTarget)
69        {
70            unsigned src = argumentToVirtualRegister(argument);
71            failTarget = emitLoadInt32(src, dst);
72        }
73
74        void loadInt32Argument(int argument, RegisterID dst)
75        {
76            Jump conversionFailed;
77            loadInt32Argument(argument, dst, conversionFailed);
78            m_failures.append(conversionFailed);
79        }
80
81        void appendFailure(const Jump& failure)
82        {
83            m_failures.append(failure);
84        }
85
86        void returnJSValue(RegisterID src)
87        {
88            if (src != regT0)
89                move(src, regT0);
90            loadPtr(payloadFor(RegisterFile::CallerFrame, callFrameRegister), callFrameRegister);
91            ret();
92        }
93
94        void returnDouble(FPRegisterID src)
95        {
96#if USE(JSVALUE64)
97            moveDoubleToPtr(src, regT0);
98            subPtr(tagTypeNumberRegister, regT0);
99#else
100            storeDouble(src, Address(stackPointerRegister, -(int)sizeof(double)));
101            loadPtr(Address(stackPointerRegister, OBJECT_OFFSETOF(JSValue, u.asBits.tag) - sizeof(double)), regT1);
102            loadPtr(Address(stackPointerRegister, OBJECT_OFFSETOF(JSValue, u.asBits.payload) - sizeof(double)), regT0);
103#endif
104            loadPtr(payloadFor(RegisterFile::CallerFrame, callFrameRegister), callFrameRegister);
105            ret();
106        }
107
108        void returnInt32(RegisterID src)
109        {
110            if (src != regT0)
111                move(src, regT0);
112            tagReturnAsInt32();
113            loadPtr(payloadFor(RegisterFile::CallerFrame, callFrameRegister), callFrameRegister);
114            ret();
115        }
116
117        void returnJSCell(RegisterID src)
118        {
119            if (src != regT0)
120                move(src, regT0);
121            tagReturnAsJSCell();
122            loadPtr(payloadFor(RegisterFile::CallerFrame, callFrameRegister), callFrameRegister);
123            ret();
124        }
125
126        MacroAssemblerCodePtr finalize(MacroAssemblerCodePtr fallback)
127        {
128            LinkBuffer patchBuffer(this, m_pool.get(), 0);
129            patchBuffer.link(m_failures, CodeLocationLabel(fallback));
130            return patchBuffer.finalizeCode().m_code;
131        }
132
133    private:
134        int argumentToVirtualRegister(unsigned argument)
135        {
136            return -static_cast<int>(RegisterFile::CallFrameHeaderSize + (m_expectedArgCount - argument));
137        }
138
139        void tagReturnAsInt32()
140        {
141#if USE(JSVALUE64)
142            orPtr(tagTypeNumberRegister, regT0);
143#else
144            move(TrustedImm32(JSValue::Int32Tag), regT1);
145#endif
146        }
147
148        void tagReturnAsJSCell()
149        {
150#if USE(JSVALUE32_64)
151            move(TrustedImm32(JSValue::CellTag), regT1);
152#endif
153        }
154
155        int m_expectedArgCount;
156        JSGlobalData* m_globalData;
157        RefPtr<ExecutablePool> m_pool;
158        MacroAssembler::JumpList m_failures;
159    };
160
161}
162
163#endif // ENABLE(JIT)
164
165#endif // SpecializedThunkJIT_h
166