]> git.saurik.com Git - apple/javascriptcore.git/blame - jit/JITArithmetic.cpp
JavaScriptCore-903.5.tar.gz
[apple/javascriptcore.git] / jit / JITArithmetic.cpp
CommitLineData
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
A
29#if USE(JSVALUE64)
30#include "JIT.h"
9dae56ea
A
31
32#include "CodeBlock.h"
33#include "JITInlineMethods.h"
ba379fdc 34#include "JITStubCall.h"
4e4e5a6f 35#include "JITStubs.h"
9dae56ea
A
36#include "JSArray.h"
37#include "JSFunction.h"
38#include "Interpreter.h"
39#include "ResultType.h"
40#include "SamplingTool.h"
41
42#ifndef NDEBUG
43#include <stdio.h>
44#endif
45
ba379fdc
A
46using namespace std;
47
48namespace JSC {
49
ba379fdc
A
50void JIT::emit_op_lshift(Instruction* currentInstruction)
51{
52 unsigned result = currentInstruction[1].u.operand;
53 unsigned op1 = currentInstruction[2].u.operand;
54 unsigned op2 = currentInstruction[3].u.operand;
55
56 emitGetVirtualRegisters(op1, regT0, op2, regT2);
57 // FIXME: would we be better using 'emitJumpSlowCaseIfNotImmediateIntegers'? - we *probably* ought to be consistent.
58 emitJumpSlowCaseIfNotImmediateInteger(regT0);
59 emitJumpSlowCaseIfNotImmediateInteger(regT2);
60 emitFastArithImmToInt(regT0);
61 emitFastArithImmToInt(regT2);
ba379fdc 62 lshift32(regT2, regT0);
ba379fdc
A
63 emitFastArithReTagImmediate(regT0, regT0);
64 emitPutVirtualRegister(result);
65}
66
67void JIT::emitSlow_op_lshift(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
68{
69 unsigned result = currentInstruction[1].u.operand;
70 unsigned op1 = currentInstruction[2].u.operand;
71 unsigned op2 = currentInstruction[3].u.operand;
72
ba379fdc
A
73 UNUSED_PARAM(op1);
74 UNUSED_PARAM(op2);
75 linkSlowCase(iter);
76 linkSlowCase(iter);
ba379fdc
A
77 JITStubCall stubCall(this, cti_op_lshift);
78 stubCall.addArgument(regT0);
79 stubCall.addArgument(regT2);
80 stubCall.call(result);
81}
82
83void JIT::emit_op_rshift(Instruction* currentInstruction)
84{
85 unsigned result = currentInstruction[1].u.operand;
86 unsigned op1 = currentInstruction[2].u.operand;
87 unsigned op2 = currentInstruction[3].u.operand;
88
89 if (isOperandConstantImmediateInt(op2)) {
90 // isOperandConstantImmediateInt(op2) => 1 SlowCase
91 emitGetVirtualRegister(op1, regT0);
92 emitJumpSlowCaseIfNotImmediateInteger(regT0);
93 // Mask with 0x1f as per ecma-262 11.7.2 step 7.
ba379fdc 94 rshift32(Imm32(getConstantOperandImmediateInt(op2) & 0x1f), regT0);
ba379fdc
A
95 } else {
96 emitGetVirtualRegisters(op1, regT0, op2, regT2);
97 if (supportsFloatingPointTruncate()) {
98 Jump lhsIsInt = emitJumpIfImmediateInteger(regT0);
ba379fdc
A
99 // supportsFloatingPoint() && USE(JSVALUE64) => 3 SlowCases
100 addSlowCase(emitJumpIfNotImmediateNumber(regT0));
101 addPtr(tagTypeNumberRegister, regT0);
102 movePtrToDouble(regT0, fpRegT0);
103 addSlowCase(branchTruncateDoubleToInt32(fpRegT0, regT0));
ba379fdc
A
104 lhsIsInt.link(this);
105 emitJumpSlowCaseIfNotImmediateInteger(regT2);
106 } else {
107 // !supportsFloatingPoint() => 2 SlowCases
108 emitJumpSlowCaseIfNotImmediateInteger(regT0);
109 emitJumpSlowCaseIfNotImmediateInteger(regT2);
110 }
111 emitFastArithImmToInt(regT2);
ba379fdc 112 rshift32(regT2, regT0);
ba379fdc 113 }
ba379fdc 114 emitFastArithIntToImmNoCheck(regT0, regT0);
ba379fdc
A
115 emitPutVirtualRegister(result);
116}
117
118void JIT::emitSlow_op_rshift(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
119{
120 unsigned result = currentInstruction[1].u.operand;
121 unsigned op1 = currentInstruction[2].u.operand;
122 unsigned op2 = currentInstruction[3].u.operand;
123
124 JITStubCall stubCall(this, cti_op_rshift);
125
126 if (isOperandConstantImmediateInt(op2)) {
127 linkSlowCase(iter);
128 stubCall.addArgument(regT0);
129 stubCall.addArgument(op2, regT2);
130 } else {
131 if (supportsFloatingPointTruncate()) {
ba379fdc
A
132 linkSlowCase(iter);
133 linkSlowCase(iter);
134 linkSlowCase(iter);
ba379fdc
A
135 // We're reloading op1 to regT0 as we can no longer guarantee that
136 // we have not munged the operand. It may have already been shifted
137 // correctly, but it still will not have been tagged.
138 stubCall.addArgument(op1, regT0);
139 stubCall.addArgument(regT2);
140 } else {
141 linkSlowCase(iter);
142 linkSlowCase(iter);
143 stubCall.addArgument(regT0);
144 stubCall.addArgument(regT2);
145 }
146 }
147
148 stubCall.call(result);
149}
150
4e4e5a6f
A
151void JIT::emit_op_urshift(Instruction* currentInstruction)
152{
153 unsigned dst = currentInstruction[1].u.operand;
154 unsigned op1 = currentInstruction[2].u.operand;
155 unsigned op2 = currentInstruction[3].u.operand;
156
157 // Slow case of urshift makes assumptions about what registers hold the
158 // shift arguments, so any changes must be updated there as well.
159 if (isOperandConstantImmediateInt(op2)) {
160 emitGetVirtualRegister(op1, regT0);
161 emitJumpSlowCaseIfNotImmediateInteger(regT0);
162 emitFastArithImmToInt(regT0);
163 int shift = getConstantOperand(op2).asInt32();
164 if (shift)
165 urshift32(Imm32(shift & 0x1f), regT0);
166 // unsigned shift < 0 or shift = k*2^32 may result in (essentially)
167 // a toUint conversion, which can result in a value we can represent
168 // as an immediate int.
169 if (shift < 0 || !(shift & 31))
14957cd0 170 addSlowCase(branch32(LessThan, regT0, TrustedImm32(0)));
4e4e5a6f
A
171 emitFastArithReTagImmediate(regT0, regT0);
172 emitPutVirtualRegister(dst, regT0);
173 return;
174 }
175 emitGetVirtualRegisters(op1, regT0, op2, regT1);
176 if (!isOperandConstantImmediateInt(op1))
177 emitJumpSlowCaseIfNotImmediateInteger(regT0);
178 emitJumpSlowCaseIfNotImmediateInteger(regT1);
179 emitFastArithImmToInt(regT0);
180 emitFastArithImmToInt(regT1);
181 urshift32(regT1, regT0);
14957cd0 182 addSlowCase(branch32(LessThan, regT0, TrustedImm32(0)));
4e4e5a6f
A
183 emitFastArithReTagImmediate(regT0, regT0);
184 emitPutVirtualRegister(dst, regT0);
185}
186
187void JIT::emitSlow_op_urshift(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
188{
189 unsigned dst = currentInstruction[1].u.operand;
190 unsigned op1 = currentInstruction[2].u.operand;
191 unsigned op2 = currentInstruction[3].u.operand;
192 if (isOperandConstantImmediateInt(op2)) {
193 int shift = getConstantOperand(op2).asInt32();
194 // op1 = regT0
195 linkSlowCase(iter); // int32 check
4e4e5a6f
A
196 if (supportsFloatingPointTruncate()) {
197 JumpList failures;
198 failures.append(emitJumpIfNotImmediateNumber(regT0)); // op1 is not a double
199 addPtr(tagTypeNumberRegister, regT0);
200 movePtrToDouble(regT0, fpRegT0);
201 failures.append(branchTruncateDoubleToInt32(fpRegT0, regT0));
202 if (shift)
203 urshift32(Imm32(shift & 0x1f), regT0);
204 if (shift < 0 || !(shift & 31))
14957cd0 205 failures.append(branch32(LessThan, regT0, TrustedImm32(0)));
4e4e5a6f
A
206 emitFastArithReTagImmediate(regT0, regT0);
207 emitPutVirtualRegister(dst, regT0);
208 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_rshift));
209 failures.link(this);
210 }
4e4e5a6f
A
211 if (shift < 0 || !(shift & 31))
212 linkSlowCase(iter); // failed to box in hot path
4e4e5a6f
A
213 } else {
214 // op1 = regT0
215 // op2 = regT1
216 if (!isOperandConstantImmediateInt(op1)) {
217 linkSlowCase(iter); // int32 check -- op1 is not an int
4e4e5a6f
A
218 if (supportsFloatingPointTruncate()) {
219 JumpList failures;
220 failures.append(emitJumpIfNotImmediateNumber(regT0)); // op1 is not a double
221 addPtr(tagTypeNumberRegister, regT0);
222 movePtrToDouble(regT0, fpRegT0);
223 failures.append(branchTruncateDoubleToInt32(fpRegT0, regT0));
224 failures.append(emitJumpIfNotImmediateInteger(regT1)); // op2 is not an int
225 emitFastArithImmToInt(regT1);
226 urshift32(regT1, regT0);
14957cd0 227 failures.append(branch32(LessThan, regT0, TrustedImm32(0)));
4e4e5a6f
A
228 emitFastArithReTagImmediate(regT0, regT0);
229 emitPutVirtualRegister(dst, regT0);
230 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_rshift));
231 failures.link(this);
232 }
4e4e5a6f
A
233 }
234
235 linkSlowCase(iter); // int32 check - op2 is not an int
236 linkSlowCase(iter); // Can't represent unsigned result as an immediate
4e4e5a6f
A
237 }
238
239 JITStubCall stubCall(this, cti_op_urshift);
240 stubCall.addArgument(op1, regT0);
241 stubCall.addArgument(op2, regT1);
242 stubCall.call(dst);
243}
244
ba379fdc
A
245void JIT::emit_op_jnless(Instruction* currentInstruction)
246{
247 unsigned op1 = currentInstruction[1].u.operand;
248 unsigned op2 = currentInstruction[2].u.operand;
249 unsigned target = currentInstruction[3].u.operand;
250
251 // We generate inline code for the following cases in the fast path:
252 // - int immediate to constant int immediate
253 // - constant int immediate to int immediate
254 // - int immediate to int immediate
255
4e4e5a6f
A
256 if (isOperandConstantImmediateChar(op1)) {
257 emitGetVirtualRegister(op2, regT0);
258 addSlowCase(emitJumpIfNotJSCell(regT0));
259 JumpList failures;
260 emitLoadCharacterString(regT0, regT0, failures);
261 addSlowCase(failures);
262 addJump(branch32(LessThanOrEqual, regT0, Imm32(asString(getConstantOperand(op1))->tryGetValue()[0])), target);
263 return;
264 }
265 if (isOperandConstantImmediateChar(op2)) {
266 emitGetVirtualRegister(op1, regT0);
267 addSlowCase(emitJumpIfNotJSCell(regT0));
268 JumpList failures;
269 emitLoadCharacterString(regT0, regT0, failures);
270 addSlowCase(failures);
271 addJump(branch32(GreaterThanOrEqual, regT0, Imm32(asString(getConstantOperand(op2))->tryGetValue()[0])), target);
272 return;
273 }
ba379fdc
A
274 if (isOperandConstantImmediateInt(op2)) {
275 emitGetVirtualRegister(op1, regT0);
276 emitJumpSlowCaseIfNotImmediateInteger(regT0);
ba379fdc 277 int32_t op2imm = getConstantOperandImmediateInt(op2);
f9bf01c6 278 addJump(branch32(GreaterThanOrEqual, regT0, Imm32(op2imm)), target);
ba379fdc
A
279 } else if (isOperandConstantImmediateInt(op1)) {
280 emitGetVirtualRegister(op2, regT1);
281 emitJumpSlowCaseIfNotImmediateInteger(regT1);
ba379fdc 282 int32_t op1imm = getConstantOperandImmediateInt(op1);
f9bf01c6 283 addJump(branch32(LessThanOrEqual, regT1, Imm32(op1imm)), target);
ba379fdc
A
284 } else {
285 emitGetVirtualRegisters(op1, regT0, op2, regT1);
286 emitJumpSlowCaseIfNotImmediateInteger(regT0);
287 emitJumpSlowCaseIfNotImmediateInteger(regT1);
288
f9bf01c6 289 addJump(branch32(GreaterThanOrEqual, regT0, regT1), target);
ba379fdc
A
290 }
291}
292
293void JIT::emitSlow_op_jnless(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
294{
295 unsigned op1 = currentInstruction[1].u.operand;
296 unsigned op2 = currentInstruction[2].u.operand;
297 unsigned target = currentInstruction[3].u.operand;
298
299 // We generate inline code for the following cases in the slow path:
300 // - floating-point number to constant int immediate
301 // - constant int immediate to floating-point number
302 // - floating-point number to floating-point number.
4e4e5a6f
A
303 if (isOperandConstantImmediateChar(op1) || isOperandConstantImmediateChar(op2)) {
304 linkSlowCase(iter);
305 linkSlowCase(iter);
306 linkSlowCase(iter);
307 linkSlowCase(iter);
308 JITStubCall stubCall(this, cti_op_jless);
309 stubCall.addArgument(op1, regT0);
310 stubCall.addArgument(op2, regT1);
311 stubCall.call();
312 emitJumpSlowToHot(branchTest32(Zero, regT0), target);
313 return;
314 }
ba379fdc
A
315
316 if (isOperandConstantImmediateInt(op2)) {
317 linkSlowCase(iter);
318
319 if (supportsFloatingPoint()) {
ba379fdc
A
320 Jump fail1 = emitJumpIfNotImmediateNumber(regT0);
321 addPtr(tagTypeNumberRegister, regT0);
322 movePtrToDouble(regT0, fpRegT0);
4e4e5a6f 323
ba379fdc 324 int32_t op2imm = getConstantOperand(op2).asInt32();;
4e4e5a6f 325
ba379fdc
A
326 move(Imm32(op2imm), regT1);
327 convertInt32ToDouble(regT1, fpRegT1);
328
f9bf01c6 329 emitJumpSlowToHot(branchDouble(DoubleLessThanOrEqualOrUnordered, fpRegT1, fpRegT0), target);
ba379fdc
A
330
331 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnless));
332
ba379fdc 333 fail1.link(this);
ba379fdc
A
334 }
335
336 JITStubCall stubCall(this, cti_op_jless);
337 stubCall.addArgument(regT0);
338 stubCall.addArgument(op2, regT2);
339 stubCall.call();
f9bf01c6 340 emitJumpSlowToHot(branchTest32(Zero, regT0), target);
ba379fdc
A
341
342 } else if (isOperandConstantImmediateInt(op1)) {
343 linkSlowCase(iter);
9dae56ea 344
ba379fdc 345 if (supportsFloatingPoint()) {
ba379fdc
A
346 Jump fail1 = emitJumpIfNotImmediateNumber(regT1);
347 addPtr(tagTypeNumberRegister, regT1);
348 movePtrToDouble(regT1, fpRegT1);
4e4e5a6f 349
ba379fdc 350 int32_t op1imm = getConstantOperand(op1).asInt32();;
4e4e5a6f 351
ba379fdc
A
352 move(Imm32(op1imm), regT0);
353 convertInt32ToDouble(regT0, fpRegT0);
9dae56ea 354
f9bf01c6
A
355 emitJumpSlowToHot(branchDouble(DoubleLessThanOrEqualOrUnordered, fpRegT1, fpRegT0), target);
356
357 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnless));
358
f9bf01c6 359 fail1.link(this);
f9bf01c6
A
360 }
361
362 JITStubCall stubCall(this, cti_op_jless);
363 stubCall.addArgument(op1, regT2);
364 stubCall.addArgument(regT1);
365 stubCall.call();
366 emitJumpSlowToHot(branchTest32(Zero, regT0), target);
367
368 } else {
369 linkSlowCase(iter);
370
371 if (supportsFloatingPoint()) {
f9bf01c6
A
372 Jump fail1 = emitJumpIfNotImmediateNumber(regT0);
373 Jump fail2 = emitJumpIfNotImmediateNumber(regT1);
374 Jump fail3 = emitJumpIfImmediateInteger(regT1);
375 addPtr(tagTypeNumberRegister, regT0);
376 addPtr(tagTypeNumberRegister, regT1);
377 movePtrToDouble(regT0, fpRegT0);
378 movePtrToDouble(regT1, fpRegT1);
f9bf01c6
A
379
380 emitJumpSlowToHot(branchDouble(DoubleLessThanOrEqualOrUnordered, fpRegT1, fpRegT0), target);
381
382 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnless));
383
f9bf01c6
A
384 fail1.link(this);
385 fail2.link(this);
386 fail3.link(this);
f9bf01c6
A
387 }
388
389 linkSlowCase(iter);
390 JITStubCall stubCall(this, cti_op_jless);
391 stubCall.addArgument(regT0);
392 stubCall.addArgument(regT1);
393 stubCall.call();
394 emitJumpSlowToHot(branchTest32(Zero, regT0), target);
395 }
396}
397
398void JIT::emit_op_jless(Instruction* currentInstruction)
399{
400 unsigned op1 = currentInstruction[1].u.operand;
401 unsigned op2 = currentInstruction[2].u.operand;
402 unsigned target = currentInstruction[3].u.operand;
403
404 // We generate inline code for the following cases in the fast path:
405 // - int immediate to constant int immediate
406 // - constant int immediate to int immediate
407 // - int immediate to int immediate
408
4e4e5a6f
A
409 if (isOperandConstantImmediateChar(op1)) {
410 emitGetVirtualRegister(op2, regT0);
411 addSlowCase(emitJumpIfNotJSCell(regT0));
412 JumpList failures;
413 emitLoadCharacterString(regT0, regT0, failures);
414 addSlowCase(failures);
415 addJump(branch32(GreaterThan, regT0, Imm32(asString(getConstantOperand(op1))->tryGetValue()[0])), target);
416 return;
417 }
418 if (isOperandConstantImmediateChar(op2)) {
419 emitGetVirtualRegister(op1, regT0);
420 addSlowCase(emitJumpIfNotJSCell(regT0));
421 JumpList failures;
422 emitLoadCharacterString(regT0, regT0, failures);
423 addSlowCase(failures);
424 addJump(branch32(LessThan, regT0, Imm32(asString(getConstantOperand(op2))->tryGetValue()[0])), target);
425 return;
426 }
f9bf01c6
A
427 if (isOperandConstantImmediateInt(op2)) {
428 emitGetVirtualRegister(op1, regT0);
429 emitJumpSlowCaseIfNotImmediateInteger(regT0);
f9bf01c6 430 int32_t op2imm = getConstantOperandImmediateInt(op2);
f9bf01c6
A
431 addJump(branch32(LessThan, regT0, Imm32(op2imm)), target);
432 } else if (isOperandConstantImmediateInt(op1)) {
433 emitGetVirtualRegister(op2, regT1);
434 emitJumpSlowCaseIfNotImmediateInteger(regT1);
f9bf01c6 435 int32_t op1imm = getConstantOperandImmediateInt(op1);
f9bf01c6
A
436 addJump(branch32(GreaterThan, regT1, Imm32(op1imm)), target);
437 } else {
438 emitGetVirtualRegisters(op1, regT0, op2, regT1);
439 emitJumpSlowCaseIfNotImmediateInteger(regT0);
440 emitJumpSlowCaseIfNotImmediateInteger(regT1);
441
442 addJump(branch32(LessThan, regT0, regT1), target);
443 }
444}
445
446void JIT::emitSlow_op_jless(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
447{
448 unsigned op1 = currentInstruction[1].u.operand;
449 unsigned op2 = currentInstruction[2].u.operand;
450 unsigned target = currentInstruction[3].u.operand;
451
452 // We generate inline code for the following cases in the slow path:
453 // - floating-point number to constant int immediate
454 // - constant int immediate to floating-point number
455 // - floating-point number to floating-point number.
4e4e5a6f
A
456 if (isOperandConstantImmediateChar(op1) || isOperandConstantImmediateChar(op2)) {
457 linkSlowCase(iter);
458 linkSlowCase(iter);
459 linkSlowCase(iter);
460 linkSlowCase(iter);
461 JITStubCall stubCall(this, cti_op_jless);
462 stubCall.addArgument(op1, regT0);
463 stubCall.addArgument(op2, regT1);
464 stubCall.call();
465 emitJumpSlowToHot(branchTest32(NonZero, regT0), target);
466 return;
467 }
f9bf01c6
A
468
469 if (isOperandConstantImmediateInt(op2)) {
470 linkSlowCase(iter);
471
472 if (supportsFloatingPoint()) {
f9bf01c6
A
473 Jump fail1 = emitJumpIfNotImmediateNumber(regT0);
474 addPtr(tagTypeNumberRegister, regT0);
475 movePtrToDouble(regT0, fpRegT0);
4e4e5a6f 476
f9bf01c6 477 int32_t op2imm = getConstantOperand(op2).asInt32();
4e4e5a6f 478
f9bf01c6
A
479 move(Imm32(op2imm), regT1);
480 convertInt32ToDouble(regT1, fpRegT1);
481
482 emitJumpSlowToHot(branchDouble(DoubleLessThan, fpRegT0, fpRegT1), target);
483
484 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnless));
485
f9bf01c6 486 fail1.link(this);
f9bf01c6
A
487 }
488
489 JITStubCall stubCall(this, cti_op_jless);
490 stubCall.addArgument(regT0);
491 stubCall.addArgument(op2, regT2);
492 stubCall.call();
493 emitJumpSlowToHot(branchTest32(NonZero, regT0), target);
494
495 } else if (isOperandConstantImmediateInt(op1)) {
496 linkSlowCase(iter);
497
498 if (supportsFloatingPoint()) {
f9bf01c6
A
499 Jump fail1 = emitJumpIfNotImmediateNumber(regT1);
500 addPtr(tagTypeNumberRegister, regT1);
501 movePtrToDouble(regT1, fpRegT1);
4e4e5a6f 502
f9bf01c6 503 int32_t op1imm = getConstantOperand(op1).asInt32();
4e4e5a6f 504
f9bf01c6
A
505 move(Imm32(op1imm), regT0);
506 convertInt32ToDouble(regT0, fpRegT0);
507
508 emitJumpSlowToHot(branchDouble(DoubleLessThan, fpRegT0, fpRegT1), target);
9dae56ea 509
ba379fdc
A
510 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnless));
511
ba379fdc 512 fail1.link(this);
ba379fdc
A
513 }
514
515 JITStubCall stubCall(this, cti_op_jless);
516 stubCall.addArgument(op1, regT2);
517 stubCall.addArgument(regT1);
518 stubCall.call();
f9bf01c6 519 emitJumpSlowToHot(branchTest32(NonZero, regT0), target);
ba379fdc
A
520
521 } else {
522 linkSlowCase(iter);
523
524 if (supportsFloatingPoint()) {
ba379fdc
A
525 Jump fail1 = emitJumpIfNotImmediateNumber(regT0);
526 Jump fail2 = emitJumpIfNotImmediateNumber(regT1);
527 Jump fail3 = emitJumpIfImmediateInteger(regT1);
528 addPtr(tagTypeNumberRegister, regT0);
529 addPtr(tagTypeNumberRegister, regT1);
530 movePtrToDouble(regT0, fpRegT0);
531 movePtrToDouble(regT1, fpRegT1);
ba379fdc 532
f9bf01c6 533 emitJumpSlowToHot(branchDouble(DoubleLessThan, fpRegT0, fpRegT1), target);
ba379fdc
A
534
535 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnless));
536
ba379fdc
A
537 fail1.link(this);
538 fail2.link(this);
539 fail3.link(this);
ba379fdc
A
540 }
541
542 linkSlowCase(iter);
543 JITStubCall stubCall(this, cti_op_jless);
544 stubCall.addArgument(regT0);
545 stubCall.addArgument(regT1);
546 stubCall.call();
f9bf01c6 547 emitJumpSlowToHot(branchTest32(NonZero, regT0), target);
ba379fdc 548 }
9dae56ea 549}
ba379fdc 550
4e4e5a6f 551void JIT::emit_op_jlesseq(Instruction* currentInstruction, bool invert)
9dae56ea 552{
ba379fdc
A
553 unsigned op1 = currentInstruction[1].u.operand;
554 unsigned op2 = currentInstruction[2].u.operand;
555 unsigned target = currentInstruction[3].u.operand;
556
557 // We generate inline code for the following cases in the fast path:
558 // - int immediate to constant int immediate
559 // - constant int immediate to int immediate
560 // - int immediate to int immediate
561
4e4e5a6f
A
562 if (isOperandConstantImmediateChar(op1)) {
563 emitGetVirtualRegister(op2, regT0);
564 addSlowCase(emitJumpIfNotJSCell(regT0));
565 JumpList failures;
566 emitLoadCharacterString(regT0, regT0, failures);
567 addSlowCase(failures);
568 addJump(branch32(invert ? LessThan : GreaterThanOrEqual, regT0, Imm32(asString(getConstantOperand(op1))->tryGetValue()[0])), target);
569 return;
570 }
571 if (isOperandConstantImmediateChar(op2)) {
572 emitGetVirtualRegister(op1, regT0);
573 addSlowCase(emitJumpIfNotJSCell(regT0));
574 JumpList failures;
575 emitLoadCharacterString(regT0, regT0, failures);
576 addSlowCase(failures);
577 addJump(branch32(invert ? GreaterThan : LessThanOrEqual, regT0, Imm32(asString(getConstantOperand(op2))->tryGetValue()[0])), target);
578 return;
579 }
ba379fdc
A
580 if (isOperandConstantImmediateInt(op2)) {
581 emitGetVirtualRegister(op1, regT0);
582 emitJumpSlowCaseIfNotImmediateInteger(regT0);
ba379fdc 583 int32_t op2imm = getConstantOperandImmediateInt(op2);
4e4e5a6f 584 addJump(branch32(invert ? GreaterThan : LessThanOrEqual, regT0, Imm32(op2imm)), target);
ba379fdc
A
585 } else if (isOperandConstantImmediateInt(op1)) {
586 emitGetVirtualRegister(op2, regT1);
587 emitJumpSlowCaseIfNotImmediateInteger(regT1);
ba379fdc 588 int32_t op1imm = getConstantOperandImmediateInt(op1);
4e4e5a6f 589 addJump(branch32(invert ? LessThan : GreaterThanOrEqual, regT1, Imm32(op1imm)), target);
ba379fdc
A
590 } else {
591 emitGetVirtualRegisters(op1, regT0, op2, regT1);
592 emitJumpSlowCaseIfNotImmediateInteger(regT0);
593 emitJumpSlowCaseIfNotImmediateInteger(regT1);
594
4e4e5a6f 595 addJump(branch32(invert ? GreaterThan : LessThanOrEqual, regT0, regT1), target);
ba379fdc 596 }
9dae56ea
A
597}
598
4e4e5a6f 599void JIT::emitSlow_op_jlesseq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter, bool invert)
9dae56ea 600{
ba379fdc
A
601 unsigned op1 = currentInstruction[1].u.operand;
602 unsigned op2 = currentInstruction[2].u.operand;
603 unsigned target = currentInstruction[3].u.operand;
604
605 // We generate inline code for the following cases in the slow path:
606 // - floating-point number to constant int immediate
607 // - constant int immediate to floating-point number
608 // - floating-point number to floating-point number.
609
4e4e5a6f
A
610 if (isOperandConstantImmediateChar(op1) || isOperandConstantImmediateChar(op2)) {
611 linkSlowCase(iter);
612 linkSlowCase(iter);
613 linkSlowCase(iter);
614 linkSlowCase(iter);
615 JITStubCall stubCall(this, cti_op_jlesseq);
616 stubCall.addArgument(op1, regT0);
617 stubCall.addArgument(op2, regT1);
618 stubCall.call();
619 emitJumpSlowToHot(branchTest32(invert ? Zero : NonZero, regT0), target);
620 return;
621 }
622
9dae56ea 623 if (isOperandConstantImmediateInt(op2)) {
ba379fdc
A
624 linkSlowCase(iter);
625
626 if (supportsFloatingPoint()) {
ba379fdc
A
627 Jump fail1 = emitJumpIfNotImmediateNumber(regT0);
628 addPtr(tagTypeNumberRegister, regT0);
629 movePtrToDouble(regT0, fpRegT0);
4e4e5a6f 630
ba379fdc 631 int32_t op2imm = getConstantOperand(op2).asInt32();;
4e4e5a6f 632
ba379fdc
A
633 move(Imm32(op2imm), regT1);
634 convertInt32ToDouble(regT1, fpRegT1);
635
4e4e5a6f 636 emitJumpSlowToHot(branchDouble(invert ? DoubleLessThanOrUnordered : DoubleGreaterThanOrEqual, fpRegT1, fpRegT0), target);
ba379fdc
A
637
638 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnlesseq));
639
ba379fdc 640 fail1.link(this);
ba379fdc
A
641 }
642
643 JITStubCall stubCall(this, cti_op_jlesseq);
644 stubCall.addArgument(regT0);
645 stubCall.addArgument(op2, regT2);
646 stubCall.call();
4e4e5a6f 647 emitJumpSlowToHot(branchTest32(invert ? Zero : NonZero, regT0), target);
ba379fdc
A
648
649 } else if (isOperandConstantImmediateInt(op1)) {
650 linkSlowCase(iter);
651
652 if (supportsFloatingPoint()) {
ba379fdc
A
653 Jump fail1 = emitJumpIfNotImmediateNumber(regT1);
654 addPtr(tagTypeNumberRegister, regT1);
655 movePtrToDouble(regT1, fpRegT1);
4e4e5a6f 656
ba379fdc 657 int32_t op1imm = getConstantOperand(op1).asInt32();;
4e4e5a6f 658
ba379fdc
A
659 move(Imm32(op1imm), regT0);
660 convertInt32ToDouble(regT0, fpRegT0);
661
4e4e5a6f 662 emitJumpSlowToHot(branchDouble(invert ? DoubleLessThanOrUnordered : DoubleGreaterThanOrEqual, fpRegT1, fpRegT0), target);
ba379fdc
A
663
664 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnlesseq));
665
ba379fdc 666 fail1.link(this);
ba379fdc
A
667 }
668
669 JITStubCall stubCall(this, cti_op_jlesseq);
670 stubCall.addArgument(op1, regT2);
671 stubCall.addArgument(regT1);
672 stubCall.call();
4e4e5a6f 673 emitJumpSlowToHot(branchTest32(invert ? Zero : NonZero, regT0), target);
ba379fdc
A
674
675 } else {
9dae56ea 676 linkSlowCase(iter);
9dae56ea 677
ba379fdc 678 if (supportsFloatingPoint()) {
ba379fdc
A
679 Jump fail1 = emitJumpIfNotImmediateNumber(regT0);
680 Jump fail2 = emitJumpIfNotImmediateNumber(regT1);
681 Jump fail3 = emitJumpIfImmediateInteger(regT1);
682 addPtr(tagTypeNumberRegister, regT0);
683 addPtr(tagTypeNumberRegister, regT1);
684 movePtrToDouble(regT0, fpRegT0);
685 movePtrToDouble(regT1, fpRegT1);
ba379fdc 686
4e4e5a6f 687 emitJumpSlowToHot(branchDouble(invert ? DoubleLessThanOrUnordered : DoubleGreaterThanOrEqual, fpRegT1, fpRegT0), target);
ba379fdc
A
688
689 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnlesseq));
690
ba379fdc
A
691 fail1.link(this);
692 fail2.link(this);
693 fail3.link(this);
ba379fdc
A
694 }
695
696 linkSlowCase(iter);
697 JITStubCall stubCall(this, cti_op_jlesseq);
698 stubCall.addArgument(regT0);
699 stubCall.addArgument(regT1);
700 stubCall.call();
4e4e5a6f 701 emitJumpSlowToHot(branchTest32(invert ? Zero : NonZero, regT0), target);
ba379fdc 702 }
9dae56ea
A
703}
704
4e4e5a6f
A
705void JIT::emit_op_jnlesseq(Instruction* currentInstruction)
706{
707 emit_op_jlesseq(currentInstruction, true);
708}
709
710void JIT::emitSlow_op_jnlesseq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
711{
712 emitSlow_op_jlesseq(currentInstruction, iter, true);
713}
714
ba379fdc 715void JIT::emit_op_bitand(Instruction* currentInstruction)
9dae56ea 716{
ba379fdc
A
717 unsigned result = currentInstruction[1].u.operand;
718 unsigned op1 = currentInstruction[2].u.operand;
719 unsigned op2 = currentInstruction[3].u.operand;
720
9dae56ea 721 if (isOperandConstantImmediateInt(op1)) {
ba379fdc
A
722 emitGetVirtualRegister(op2, regT0);
723 emitJumpSlowCaseIfNotImmediateInteger(regT0);
9dae56ea 724 int32_t imm = getConstantOperandImmediateInt(op1);
ba379fdc 725 andPtr(Imm32(imm), regT0);
9dae56ea 726 if (imm >= 0)
ba379fdc 727 emitFastArithIntToImmNoCheck(regT0, regT0);
9dae56ea 728 } else if (isOperandConstantImmediateInt(op2)) {
ba379fdc
A
729 emitGetVirtualRegister(op1, regT0);
730 emitJumpSlowCaseIfNotImmediateInteger(regT0);
9dae56ea 731 int32_t imm = getConstantOperandImmediateInt(op2);
ba379fdc 732 andPtr(Imm32(imm), regT0);
9dae56ea 733 if (imm >= 0)
ba379fdc 734 emitFastArithIntToImmNoCheck(regT0, regT0);
9dae56ea 735 } else {
ba379fdc
A
736 emitGetVirtualRegisters(op1, regT0, op2, regT1);
737 andPtr(regT1, regT0);
738 emitJumpSlowCaseIfNotImmediateInteger(regT0);
9dae56ea
A
739 }
740 emitPutVirtualRegister(result);
741}
ba379fdc
A
742
743void JIT::emitSlow_op_bitand(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
9dae56ea 744{
ba379fdc
A
745 unsigned result = currentInstruction[1].u.operand;
746 unsigned op1 = currentInstruction[2].u.operand;
747 unsigned op2 = currentInstruction[3].u.operand;
748
9dae56ea
A
749 linkSlowCase(iter);
750 if (isOperandConstantImmediateInt(op1)) {
ba379fdc
A
751 JITStubCall stubCall(this, cti_op_bitand);
752 stubCall.addArgument(op1, regT2);
753 stubCall.addArgument(regT0);
754 stubCall.call(result);
9dae56ea 755 } else if (isOperandConstantImmediateInt(op2)) {
ba379fdc
A
756 JITStubCall stubCall(this, cti_op_bitand);
757 stubCall.addArgument(regT0);
758 stubCall.addArgument(op2, regT2);
759 stubCall.call(result);
9dae56ea 760 } else {
ba379fdc
A
761 JITStubCall stubCall(this, cti_op_bitand);
762 stubCall.addArgument(op1, regT2);
763 stubCall.addArgument(regT1);
764 stubCall.call(result);
9dae56ea 765 }
9dae56ea
A
766}
767
ba379fdc 768void JIT::emit_op_post_inc(Instruction* currentInstruction)
9dae56ea 769{
ba379fdc
A
770 unsigned result = currentInstruction[1].u.operand;
771 unsigned srcDst = currentInstruction[2].u.operand;
772
773 emitGetVirtualRegister(srcDst, regT0);
774 move(regT0, regT1);
775 emitJumpSlowCaseIfNotImmediateInteger(regT0);
14957cd0 776 addSlowCase(branchAdd32(Overflow, TrustedImm32(1), regT1));
ba379fdc 777 emitFastArithIntToImmNoCheck(regT1, regT1);
ba379fdc 778 emitPutVirtualRegister(srcDst, regT1);
9dae56ea
A
779 emitPutVirtualRegister(result);
780}
781
ba379fdc 782void JIT::emitSlow_op_post_inc(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
9dae56ea 783{
ba379fdc
A
784 unsigned result = currentInstruction[1].u.operand;
785 unsigned srcDst = currentInstruction[2].u.operand;
786
9dae56ea
A
787 linkSlowCase(iter);
788 linkSlowCase(iter);
ba379fdc
A
789 JITStubCall stubCall(this, cti_op_post_inc);
790 stubCall.addArgument(regT0);
791 stubCall.addArgument(Imm32(srcDst));
792 stubCall.call(result);
9dae56ea
A
793}
794
ba379fdc 795void JIT::emit_op_post_dec(Instruction* currentInstruction)
9dae56ea 796{
ba379fdc
A
797 unsigned result = currentInstruction[1].u.operand;
798 unsigned srcDst = currentInstruction[2].u.operand;
799
800 emitGetVirtualRegister(srcDst, regT0);
801 move(regT0, regT1);
802 emitJumpSlowCaseIfNotImmediateInteger(regT0);
14957cd0 803 addSlowCase(branchSub32(Zero, TrustedImm32(1), regT1));
ba379fdc 804 emitFastArithIntToImmNoCheck(regT1, regT1);
ba379fdc 805 emitPutVirtualRegister(srcDst, regT1);
9dae56ea
A
806 emitPutVirtualRegister(result);
807}
ba379fdc
A
808
809void JIT::emitSlow_op_post_dec(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
9dae56ea 810{
ba379fdc
A
811 unsigned result = currentInstruction[1].u.operand;
812 unsigned srcDst = currentInstruction[2].u.operand;
813
9dae56ea
A
814 linkSlowCase(iter);
815 linkSlowCase(iter);
ba379fdc
A
816 JITStubCall stubCall(this, cti_op_post_dec);
817 stubCall.addArgument(regT0);
818 stubCall.addArgument(Imm32(srcDst));
819 stubCall.call(result);
9dae56ea
A
820}
821
ba379fdc 822void JIT::emit_op_pre_inc(Instruction* currentInstruction)
9dae56ea 823{
ba379fdc
A
824 unsigned srcDst = currentInstruction[1].u.operand;
825
826 emitGetVirtualRegister(srcDst, regT0);
827 emitJumpSlowCaseIfNotImmediateInteger(regT0);
14957cd0 828 addSlowCase(branchAdd32(Overflow, TrustedImm32(1), regT0));
ba379fdc 829 emitFastArithIntToImmNoCheck(regT0, regT0);
9dae56ea
A
830 emitPutVirtualRegister(srcDst);
831}
ba379fdc
A
832
833void JIT::emitSlow_op_pre_inc(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
9dae56ea 834{
ba379fdc
A
835 unsigned srcDst = currentInstruction[1].u.operand;
836
9dae56ea
A
837 Jump notImm = getSlowCase(iter);
838 linkSlowCase(iter);
ba379fdc 839 emitGetVirtualRegister(srcDst, regT0);
9dae56ea 840 notImm.link(this);
ba379fdc
A
841 JITStubCall stubCall(this, cti_op_pre_inc);
842 stubCall.addArgument(regT0);
843 stubCall.call(srcDst);
9dae56ea
A
844}
845
ba379fdc 846void JIT::emit_op_pre_dec(Instruction* currentInstruction)
9dae56ea 847{
ba379fdc
A
848 unsigned srcDst = currentInstruction[1].u.operand;
849
850 emitGetVirtualRegister(srcDst, regT0);
851 emitJumpSlowCaseIfNotImmediateInteger(regT0);
14957cd0 852 addSlowCase(branchSub32(Zero, TrustedImm32(1), regT0));
ba379fdc 853 emitFastArithIntToImmNoCheck(regT0, regT0);
9dae56ea
A
854 emitPutVirtualRegister(srcDst);
855}
ba379fdc
A
856
857void JIT::emitSlow_op_pre_dec(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
9dae56ea 858{
ba379fdc
A
859 unsigned srcDst = currentInstruction[1].u.operand;
860
9dae56ea
A
861 Jump notImm = getSlowCase(iter);
862 linkSlowCase(iter);
ba379fdc 863 emitGetVirtualRegister(srcDst, regT0);
9dae56ea 864 notImm.link(this);
ba379fdc
A
865 JITStubCall stubCall(this, cti_op_pre_dec);
866 stubCall.addArgument(regT0);
867 stubCall.call(srcDst);
9dae56ea
A
868}
869
ba379fdc 870/* ------------------------------ BEGIN: OP_MOD ------------------------------ */
9dae56ea 871
14957cd0 872#if CPU(X86) || CPU(X86_64) || CPU(MIPS)
9dae56ea 873
ba379fdc 874void JIT::emit_op_mod(Instruction* currentInstruction)
9dae56ea
A
875{
876 unsigned result = currentInstruction[1].u.operand;
877 unsigned op1 = currentInstruction[2].u.operand;
878 unsigned op2 = currentInstruction[3].u.operand;
879
14957cd0
A
880#if CPU(X86) || CPU(X86_64)
881 // Make sure registers are correct for x86 IDIV instructions.
882 ASSERT(regT0 == X86Registers::eax);
883 ASSERT(regT1 == X86Registers::edx);
884 ASSERT(regT2 == X86Registers::ecx);
ba379fdc 885#endif
14957cd0
A
886
887 emitGetVirtualRegisters(op1, regT0, op2, regT2);
888 emitJumpSlowCaseIfNotImmediateInteger(regT0);
889 emitJumpSlowCaseIfNotImmediateInteger(regT2);
890
891 addSlowCase(branchPtr(Equal, regT2, TrustedImmPtr(JSValue::encode(jsNumber(0)))));
892 m_assembler.cdq();
893 m_assembler.idivl_r(regT2);
894 emitFastArithReTagImmediate(regT1, regT0);
9dae56ea
A
895 emitPutVirtualRegister(result);
896}
9dae56ea 897
ba379fdc 898void JIT::emitSlow_op_mod(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
9dae56ea
A
899{
900 unsigned result = currentInstruction[1].u.operand;
9dae56ea 901
ba379fdc
A
902 linkSlowCase(iter);
903 linkSlowCase(iter);
ba379fdc 904 linkSlowCase(iter);
ba379fdc 905 JITStubCall stubCall(this, cti_op_mod);
14957cd0
A
906 stubCall.addArgument(regT0);
907 stubCall.addArgument(regT2);
ba379fdc 908 stubCall.call(result);
9dae56ea
A
909}
910
14957cd0 911#else // CPU(X86) || CPU(X86_64) || CPU(MIPS)
ba379fdc
A
912
913void JIT::emit_op_mod(Instruction* currentInstruction)
9dae56ea
A
914{
915 unsigned result = currentInstruction[1].u.operand;
916 unsigned op1 = currentInstruction[2].u.operand;
917 unsigned op2 = currentInstruction[3].u.operand;
918
ba379fdc
A
919 JITStubCall stubCall(this, cti_op_mod);
920 stubCall.addArgument(op1, regT2);
921 stubCall.addArgument(op2, regT2);
922 stubCall.call(result);
9dae56ea 923}
ba379fdc 924
4e4e5a6f 925void JIT::emitSlow_op_mod(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
9dae56ea 926{
14957cd0 927#if ENABLE(JIT_USE_SOFT_MODULO)
4e4e5a6f
A
928 unsigned result = currentInstruction[1].u.operand;
929 unsigned op1 = currentInstruction[2].u.operand;
930 unsigned op2 = currentInstruction[3].u.operand;
931 linkSlowCase(iter);
932 linkSlowCase(iter);
933 linkSlowCase(iter);
934 JITStubCall stubCall(this, cti_op_mod);
935 stubCall.addArgument(op1, regT2);
936 stubCall.addArgument(op2, regT2);
937 stubCall.call(result);
938#else
9dae56ea 939 ASSERT_NOT_REACHED();
4e4e5a6f 940#endif
9dae56ea
A
941}
942
f9bf01c6 943#endif // CPU(X86) || CPU(X86_64)
ba379fdc
A
944
945/* ------------------------------ END: OP_MOD ------------------------------ */
946
ba379fdc 947/* ------------------------------ BEGIN: USE(JSVALUE64) (OP_ADD, OP_SUB, OP_MUL) ------------------------------ */
9dae56ea
A
948
949void JIT::compileBinaryArithOp(OpcodeID opcodeID, unsigned, unsigned op1, unsigned op2, OperandTypes)
950{
ba379fdc
A
951 emitGetVirtualRegisters(op1, regT0, op2, regT1);
952 emitJumpSlowCaseIfNotImmediateInteger(regT0);
953 emitJumpSlowCaseIfNotImmediateInteger(regT1);
9dae56ea 954 if (opcodeID == op_add)
ba379fdc 955 addSlowCase(branchAdd32(Overflow, regT1, regT0));
9dae56ea 956 else if (opcodeID == op_sub)
ba379fdc 957 addSlowCase(branchSub32(Overflow, regT1, regT0));
9dae56ea
A
958 else {
959 ASSERT(opcodeID == op_mul);
ba379fdc
A
960 addSlowCase(branchMul32(Overflow, regT1, regT0));
961 addSlowCase(branchTest32(Zero, regT0));
9dae56ea 962 }
ba379fdc 963 emitFastArithIntToImmNoCheck(regT0, regT0);
9dae56ea
A
964}
965
f9bf01c6 966void JIT::compileBinaryArithOpSlowCase(OpcodeID opcodeID, Vector<SlowCaseEntry>::iterator& iter, unsigned result, unsigned op1, unsigned op2, OperandTypes types, bool op1HasImmediateIntFastCase, bool op2HasImmediateIntFastCase)
9dae56ea
A
967{
968 // We assume that subtracting TagTypeNumber is equivalent to adding DoubleEncodeOffset.
14957cd0 969 COMPILE_ASSERT(((TagTypeNumber + DoubleEncodeOffset) == 0), TagTypeNumber_PLUS_DoubleEncodeOffset_EQUALS_0);
4e4e5a6f 970
f9bf01c6
A
971 Jump notImm1;
972 Jump notImm2;
973 if (op1HasImmediateIntFastCase) {
974 notImm2 = getSlowCase(iter);
975 } else if (op2HasImmediateIntFastCase) {
976 notImm1 = getSlowCase(iter);
977 } else {
978 notImm1 = getSlowCase(iter);
979 notImm2 = getSlowCase(iter);
980 }
9dae56ea
A
981
982 linkSlowCase(iter); // Integer overflow case - we could handle this in JIT code, but this is likely rare.
f9bf01c6 983 if (opcodeID == op_mul && !op1HasImmediateIntFastCase && !op2HasImmediateIntFastCase) // op_mul has an extra slow case to handle 0 * negative number.
9dae56ea 984 linkSlowCase(iter);
ba379fdc 985 emitGetVirtualRegister(op1, regT0);
9dae56ea
A
986
987 Label stubFunctionCall(this);
ba379fdc 988 JITStubCall stubCall(this, opcodeID == op_add ? cti_op_add : opcodeID == op_sub ? cti_op_sub : cti_op_mul);
f9bf01c6
A
989 if (op1HasImmediateIntFastCase || op2HasImmediateIntFastCase) {
990 emitGetVirtualRegister(op1, regT0);
991 emitGetVirtualRegister(op2, regT1);
992 }
ba379fdc
A
993 stubCall.addArgument(regT0);
994 stubCall.addArgument(regT1);
995 stubCall.call(result);
9dae56ea
A
996 Jump end = jump();
997
f9bf01c6
A
998 if (op1HasImmediateIntFastCase) {
999 notImm2.link(this);
1000 if (!types.second().definitelyIsNumber())
1001 emitJumpIfNotImmediateNumber(regT0).linkTo(stubFunctionCall, this);
1002 emitGetVirtualRegister(op1, regT1);
1003 convertInt32ToDouble(regT1, fpRegT1);
1004 addPtr(tagTypeNumberRegister, regT0);
1005 movePtrToDouble(regT0, fpRegT2);
1006 } else if (op2HasImmediateIntFastCase) {
1007 notImm1.link(this);
1008 if (!types.first().definitelyIsNumber())
1009 emitJumpIfNotImmediateNumber(regT0).linkTo(stubFunctionCall, this);
1010 emitGetVirtualRegister(op2, regT1);
1011 convertInt32ToDouble(regT1, fpRegT1);
1012 addPtr(tagTypeNumberRegister, regT0);
1013 movePtrToDouble(regT0, fpRegT2);
1014 } else {
1015 // if we get here, eax is not an int32, edx not yet checked.
1016 notImm1.link(this);
1017 if (!types.first().definitelyIsNumber())
1018 emitJumpIfNotImmediateNumber(regT0).linkTo(stubFunctionCall, this);
1019 if (!types.second().definitelyIsNumber())
1020 emitJumpIfNotImmediateNumber(regT1).linkTo(stubFunctionCall, this);
1021 addPtr(tagTypeNumberRegister, regT0);
1022 movePtrToDouble(regT0, fpRegT1);
1023 Jump op2isDouble = emitJumpIfNotImmediateInteger(regT1);
1024 convertInt32ToDouble(regT1, fpRegT2);
1025 Jump op2wasInteger = jump();
1026
1027 // if we get here, eax IS an int32, edx is not.
1028 notImm2.link(this);
1029 if (!types.second().definitelyIsNumber())
1030 emitJumpIfNotImmediateNumber(regT1).linkTo(stubFunctionCall, this);
1031 convertInt32ToDouble(regT0, fpRegT1);
1032 op2isDouble.link(this);
1033 addPtr(tagTypeNumberRegister, regT1);
1034 movePtrToDouble(regT1, fpRegT2);
1035 op2wasInteger.link(this);
1036 }
9dae56ea
A
1037
1038 if (opcodeID == op_add)
ba379fdc 1039 addDouble(fpRegT2, fpRegT1);
9dae56ea 1040 else if (opcodeID == op_sub)
ba379fdc 1041 subDouble(fpRegT2, fpRegT1);
f9bf01c6 1042 else if (opcodeID == op_mul)
ba379fdc 1043 mulDouble(fpRegT2, fpRegT1);
f9bf01c6
A
1044 else {
1045 ASSERT(opcodeID == op_div);
1046 divDouble(fpRegT2, fpRegT1);
9dae56ea 1047 }
ba379fdc
A
1048 moveDoubleToPtr(fpRegT1, regT0);
1049 subPtr(tagTypeNumberRegister, regT0);
1050 emitPutVirtualRegister(result, regT0);
9dae56ea
A
1051
1052 end.link(this);
1053}
1054
ba379fdc 1055void JIT::emit_op_add(Instruction* currentInstruction)
9dae56ea
A
1056{
1057 unsigned result = currentInstruction[1].u.operand;
1058 unsigned op1 = currentInstruction[2].u.operand;
1059 unsigned op2 = currentInstruction[3].u.operand;
1060 OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand);
1061
1062 if (!types.first().mightBeNumber() || !types.second().mightBeNumber()) {
ba379fdc
A
1063 JITStubCall stubCall(this, cti_op_add);
1064 stubCall.addArgument(op1, regT2);
1065 stubCall.addArgument(op2, regT2);
1066 stubCall.call(result);
9dae56ea
A
1067 return;
1068 }
1069
1070 if (isOperandConstantImmediateInt(op1)) {
ba379fdc
A
1071 emitGetVirtualRegister(op2, regT0);
1072 emitJumpSlowCaseIfNotImmediateInteger(regT0);
1073 addSlowCase(branchAdd32(Overflow, Imm32(getConstantOperandImmediateInt(op1)), regT0));
1074 emitFastArithIntToImmNoCheck(regT0, regT0);
9dae56ea 1075 } else if (isOperandConstantImmediateInt(op2)) {
ba379fdc
A
1076 emitGetVirtualRegister(op1, regT0);
1077 emitJumpSlowCaseIfNotImmediateInteger(regT0);
1078 addSlowCase(branchAdd32(Overflow, Imm32(getConstantOperandImmediateInt(op2)), regT0));
1079 emitFastArithIntToImmNoCheck(regT0, regT0);
9dae56ea
A
1080 } else
1081 compileBinaryArithOp(op_add, result, op1, op2, types);
1082
1083 emitPutVirtualRegister(result);
1084}
ba379fdc
A
1085
1086void JIT::emitSlow_op_add(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
9dae56ea
A
1087{
1088 unsigned result = currentInstruction[1].u.operand;
1089 unsigned op1 = currentInstruction[2].u.operand;
1090 unsigned op2 = currentInstruction[3].u.operand;
f9bf01c6 1091 OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand);
9dae56ea 1092
f9bf01c6
A
1093 if (!types.first().mightBeNumber() || !types.second().mightBeNumber())
1094 return;
1095
1096 bool op1HasImmediateIntFastCase = isOperandConstantImmediateInt(op1);
1097 bool op2HasImmediateIntFastCase = !op1HasImmediateIntFastCase && isOperandConstantImmediateInt(op2);
14957cd0 1098 compileBinaryArithOpSlowCase(op_add, iter, result, op1, op2, types, op1HasImmediateIntFastCase, op2HasImmediateIntFastCase);
9dae56ea
A
1099}
1100
ba379fdc 1101void JIT::emit_op_mul(Instruction* currentInstruction)
9dae56ea
A
1102{
1103 unsigned result = currentInstruction[1].u.operand;
1104 unsigned op1 = currentInstruction[2].u.operand;
1105 unsigned op2 = currentInstruction[3].u.operand;
1106 OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand);
1107
1108 // For now, only plant a fast int case if the constant operand is greater than zero.
1109 int32_t value;
1110 if (isOperandConstantImmediateInt(op1) && ((value = getConstantOperandImmediateInt(op1)) > 0)) {
ba379fdc
A
1111 emitGetVirtualRegister(op2, regT0);
1112 emitJumpSlowCaseIfNotImmediateInteger(regT0);
1113 addSlowCase(branchMul32(Overflow, Imm32(value), regT0, regT0));
1114 emitFastArithReTagImmediate(regT0, regT0);
9dae56ea 1115 } else if (isOperandConstantImmediateInt(op2) && ((value = getConstantOperandImmediateInt(op2)) > 0)) {
ba379fdc
A
1116 emitGetVirtualRegister(op1, regT0);
1117 emitJumpSlowCaseIfNotImmediateInteger(regT0);
1118 addSlowCase(branchMul32(Overflow, Imm32(value), regT0, regT0));
1119 emitFastArithReTagImmediate(regT0, regT0);
9dae56ea
A
1120 } else
1121 compileBinaryArithOp(op_mul, result, op1, op2, types);
1122
1123 emitPutVirtualRegister(result);
1124}
ba379fdc
A
1125
1126void JIT::emitSlow_op_mul(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
9dae56ea
A
1127{
1128 unsigned result = currentInstruction[1].u.operand;
1129 unsigned op1 = currentInstruction[2].u.operand;
1130 unsigned op2 = currentInstruction[3].u.operand;
1131 OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand);
1132
f9bf01c6
A
1133 bool op1HasImmediateIntFastCase = isOperandConstantImmediateInt(op1) && getConstantOperandImmediateInt(op1) > 0;
1134 bool op2HasImmediateIntFastCase = !op1HasImmediateIntFastCase && isOperandConstantImmediateInt(op2) && getConstantOperandImmediateInt(op2) > 0;
14957cd0 1135 compileBinaryArithOpSlowCase(op_mul, iter, result, op1, op2, types, op1HasImmediateIntFastCase, op2HasImmediateIntFastCase);
f9bf01c6
A
1136}
1137
1138void JIT::emit_op_div(Instruction* currentInstruction)
1139{
1140 unsigned dst = currentInstruction[1].u.operand;
1141 unsigned op1 = currentInstruction[2].u.operand;
1142 unsigned op2 = currentInstruction[3].u.operand;
1143 OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand);
1144
1145 if (isOperandConstantImmediateDouble(op1)) {
1146 emitGetVirtualRegister(op1, regT0);
1147 addPtr(tagTypeNumberRegister, regT0);
1148 movePtrToDouble(regT0, fpRegT0);
1149 } else if (isOperandConstantImmediateInt(op1)) {
1150 emitLoadInt32ToDouble(op1, fpRegT0);
1151 } else {
1152 emitGetVirtualRegister(op1, regT0);
1153 if (!types.first().definitelyIsNumber())
1154 emitJumpSlowCaseIfNotImmediateNumber(regT0);
1155 Jump notInt = emitJumpIfNotImmediateInteger(regT0);
1156 convertInt32ToDouble(regT0, fpRegT0);
1157 Jump skipDoubleLoad = jump();
1158 notInt.link(this);
1159 addPtr(tagTypeNumberRegister, regT0);
1160 movePtrToDouble(regT0, fpRegT0);
1161 skipDoubleLoad.link(this);
1162 }
4e4e5a6f 1163
f9bf01c6
A
1164 if (isOperandConstantImmediateDouble(op2)) {
1165 emitGetVirtualRegister(op2, regT1);
1166 addPtr(tagTypeNumberRegister, regT1);
1167 movePtrToDouble(regT1, fpRegT1);
1168 } else if (isOperandConstantImmediateInt(op2)) {
1169 emitLoadInt32ToDouble(op2, fpRegT1);
1170 } else {
1171 emitGetVirtualRegister(op2, regT1);
1172 if (!types.second().definitelyIsNumber())
1173 emitJumpSlowCaseIfNotImmediateNumber(regT1);
1174 Jump notInt = emitJumpIfNotImmediateInteger(regT1);
1175 convertInt32ToDouble(regT1, fpRegT1);
1176 Jump skipDoubleLoad = jump();
1177 notInt.link(this);
1178 addPtr(tagTypeNumberRegister, regT1);
1179 movePtrToDouble(regT1, fpRegT1);
1180 skipDoubleLoad.link(this);
1181 }
1182 divDouble(fpRegT1, fpRegT0);
1183
1184 // Double result.
1185 moveDoubleToPtr(fpRegT0, regT0);
1186 subPtr(tagTypeNumberRegister, regT0);
1187
1188 emitPutVirtualRegister(dst, regT0);
1189}
1190
1191void JIT::emitSlow_op_div(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1192{
1193 unsigned result = currentInstruction[1].u.operand;
1194 unsigned op1 = currentInstruction[2].u.operand;
1195 unsigned op2 = currentInstruction[3].u.operand;
1196 OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand);
1197 if (types.first().definitelyIsNumber() && types.second().definitelyIsNumber()) {
1198#ifndef NDEBUG
1199 breakpoint();
1200#endif
1201 return;
1202 }
1203 if (!isOperandConstantImmediateDouble(op1) && !isOperandConstantImmediateInt(op1)) {
1204 if (!types.first().definitelyIsNumber())
1205 linkSlowCase(iter);
1206 }
1207 if (!isOperandConstantImmediateDouble(op2) && !isOperandConstantImmediateInt(op2)) {
1208 if (!types.second().definitelyIsNumber())
1209 linkSlowCase(iter);
1210 }
1211 // There is an extra slow case for (op1 * -N) or (-N * op2), to check for 0 since this should produce a result of -0.
1212 JITStubCall stubCall(this, cti_op_div);
1213 stubCall.addArgument(op1, regT2);
1214 stubCall.addArgument(op2, regT2);
1215 stubCall.call(result);
9dae56ea
A
1216}
1217
ba379fdc 1218void JIT::emit_op_sub(Instruction* currentInstruction)
9dae56ea
A
1219{
1220 unsigned result = currentInstruction[1].u.operand;
1221 unsigned op1 = currentInstruction[2].u.operand;
1222 unsigned op2 = currentInstruction[3].u.operand;
1223 OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand);
1224
1225 compileBinaryArithOp(op_sub, result, op1, op2, types);
9dae56ea
A
1226 emitPutVirtualRegister(result);
1227}
ba379fdc
A
1228
1229void JIT::emitSlow_op_sub(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
9dae56ea
A
1230{
1231 unsigned result = currentInstruction[1].u.operand;
1232 unsigned op1 = currentInstruction[2].u.operand;
1233 unsigned op2 = currentInstruction[3].u.operand;
1234 OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand);
1235
f9bf01c6 1236 compileBinaryArithOpSlowCase(op_sub, iter, result, op1, op2, types, false, false);
9dae56ea
A
1237}
1238
ba379fdc
A
1239/* ------------------------------ END: OP_ADD, OP_SUB, OP_MUL ------------------------------ */
1240
9dae56ea
A
1241} // namespace JSC
1242
14957cd0 1243#endif // USE(JSVALUE64)
9dae56ea 1244#endif // ENABLE(JIT)