source: webkit/trunk/JavaScriptCore/jit/JITArithmetic.cpp@ 39020

Last change on this file since 39020 was 39020, checked in by [email protected], 16 years ago

2008-12-04 Gavin Barraclough <[email protected]>

Reviewed by Geoff Garen.

Start porting the JIT to use the MacroAssembler.

https://bugs.webkit.org/show_bug.cgi?id=22671
No change in performance.

  • assembler/MacroAssembler.h: (JSC::MacroAssembler::Jump::operator X86Assembler::JmpSrc): (JSC::MacroAssembler::add32): (JSC::MacroAssembler::and32): (JSC::MacroAssembler::lshift32): (JSC::MacroAssembler::rshift32): (JSC::MacroAssembler::storePtr): (JSC::MacroAssembler::store32): (JSC::MacroAssembler::poke): (JSC::MacroAssembler::move): (JSC::MacroAssembler::compareImm32ForBranchEquality): (JSC::MacroAssembler::jnePtr): (JSC::MacroAssembler::jnset32): (JSC::MacroAssembler::jset32): (JSC::MacroAssembler::jzeroSub32): (JSC::MacroAssembler::joverAdd32): (JSC::MacroAssembler::call):
  • assembler/X86Assembler.h: (JSC::X86Assembler::shll_i8r):
  • jit/JIT.cpp: (JSC::JIT::privateCompileMainPass): (JSC::JIT::privateCompile): (JSC::JIT::privateCompileCTIMachineTrampolines):
  • jit/JIT.h:
  • jit/JITArithmetic.cpp: (JSC::JIT::compileBinaryArithOp):
  • jit/JITInlineMethods.h: (JSC::JIT::emitGetVirtualRegister): (JSC::JIT::emitPutCTIArg): (JSC::JIT::emitPutCTIArgConstant): (JSC::JIT::emitGetCTIArg): (JSC::JIT::emitPutCTIArgFromVirtualRegister): (JSC::JIT::emitPutCTIParam): (JSC::JIT::emitGetCTIParam): (JSC::JIT::emitPutToCallFrameHeader): (JSC::JIT::emitPutImmediateToCallFrameHeader): (JSC::JIT::emitGetFromCallFrameHeader): (JSC::JIT::emitPutVirtualRegister): (JSC::JIT::emitInitRegister): (JSC::JIT::emitNakedCall): (JSC::JIT::restoreArgumentReference): (JSC::JIT::restoreArgumentReferenceForTrampoline): (JSC::JIT::emitCTICall): (JSC::JIT::checkStructure): (JSC::JIT::emitJumpSlowCaseIfNotJSCell): (JSC::JIT::emitJumpSlowCaseIfNotImmNum): (JSC::JIT::emitJumpSlowCaseIfNotImmNums): (JSC::JIT::emitFastArithDeTagImmediate): (JSC::JIT::emitFastArithDeTagImmediateJumpIfZero): (JSC::JIT::emitFastArithReTagImmediate): (JSC::JIT::emitFastArithPotentiallyReTagImmediate): (JSC::JIT::emitFastArithImmToInt): (JSC::JIT::emitFastArithIntToImmOrSlowCase): (JSC::JIT::emitFastArithIntToImmNoCheck): (JSC::JIT::emitTagAsBoolImmediate):
  • jit/JITPropertyAccess.cpp: (JSC::JIT::privateCompilePutByIdTransition):
File size: 13.6 KB
Line 
1/*
2 * Copyright (C) 2008 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. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "JIT.h"
28
29#if ENABLE(JIT)
30
31#include "CodeBlock.h"
32#include "JITInlineMethods.h"
33#include "JSArray.h"
34#include "JSFunction.h"
35#include "Interpreter.h"
36#include "ResultType.h"
37#include "SamplingTool.h"
38
39#ifndef NDEBUG
40#include <stdio.h>
41#endif
42
43using namespace std;
44
45namespace JSC {
46
47#if !ENABLE(JIT_OPTIMIZE_ARITHMETIC)
48
49void JIT::compileBinaryArithOp(OpcodeID opcodeID, unsigned dst, unsigned src1, unsigned src2, OperandTypes, unsigned i)
50{
51 emitPutCTIArgFromVirtualRegister(src1, 0, X86::ecx);
52 emitPutCTIArgFromVirtualRegister(src2, 4, X86::ecx);
53 if (opcodeID == op_add)
54 emitCTICall(i, Interpreter::cti_op_add);
55 else if (opcodeID == op_sub)
56 emitCTICall(i, Interpreter::cti_op_sub);
57 else {
58 ASSERT(opcodeID == op_mul);
59 emitCTICall(i, Interpreter::cti_op_mul);
60 }
61 emitPutVirtualRegister(dst);
62}
63
64void JIT::compileBinaryArithOpSlowCase(OpcodeID, Vector<SlowCaseEntry>::iterator&, unsigned, unsigned, unsigned, OperandTypes, unsigned)
65{
66 ASSERT_NOT_REACHED();
67}
68
69#else
70
71#if PLATFORM(MAC)
72
73static inline bool isSSE2Present()
74{
75 return true; // All X86 Macs are guaranteed to support at least SSE2
76}
77
78#else
79
80static bool isSSE2Present()
81{
82 static const int SSE2FeatureBit = 1 << 26;
83 struct SSE2Check {
84 SSE2Check()
85 {
86 int flags;
87#if COMPILER(MSVC)
88 _asm {
89 mov eax, 1 // cpuid function 1 gives us the standard feature set
90 cpuid;
91 mov flags, edx;
92 }
93#else
94 flags = 0;
95 // FIXME: Add GCC code to do above asm
96#endif
97 present = (flags & SSE2FeatureBit) != 0;
98 }
99 bool present;
100 };
101 static SSE2Check check;
102 return check.present;
103}
104
105#endif
106
107/*
108 This is required since number representation is canonical - values representable as a JSImmediate should not be stored in a JSNumberCell.
109
110 In the common case, the double value from 'xmmSource' is written to the reusable JSNumberCell pointed to by 'jsNumberCell', then 'jsNumberCell'
111 is written to the output SF Register 'dst', and then a jump is planted (stored into *wroteJSNumberCell).
112
113 However if the value from xmmSource is representable as a JSImmediate, then the JSImmediate value will be written to the output, and flow
114 control will fall through from the code planted.
115*/
116void JIT::putDoubleResultToJSNumberCellOrJSImmediate(X86::XMMRegisterID xmmSource, X86::RegisterID jsNumberCell, unsigned dst, JmpSrc* wroteJSNumberCell, X86::XMMRegisterID tempXmm, X86::RegisterID tempReg1, X86::RegisterID tempReg2)
117{
118 // convert (double -> JSImmediate -> double), and check if the value is unchanged - in which case the value is representable as a JSImmediate.
119 __ cvttsd2si_rr(xmmSource, tempReg1);
120 __ addl_rr(tempReg1, tempReg1);
121 __ sarl_i8r(1, tempReg1);
122 __ cvtsi2sd_rr(tempReg1, tempXmm);
123 // Compare & branch if immediate.
124 __ ucomis_rr(tempXmm, xmmSource);
125 JmpSrc resultIsImm = __ je();
126 JmpDst resultLookedLikeImmButActuallyIsnt = __ label();
127
128 // Store the result to the JSNumberCell and jump.
129 __ movsd_rm(xmmSource, FIELD_OFFSET(JSNumberCell, m_value), jsNumberCell);
130 if (jsNumberCell != X86::eax)
131 __ movl_rr(jsNumberCell, X86::eax);
132 emitPutVirtualRegister(dst);
133 *wroteJSNumberCell = __ jmp();
134
135 __ link(resultIsImm, __ label());
136 // value == (double)(JSImmediate)value... or at least, it looks that way...
137 // ucomi will report that (0 == -0), and will report true if either input in NaN (result is unordered).
138 __ link(__ jp(), resultLookedLikeImmButActuallyIsnt); // Actually was a NaN
139 __ pextrw_irr(3, xmmSource, tempReg2);
140 __ cmpl_i32r(0x8000, tempReg2);
141 __ link(__ je(), resultLookedLikeImmButActuallyIsnt); // Actually was -0
142 // Yes it really really really is representable as a JSImmediate.
143 emitFastArithIntToImmNoCheck(tempReg1);
144 if (tempReg1 != X86::eax)
145 __ movl_rr(tempReg1, X86::eax);
146 emitPutVirtualRegister(dst);
147}
148
149void JIT::compileBinaryArithOp(OpcodeID opcodeID, unsigned dst, unsigned src1, unsigned src2, OperandTypes types, unsigned i)
150{
151 Structure* numberStructure = m_globalData->numberStructure.get();
152 JmpSrc wasJSNumberCell1;
153 JmpSrc wasJSNumberCell1b;
154 JmpSrc wasJSNumberCell2;
155 JmpSrc wasJSNumberCell2b;
156
157 emitGetVirtualRegisters(src1, X86::eax, src2, X86::edx, i);
158
159 if (types.second().isReusable() && isSSE2Present()) {
160 ASSERT(types.second().mightBeNumber());
161
162 // Check op2 is a number
163 __ testl_i32r(JSImmediate::TagBitTypeInteger, X86::edx);
164 JmpSrc op2imm = __ jne();
165 if (!types.second().definitelyIsNumber()) {
166 emitJumpSlowCaseIfNotJSCell(X86::edx, i, src2);
167 __ cmpl_i32m(reinterpret_cast<unsigned>(numberStructure), FIELD_OFFSET(JSCell, m_structure), X86::edx);
168 m_slowCases.append(SlowCaseEntry(__ jne(), i));
169 }
170
171 // (1) In this case src2 is a reusable number cell.
172 // Slow case if src1 is not a number type.
173 __ testl_i32r(JSImmediate::TagBitTypeInteger, X86::eax);
174 JmpSrc op1imm = __ jne();
175 if (!types.first().definitelyIsNumber()) {
176 emitJumpSlowCaseIfNotJSCell(X86::eax, i, src1);
177 __ cmpl_i32m(reinterpret_cast<unsigned>(numberStructure), FIELD_OFFSET(JSCell, m_structure), X86::eax);
178 m_slowCases.append(SlowCaseEntry(__ jne(), i));
179 }
180
181 // (1a) if we get here, src1 is also a number cell
182 __ movsd_mr(FIELD_OFFSET(JSNumberCell, m_value), X86::eax, X86::xmm0);
183 JmpSrc loadedDouble = __ jmp();
184 // (1b) if we get here, src1 is an immediate
185 __ link(op1imm, __ label());
186 emitFastArithImmToInt(X86::eax);
187 __ cvtsi2sd_rr(X86::eax, X86::xmm0);
188 // (1c)
189 __ link(loadedDouble, __ label());
190 if (opcodeID == op_add)
191 __ addsd_mr(FIELD_OFFSET(JSNumberCell, m_value), X86::edx, X86::xmm0);
192 else if (opcodeID == op_sub)
193 __ subsd_mr(FIELD_OFFSET(JSNumberCell, m_value), X86::edx, X86::xmm0);
194 else {
195 ASSERT(opcodeID == op_mul);
196 __ mulsd_mr(FIELD_OFFSET(JSNumberCell, m_value), X86::edx, X86::xmm0);
197 }
198
199 putDoubleResultToJSNumberCellOrJSImmediate(X86::xmm0, X86::edx, dst, &wasJSNumberCell2, X86::xmm1, X86::ecx, X86::eax);
200 wasJSNumberCell2b = __ jmp();
201
202 // (2) This handles cases where src2 is an immediate number.
203 // Two slow cases - either src1 isn't an immediate, or the subtract overflows.
204 __ link(op2imm, __ label());
205 emitJumpSlowCaseIfNotImmNum(X86::eax, i);
206 } else if (types.first().isReusable() && isSSE2Present()) {
207 ASSERT(types.first().mightBeNumber());
208
209 // Check op1 is a number
210 __ testl_i32r(JSImmediate::TagBitTypeInteger, X86::eax);
211 JmpSrc op1imm = __ jne();
212 if (!types.first().definitelyIsNumber()) {
213 emitJumpSlowCaseIfNotJSCell(X86::eax, i, src1);
214 __ cmpl_i32m(reinterpret_cast<unsigned>(numberStructure), FIELD_OFFSET(JSCell, m_structure), X86::eax);
215 m_slowCases.append(SlowCaseEntry(__ jne(), i));
216 }
217
218 // (1) In this case src1 is a reusable number cell.
219 // Slow case if src2 is not a number type.
220 __ testl_i32r(JSImmediate::TagBitTypeInteger, X86::edx);
221 JmpSrc op2imm = __ jne();
222 if (!types.second().definitelyIsNumber()) {
223 emitJumpSlowCaseIfNotJSCell(X86::edx, i, src2);
224 __ cmpl_i32m(reinterpret_cast<unsigned>(numberStructure), FIELD_OFFSET(JSCell, m_structure), X86::edx);
225 m_slowCases.append(SlowCaseEntry(__ jne(), i));
226 }
227
228 // (1a) if we get here, src2 is also a number cell
229 __ movsd_mr(FIELD_OFFSET(JSNumberCell, m_value), X86::edx, X86::xmm1);
230 JmpSrc loadedDouble = __ jmp();
231 // (1b) if we get here, src2 is an immediate
232 __ link(op2imm, __ label());
233 emitFastArithImmToInt(X86::edx);
234 __ cvtsi2sd_rr(X86::edx, X86::xmm1);
235 // (1c)
236 __ link(loadedDouble, __ label());
237 __ movsd_mr(FIELD_OFFSET(JSNumberCell, m_value), X86::eax, X86::xmm0);
238 if (opcodeID == op_add)
239 __ addsd_rr(X86::xmm1, X86::xmm0);
240 else if (opcodeID == op_sub)
241 __ subsd_rr(X86::xmm1, X86::xmm0);
242 else {
243 ASSERT(opcodeID == op_mul);
244 __ mulsd_rr(X86::xmm1, X86::xmm0);
245 }
246 __ movsd_rm(X86::xmm0, FIELD_OFFSET(JSNumberCell, m_value), X86::eax);
247 emitPutVirtualRegister(dst);
248
249 putDoubleResultToJSNumberCellOrJSImmediate(X86::xmm0, X86::eax, dst, &wasJSNumberCell1, X86::xmm1, X86::ecx, X86::edx);
250 wasJSNumberCell1b = __ jmp();
251
252 // (2) This handles cases where src1 is an immediate number.
253 // Two slow cases - either src2 isn't an immediate, or the subtract overflows.
254 __ link(op1imm, __ label());
255 emitJumpSlowCaseIfNotImmNum(X86::edx, i);
256 } else
257 emitJumpSlowCaseIfNotImmNums(X86::eax, X86::edx, X86::ecx, i);
258
259 if (opcodeID == op_add) {
260 emitFastArithDeTagImmediate(X86::eax);
261 __ addl_rr(X86::edx, X86::eax);
262 m_slowCases.append(SlowCaseEntry(__ jo(), i));
263 } else if (opcodeID == op_sub) {
264 __ subl_rr(X86::edx, X86::eax);
265 m_slowCases.append(SlowCaseEntry(__ jo(), i));
266 emitFastArithReTagImmediate(X86::eax);
267 } else {
268 ASSERT(opcodeID == op_mul);
269 // convert eax & edx from JSImmediates to ints, and check if either are zero
270 emitFastArithImmToInt(X86::edx);
271 JmpSrc op1Zero = emitFastArithDeTagImmediateJumpIfZero(X86::eax);
272 __ testl_rr(X86::edx, X86::edx);
273 JmpSrc op2NonZero = __ jne();
274 __ link(op1Zero, __ label());
275 // if either input is zero, add the two together, and check if the result is < 0.
276 // If it is, we have a problem (N < 0), (N * 0) == -0, not representatble as a JSImmediate.
277 __ movl_rr(X86::eax, X86::ecx);
278 __ addl_rr(X86::edx, X86::ecx);
279 m_slowCases.append(SlowCaseEntry(__ js(), i));
280 // Skip the above check if neither input is zero
281 __ link(op2NonZero, __ label());
282 __ imull_rr(X86::edx, X86::eax);
283 m_slowCases.append(SlowCaseEntry(__ jo(), i));
284 emitFastArithReTagImmediate(X86::eax);
285 }
286 emitPutVirtualRegister(dst);
287
288 if (types.second().isReusable() && isSSE2Present()) {
289 __ link(wasJSNumberCell2, __ label());
290 __ link(wasJSNumberCell2b, __ label());
291 }
292 else if (types.first().isReusable() && isSSE2Present()) {
293 __ link(wasJSNumberCell1, __ label());
294 __ link(wasJSNumberCell1b, __ label());
295 }
296}
297
298void JIT::compileBinaryArithOpSlowCase(OpcodeID opcodeID, Vector<SlowCaseEntry>::iterator& iter, unsigned dst, unsigned src1, unsigned src2, OperandTypes types, unsigned i)
299{
300 JmpDst here = __ label();
301 __ link(iter->from, here);
302 if (types.second().isReusable() && isSSE2Present()) {
303 if (!types.first().definitelyIsNumber()) {
304 if (linkSlowCaseIfNotJSCell(++iter, src1))
305 ++iter;
306 __ link(iter->from, here);
307 }
308 if (!types.second().definitelyIsNumber()) {
309 if (linkSlowCaseIfNotJSCell(++iter, src2))
310 ++iter;
311 __ link(iter->from, here);
312 }
313 __ link((++iter)->from, here);
314 } else if (types.first().isReusable() && isSSE2Present()) {
315 if (!types.first().definitelyIsNumber()) {
316 if (linkSlowCaseIfNotJSCell(++iter, src1))
317 ++iter;
318 __ link(iter->from, here);
319 }
320 if (!types.second().definitelyIsNumber()) {
321 if (linkSlowCaseIfNotJSCell(++iter, src2))
322 ++iter;
323 __ link(iter->from, here);
324 }
325 __ link((++iter)->from, here);
326 } else
327 __ link((++iter)->from, here);
328
329 // additional entry point to handle -0 cases.
330 if (opcodeID == op_mul)
331 __ link((++iter)->from, here);
332
333 emitPutCTIArgFromVirtualRegister(src1, 0, X86::ecx);
334 emitPutCTIArgFromVirtualRegister(src2, 4, X86::ecx);
335 if (opcodeID == op_add)
336 emitCTICall(i, Interpreter::cti_op_add);
337 else if (opcodeID == op_sub)
338 emitCTICall(i, Interpreter::cti_op_sub);
339 else {
340 ASSERT(opcodeID == op_mul);
341 emitCTICall(i, Interpreter::cti_op_mul);
342 }
343 emitPutVirtualRegister(dst);
344}
345
346#endif
347
348} // namespace JSC
349
350#endif // ENABLE(JIT)
Note: See TracBrowser for help on using the repository browser.