1 | /*
|
---|
2 | * Copyright (C) 2010-2022 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 | #pragma once
|
---|
27 |
|
---|
28 | #if ENABLE(JIT)
|
---|
29 |
|
---|
30 | #include "JIT.h"
|
---|
31 | #include "JITInlines.h"
|
---|
32 | #include "JSInterfaceJIT.h"
|
---|
33 | #include "LinkBuffer.h"
|
---|
34 |
|
---|
35 | namespace JSC {
|
---|
36 |
|
---|
37 | class SpecializedThunkJIT : public JSInterfaceJIT {
|
---|
38 | public:
|
---|
39 | static constexpr int ThisArgument = -1;
|
---|
40 | SpecializedThunkJIT(VM& vm, int expectedArgCount)
|
---|
41 | : JSInterfaceJIT(&vm)
|
---|
42 | {
|
---|
43 | emitFunctionPrologue();
|
---|
44 | emitSaveThenMaterializeTagRegisters();
|
---|
45 | // Check that we have the expected number of arguments
|
---|
46 | m_failures.append(branch32(NotEqual, payloadFor(CallFrameSlot::argumentCountIncludingThis), TrustedImm32(expectedArgCount + 1)));
|
---|
47 | }
|
---|
48 |
|
---|
49 | explicit SpecializedThunkJIT(VM& vm)
|
---|
50 | : JSInterfaceJIT(&vm)
|
---|
51 | {
|
---|
52 | emitFunctionPrologue();
|
---|
53 | emitSaveThenMaterializeTagRegisters();
|
---|
54 | }
|
---|
55 |
|
---|
56 | void loadDoubleArgument(int argument, FPRegisterID dst, RegisterID scratch)
|
---|
57 | {
|
---|
58 | VirtualRegister src = virtualRegisterForArgumentIncludingThis(argument + 1);
|
---|
59 | m_failures.append(emitLoadDouble(src, dst, scratch));
|
---|
60 | }
|
---|
61 |
|
---|
62 | void loadCellArgument(int argument, RegisterID dst)
|
---|
63 | {
|
---|
64 | VirtualRegister src = virtualRegisterForArgumentIncludingThis(argument + 1);
|
---|
65 | m_failures.append(emitLoadJSCell(src, dst));
|
---|
66 | }
|
---|
67 |
|
---|
68 | void loadJSStringArgument(int argument, RegisterID dst)
|
---|
69 | {
|
---|
70 | loadCellArgument(argument, dst);
|
---|
71 | m_failures.append(branchIfNotString(dst));
|
---|
72 | }
|
---|
73 |
|
---|
74 | void loadInt32Argument(int argument, RegisterID dst, Jump& failTarget)
|
---|
75 | {
|
---|
76 | VirtualRegister src = virtualRegisterForArgumentIncludingThis(argument + 1);
|
---|
77 | failTarget = emitLoadInt32(src, dst);
|
---|
78 | }
|
---|
79 |
|
---|
80 | void loadInt32Argument(int argument, RegisterID dst)
|
---|
81 | {
|
---|
82 | Jump conversionFailed;
|
---|
83 | loadInt32Argument(argument, dst, conversionFailed);
|
---|
84 | m_failures.append(conversionFailed);
|
---|
85 | }
|
---|
86 |
|
---|
87 | void appendFailure(const Jump& failure)
|
---|
88 | {
|
---|
89 | m_failures.append(failure);
|
---|
90 | }
|
---|
91 | #if USE(JSVALUE64)
|
---|
92 | void returnJSValue(RegisterID src)
|
---|
93 | {
|
---|
94 | if (src != regT0)
|
---|
95 | move(src, regT0);
|
---|
96 |
|
---|
97 | emitRestoreSavedTagRegisters();
|
---|
98 | emitFunctionEpilogue();
|
---|
99 | ret();
|
---|
100 | }
|
---|
101 | #else
|
---|
102 | void returnJSValue(RegisterID payload, RegisterID tag)
|
---|
103 | {
|
---|
104 | ASSERT_UNUSED(payload, payload == regT0);
|
---|
105 | ASSERT_UNUSED(tag, tag == regT1);
|
---|
106 | emitRestoreSavedTagRegisters();
|
---|
107 | emitFunctionEpilogue();
|
---|
108 | ret();
|
---|
109 | }
|
---|
110 | #endif
|
---|
111 |
|
---|
112 | void returnDouble(FPRegisterID src)
|
---|
113 | {
|
---|
114 | #if USE(JSVALUE64)
|
---|
115 | moveDoubleTo64(src, regT0);
|
---|
116 | Jump zero = branchTest64(Zero, regT0);
|
---|
117 | sub64(numberTagRegister, regT0);
|
---|
118 | Jump done = jump();
|
---|
119 | zero.link(this);
|
---|
120 | move(numberTagRegister, regT0);
|
---|
121 | done.link(this);
|
---|
122 | #else
|
---|
123 | moveDoubleToInts(src, regT0, regT1);
|
---|
124 | Jump lowNonZero = branchTestPtr(NonZero, regT1);
|
---|
125 | Jump highNonZero = branchTestPtr(NonZero, regT0);
|
---|
126 | move(TrustedImm32(0), regT0);
|
---|
127 | move(TrustedImm32(JSValue::Int32Tag), regT1);
|
---|
128 | lowNonZero.link(this);
|
---|
129 | highNonZero.link(this);
|
---|
130 | #endif
|
---|
131 | emitRestoreSavedTagRegisters();
|
---|
132 | emitFunctionEpilogue();
|
---|
133 | ret();
|
---|
134 | }
|
---|
135 |
|
---|
136 | void returnInt32(RegisterID src)
|
---|
137 | {
|
---|
138 | if (src != regT0)
|
---|
139 | move(src, regT0);
|
---|
140 | tagReturnAsInt32();
|
---|
141 | emitRestoreSavedTagRegisters();
|
---|
142 | emitFunctionEpilogue();
|
---|
143 | ret();
|
---|
144 | }
|
---|
145 |
|
---|
146 | void returnJSCell(RegisterID src)
|
---|
147 | {
|
---|
148 | if (src != regT0)
|
---|
149 | move(src, regT0);
|
---|
150 | tagReturnAsJSCell();
|
---|
151 | emitRestoreSavedTagRegisters();
|
---|
152 | emitFunctionEpilogue();
|
---|
153 | ret();
|
---|
154 | }
|
---|
155 |
|
---|
156 | MacroAssemblerCodeRef<JITThunkPtrTag> finalize(MacroAssemblerCodePtr<JITThunkPtrTag> fallback, const char* thunkKind)
|
---|
157 | {
|
---|
158 | LinkBuffer patchBuffer(*this, GLOBAL_THUNK_ID, LinkBuffer::Profile::SpecializedThunk);
|
---|
159 | patchBuffer.link(m_failures, CodeLocationLabel<JITThunkPtrTag>(fallback));
|
---|
160 | for (unsigned i = 0; i < m_calls.size(); i++)
|
---|
161 | patchBuffer.link(m_calls[i].first, m_calls[i].second);
|
---|
162 | return FINALIZE_THUNK(patchBuffer, JITThunkPtrTag, "Specialized thunk for %s", thunkKind);
|
---|
163 | }
|
---|
164 |
|
---|
165 | // Assumes that the target function uses fpRegister0 as the first argument
|
---|
166 | // and return value. Like any sensible architecture would.
|
---|
167 | void callDoubleToDouble(FunctionPtr<CFunctionPtrTag> function)
|
---|
168 | {
|
---|
169 | m_calls.append(std::make_pair(call(OperationPtrTag), function.retagged<OperationPtrTag>()));
|
---|
170 | }
|
---|
171 |
|
---|
172 | void callDoubleToDoublePreservingReturn(FunctionPtr<CFunctionPtrTag> function)
|
---|
173 | {
|
---|
174 | if (!isX86())
|
---|
175 | preserveReturnAddressAfterCall(regT3);
|
---|
176 | callDoubleToDouble(function);
|
---|
177 | if (!isX86())
|
---|
178 | restoreReturnAddressBeforeReturn(regT3);
|
---|
179 | }
|
---|
180 |
|
---|
181 | private:
|
---|
182 | void tagReturnAsInt32()
|
---|
183 | {
|
---|
184 | #if USE(JSVALUE64)
|
---|
185 | or64(numberTagRegister, regT0);
|
---|
186 | #else
|
---|
187 | move(TrustedImm32(JSValue::Int32Tag), regT1);
|
---|
188 | #endif
|
---|
189 | }
|
---|
190 |
|
---|
191 | void tagReturnAsJSCell()
|
---|
192 | {
|
---|
193 | #if USE(JSVALUE32_64)
|
---|
194 | move(TrustedImm32(JSValue::CellTag), regT1);
|
---|
195 | #endif
|
---|
196 | }
|
---|
197 |
|
---|
198 | MacroAssembler::JumpList m_failures;
|
---|
199 | Vector<std::pair<Call, FunctionPtr<OperationPtrTag>>> m_calls;
|
---|
200 | };
|
---|
201 |
|
---|
202 | }
|
---|
203 |
|
---|
204 | #endif // ENABLE(JIT)
|
---|