2 * Copyright (C) 2010 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "ThunkGenerators.h"
29 #include "CodeBlock.h"
30 #include <wtf/InlineASM.h>
31 #include "SpecializedThunkJIT.h"
32 #include <wtf/text/StringImpl.h>
38 static void stringCharLoad(SpecializedThunkJIT
& jit
)
41 jit
.loadJSStringArgument(SpecializedThunkJIT::ThisArgument
, SpecializedThunkJIT::regT0
);
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
);
46 jit
.appendFailure(jit
.branchTest32(MacroAssembler::Zero
, SpecializedThunkJIT::regT0
));
49 jit
.loadInt32Argument(0, SpecializedThunkJIT::regT1
); // regT1 contains the index
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
));
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());
64 jit
.load16(MacroAssembler::BaseIndex(SpecializedThunkJIT::regT0
, SpecializedThunkJIT::regT1
, MacroAssembler::TimesTwo
, 0), SpecializedThunkJIT::regT0
);
68 static void charToString(SpecializedThunkJIT
& jit
, JSGlobalData
* globalData
, MacroAssembler::RegisterID src
, MacroAssembler::RegisterID dst
, MacroAssembler::RegisterID scratch
)
70 jit
.appendFailure(jit
.branch32(MacroAssembler::AboveOrEqual
, src
, MacroAssembler::TrustedImm32(0x100)));
71 jit
.move(MacroAssembler::TrustedImmPtr(globalData
->smallStrings
.singleCharacterStrings()), scratch
);
72 jit
.loadPtr(MacroAssembler::BaseIndex(scratch
, src
, MacroAssembler::ScalePtr
, 0), dst
);
73 jit
.appendFailure(jit
.branchTestPtr(MacroAssembler::Zero
, dst
));
76 MacroAssemblerCodeRef
charCodeAtThunkGenerator(JSGlobalData
* globalData
)
78 SpecializedThunkJIT
jit(1, globalData
);
80 jit
.returnInt32(SpecializedThunkJIT::regT0
);
81 return jit
.finalize(*globalData
, globalData
->jitStubs
->ctiNativeCall());
84 MacroAssemblerCodeRef
charAtThunkGenerator(JSGlobalData
* globalData
)
86 SpecializedThunkJIT
jit(1, globalData
);
88 charToString(jit
, globalData
, SpecializedThunkJIT::regT0
, SpecializedThunkJIT::regT0
, SpecializedThunkJIT::regT1
);
89 jit
.returnJSCell(SpecializedThunkJIT::regT0
);
90 return jit
.finalize(*globalData
, globalData
->jitStubs
->ctiNativeCall());
93 MacroAssemblerCodeRef
fromCharCodeThunkGenerator(JSGlobalData
* globalData
)
95 SpecializedThunkJIT
jit(1, globalData
);
97 jit
.loadInt32Argument(0, SpecializedThunkJIT::regT0
);
98 charToString(jit
, globalData
, SpecializedThunkJIT::regT0
, SpecializedThunkJIT::regT0
, SpecializedThunkJIT::regT1
);
99 jit
.returnJSCell(SpecializedThunkJIT::regT0
);
100 return jit
.finalize(*globalData
, globalData
->jitStubs
->ctiNativeCall());
103 MacroAssemblerCodeRef
sqrtThunkGenerator(JSGlobalData
* globalData
)
105 SpecializedThunkJIT
jit(1, globalData
);
106 if (!jit
.supportsFloatingPointSqrt())
107 return MacroAssemblerCodeRef::createSelfManagedCodeRef(globalData
->jitStubs
->ctiNativeCall());
109 jit
.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0
, SpecializedThunkJIT::regT0
);
110 jit
.sqrtDouble(SpecializedThunkJIT::fpRegT0
, SpecializedThunkJIT::fpRegT0
);
111 jit
.returnDouble(SpecializedThunkJIT::fpRegT0
);
112 return jit
.finalize(*globalData
, globalData
->jitStubs
->ctiNativeCall());
116 #define UnaryDoubleOpWrapper(function) function##Wrapper
117 enum MathThunkCallingConvention
{ };
118 typedef MathThunkCallingConvention(*MathThunk
)(MathThunkCallingConvention
);
121 double jsRound(double);
122 double jsRound(double d
)
124 double integer
= ceil(d
);
125 return integer
- (integer
- d
> 0.5);
130 #if CPU(X86_64) && COMPILER(GCC) && (PLATFORM(MAC) || OS(LINUX))
132 #define defineUnaryDoubleOpWrapper(function) \
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" \
142 MathThunkCallingConvention function##Thunk(MathThunkCallingConvention); \
144 static MathThunk UnaryDoubleOpWrapper(function) = &function##Thunk;
146 #elif CPU(X86) && COMPILER(GCC) && (PLATFORM(MAC) || OS(LINUX))
147 #define defineUnaryDoubleOpWrapper(function) \
150 ".globl " SYMBOL_STRING(function##Thunk) "\n" \
151 HIDE_SYMBOL(function##Thunk) "\n" \
152 SYMBOL_STRING(function##Thunk) ":" "\n" \
154 "movsd %xmm0, (%esp) \n" \
155 "call " SYMBOL_STRING_RELOCATION(function) "\n" \
157 "movsd (%esp), %xmm0 \n" \
162 MathThunkCallingConvention function##Thunk(MathThunkCallingConvention); \
164 static MathThunk UnaryDoubleOpWrapper(function) = &function##Thunk;
168 #define defineUnaryDoubleOpWrapper(function) \
169 static MathThunk UnaryDoubleOpWrapper(function) = 0
172 defineUnaryDoubleOpWrapper(jsRound
);
173 defineUnaryDoubleOpWrapper(exp
);
174 defineUnaryDoubleOpWrapper(log
);
175 defineUnaryDoubleOpWrapper(floor
);
176 defineUnaryDoubleOpWrapper(ceil
);
178 MacroAssemblerCodeRef
floorThunkGenerator(JSGlobalData
* globalData
)
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());
197 MacroAssemblerCodeRef
ceilThunkGenerator(JSGlobalData
* globalData
)
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());
216 static const double oneConstant
= 1.0;
217 static const double negativeHalfConstant
= -0.5;
219 MacroAssemblerCodeRef
roundThunkGenerator(JSGlobalData
* globalData
)
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());
238 MacroAssemblerCodeRef
expThunkGenerator(JSGlobalData
* globalData
)
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());
251 MacroAssemblerCodeRef
logThunkGenerator(JSGlobalData
* globalData
)
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());
264 MacroAssemblerCodeRef
absThunkGenerator(JSGlobalData
* globalData
)
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());
284 MacroAssemblerCodeRef
powThunkGenerator(JSGlobalData
* globalData
)
286 SpecializedThunkJIT
jit(2, globalData
);
287 if (!jit
.supportsFloatingPoint())
288 return MacroAssemblerCodeRef::createSelfManagedCodeRef(globalData
->jitStubs
->ctiNativeCall());
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
);
294 jit
.appendFailure(jit
.branch32(MacroAssembler::LessThan
, SpecializedThunkJIT::regT0
, MacroAssembler::TrustedImm32(0)));
296 MacroAssembler::Jump exponentIsZero
= jit
.branchTest32(MacroAssembler::Zero
, SpecializedThunkJIT::regT0
);
297 MacroAssembler::Label
startLoop(jit
.label());
299 MacroAssembler::Jump exponentIsEven
= jit
.branchTest32(MacroAssembler::Zero
, SpecializedThunkJIT::regT0
, MacroAssembler::TrustedImm32(1));
300 jit
.mulDouble(SpecializedThunkJIT::fpRegT0
, SpecializedThunkJIT::fpRegT1
);
301 exponentIsEven
.link(&jit
);
302 jit
.mulDouble(SpecializedThunkJIT::fpRegT0
, SpecializedThunkJIT::fpRegT0
);
303 jit
.rshift32(MacroAssembler::TrustedImm32(1), SpecializedThunkJIT::regT0
);
304 jit
.branchTest32(MacroAssembler::NonZero
, SpecializedThunkJIT::regT0
).linkTo(startLoop
, &jit
);
306 exponentIsZero
.link(&jit
);
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
);
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
);
325 SpecializedThunkJIT::JumpList doubleResult
;
326 jit
.branchConvertDoubleToInt32(SpecializedThunkJIT::fpRegT1
, SpecializedThunkJIT::regT0
, doubleResult
, SpecializedThunkJIT::fpRegT0
);
327 jit
.returnInt32(SpecializedThunkJIT::regT0
);
328 doubleResult
.link(&jit
);
329 jit
.returnDouble(SpecializedThunkJIT::fpRegT1
);
331 jit
.appendFailure(nonIntExponent
);
333 return jit
.finalize(*globalData
, globalData
->jitStubs
->ctiNativeCall());
338 #endif // ENABLE(JIT)