]> git.saurik.com Git - apple/javascriptcore.git/blame - jit/ThunkGenerators.cpp
JavaScriptCore-1097.13.tar.gz
[apple/javascriptcore.git] / jit / ThunkGenerators.cpp
CommitLineData
4e4e5a6f
A
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#include "config.h"
27#include "ThunkGenerators.h"
28
29#include "CodeBlock.h"
6fe7ccc8 30#include <wtf/InlineASM.h>
4e4e5a6f 31#include "SpecializedThunkJIT.h"
6fe7ccc8 32#include <wtf/text/StringImpl.h>
4e4e5a6f
A
33
34#if ENABLE(JIT)
35
36namespace JSC {
37
38static void stringCharLoad(SpecializedThunkJIT& jit)
39{
40 // load string
41 jit.loadJSStringArgument(SpecializedThunkJIT::ThisArgument, SpecializedThunkJIT::regT0);
4e4e5a6f
A
42
43 // Load string length to regT2, and start the process of loading the data pointer into regT0
44 jit.load32(MacroAssembler::Address(SpecializedThunkJIT::regT0, ThunkHelpers::jsStringLengthOffset()), SpecializedThunkJIT::regT2);
45 jit.loadPtr(MacroAssembler::Address(SpecializedThunkJIT::regT0, ThunkHelpers::jsStringValueOffset()), SpecializedThunkJIT::regT0);
6fe7ccc8 46 jit.appendFailure(jit.branchTest32(MacroAssembler::Zero, SpecializedThunkJIT::regT0));
4e4e5a6f
A
47
48 // load index
49 jit.loadInt32Argument(0, SpecializedThunkJIT::regT1); // regT1 contains the index
50
51 // Do an unsigned compare to simultaneously filter negative indices as well as indices that are too large
52 jit.appendFailure(jit.branch32(MacroAssembler::AboveOrEqual, SpecializedThunkJIT::regT1, SpecializedThunkJIT::regT2));
53
54 // Load the character
6fe7ccc8
A
55 SpecializedThunkJIT::JumpList is16Bit;
56 SpecializedThunkJIT::JumpList cont8Bit;
57 // Load the string flags
58 jit.loadPtr(MacroAssembler::Address(SpecializedThunkJIT::regT0, ThunkHelpers::stringImplFlagsOffset()), SpecializedThunkJIT::regT2);
59 jit.loadPtr(MacroAssembler::Address(SpecializedThunkJIT::regT0, ThunkHelpers::stringImplDataOffset()), SpecializedThunkJIT::regT0);
60 is16Bit.append(jit.branchTest32(MacroAssembler::Zero, SpecializedThunkJIT::regT2, MacroAssembler::TrustedImm32(ThunkHelpers::stringImpl8BitFlag())));
61 jit.load8(MacroAssembler::BaseIndex(SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT1, MacroAssembler::TimesOne, 0), SpecializedThunkJIT::regT0);
62 cont8Bit.append(jit.jump());
63 is16Bit.link(&jit);
4e4e5a6f 64 jit.load16(MacroAssembler::BaseIndex(SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT1, MacroAssembler::TimesTwo, 0), SpecializedThunkJIT::regT0);
6fe7ccc8 65 cont8Bit.link(&jit);
4e4e5a6f
A
66}
67
68static void charToString(SpecializedThunkJIT& jit, JSGlobalData* globalData, MacroAssembler::RegisterID src, MacroAssembler::RegisterID dst, MacroAssembler::RegisterID scratch)
69{
14957cd0
A
70 jit.appendFailure(jit.branch32(MacroAssembler::AboveOrEqual, src, MacroAssembler::TrustedImm32(0x100)));
71 jit.move(MacroAssembler::TrustedImmPtr(globalData->smallStrings.singleCharacterStrings()), scratch);
4e4e5a6f
A
72 jit.loadPtr(MacroAssembler::BaseIndex(scratch, src, MacroAssembler::ScalePtr, 0), dst);
73 jit.appendFailure(jit.branchTestPtr(MacroAssembler::Zero, dst));
74}
75
6fe7ccc8 76MacroAssemblerCodeRef charCodeAtThunkGenerator(JSGlobalData* globalData)
4e4e5a6f 77{
6fe7ccc8 78 SpecializedThunkJIT jit(1, globalData);
4e4e5a6f
A
79 stringCharLoad(jit);
80 jit.returnInt32(SpecializedThunkJIT::regT0);
14957cd0 81 return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall());
4e4e5a6f
A
82}
83
6fe7ccc8 84MacroAssemblerCodeRef charAtThunkGenerator(JSGlobalData* globalData)
4e4e5a6f 85{
6fe7ccc8 86 SpecializedThunkJIT jit(1, globalData);
4e4e5a6f
A
87 stringCharLoad(jit);
88 charToString(jit, globalData, SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT1);
89 jit.returnJSCell(SpecializedThunkJIT::regT0);
14957cd0 90 return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall());
4e4e5a6f
A
91}
92
6fe7ccc8 93MacroAssemblerCodeRef fromCharCodeThunkGenerator(JSGlobalData* globalData)
4e4e5a6f 94{
6fe7ccc8 95 SpecializedThunkJIT jit(1, globalData);
4e4e5a6f
A
96 // load char code
97 jit.loadInt32Argument(0, SpecializedThunkJIT::regT0);
98 charToString(jit, globalData, SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT0, SpecializedThunkJIT::regT1);
99 jit.returnJSCell(SpecializedThunkJIT::regT0);
14957cd0 100 return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall());
4e4e5a6f
A
101}
102
6fe7ccc8 103MacroAssemblerCodeRef sqrtThunkGenerator(JSGlobalData* globalData)
4e4e5a6f 104{
6fe7ccc8 105 SpecializedThunkJIT jit(1, globalData);
4e4e5a6f 106 if (!jit.supportsFloatingPointSqrt())
6fe7ccc8 107 return MacroAssemblerCodeRef::createSelfManagedCodeRef(globalData->jitStubs->ctiNativeCall());
4e4e5a6f
A
108
109 jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);
110 jit.sqrtDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT0);
111 jit.returnDouble(SpecializedThunkJIT::fpRegT0);
14957cd0 112 return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall());
4e4e5a6f
A
113}
114
6fe7ccc8
A
115
116#define UnaryDoubleOpWrapper(function) function##Wrapper
117enum MathThunkCallingConvention { };
118typedef MathThunkCallingConvention(*MathThunk)(MathThunkCallingConvention);
119extern "C" {
120
121double jsRound(double);
122double jsRound(double d)
123{
124 double integer = ceil(d);
125 return integer - (integer - d > 0.5);
126}
127
128}
129
130#if CPU(X86_64) && COMPILER(GCC) && (PLATFORM(MAC) || OS(LINUX))
131
132#define defineUnaryDoubleOpWrapper(function) \
133 asm( \
134 ".text\n" \
135 ".globl " SYMBOL_STRING(function##Thunk) "\n" \
136 HIDE_SYMBOL(function##Thunk) "\n" \
137 SYMBOL_STRING(function##Thunk) ":" "\n" \
138 "call " SYMBOL_STRING_RELOCATION(function) "\n" \
139 "ret\n" \
140 );\
141 extern "C" { \
142 MathThunkCallingConvention function##Thunk(MathThunkCallingConvention); \
143 } \
144 static MathThunk UnaryDoubleOpWrapper(function) = &function##Thunk;
145
146#elif CPU(X86) && COMPILER(GCC) && (PLATFORM(MAC) || OS(LINUX))
147#define defineUnaryDoubleOpWrapper(function) \
148 asm( \
149 ".text\n" \
150 ".globl " SYMBOL_STRING(function##Thunk) "\n" \
151 HIDE_SYMBOL(function##Thunk) "\n" \
152 SYMBOL_STRING(function##Thunk) ":" "\n" \
153 "subl $8, %esp\n" \
154 "movsd %xmm0, (%esp) \n" \
155 "call " SYMBOL_STRING_RELOCATION(function) "\n" \
156 "fstpl (%esp) \n" \
157 "movsd (%esp), %xmm0 \n" \
158 "addl $8, %esp\n" \
159 "ret\n" \
160 );\
161 extern "C" { \
162 MathThunkCallingConvention function##Thunk(MathThunkCallingConvention); \
163 } \
164 static MathThunk UnaryDoubleOpWrapper(function) = &function##Thunk;
165
166#else
167
168#define defineUnaryDoubleOpWrapper(function) \
169 static MathThunk UnaryDoubleOpWrapper(function) = 0
170#endif
171
172defineUnaryDoubleOpWrapper(jsRound);
173defineUnaryDoubleOpWrapper(exp);
174defineUnaryDoubleOpWrapper(log);
175defineUnaryDoubleOpWrapper(floor);
176defineUnaryDoubleOpWrapper(ceil);
177
178MacroAssemblerCodeRef floorThunkGenerator(JSGlobalData* globalData)
179{
180 SpecializedThunkJIT jit(1, globalData);
181 MacroAssembler::Jump nonIntJump;
182 if (!UnaryDoubleOpWrapper(floor) || !jit.supportsFloatingPoint())
183 return MacroAssemblerCodeRef::createSelfManagedCodeRef(globalData->jitStubs->ctiNativeCall());
184 jit.loadInt32Argument(0, SpecializedThunkJIT::regT0, nonIntJump);
185 jit.returnInt32(SpecializedThunkJIT::regT0);
186 nonIntJump.link(&jit);
187 jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);
188 jit.callDoubleToDouble(UnaryDoubleOpWrapper(floor));
189 SpecializedThunkJIT::JumpList doubleResult;
190 jit.branchConvertDoubleToInt32(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0, doubleResult, SpecializedThunkJIT::fpRegT1);
191 jit.returnInt32(SpecializedThunkJIT::regT0);
192 doubleResult.link(&jit);
193 jit.returnDouble(SpecializedThunkJIT::fpRegT0);
194 return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall());
195}
196
197MacroAssemblerCodeRef ceilThunkGenerator(JSGlobalData* globalData)
198{
199 SpecializedThunkJIT jit(1, globalData);
200 if (!UnaryDoubleOpWrapper(ceil) || !jit.supportsFloatingPoint())
201 return MacroAssemblerCodeRef::createSelfManagedCodeRef(globalData->jitStubs->ctiNativeCall());
202 MacroAssembler::Jump nonIntJump;
203 jit.loadInt32Argument(0, SpecializedThunkJIT::regT0, nonIntJump);
204 jit.returnInt32(SpecializedThunkJIT::regT0);
205 nonIntJump.link(&jit);
206 jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);
207 jit.callDoubleToDouble(UnaryDoubleOpWrapper(ceil));
208 SpecializedThunkJIT::JumpList doubleResult;
209 jit.branchConvertDoubleToInt32(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0, doubleResult, SpecializedThunkJIT::fpRegT1);
210 jit.returnInt32(SpecializedThunkJIT::regT0);
211 doubleResult.link(&jit);
212 jit.returnDouble(SpecializedThunkJIT::fpRegT0);
213 return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall());
214}
215
4e4e5a6f
A
216static const double oneConstant = 1.0;
217static const double negativeHalfConstant = -0.5;
6fe7ccc8
A
218
219MacroAssemblerCodeRef roundThunkGenerator(JSGlobalData* globalData)
220{
221 SpecializedThunkJIT jit(1, globalData);
222 if (!UnaryDoubleOpWrapper(jsRound) || !jit.supportsFloatingPoint())
223 return MacroAssemblerCodeRef::createSelfManagedCodeRef(globalData->jitStubs->ctiNativeCall());
224 MacroAssembler::Jump nonIntJump;
225 jit.loadInt32Argument(0, SpecializedThunkJIT::regT0, nonIntJump);
226 jit.returnInt32(SpecializedThunkJIT::regT0);
227 nonIntJump.link(&jit);
228 jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);
229 jit.callDoubleToDouble(UnaryDoubleOpWrapper(jsRound));
230 SpecializedThunkJIT::JumpList doubleResult;
231 jit.branchConvertDoubleToInt32(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0, doubleResult, SpecializedThunkJIT::fpRegT1);
232 jit.returnInt32(SpecializedThunkJIT::regT0);
233 doubleResult.link(&jit);
234 jit.returnDouble(SpecializedThunkJIT::fpRegT0);
235 return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall());
236}
237
238MacroAssemblerCodeRef expThunkGenerator(JSGlobalData* globalData)
239{
240 if (!UnaryDoubleOpWrapper(exp))
241 return MacroAssemblerCodeRef::createSelfManagedCodeRef(globalData->jitStubs->ctiNativeCall());
242 SpecializedThunkJIT jit(1, globalData);
243 if (!jit.supportsFloatingPoint())
244 return MacroAssemblerCodeRef::createSelfManagedCodeRef(globalData->jitStubs->ctiNativeCall());
245 jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);
246 jit.callDoubleToDouble(UnaryDoubleOpWrapper(exp));
247 jit.returnDouble(SpecializedThunkJIT::fpRegT0);
248 return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall());
249}
250
251MacroAssemblerCodeRef logThunkGenerator(JSGlobalData* globalData)
252{
253 if (!UnaryDoubleOpWrapper(log))
254 return MacroAssemblerCodeRef::createSelfManagedCodeRef(globalData->jitStubs->ctiNativeCall());
255 SpecializedThunkJIT jit(1, globalData);
256 if (!jit.supportsFloatingPoint())
257 return MacroAssemblerCodeRef::createSelfManagedCodeRef(globalData->jitStubs->ctiNativeCall());
258 jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);
259 jit.callDoubleToDouble(UnaryDoubleOpWrapper(log));
260 jit.returnDouble(SpecializedThunkJIT::fpRegT0);
261 return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall());
262}
263
264MacroAssemblerCodeRef absThunkGenerator(JSGlobalData* globalData)
265{
266 SpecializedThunkJIT jit(1, globalData);
267 if (!jit.supportsFloatingPointAbs())
268 return MacroAssemblerCodeRef::createSelfManagedCodeRef(globalData->jitStubs->ctiNativeCall());
269 MacroAssembler::Jump nonIntJump;
270 jit.loadInt32Argument(0, SpecializedThunkJIT::regT0, nonIntJump);
271 jit.rshift32(SpecializedThunkJIT::regT0, MacroAssembler::TrustedImm32(31), SpecializedThunkJIT::regT1);
272 jit.add32(SpecializedThunkJIT::regT1, SpecializedThunkJIT::regT0);
273 jit.xor32(SpecializedThunkJIT::regT1, SpecializedThunkJIT::regT0);
274 jit.appendFailure(jit.branch32(MacroAssembler::Equal, SpecializedThunkJIT::regT0, MacroAssembler::TrustedImm32(1 << 31)));
275 jit.returnInt32(SpecializedThunkJIT::regT0);
276 nonIntJump.link(&jit);
277 // Shame about the double int conversion here.
278 jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);
279 jit.absDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT1);
280 jit.returnDouble(SpecializedThunkJIT::fpRegT1);
281 return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall());
282}
4e4e5a6f 283
6fe7ccc8 284MacroAssemblerCodeRef powThunkGenerator(JSGlobalData* globalData)
4e4e5a6f 285{
6fe7ccc8 286 SpecializedThunkJIT jit(2, globalData);
4e4e5a6f 287 if (!jit.supportsFloatingPoint())
6fe7ccc8 288 return MacroAssemblerCodeRef::createSelfManagedCodeRef(globalData->jitStubs->ctiNativeCall());
4e4e5a6f
A
289
290 jit.loadDouble(&oneConstant, SpecializedThunkJIT::fpRegT1);
291 jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);
292 MacroAssembler::Jump nonIntExponent;
293 jit.loadInt32Argument(1, SpecializedThunkJIT::regT0, nonIntExponent);
14957cd0 294 jit.appendFailure(jit.branch32(MacroAssembler::LessThan, SpecializedThunkJIT::regT0, MacroAssembler::TrustedImm32(0)));
4e4e5a6f
A
295
296 MacroAssembler::Jump exponentIsZero = jit.branchTest32(MacroAssembler::Zero, SpecializedThunkJIT::regT0);
297 MacroAssembler::Label startLoop(jit.label());
298
14957cd0 299 MacroAssembler::Jump exponentIsEven = jit.branchTest32(MacroAssembler::Zero, SpecializedThunkJIT::regT0, MacroAssembler::TrustedImm32(1));
4e4e5a6f
A
300 jit.mulDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT1);
301 exponentIsEven.link(&jit);
302 jit.mulDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT0);
14957cd0 303 jit.rshift32(MacroAssembler::TrustedImm32(1), SpecializedThunkJIT::regT0);
4e4e5a6f
A
304 jit.branchTest32(MacroAssembler::NonZero, SpecializedThunkJIT::regT0).linkTo(startLoop, &jit);
305
306 exponentIsZero.link(&jit);
14957cd0
A
307
308 {
309 SpecializedThunkJIT::JumpList doubleResult;
310 jit.branchConvertDoubleToInt32(SpecializedThunkJIT::fpRegT1, SpecializedThunkJIT::regT0, doubleResult, SpecializedThunkJIT::fpRegT0);
311 jit.returnInt32(SpecializedThunkJIT::regT0);
312 doubleResult.link(&jit);
313 jit.returnDouble(SpecializedThunkJIT::fpRegT1);
314 }
4e4e5a6f
A
315
316 if (jit.supportsFloatingPointSqrt()) {
317 nonIntExponent.link(&jit);
318 jit.loadDouble(&negativeHalfConstant, SpecializedThunkJIT::fpRegT3);
319 jit.loadDoubleArgument(1, SpecializedThunkJIT::fpRegT2, SpecializedThunkJIT::regT0);
320 jit.appendFailure(jit.branchDouble(MacroAssembler::DoubleLessThanOrEqual, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT1));
321 jit.appendFailure(jit.branchDouble(MacroAssembler::DoubleNotEqualOrUnordered, SpecializedThunkJIT::fpRegT2, SpecializedThunkJIT::fpRegT3));
322 jit.sqrtDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT0);
323 jit.divDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT1);
14957cd0
A
324
325 SpecializedThunkJIT::JumpList doubleResult;
326 jit.branchConvertDoubleToInt32(SpecializedThunkJIT::fpRegT1, SpecializedThunkJIT::regT0, doubleResult, SpecializedThunkJIT::fpRegT0);
327 jit.returnInt32(SpecializedThunkJIT::regT0);
328 doubleResult.link(&jit);
4e4e5a6f
A
329 jit.returnDouble(SpecializedThunkJIT::fpRegT1);
330 } else
331 jit.appendFailure(nonIntExponent);
332
14957cd0 333 return jit.finalize(*globalData, globalData->jitStubs->ctiNativeCall());
4e4e5a6f
A
334}
335
336}
337
338#endif // ENABLE(JIT)