]>
Commit | Line | Data |
---|---|---|
9dae56ea A |
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 | |
4e4e5a6f | 23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
9dae56ea A |
24 | */ |
25 | ||
26 | #include "config.h" | |
9dae56ea A |
27 | |
28 | #if ENABLE(JIT) | |
14957cd0 | 29 | #include "JIT.h" |
9dae56ea A |
30 | |
31 | #include "CodeBlock.h" | |
93a37866 | 32 | #include "JITInlines.h" |
81345200 | 33 | #include "JITOperations.h" |
4e4e5a6f | 34 | #include "JITStubs.h" |
9dae56ea A |
35 | #include "JSArray.h" |
36 | #include "JSFunction.h" | |
37 | #include "Interpreter.h" | |
81345200 | 38 | #include "JSCInlines.h" |
9dae56ea A |
39 | #include "ResultType.h" |
40 | #include "SamplingTool.h" | |
81345200 | 41 | #include "SlowPathCall.h" |
9dae56ea | 42 | |
ba379fdc A |
43 | |
44 | namespace JSC { | |
45 | ||
6fe7ccc8 A |
46 | void JIT::emit_op_jless(Instruction* currentInstruction) |
47 | { | |
81345200 A |
48 | int op1 = currentInstruction[1].u.operand; |
49 | int op2 = currentInstruction[2].u.operand; | |
6fe7ccc8 A |
50 | unsigned target = currentInstruction[3].u.operand; |
51 | ||
52 | emit_compareAndJump(op_jless, op1, op2, target, LessThan); | |
53 | } | |
54 | ||
55 | void JIT::emit_op_jlesseq(Instruction* currentInstruction) | |
56 | { | |
81345200 A |
57 | int op1 = currentInstruction[1].u.operand; |
58 | int op2 = currentInstruction[2].u.operand; | |
6fe7ccc8 A |
59 | unsigned target = currentInstruction[3].u.operand; |
60 | ||
61 | emit_compareAndJump(op_jlesseq, op1, op2, target, LessThanOrEqual); | |
62 | } | |
63 | ||
64 | void JIT::emit_op_jgreater(Instruction* currentInstruction) | |
65 | { | |
81345200 A |
66 | int op1 = currentInstruction[1].u.operand; |
67 | int op2 = currentInstruction[2].u.operand; | |
6fe7ccc8 A |
68 | unsigned target = currentInstruction[3].u.operand; |
69 | ||
70 | emit_compareAndJump(op_jgreater, op1, op2, target, GreaterThan); | |
71 | } | |
72 | ||
73 | void JIT::emit_op_jgreatereq(Instruction* currentInstruction) | |
74 | { | |
81345200 A |
75 | int op1 = currentInstruction[1].u.operand; |
76 | int op2 = currentInstruction[2].u.operand; | |
6fe7ccc8 A |
77 | unsigned target = currentInstruction[3].u.operand; |
78 | ||
79 | emit_compareAndJump(op_jgreatereq, op1, op2, target, GreaterThanOrEqual); | |
80 | } | |
81 | ||
82 | void JIT::emit_op_jnless(Instruction* currentInstruction) | |
83 | { | |
81345200 A |
84 | int op1 = currentInstruction[1].u.operand; |
85 | int op2 = currentInstruction[2].u.operand; | |
6fe7ccc8 A |
86 | unsigned target = currentInstruction[3].u.operand; |
87 | ||
88 | emit_compareAndJump(op_jnless, op1, op2, target, GreaterThanOrEqual); | |
89 | } | |
90 | ||
91 | void JIT::emit_op_jnlesseq(Instruction* currentInstruction) | |
92 | { | |
81345200 A |
93 | int op1 = currentInstruction[1].u.operand; |
94 | int op2 = currentInstruction[2].u.operand; | |
6fe7ccc8 A |
95 | unsigned target = currentInstruction[3].u.operand; |
96 | ||
97 | emit_compareAndJump(op_jnlesseq, op1, op2, target, GreaterThan); | |
98 | } | |
99 | ||
100 | void JIT::emit_op_jngreater(Instruction* currentInstruction) | |
101 | { | |
81345200 A |
102 | int op1 = currentInstruction[1].u.operand; |
103 | int op2 = currentInstruction[2].u.operand; | |
6fe7ccc8 A |
104 | unsigned target = currentInstruction[3].u.operand; |
105 | ||
106 | emit_compareAndJump(op_jngreater, op1, op2, target, LessThanOrEqual); | |
107 | } | |
108 | ||
109 | void JIT::emit_op_jngreatereq(Instruction* currentInstruction) | |
110 | { | |
81345200 A |
111 | int op1 = currentInstruction[1].u.operand; |
112 | int op2 = currentInstruction[2].u.operand; | |
6fe7ccc8 A |
113 | unsigned target = currentInstruction[3].u.operand; |
114 | ||
115 | emit_compareAndJump(op_jngreatereq, op1, op2, target, LessThan); | |
116 | } | |
117 | ||
118 | void JIT::emitSlow_op_jless(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) | |
119 | { | |
81345200 A |
120 | int op1 = currentInstruction[1].u.operand; |
121 | int op2 = currentInstruction[2].u.operand; | |
6fe7ccc8 A |
122 | unsigned target = currentInstruction[3].u.operand; |
123 | ||
81345200 | 124 | emit_compareAndJumpSlow(op1, op2, target, DoubleLessThan, operationCompareLess, false, iter); |
6fe7ccc8 A |
125 | } |
126 | ||
127 | void JIT::emitSlow_op_jlesseq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) | |
128 | { | |
81345200 A |
129 | int op1 = currentInstruction[1].u.operand; |
130 | int op2 = currentInstruction[2].u.operand; | |
6fe7ccc8 A |
131 | unsigned target = currentInstruction[3].u.operand; |
132 | ||
81345200 | 133 | emit_compareAndJumpSlow(op1, op2, target, DoubleLessThanOrEqual, operationCompareLessEq, false, iter); |
6fe7ccc8 A |
134 | } |
135 | ||
136 | void JIT::emitSlow_op_jgreater(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) | |
137 | { | |
81345200 A |
138 | int op1 = currentInstruction[1].u.operand; |
139 | int op2 = currentInstruction[2].u.operand; | |
6fe7ccc8 A |
140 | unsigned target = currentInstruction[3].u.operand; |
141 | ||
81345200 | 142 | emit_compareAndJumpSlow(op1, op2, target, DoubleGreaterThan, operationCompareGreater, false, iter); |
6fe7ccc8 A |
143 | } |
144 | ||
145 | void JIT::emitSlow_op_jgreatereq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) | |
146 | { | |
81345200 A |
147 | int op1 = currentInstruction[1].u.operand; |
148 | int op2 = currentInstruction[2].u.operand; | |
6fe7ccc8 A |
149 | unsigned target = currentInstruction[3].u.operand; |
150 | ||
81345200 | 151 | emit_compareAndJumpSlow(op1, op2, target, DoubleGreaterThanOrEqual, operationCompareGreaterEq, false, iter); |
6fe7ccc8 A |
152 | } |
153 | ||
154 | void JIT::emitSlow_op_jnless(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) | |
155 | { | |
81345200 A |
156 | int op1 = currentInstruction[1].u.operand; |
157 | int op2 = currentInstruction[2].u.operand; | |
6fe7ccc8 A |
158 | unsigned target = currentInstruction[3].u.operand; |
159 | ||
81345200 | 160 | emit_compareAndJumpSlow(op1, op2, target, DoubleGreaterThanOrEqualOrUnordered, operationCompareLess, true, iter); |
6fe7ccc8 A |
161 | } |
162 | ||
163 | void JIT::emitSlow_op_jnlesseq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) | |
164 | { | |
81345200 A |
165 | int op1 = currentInstruction[1].u.operand; |
166 | int op2 = currentInstruction[2].u.operand; | |
6fe7ccc8 A |
167 | unsigned target = currentInstruction[3].u.operand; |
168 | ||
81345200 | 169 | emit_compareAndJumpSlow(op1, op2, target, DoubleGreaterThanOrUnordered, operationCompareLessEq, true, iter); |
6fe7ccc8 A |
170 | } |
171 | ||
172 | void JIT::emitSlow_op_jngreater(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) | |
173 | { | |
81345200 A |
174 | int op1 = currentInstruction[1].u.operand; |
175 | int op2 = currentInstruction[2].u.operand; | |
6fe7ccc8 A |
176 | unsigned target = currentInstruction[3].u.operand; |
177 | ||
81345200 | 178 | emit_compareAndJumpSlow(op1, op2, target, DoubleLessThanOrEqualOrUnordered, operationCompareGreater, true, iter); |
6fe7ccc8 A |
179 | } |
180 | ||
181 | void JIT::emitSlow_op_jngreatereq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) | |
182 | { | |
81345200 A |
183 | int op1 = currentInstruction[1].u.operand; |
184 | int op2 = currentInstruction[2].u.operand; | |
6fe7ccc8 A |
185 | unsigned target = currentInstruction[3].u.operand; |
186 | ||
81345200 | 187 | emit_compareAndJumpSlow(op1, op2, target, DoubleLessThanOrUnordered, operationCompareGreaterEq, true, iter); |
6fe7ccc8 A |
188 | } |
189 | ||
190 | #if USE(JSVALUE64) | |
191 | ||
192 | void JIT::emit_op_negate(Instruction* currentInstruction) | |
193 | { | |
81345200 A |
194 | int dst = currentInstruction[1].u.operand; |
195 | int src = currentInstruction[2].u.operand; | |
6fe7ccc8 A |
196 | |
197 | emitGetVirtualRegister(src, regT0); | |
198 | ||
199 | Jump srcNotInt = emitJumpIfNotImmediateInteger(regT0); | |
200 | addSlowCase(branchTest32(Zero, regT0, TrustedImm32(0x7fffffff))); | |
201 | neg32(regT0); | |
202 | emitFastArithReTagImmediate(regT0, regT0); | |
203 | ||
204 | Jump end = jump(); | |
205 | ||
206 | srcNotInt.link(this); | |
207 | emitJumpSlowCaseIfNotImmediateNumber(regT0); | |
208 | ||
93a37866 A |
209 | move(TrustedImm64((int64_t)0x8000000000000000ull), regT1); |
210 | xor64(regT1, regT0); | |
6fe7ccc8 A |
211 | |
212 | end.link(this); | |
213 | emitPutVirtualRegister(dst); | |
214 | } | |
215 | ||
216 | void JIT::emitSlow_op_negate(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) | |
217 | { | |
6fe7ccc8 A |
218 | linkSlowCase(iter); // 0x7fffffff check |
219 | linkSlowCase(iter); // double check | |
220 | ||
81345200 A |
221 | JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_negate); |
222 | slowPathCall.call(); | |
6fe7ccc8 A |
223 | } |
224 | ||
ba379fdc A |
225 | void JIT::emit_op_lshift(Instruction* currentInstruction) |
226 | { | |
81345200 A |
227 | int result = currentInstruction[1].u.operand; |
228 | int op1 = currentInstruction[2].u.operand; | |
229 | int op2 = currentInstruction[3].u.operand; | |
ba379fdc A |
230 | |
231 | emitGetVirtualRegisters(op1, regT0, op2, regT2); | |
232 | // FIXME: would we be better using 'emitJumpSlowCaseIfNotImmediateIntegers'? - we *probably* ought to be consistent. | |
233 | emitJumpSlowCaseIfNotImmediateInteger(regT0); | |
234 | emitJumpSlowCaseIfNotImmediateInteger(regT2); | |
235 | emitFastArithImmToInt(regT0); | |
236 | emitFastArithImmToInt(regT2); | |
ba379fdc | 237 | lshift32(regT2, regT0); |
ba379fdc A |
238 | emitFastArithReTagImmediate(regT0, regT0); |
239 | emitPutVirtualRegister(result); | |
240 | } | |
241 | ||
242 | void JIT::emitSlow_op_lshift(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) | |
243 | { | |
ba379fdc A |
244 | linkSlowCase(iter); |
245 | linkSlowCase(iter); | |
81345200 A |
246 | JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_lshift); |
247 | slowPathCall.call(); | |
ba379fdc A |
248 | } |
249 | ||
250 | void JIT::emit_op_rshift(Instruction* currentInstruction) | |
251 | { | |
81345200 A |
252 | int result = currentInstruction[1].u.operand; |
253 | int op1 = currentInstruction[2].u.operand; | |
254 | int op2 = currentInstruction[3].u.operand; | |
ba379fdc A |
255 | |
256 | if (isOperandConstantImmediateInt(op2)) { | |
257 | // isOperandConstantImmediateInt(op2) => 1 SlowCase | |
258 | emitGetVirtualRegister(op1, regT0); | |
259 | emitJumpSlowCaseIfNotImmediateInteger(regT0); | |
260 | // Mask with 0x1f as per ecma-262 11.7.2 step 7. | |
ba379fdc | 261 | rshift32(Imm32(getConstantOperandImmediateInt(op2) & 0x1f), regT0); |
ba379fdc A |
262 | } else { |
263 | emitGetVirtualRegisters(op1, regT0, op2, regT2); | |
264 | if (supportsFloatingPointTruncate()) { | |
265 | Jump lhsIsInt = emitJumpIfImmediateInteger(regT0); | |
ba379fdc A |
266 | // supportsFloatingPoint() && USE(JSVALUE64) => 3 SlowCases |
267 | addSlowCase(emitJumpIfNotImmediateNumber(regT0)); | |
93a37866 A |
268 | add64(tagTypeNumberRegister, regT0); |
269 | move64ToDouble(regT0, fpRegT0); | |
ba379fdc | 270 | addSlowCase(branchTruncateDoubleToInt32(fpRegT0, regT0)); |
ba379fdc A |
271 | lhsIsInt.link(this); |
272 | emitJumpSlowCaseIfNotImmediateInteger(regT2); | |
273 | } else { | |
274 | // !supportsFloatingPoint() => 2 SlowCases | |
275 | emitJumpSlowCaseIfNotImmediateInteger(regT0); | |
276 | emitJumpSlowCaseIfNotImmediateInteger(regT2); | |
277 | } | |
278 | emitFastArithImmToInt(regT2); | |
ba379fdc | 279 | rshift32(regT2, regT0); |
ba379fdc | 280 | } |
ba379fdc | 281 | emitFastArithIntToImmNoCheck(regT0, regT0); |
ba379fdc A |
282 | emitPutVirtualRegister(result); |
283 | } | |
284 | ||
285 | void JIT::emitSlow_op_rshift(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) | |
286 | { | |
81345200 | 287 | int op2 = currentInstruction[3].u.operand; |
ba379fdc | 288 | |
81345200 | 289 | if (isOperandConstantImmediateInt(op2)) |
ba379fdc | 290 | linkSlowCase(iter); |
81345200 A |
291 | |
292 | else { | |
ba379fdc | 293 | if (supportsFloatingPointTruncate()) { |
ba379fdc A |
294 | linkSlowCase(iter); |
295 | linkSlowCase(iter); | |
296 | linkSlowCase(iter); | |
ba379fdc A |
297 | } else { |
298 | linkSlowCase(iter); | |
299 | linkSlowCase(iter); | |
ba379fdc A |
300 | } |
301 | } | |
302 | ||
81345200 A |
303 | JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_rshift); |
304 | slowPathCall.call(); | |
ba379fdc A |
305 | } |
306 | ||
4e4e5a6f A |
307 | void JIT::emit_op_urshift(Instruction* currentInstruction) |
308 | { | |
81345200 A |
309 | int result = currentInstruction[1].u.operand; |
310 | int op1 = currentInstruction[2].u.operand; | |
311 | int op2 = currentInstruction[3].u.operand; | |
4e4e5a6f | 312 | |
4e4e5a6f | 313 | if (isOperandConstantImmediateInt(op2)) { |
81345200 | 314 | // isOperandConstantImmediateInt(op2) => 1 SlowCase |
4e4e5a6f A |
315 | emitGetVirtualRegister(op1, regT0); |
316 | emitJumpSlowCaseIfNotImmediateInteger(regT0); | |
81345200 A |
317 | // Mask with 0x1f as per ecma-262 11.7.2 step 7. |
318 | urshift32(Imm32(getConstantOperandImmediateInt(op2) & 0x1f), regT0); | |
319 | } else { | |
320 | emitGetVirtualRegisters(op1, regT0, op2, regT2); | |
321 | if (supportsFloatingPointTruncate()) { | |
322 | Jump lhsIsInt = emitJumpIfImmediateInteger(regT0); | |
323 | // supportsFloatingPoint() && USE(JSVALUE64) => 3 SlowCases | |
324 | addSlowCase(emitJumpIfNotImmediateNumber(regT0)); | |
325 | add64(tagTypeNumberRegister, regT0); | |
326 | move64ToDouble(regT0, fpRegT0); | |
327 | addSlowCase(branchTruncateDoubleToInt32(fpRegT0, regT0)); | |
328 | lhsIsInt.link(this); | |
329 | emitJumpSlowCaseIfNotImmediateInteger(regT2); | |
330 | } else { | |
331 | // !supportsFloatingPoint() => 2 SlowCases | |
332 | emitJumpSlowCaseIfNotImmediateInteger(regT0); | |
333 | emitJumpSlowCaseIfNotImmediateInteger(regT2); | |
334 | } | |
335 | emitFastArithImmToInt(regT2); | |
336 | urshift32(regT2, regT0); | |
4e4e5a6f | 337 | } |
81345200 A |
338 | emitFastArithIntToImmNoCheck(regT0, regT0); |
339 | emitPutVirtualRegister(result); | |
4e4e5a6f A |
340 | } |
341 | ||
342 | void JIT::emitSlow_op_urshift(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) | |
343 | { | |
81345200 A |
344 | int op2 = currentInstruction[3].u.operand; |
345 | ||
346 | if (isOperandConstantImmediateInt(op2)) | |
347 | linkSlowCase(iter); | |
348 | ||
349 | else { | |
4e4e5a6f | 350 | if (supportsFloatingPointTruncate()) { |
81345200 A |
351 | linkSlowCase(iter); |
352 | linkSlowCase(iter); | |
353 | linkSlowCase(iter); | |
354 | } else { | |
355 | linkSlowCase(iter); | |
356 | linkSlowCase(iter); | |
4e4e5a6f | 357 | } |
4e4e5a6f | 358 | } |
81345200 A |
359 | |
360 | JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_urshift); | |
361 | slowPathCall.call(); | |
362 | } | |
363 | ||
364 | void JIT::emit_op_unsigned(Instruction* currentInstruction) | |
365 | { | |
366 | int result = currentInstruction[1].u.operand; | |
367 | int op1 = currentInstruction[2].u.operand; | |
4e4e5a6f | 368 | |
81345200 A |
369 | emitGetVirtualRegister(op1, regT0); |
370 | emitJumpSlowCaseIfNotImmediateInteger(regT0); | |
371 | addSlowCase(branch32(LessThan, regT0, TrustedImm32(0))); | |
372 | emitFastArithReTagImmediate(regT0, regT0); | |
373 | emitPutVirtualRegister(result, regT0); | |
4e4e5a6f A |
374 | } |
375 | ||
81345200 A |
376 | void JIT::emitSlow_op_unsigned(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) |
377 | { | |
378 | linkSlowCase(iter); | |
379 | linkSlowCase(iter); | |
380 | ||
381 | JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_unsigned); | |
382 | slowPathCall.call(); | |
383 | } | |
384 | ||
385 | void JIT::emit_compareAndJump(OpcodeID, int op1, int op2, unsigned target, RelationalCondition condition) | |
9dae56ea | 386 | { |
ba379fdc A |
387 | // We generate inline code for the following cases in the fast path: |
388 | // - int immediate to constant int immediate | |
389 | // - constant int immediate to int immediate | |
390 | // - int immediate to int immediate | |
391 | ||
4e4e5a6f A |
392 | if (isOperandConstantImmediateChar(op1)) { |
393 | emitGetVirtualRegister(op2, regT0); | |
394 | addSlowCase(emitJumpIfNotJSCell(regT0)); | |
395 | JumpList failures; | |
396 | emitLoadCharacterString(regT0, regT0, failures); | |
397 | addSlowCase(failures); | |
6fe7ccc8 | 398 | addJump(branch32(commute(condition), regT0, Imm32(asString(getConstantOperand(op1))->tryGetValue()[0])), target); |
4e4e5a6f A |
399 | return; |
400 | } | |
401 | if (isOperandConstantImmediateChar(op2)) { | |
402 | emitGetVirtualRegister(op1, regT0); | |
403 | addSlowCase(emitJumpIfNotJSCell(regT0)); | |
404 | JumpList failures; | |
405 | emitLoadCharacterString(regT0, regT0, failures); | |
406 | addSlowCase(failures); | |
6fe7ccc8 | 407 | addJump(branch32(condition, regT0, Imm32(asString(getConstantOperand(op2))->tryGetValue()[0])), target); |
4e4e5a6f A |
408 | return; |
409 | } | |
ba379fdc A |
410 | if (isOperandConstantImmediateInt(op2)) { |
411 | emitGetVirtualRegister(op1, regT0); | |
412 | emitJumpSlowCaseIfNotImmediateInteger(regT0); | |
ba379fdc | 413 | int32_t op2imm = getConstantOperandImmediateInt(op2); |
6fe7ccc8 | 414 | addJump(branch32(condition, regT0, Imm32(op2imm)), target); |
ba379fdc A |
415 | } else if (isOperandConstantImmediateInt(op1)) { |
416 | emitGetVirtualRegister(op2, regT1); | |
417 | emitJumpSlowCaseIfNotImmediateInteger(regT1); | |
ba379fdc | 418 | int32_t op1imm = getConstantOperandImmediateInt(op1); |
6fe7ccc8 | 419 | addJump(branch32(commute(condition), regT1, Imm32(op1imm)), target); |
ba379fdc A |
420 | } else { |
421 | emitGetVirtualRegisters(op1, regT0, op2, regT1); | |
422 | emitJumpSlowCaseIfNotImmediateInteger(regT0); | |
423 | emitJumpSlowCaseIfNotImmediateInteger(regT1); | |
424 | ||
6fe7ccc8 | 425 | addJump(branch32(condition, regT0, regT1), target); |
ba379fdc | 426 | } |
9dae56ea A |
427 | } |
428 | ||
81345200 | 429 | void JIT::emit_compareAndJumpSlow(int op1, int op2, unsigned target, DoubleCondition condition, size_t (JIT_OPERATION *operation)(ExecState*, EncodedJSValue, EncodedJSValue), bool invert, Vector<SlowCaseEntry>::iterator& iter) |
9dae56ea | 430 | { |
6fe7ccc8 A |
431 | COMPILE_ASSERT(OPCODE_LENGTH(op_jless) == OPCODE_LENGTH(op_jlesseq), OPCODE_LENGTH_op_jlesseq_equals_op_jless); |
432 | COMPILE_ASSERT(OPCODE_LENGTH(op_jless) == OPCODE_LENGTH(op_jnless), OPCODE_LENGTH_op_jnless_equals_op_jless); | |
433 | COMPILE_ASSERT(OPCODE_LENGTH(op_jless) == OPCODE_LENGTH(op_jnlesseq), OPCODE_LENGTH_op_jnlesseq_equals_op_jless); | |
434 | COMPILE_ASSERT(OPCODE_LENGTH(op_jless) == OPCODE_LENGTH(op_jgreater), OPCODE_LENGTH_op_jgreater_equals_op_jless); | |
435 | COMPILE_ASSERT(OPCODE_LENGTH(op_jless) == OPCODE_LENGTH(op_jgreatereq), OPCODE_LENGTH_op_jgreatereq_equals_op_jless); | |
436 | COMPILE_ASSERT(OPCODE_LENGTH(op_jless) == OPCODE_LENGTH(op_jngreater), OPCODE_LENGTH_op_jngreater_equals_op_jless); | |
437 | COMPILE_ASSERT(OPCODE_LENGTH(op_jless) == OPCODE_LENGTH(op_jngreatereq), OPCODE_LENGTH_op_jngreatereq_equals_op_jless); | |
438 | ||
ba379fdc A |
439 | // We generate inline code for the following cases in the slow path: |
440 | // - floating-point number to constant int immediate | |
441 | // - constant int immediate to floating-point number | |
442 | // - floating-point number to floating-point number. | |
4e4e5a6f A |
443 | if (isOperandConstantImmediateChar(op1) || isOperandConstantImmediateChar(op2)) { |
444 | linkSlowCase(iter); | |
445 | linkSlowCase(iter); | |
446 | linkSlowCase(iter); | |
447 | linkSlowCase(iter); | |
81345200 A |
448 | |
449 | emitGetVirtualRegister(op1, argumentGPR0); | |
450 | emitGetVirtualRegister(op2, argumentGPR1); | |
451 | callOperation(operation, argumentGPR0, argumentGPR1); | |
452 | emitJumpSlowToHot(branchTest32(invert ? Zero : NonZero, returnValueGPR), target); | |
4e4e5a6f A |
453 | return; |
454 | } | |
455 | ||
9dae56ea | 456 | if (isOperandConstantImmediateInt(op2)) { |
ba379fdc A |
457 | linkSlowCase(iter); |
458 | ||
459 | if (supportsFloatingPoint()) { | |
ba379fdc | 460 | Jump fail1 = emitJumpIfNotImmediateNumber(regT0); |
93a37866 A |
461 | add64(tagTypeNumberRegister, regT0); |
462 | move64ToDouble(regT0, fpRegT0); | |
4e4e5a6f | 463 | |
6fe7ccc8 | 464 | int32_t op2imm = getConstantOperand(op2).asInt32(); |
4e4e5a6f | 465 | |
ba379fdc A |
466 | move(Imm32(op2imm), regT1); |
467 | convertInt32ToDouble(regT1, fpRegT1); | |
468 | ||
6fe7ccc8 | 469 | emitJumpSlowToHot(branchDouble(condition, fpRegT0, fpRegT1), target); |
ba379fdc | 470 | |
6fe7ccc8 | 471 | emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jless)); |
ba379fdc | 472 | |
ba379fdc | 473 | fail1.link(this); |
ba379fdc A |
474 | } |
475 | ||
81345200 A |
476 | emitGetVirtualRegister(op2, regT1); |
477 | callOperation(operation, regT0, regT1); | |
478 | emitJumpSlowToHot(branchTest32(invert ? Zero : NonZero, returnValueGPR), target); | |
ba379fdc A |
479 | } else if (isOperandConstantImmediateInt(op1)) { |
480 | linkSlowCase(iter); | |
481 | ||
482 | if (supportsFloatingPoint()) { | |
ba379fdc | 483 | Jump fail1 = emitJumpIfNotImmediateNumber(regT1); |
93a37866 A |
484 | add64(tagTypeNumberRegister, regT1); |
485 | move64ToDouble(regT1, fpRegT1); | |
4e4e5a6f | 486 | |
6fe7ccc8 | 487 | int32_t op1imm = getConstantOperand(op1).asInt32(); |
4e4e5a6f | 488 | |
ba379fdc A |
489 | move(Imm32(op1imm), regT0); |
490 | convertInt32ToDouble(regT0, fpRegT0); | |
491 | ||
6fe7ccc8 | 492 | emitJumpSlowToHot(branchDouble(condition, fpRegT0, fpRegT1), target); |
ba379fdc | 493 | |
6fe7ccc8 | 494 | emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jless)); |
ba379fdc | 495 | |
ba379fdc | 496 | fail1.link(this); |
ba379fdc A |
497 | } |
498 | ||
81345200 A |
499 | emitGetVirtualRegister(op1, regT2); |
500 | callOperation(operation, regT2, regT1); | |
501 | emitJumpSlowToHot(branchTest32(invert ? Zero : NonZero, returnValueGPR), target); | |
ba379fdc | 502 | } else { |
9dae56ea | 503 | linkSlowCase(iter); |
9dae56ea | 504 | |
ba379fdc | 505 | if (supportsFloatingPoint()) { |
ba379fdc A |
506 | Jump fail1 = emitJumpIfNotImmediateNumber(regT0); |
507 | Jump fail2 = emitJumpIfNotImmediateNumber(regT1); | |
508 | Jump fail3 = emitJumpIfImmediateInteger(regT1); | |
93a37866 A |
509 | add64(tagTypeNumberRegister, regT0); |
510 | add64(tagTypeNumberRegister, regT1); | |
511 | move64ToDouble(regT0, fpRegT0); | |
512 | move64ToDouble(regT1, fpRegT1); | |
ba379fdc | 513 | |
6fe7ccc8 | 514 | emitJumpSlowToHot(branchDouble(condition, fpRegT0, fpRegT1), target); |
ba379fdc | 515 | |
6fe7ccc8 | 516 | emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jless)); |
ba379fdc | 517 | |
ba379fdc A |
518 | fail1.link(this); |
519 | fail2.link(this); | |
520 | fail3.link(this); | |
ba379fdc A |
521 | } |
522 | ||
523 | linkSlowCase(iter); | |
81345200 A |
524 | callOperation(operation, regT0, regT1); |
525 | emitJumpSlowToHot(branchTest32(invert ? Zero : NonZero, returnValueGPR), target); | |
ba379fdc | 526 | } |
9dae56ea A |
527 | } |
528 | ||
ba379fdc | 529 | void JIT::emit_op_bitand(Instruction* currentInstruction) |
9dae56ea | 530 | { |
81345200 A |
531 | int result = currentInstruction[1].u.operand; |
532 | int op1 = currentInstruction[2].u.operand; | |
533 | int op2 = currentInstruction[3].u.operand; | |
ba379fdc | 534 | |
9dae56ea | 535 | if (isOperandConstantImmediateInt(op1)) { |
ba379fdc A |
536 | emitGetVirtualRegister(op2, regT0); |
537 | emitJumpSlowCaseIfNotImmediateInteger(regT0); | |
9dae56ea | 538 | int32_t imm = getConstantOperandImmediateInt(op1); |
93a37866 | 539 | and64(Imm32(imm), regT0); |
9dae56ea | 540 | if (imm >= 0) |
ba379fdc | 541 | emitFastArithIntToImmNoCheck(regT0, regT0); |
9dae56ea | 542 | } else if (isOperandConstantImmediateInt(op2)) { |
ba379fdc A |
543 | emitGetVirtualRegister(op1, regT0); |
544 | emitJumpSlowCaseIfNotImmediateInteger(regT0); | |
9dae56ea | 545 | int32_t imm = getConstantOperandImmediateInt(op2); |
93a37866 | 546 | and64(Imm32(imm), regT0); |
9dae56ea | 547 | if (imm >= 0) |
ba379fdc | 548 | emitFastArithIntToImmNoCheck(regT0, regT0); |
9dae56ea | 549 | } else { |
ba379fdc | 550 | emitGetVirtualRegisters(op1, regT0, op2, regT1); |
93a37866 | 551 | and64(regT1, regT0); |
ba379fdc | 552 | emitJumpSlowCaseIfNotImmediateInteger(regT0); |
9dae56ea A |
553 | } |
554 | emitPutVirtualRegister(result); | |
555 | } | |
ba379fdc A |
556 | |
557 | void JIT::emitSlow_op_bitand(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) | |
9dae56ea A |
558 | { |
559 | linkSlowCase(iter); | |
81345200 A |
560 | |
561 | JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_bitand); | |
562 | slowPathCall.call(); | |
9dae56ea A |
563 | } |
564 | ||
93a37866 | 565 | void JIT::emit_op_inc(Instruction* currentInstruction) |
9dae56ea | 566 | { |
81345200 | 567 | int srcDst = currentInstruction[1].u.operand; |
ba379fdc A |
568 | |
569 | emitGetVirtualRegister(srcDst, regT0); | |
570 | emitJumpSlowCaseIfNotImmediateInteger(regT0); | |
14957cd0 | 571 | addSlowCase(branchAdd32(Overflow, TrustedImm32(1), regT0)); |
ba379fdc | 572 | emitFastArithIntToImmNoCheck(regT0, regT0); |
9dae56ea A |
573 | emitPutVirtualRegister(srcDst); |
574 | } | |
ba379fdc | 575 | |
93a37866 | 576 | void JIT::emitSlow_op_inc(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) |
9dae56ea | 577 | { |
9dae56ea | 578 | linkSlowCase(iter); |
81345200 A |
579 | linkSlowCase(iter); |
580 | JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_inc); | |
581 | slowPathCall.call(); | |
9dae56ea A |
582 | } |
583 | ||
93a37866 | 584 | void JIT::emit_op_dec(Instruction* currentInstruction) |
9dae56ea | 585 | { |
81345200 | 586 | int srcDst = currentInstruction[1].u.operand; |
ba379fdc A |
587 | |
588 | emitGetVirtualRegister(srcDst, regT0); | |
589 | emitJumpSlowCaseIfNotImmediateInteger(regT0); | |
6fe7ccc8 | 590 | addSlowCase(branchSub32(Overflow, TrustedImm32(1), regT0)); |
ba379fdc | 591 | emitFastArithIntToImmNoCheck(regT0, regT0); |
9dae56ea A |
592 | emitPutVirtualRegister(srcDst); |
593 | } | |
ba379fdc | 594 | |
93a37866 | 595 | void JIT::emitSlow_op_dec(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) |
9dae56ea | 596 | { |
9dae56ea | 597 | linkSlowCase(iter); |
81345200 A |
598 | linkSlowCase(iter); |
599 | JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_dec); | |
600 | slowPathCall.call(); | |
9dae56ea A |
601 | } |
602 | ||
ba379fdc | 603 | /* ------------------------------ BEGIN: OP_MOD ------------------------------ */ |
9dae56ea | 604 | |
6fe7ccc8 | 605 | #if CPU(X86) || CPU(X86_64) |
9dae56ea | 606 | |
ba379fdc | 607 | void JIT::emit_op_mod(Instruction* currentInstruction) |
9dae56ea | 608 | { |
81345200 A |
609 | int result = currentInstruction[1].u.operand; |
610 | int op1 = currentInstruction[2].u.operand; | |
611 | int op2 = currentInstruction[3].u.operand; | |
9dae56ea | 612 | |
14957cd0 A |
613 | // Make sure registers are correct for x86 IDIV instructions. |
614 | ASSERT(regT0 == X86Registers::eax); | |
615 | ASSERT(regT1 == X86Registers::edx); | |
616 | ASSERT(regT2 == X86Registers::ecx); | |
14957cd0 | 617 | |
6fe7ccc8 A |
618 | emitGetVirtualRegisters(op1, regT3, op2, regT2); |
619 | emitJumpSlowCaseIfNotImmediateInteger(regT3); | |
14957cd0 A |
620 | emitJumpSlowCaseIfNotImmediateInteger(regT2); |
621 | ||
6fe7ccc8 A |
622 | move(regT3, regT0); |
623 | addSlowCase(branchTest32(Zero, regT2)); | |
624 | Jump denominatorNotNeg1 = branch32(NotEqual, regT2, TrustedImm32(-1)); | |
625 | addSlowCase(branch32(Equal, regT0, TrustedImm32(-2147483647-1))); | |
626 | denominatorNotNeg1.link(this); | |
14957cd0 A |
627 | m_assembler.cdq(); |
628 | m_assembler.idivl_r(regT2); | |
6fe7ccc8 A |
629 | Jump numeratorPositive = branch32(GreaterThanOrEqual, regT3, TrustedImm32(0)); |
630 | addSlowCase(branchTest32(Zero, regT1)); | |
631 | numeratorPositive.link(this); | |
14957cd0 | 632 | emitFastArithReTagImmediate(regT1, regT0); |
9dae56ea A |
633 | emitPutVirtualRegister(result); |
634 | } | |
9dae56ea | 635 | |
ba379fdc | 636 | void JIT::emitSlow_op_mod(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) |
9dae56ea | 637 | { |
6fe7ccc8 A |
638 | linkSlowCase(iter); |
639 | linkSlowCase(iter); | |
ba379fdc A |
640 | linkSlowCase(iter); |
641 | linkSlowCase(iter); | |
ba379fdc | 642 | linkSlowCase(iter); |
81345200 A |
643 | JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_mod); |
644 | slowPathCall.call(); | |
9dae56ea A |
645 | } |
646 | ||
6fe7ccc8 | 647 | #else // CPU(X86) || CPU(X86_64) |
ba379fdc A |
648 | |
649 | void JIT::emit_op_mod(Instruction* currentInstruction) | |
9dae56ea | 650 | { |
81345200 A |
651 | JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_mod); |
652 | slowPathCall.call(); | |
9dae56ea | 653 | } |
ba379fdc | 654 | |
93a37866 | 655 | void JIT::emitSlow_op_mod(Instruction*, Vector<SlowCaseEntry>::iterator&) |
9dae56ea | 656 | { |
93a37866 | 657 | UNREACHABLE_FOR_PLATFORM(); |
9dae56ea A |
658 | } |
659 | ||
f9bf01c6 | 660 | #endif // CPU(X86) || CPU(X86_64) |
ba379fdc A |
661 | |
662 | /* ------------------------------ END: OP_MOD ------------------------------ */ | |
663 | ||
ba379fdc | 664 | /* ------------------------------ BEGIN: USE(JSVALUE64) (OP_ADD, OP_SUB, OP_MUL) ------------------------------ */ |
9dae56ea | 665 | |
81345200 | 666 | void JIT::compileBinaryArithOp(OpcodeID opcodeID, int, int op1, int op2, OperandTypes) |
9dae56ea | 667 | { |
ba379fdc A |
668 | emitGetVirtualRegisters(op1, regT0, op2, regT1); |
669 | emitJumpSlowCaseIfNotImmediateInteger(regT0); | |
670 | emitJumpSlowCaseIfNotImmediateInteger(regT1); | |
6fe7ccc8 | 671 | RareCaseProfile* profile = m_codeBlock->addSpecialFastCaseProfile(m_bytecodeOffset); |
9dae56ea | 672 | if (opcodeID == op_add) |
ba379fdc | 673 | addSlowCase(branchAdd32(Overflow, regT1, regT0)); |
9dae56ea | 674 | else if (opcodeID == op_sub) |
ba379fdc | 675 | addSlowCase(branchSub32(Overflow, regT1, regT0)); |
9dae56ea A |
676 | else { |
677 | ASSERT(opcodeID == op_mul); | |
93a37866 | 678 | if (shouldEmitProfiling()) { |
6fe7ccc8 A |
679 | // We want to be able to measure if this is taking the slow case just |
680 | // because of negative zero. If this produces positive zero, then we | |
681 | // don't want the slow case to be taken because that will throw off | |
682 | // speculative compilation. | |
683 | move(regT0, regT2); | |
684 | addSlowCase(branchMul32(Overflow, regT1, regT2)); | |
685 | JumpList done; | |
686 | done.append(branchTest32(NonZero, regT2)); | |
687 | Jump negativeZero = branch32(LessThan, regT0, TrustedImm32(0)); | |
688 | done.append(branch32(GreaterThanOrEqual, regT1, TrustedImm32(0))); | |
689 | negativeZero.link(this); | |
690 | // We only get here if we have a genuine negative zero. Record this, | |
691 | // so that the speculative JIT knows that we failed speculation | |
692 | // because of a negative zero. | |
693 | add32(TrustedImm32(1), AbsoluteAddress(&profile->m_counter)); | |
694 | addSlowCase(jump()); | |
695 | done.link(this); | |
696 | move(regT2, regT0); | |
697 | } else { | |
698 | addSlowCase(branchMul32(Overflow, regT1, regT0)); | |
699 | addSlowCase(branchTest32(Zero, regT0)); | |
700 | } | |
9dae56ea | 701 | } |
ba379fdc | 702 | emitFastArithIntToImmNoCheck(regT0, regT0); |
9dae56ea A |
703 | } |
704 | ||
81345200 | 705 | void JIT::compileBinaryArithOpSlowCase(Instruction* currentInstruction, OpcodeID opcodeID, Vector<SlowCaseEntry>::iterator& iter, int result, int op1, int op2, OperandTypes types, bool op1HasImmediateIntFastCase, bool op2HasImmediateIntFastCase) |
9dae56ea A |
706 | { |
707 | // We assume that subtracting TagTypeNumber is equivalent to adding DoubleEncodeOffset. | |
14957cd0 | 708 | COMPILE_ASSERT(((TagTypeNumber + DoubleEncodeOffset) == 0), TagTypeNumber_PLUS_DoubleEncodeOffset_EQUALS_0); |
4e4e5a6f | 709 | |
f9bf01c6 A |
710 | Jump notImm1; |
711 | Jump notImm2; | |
712 | if (op1HasImmediateIntFastCase) { | |
713 | notImm2 = getSlowCase(iter); | |
714 | } else if (op2HasImmediateIntFastCase) { | |
715 | notImm1 = getSlowCase(iter); | |
716 | } else { | |
717 | notImm1 = getSlowCase(iter); | |
718 | notImm2 = getSlowCase(iter); | |
719 | } | |
9dae56ea A |
720 | |
721 | linkSlowCase(iter); // Integer overflow case - we could handle this in JIT code, but this is likely rare. | |
f9bf01c6 | 722 | if (opcodeID == op_mul && !op1HasImmediateIntFastCase && !op2HasImmediateIntFastCase) // op_mul has an extra slow case to handle 0 * negative number. |
9dae56ea | 723 | linkSlowCase(iter); |
9dae56ea A |
724 | |
725 | Label stubFunctionCall(this); | |
81345200 A |
726 | |
727 | JITSlowPathCall slowPathCall(this, currentInstruction, opcodeID == op_add ? slow_path_add : opcodeID == op_sub ? slow_path_sub : slow_path_mul); | |
728 | slowPathCall.call(); | |
9dae56ea A |
729 | Jump end = jump(); |
730 | ||
f9bf01c6 A |
731 | if (op1HasImmediateIntFastCase) { |
732 | notImm2.link(this); | |
733 | if (!types.second().definitelyIsNumber()) | |
734 | emitJumpIfNotImmediateNumber(regT0).linkTo(stubFunctionCall, this); | |
735 | emitGetVirtualRegister(op1, regT1); | |
736 | convertInt32ToDouble(regT1, fpRegT1); | |
93a37866 A |
737 | add64(tagTypeNumberRegister, regT0); |
738 | move64ToDouble(regT0, fpRegT2); | |
f9bf01c6 A |
739 | } else if (op2HasImmediateIntFastCase) { |
740 | notImm1.link(this); | |
741 | if (!types.first().definitelyIsNumber()) | |
742 | emitJumpIfNotImmediateNumber(regT0).linkTo(stubFunctionCall, this); | |
743 | emitGetVirtualRegister(op2, regT1); | |
744 | convertInt32ToDouble(regT1, fpRegT1); | |
93a37866 A |
745 | add64(tagTypeNumberRegister, regT0); |
746 | move64ToDouble(regT0, fpRegT2); | |
f9bf01c6 A |
747 | } else { |
748 | // if we get here, eax is not an int32, edx not yet checked. | |
749 | notImm1.link(this); | |
750 | if (!types.first().definitelyIsNumber()) | |
751 | emitJumpIfNotImmediateNumber(regT0).linkTo(stubFunctionCall, this); | |
752 | if (!types.second().definitelyIsNumber()) | |
753 | emitJumpIfNotImmediateNumber(regT1).linkTo(stubFunctionCall, this); | |
93a37866 A |
754 | add64(tagTypeNumberRegister, regT0); |
755 | move64ToDouble(regT0, fpRegT1); | |
f9bf01c6 A |
756 | Jump op2isDouble = emitJumpIfNotImmediateInteger(regT1); |
757 | convertInt32ToDouble(regT1, fpRegT2); | |
758 | Jump op2wasInteger = jump(); | |
759 | ||
760 | // if we get here, eax IS an int32, edx is not. | |
761 | notImm2.link(this); | |
762 | if (!types.second().definitelyIsNumber()) | |
763 | emitJumpIfNotImmediateNumber(regT1).linkTo(stubFunctionCall, this); | |
764 | convertInt32ToDouble(regT0, fpRegT1); | |
765 | op2isDouble.link(this); | |
93a37866 A |
766 | add64(tagTypeNumberRegister, regT1); |
767 | move64ToDouble(regT1, fpRegT2); | |
f9bf01c6 A |
768 | op2wasInteger.link(this); |
769 | } | |
9dae56ea A |
770 | |
771 | if (opcodeID == op_add) | |
ba379fdc | 772 | addDouble(fpRegT2, fpRegT1); |
9dae56ea | 773 | else if (opcodeID == op_sub) |
ba379fdc | 774 | subDouble(fpRegT2, fpRegT1); |
f9bf01c6 | 775 | else if (opcodeID == op_mul) |
ba379fdc | 776 | mulDouble(fpRegT2, fpRegT1); |
f9bf01c6 A |
777 | else { |
778 | ASSERT(opcodeID == op_div); | |
779 | divDouble(fpRegT2, fpRegT1); | |
9dae56ea | 780 | } |
93a37866 A |
781 | moveDoubleTo64(fpRegT1, regT0); |
782 | sub64(tagTypeNumberRegister, regT0); | |
ba379fdc | 783 | emitPutVirtualRegister(result, regT0); |
9dae56ea A |
784 | |
785 | end.link(this); | |
786 | } | |
787 | ||
ba379fdc | 788 | void JIT::emit_op_add(Instruction* currentInstruction) |
9dae56ea | 789 | { |
81345200 A |
790 | int result = currentInstruction[1].u.operand; |
791 | int op1 = currentInstruction[2].u.operand; | |
792 | int op2 = currentInstruction[3].u.operand; | |
9dae56ea A |
793 | OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); |
794 | ||
795 | if (!types.first().mightBeNumber() || !types.second().mightBeNumber()) { | |
6fe7ccc8 | 796 | addSlowCase(); |
81345200 A |
797 | JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_add); |
798 | slowPathCall.call(); | |
9dae56ea A |
799 | return; |
800 | } | |
801 | ||
802 | if (isOperandConstantImmediateInt(op1)) { | |
ba379fdc A |
803 | emitGetVirtualRegister(op2, regT0); |
804 | emitJumpSlowCaseIfNotImmediateInteger(regT0); | |
6fe7ccc8 A |
805 | addSlowCase(branchAdd32(Overflow, regT0, Imm32(getConstantOperandImmediateInt(op1)), regT1)); |
806 | emitFastArithIntToImmNoCheck(regT1, regT0); | |
9dae56ea | 807 | } else if (isOperandConstantImmediateInt(op2)) { |
ba379fdc A |
808 | emitGetVirtualRegister(op1, regT0); |
809 | emitJumpSlowCaseIfNotImmediateInteger(regT0); | |
6fe7ccc8 A |
810 | addSlowCase(branchAdd32(Overflow, regT0, Imm32(getConstantOperandImmediateInt(op2)), regT1)); |
811 | emitFastArithIntToImmNoCheck(regT1, regT0); | |
9dae56ea A |
812 | } else |
813 | compileBinaryArithOp(op_add, result, op1, op2, types); | |
814 | ||
815 | emitPutVirtualRegister(result); | |
816 | } | |
ba379fdc A |
817 | |
818 | void JIT::emitSlow_op_add(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) | |
9dae56ea | 819 | { |
81345200 A |
820 | int result = currentInstruction[1].u.operand; |
821 | int op1 = currentInstruction[2].u.operand; | |
822 | int op2 = currentInstruction[3].u.operand; | |
f9bf01c6 | 823 | OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); |
9dae56ea | 824 | |
6fe7ccc8 A |
825 | if (!types.first().mightBeNumber() || !types.second().mightBeNumber()) { |
826 | linkDummySlowCase(iter); | |
f9bf01c6 | 827 | return; |
6fe7ccc8 | 828 | } |
f9bf01c6 A |
829 | |
830 | bool op1HasImmediateIntFastCase = isOperandConstantImmediateInt(op1); | |
831 | bool op2HasImmediateIntFastCase = !op1HasImmediateIntFastCase && isOperandConstantImmediateInt(op2); | |
81345200 | 832 | compileBinaryArithOpSlowCase(currentInstruction, op_add, iter, result, op1, op2, types, op1HasImmediateIntFastCase, op2HasImmediateIntFastCase); |
9dae56ea A |
833 | } |
834 | ||
ba379fdc | 835 | void JIT::emit_op_mul(Instruction* currentInstruction) |
9dae56ea | 836 | { |
81345200 A |
837 | int result = currentInstruction[1].u.operand; |
838 | int op1 = currentInstruction[2].u.operand; | |
839 | int op2 = currentInstruction[3].u.operand; | |
9dae56ea A |
840 | OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); |
841 | ||
842 | // For now, only plant a fast int case if the constant operand is greater than zero. | |
843 | int32_t value; | |
844 | if (isOperandConstantImmediateInt(op1) && ((value = getConstantOperandImmediateInt(op1)) > 0)) { | |
6fe7ccc8 A |
845 | // Add a special fast case profile because the DFG JIT will expect one. |
846 | m_codeBlock->addSpecialFastCaseProfile(m_bytecodeOffset); | |
ba379fdc A |
847 | emitGetVirtualRegister(op2, regT0); |
848 | emitJumpSlowCaseIfNotImmediateInteger(regT0); | |
6fe7ccc8 A |
849 | addSlowCase(branchMul32(Overflow, Imm32(value), regT0, regT1)); |
850 | emitFastArithReTagImmediate(regT1, regT0); | |
9dae56ea | 851 | } else if (isOperandConstantImmediateInt(op2) && ((value = getConstantOperandImmediateInt(op2)) > 0)) { |
6fe7ccc8 A |
852 | // Add a special fast case profile because the DFG JIT will expect one. |
853 | m_codeBlock->addSpecialFastCaseProfile(m_bytecodeOffset); | |
ba379fdc A |
854 | emitGetVirtualRegister(op1, regT0); |
855 | emitJumpSlowCaseIfNotImmediateInteger(regT0); | |
6fe7ccc8 A |
856 | addSlowCase(branchMul32(Overflow, Imm32(value), regT0, regT1)); |
857 | emitFastArithReTagImmediate(regT1, regT0); | |
9dae56ea A |
858 | } else |
859 | compileBinaryArithOp(op_mul, result, op1, op2, types); | |
860 | ||
861 | emitPutVirtualRegister(result); | |
862 | } | |
ba379fdc A |
863 | |
864 | void JIT::emitSlow_op_mul(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) | |
9dae56ea | 865 | { |
81345200 A |
866 | int result = currentInstruction[1].u.operand; |
867 | int op1 = currentInstruction[2].u.operand; | |
868 | int op2 = currentInstruction[3].u.operand; | |
9dae56ea A |
869 | OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); |
870 | ||
f9bf01c6 A |
871 | bool op1HasImmediateIntFastCase = isOperandConstantImmediateInt(op1) && getConstantOperandImmediateInt(op1) > 0; |
872 | bool op2HasImmediateIntFastCase = !op1HasImmediateIntFastCase && isOperandConstantImmediateInt(op2) && getConstantOperandImmediateInt(op2) > 0; | |
81345200 | 873 | compileBinaryArithOpSlowCase(currentInstruction, op_mul, iter, result, op1, op2, types, op1HasImmediateIntFastCase, op2HasImmediateIntFastCase); |
f9bf01c6 A |
874 | } |
875 | ||
876 | void JIT::emit_op_div(Instruction* currentInstruction) | |
877 | { | |
81345200 A |
878 | int dst = currentInstruction[1].u.operand; |
879 | int op1 = currentInstruction[2].u.operand; | |
880 | int op2 = currentInstruction[3].u.operand; | |
f9bf01c6 A |
881 | OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); |
882 | ||
883 | if (isOperandConstantImmediateDouble(op1)) { | |
884 | emitGetVirtualRegister(op1, regT0); | |
93a37866 A |
885 | add64(tagTypeNumberRegister, regT0); |
886 | move64ToDouble(regT0, fpRegT0); | |
f9bf01c6 A |
887 | } else if (isOperandConstantImmediateInt(op1)) { |
888 | emitLoadInt32ToDouble(op1, fpRegT0); | |
889 | } else { | |
890 | emitGetVirtualRegister(op1, regT0); | |
891 | if (!types.first().definitelyIsNumber()) | |
892 | emitJumpSlowCaseIfNotImmediateNumber(regT0); | |
893 | Jump notInt = emitJumpIfNotImmediateInteger(regT0); | |
894 | convertInt32ToDouble(regT0, fpRegT0); | |
895 | Jump skipDoubleLoad = jump(); | |
896 | notInt.link(this); | |
93a37866 A |
897 | add64(tagTypeNumberRegister, regT0); |
898 | move64ToDouble(regT0, fpRegT0); | |
f9bf01c6 A |
899 | skipDoubleLoad.link(this); |
900 | } | |
4e4e5a6f | 901 | |
f9bf01c6 A |
902 | if (isOperandConstantImmediateDouble(op2)) { |
903 | emitGetVirtualRegister(op2, regT1); | |
93a37866 A |
904 | add64(tagTypeNumberRegister, regT1); |
905 | move64ToDouble(regT1, fpRegT1); | |
f9bf01c6 A |
906 | } else if (isOperandConstantImmediateInt(op2)) { |
907 | emitLoadInt32ToDouble(op2, fpRegT1); | |
908 | } else { | |
909 | emitGetVirtualRegister(op2, regT1); | |
910 | if (!types.second().definitelyIsNumber()) | |
911 | emitJumpSlowCaseIfNotImmediateNumber(regT1); | |
912 | Jump notInt = emitJumpIfNotImmediateInteger(regT1); | |
913 | convertInt32ToDouble(regT1, fpRegT1); | |
914 | Jump skipDoubleLoad = jump(); | |
915 | notInt.link(this); | |
93a37866 A |
916 | add64(tagTypeNumberRegister, regT1); |
917 | move64ToDouble(regT1, fpRegT1); | |
f9bf01c6 A |
918 | skipDoubleLoad.link(this); |
919 | } | |
920 | divDouble(fpRegT1, fpRegT0); | |
6fe7ccc8 | 921 | |
6fe7ccc8 A |
922 | // Is the result actually an integer? The DFG JIT would really like to know. If it's |
923 | // not an integer, we increment a count. If this together with the slow case counter | |
924 | // are below threshold then the DFG JIT will compile this division with a specualtion | |
925 | // that the remainder is zero. | |
926 | ||
927 | // As well, there are cases where a double result here would cause an important field | |
928 | // in the heap to sometimes have doubles in it, resulting in double predictions getting | |
929 | // propagated to a use site where it might cause damage (such as the index to an array | |
930 | // access). So if we are DFG compiling anything in the program, we want this code to | |
931 | // ensure that it produces integers whenever possible. | |
932 | ||
6fe7ccc8 A |
933 | JumpList notInteger; |
934 | branchConvertDoubleToInt32(fpRegT0, regT0, notInteger, fpRegT1); | |
935 | // If we've got an integer, we might as well make that the result of the division. | |
936 | emitFastArithReTagImmediate(regT0, regT0); | |
937 | Jump isInteger = jump(); | |
938 | notInteger.link(this); | |
93a37866 A |
939 | moveDoubleTo64(fpRegT0, regT0); |
940 | Jump doubleZero = branchTest64(Zero, regT0); | |
6fe7ccc8 | 941 | add32(TrustedImm32(1), AbsoluteAddress(&m_codeBlock->addSpecialFastCaseProfile(m_bytecodeOffset)->m_counter)); |
93a37866 A |
942 | sub64(tagTypeNumberRegister, regT0); |
943 | Jump trueDouble = jump(); | |
944 | doubleZero.link(this); | |
945 | move(tagTypeNumberRegister, regT0); | |
946 | trueDouble.link(this); | |
6fe7ccc8 | 947 | isInteger.link(this); |
f9bf01c6 A |
948 | |
949 | emitPutVirtualRegister(dst, regT0); | |
950 | } | |
951 | ||
952 | void JIT::emitSlow_op_div(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) | |
953 | { | |
81345200 A |
954 | int op1 = currentInstruction[2].u.operand; |
955 | int op2 = currentInstruction[3].u.operand; | |
f9bf01c6 A |
956 | OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); |
957 | if (types.first().definitelyIsNumber() && types.second().definitelyIsNumber()) { | |
81345200 A |
958 | if (!ASSERT_DISABLED) |
959 | abortWithReason(JITDivOperandsAreNotNumbers); | |
f9bf01c6 A |
960 | return; |
961 | } | |
962 | if (!isOperandConstantImmediateDouble(op1) && !isOperandConstantImmediateInt(op1)) { | |
963 | if (!types.first().definitelyIsNumber()) | |
964 | linkSlowCase(iter); | |
965 | } | |
966 | if (!isOperandConstantImmediateDouble(op2) && !isOperandConstantImmediateInt(op2)) { | |
967 | if (!types.second().definitelyIsNumber()) | |
968 | linkSlowCase(iter); | |
969 | } | |
970 | // There is an extra slow case for (op1 * -N) or (-N * op2), to check for 0 since this should produce a result of -0. | |
81345200 A |
971 | JITSlowPathCall slowPathCall(this, currentInstruction, slow_path_div); |
972 | slowPathCall.call(); | |
9dae56ea A |
973 | } |
974 | ||
ba379fdc | 975 | void JIT::emit_op_sub(Instruction* currentInstruction) |
9dae56ea | 976 | { |
81345200 A |
977 | int result = currentInstruction[1].u.operand; |
978 | int op1 = currentInstruction[2].u.operand; | |
979 | int op2 = currentInstruction[3].u.operand; | |
9dae56ea A |
980 | OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); |
981 | ||
982 | compileBinaryArithOp(op_sub, result, op1, op2, types); | |
9dae56ea A |
983 | emitPutVirtualRegister(result); |
984 | } | |
ba379fdc A |
985 | |
986 | void JIT::emitSlow_op_sub(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) | |
9dae56ea | 987 | { |
81345200 A |
988 | int result = currentInstruction[1].u.operand; |
989 | int op1 = currentInstruction[2].u.operand; | |
990 | int op2 = currentInstruction[3].u.operand; | |
9dae56ea A |
991 | OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); |
992 | ||
81345200 | 993 | compileBinaryArithOpSlowCase(currentInstruction, op_sub, iter, result, op1, op2, types, false, false); |
9dae56ea A |
994 | } |
995 | ||
ba379fdc A |
996 | /* ------------------------------ END: OP_ADD, OP_SUB, OP_MUL ------------------------------ */ |
997 | ||
6fe7ccc8 A |
998 | #endif // USE(JSVALUE64) |
999 | ||
9dae56ea A |
1000 | } // namespace JSC |
1001 | ||
1002 | #endif // ENABLE(JIT) |