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