1/*
2 * Copyright (C) 2008 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "JIT.h"
28
29#if ENABLE(JIT)
30
31#include "CodeBlock.h"
32#include "JITInlineMethods.h"
33#include "JITStubCall.h"
34#include "JSArray.h"
35#include "JSFunction.h"
36#include "Interpreter.h"
37#include "ResultType.h"
38#include "SamplingTool.h"
39
40#ifndef NDEBUG
41#include <stdio.h>
42#endif
43
44using namespace std;
45
46namespace JSC {
47
48#if USE(JSVALUE32_64)
49
50void JIT::emit_op_negate(Instruction* currentInstruction)
51{
52 unsigned dst = currentInstruction[1].u.operand;
53 unsigned src = currentInstruction[2].u.operand;
54
55 emitLoad(src, regT1, regT0);
56
57 Jump srcNotInt = branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag));
58 addSlowCase(branch32(Equal, regT0, Imm32(0)));
59 addSlowCase(branchNeg32(Overflow, regT0));
60 emitStoreInt32(dst, regT0, (dst == src));
61
62 Jump end = jump();
63
64 srcNotInt.link(this);
65 addSlowCase(branch32(Above, regT1, Imm32(JSValue::LowestTag)));
66
67 xor32(Imm32(1 << 31), regT1);
68 store32(regT1, tagFor(dst));
69 if (dst != src)
70 store32(regT0, payloadFor(dst));
71
72 end.link(this);
73}
74
75void JIT::emitSlow_op_negate(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
76{
77 unsigned dst = currentInstruction[1].u.operand;
78
79 linkSlowCase(iter); // 0 check
80 linkSlowCase(iter); // overflow check
81 linkSlowCase(iter); // double check
82
83 JITStubCall stubCall(this, cti_op_negate);
84 stubCall.addArgument(regT1, regT0);
85 stubCall.call(dst);
86}
87
88void JIT::emit_op_jnless(Instruction* currentInstruction)
89{
90 unsigned op1 = currentInstruction[1].u.operand;
91 unsigned op2 = currentInstruction[2].u.operand;
92 unsigned target = currentInstruction[3].u.operand;
93
94 JumpList notInt32Op1;
95 JumpList notInt32Op2;
96
97 // Int32 less.
98 if (isOperandConstantImmediateInt(op1)) {
99 emitLoad(op2, regT3, regT2);
100 notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
101 addJump(branch32(LessThanOrEqual, regT2, Imm32(getConstantOperand(op1).asInt32())), target);
102 } else if (isOperandConstantImmediateInt(op2)) {
103 emitLoad(op1, regT1, regT0);
104 notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
105 addJump(branch32(GreaterThanOrEqual, regT0, Imm32(getConstantOperand(op2).asInt32())), target);
106 } else {
107 emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
108 notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
109 notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
110 addJump(branch32(GreaterThanOrEqual, regT0, regT2), target);
111 }
112
113 if (!supportsFloatingPoint()) {
114 addSlowCase(notInt32Op1);
115 addSlowCase(notInt32Op2);
116 return;
117 }
118 Jump end = jump();
119
120 // Double less.
121 emitBinaryDoubleOp(op_jnless, target, op1, op2, OperandTypes(), notInt32Op1, notInt32Op2, !isOperandConstantImmediateInt(op1), isOperandConstantImmediateInt(op1) || !isOperandConstantImmediateInt(op2));
122 end.link(this);
123}
124
125void JIT::emitSlow_op_jnless(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
126{
127 unsigned op1 = currentInstruction[1].u.operand;
128 unsigned op2 = currentInstruction[2].u.operand;
129 unsigned target = currentInstruction[3].u.operand;
130
131 if (!supportsFloatingPoint()) {
132 if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2))
133 linkSlowCase(iter); // int32 check
134 linkSlowCase(iter); // int32 check
135 } else {
136 if (!isOperandConstantImmediateInt(op1)) {
137 linkSlowCase(iter); // double check
138 linkSlowCase(iter); // int32 check
139 }
140 if (isOperandConstantImmediateInt(op1) || !isOperandConstantImmediateInt(op2))
141 linkSlowCase(iter); // double check
142 }
143
144 JITStubCall stubCall(this, cti_op_jless);
145 stubCall.addArgument(op1);
146 stubCall.addArgument(op2);
147 stubCall.call();
148 emitJumpSlowToHot(branchTest32(Zero, regT0), target);
149}
150
151void JIT::emit_op_jless(Instruction* currentInstruction)
152{
153 unsigned op1 = currentInstruction[1].u.operand;
154 unsigned op2 = currentInstruction[2].u.operand;
155 unsigned target = currentInstruction[3].u.operand;
156
157 JumpList notInt32Op1;
158 JumpList notInt32Op2;
159
160 // Int32 less.
161 if (isOperandConstantImmediateInt(op1)) {
162 emitLoad(op2, regT3, regT2);
163 notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
164 addJump(branch32(GreaterThan, regT2, Imm32(getConstantOperand(op1).asInt32())), target);
165 } else if (isOperandConstantImmediateInt(op2)) {
166 emitLoad(op1, regT1, regT0);
167 notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
168 addJump(branch32(LessThan, regT0, Imm32(getConstantOperand(op2).asInt32())), target);
169 } else {
170 emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
171 notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
172 notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
173 addJump(branch32(LessThan, regT0, regT2), target);
174 }
175
176 if (!supportsFloatingPoint()) {
177 addSlowCase(notInt32Op1);
178 addSlowCase(notInt32Op2);
179 return;
180 }
181 Jump end = jump();
182
183 // Double less.
184 emitBinaryDoubleOp(op_jless, target, op1, op2, OperandTypes(), notInt32Op1, notInt32Op2, !isOperandConstantImmediateInt(op1), isOperandConstantImmediateInt(op1) || !isOperandConstantImmediateInt(op2));
185 end.link(this);
186}
187
188void JIT::emitSlow_op_jless(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
189{
190 unsigned op1 = currentInstruction[1].u.operand;
191 unsigned op2 = currentInstruction[2].u.operand;
192 unsigned target = currentInstruction[3].u.operand;
193
194 if (!supportsFloatingPoint()) {
195 if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2))
196 linkSlowCase(iter); // int32 check
197 linkSlowCase(iter); // int32 check
198 } else {
199 if (!isOperandConstantImmediateInt(op1)) {
200 linkSlowCase(iter); // double check
201 linkSlowCase(iter); // int32 check
202 }
203 if (isOperandConstantImmediateInt(op1) || !isOperandConstantImmediateInt(op2))
204 linkSlowCase(iter); // double check
205 }
206
207 JITStubCall stubCall(this, cti_op_jless);
208 stubCall.addArgument(op1);
209 stubCall.addArgument(op2);
210 stubCall.call();
211 emitJumpSlowToHot(branchTest32(NonZero, regT0), target);
212}
213
214void JIT::emit_op_jnlesseq(Instruction* currentInstruction)
215{
216 unsigned op1 = currentInstruction[1].u.operand;
217 unsigned op2 = currentInstruction[2].u.operand;
218 unsigned target = currentInstruction[3].u.operand;
219
220 JumpList notInt32Op1;
221 JumpList notInt32Op2;
222
223 // Int32 less.
224 if (isOperandConstantImmediateInt(op1)) {
225 emitLoad(op2, regT3, regT2);
226 notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
227 addJump(branch32(LessThan, regT2, Imm32(getConstantOperand(op1).asInt32())), target);
228 } else if (isOperandConstantImmediateInt(op2)) {
229 emitLoad(op1, regT1, regT0);
230 notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
231 addJump(branch32(GreaterThan, regT0, Imm32(getConstantOperand(op2).asInt32())), target);
232 } else {
233 emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
234 notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
235 notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
236 addJump(branch32(GreaterThan, regT0, regT2), target);
237 }
238
239 if (!supportsFloatingPoint()) {
240 addSlowCase(notInt32Op1);
241 addSlowCase(notInt32Op2);
242 return;
243 }
244 Jump end = jump();
245
246 // Double less.
247 emitBinaryDoubleOp(op_jnlesseq, target, op1, op2, OperandTypes(), notInt32Op1, notInt32Op2, !isOperandConstantImmediateInt(op1), isOperandConstantImmediateInt(op1) || !isOperandConstantImmediateInt(op2));
248 end.link(this);
249}
250
251void JIT::emitSlow_op_jnlesseq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
252{
253 unsigned op1 = currentInstruction[1].u.operand;
254 unsigned op2 = currentInstruction[2].u.operand;
255 unsigned target = currentInstruction[3].u.operand;
256
257 if (!supportsFloatingPoint()) {
258 if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2))
259 linkSlowCase(iter); // int32 check
260 linkSlowCase(iter); // int32 check
261 } else {
262 if (!isOperandConstantImmediateInt(op1)) {
263 linkSlowCase(iter); // double check
264 linkSlowCase(iter); // int32 check
265 }
266 if (isOperandConstantImmediateInt(op1) || !isOperandConstantImmediateInt(op2))
267 linkSlowCase(iter); // double check
268 }
269
270 JITStubCall stubCall(this, cti_op_jlesseq);
271 stubCall.addArgument(op1);
272 stubCall.addArgument(op2);
273 stubCall.call();
274 emitJumpSlowToHot(branchTest32(Zero, regT0), target);
275}
276
277// LeftShift (<<)
278
279void JIT::emit_op_lshift(Instruction* currentInstruction)
280{
281 unsigned dst = currentInstruction[1].u.operand;
282 unsigned op1 = currentInstruction[2].u.operand;
283 unsigned op2 = currentInstruction[3].u.operand;
284
285 if (isOperandConstantImmediateInt(op2)) {
286 emitLoad(op1, regT1, regT0);
287 addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
288 lshift32(Imm32(getConstantOperand(op2).asInt32()), regT0);
289 emitStoreInt32(dst, regT0, dst == op1);
290 return;
291 }
292
293 emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
294 if (!isOperandConstantImmediateInt(op1))
295 addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
296 addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
297 lshift32(regT2, regT0);
298 emitStoreInt32(dst, regT0, dst == op1 || dst == op2);
299}
300
301void JIT::emitSlow_op_lshift(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
302{
303 unsigned dst = currentInstruction[1].u.operand;
304 unsigned op1 = currentInstruction[2].u.operand;
305 unsigned op2 = currentInstruction[3].u.operand;
306
307 if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2))
308 linkSlowCase(iter); // int32 check
309 linkSlowCase(iter); // int32 check
310
311 JITStubCall stubCall(this, cti_op_lshift);
312 stubCall.addArgument(op1);
313 stubCall.addArgument(op2);
314 stubCall.call(dst);
315}
316
317// RightShift (>>)
318
319void JIT::emit_op_rshift(Instruction* currentInstruction)
320{
321 unsigned dst = currentInstruction[1].u.operand;
322 unsigned op1 = currentInstruction[2].u.operand;
323 unsigned op2 = currentInstruction[3].u.operand;
324
325 if (isOperandConstantImmediateInt(op2)) {
326 emitLoad(op1, regT1, regT0);
327 addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
328 rshift32(Imm32(getConstantOperand(op2).asInt32()), regT0);
329 emitStoreInt32(dst, regT0, dst == op1);
330 return;
331 }
332
333 emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
334 if (!isOperandConstantImmediateInt(op1))
335 addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
336 addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
337 rshift32(regT2, regT0);
338 emitStoreInt32(dst, regT0, dst == op1 || dst == op2);
339}
340
341void JIT::emitSlow_op_rshift(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
342{
343 unsigned dst = currentInstruction[1].u.operand;
344 unsigned op1 = currentInstruction[2].u.operand;
345 unsigned op2 = currentInstruction[3].u.operand;
346
347 if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2))
348 linkSlowCase(iter); // int32 check
349 linkSlowCase(iter); // int32 check
350
351 JITStubCall stubCall(this, cti_op_rshift);
352 stubCall.addArgument(op1);
353 stubCall.addArgument(op2);
354 stubCall.call(dst);
355}
356
357// BitAnd (&)
358
359void JIT::emit_op_bitand(Instruction* currentInstruction)
360{
361 unsigned dst = currentInstruction[1].u.operand;
362 unsigned op1 = currentInstruction[2].u.operand;
363 unsigned op2 = currentInstruction[3].u.operand;
364
365 unsigned op;
366 int32_t constant;
367 if (getOperandConstantImmediateInt(op1, op2, op, constant)) {
368 emitLoad(op, regT1, regT0);
369 addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
370 and32(Imm32(constant), regT0);
371 emitStoreInt32(dst, regT0, (op == dst));
372 return;
373 }
374
375 emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
376 addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
377 addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
378 and32(regT2, regT0);
379 emitStoreInt32(dst, regT0, (op1 == dst || op2 == dst));
380}
381
382void JIT::emitSlow_op_bitand(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
383{
384 unsigned dst = currentInstruction[1].u.operand;
385 unsigned op1 = currentInstruction[2].u.operand;
386 unsigned op2 = currentInstruction[3].u.operand;
387
388 if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2))
389 linkSlowCase(iter); // int32 check
390 linkSlowCase(iter); // int32 check
391
392 JITStubCall stubCall(this, cti_op_bitand);
393 stubCall.addArgument(op1);
394 stubCall.addArgument(op2);
395 stubCall.call(dst);
396}
397
398// BitOr (|)
399
400void JIT::emit_op_bitor(Instruction* currentInstruction)
401{
402 unsigned dst = currentInstruction[1].u.operand;
403 unsigned op1 = currentInstruction[2].u.operand;
404 unsigned op2 = currentInstruction[3].u.operand;
405
406 unsigned op;
407 int32_t constant;
408 if (getOperandConstantImmediateInt(op1, op2, op, constant)) {
409 emitLoad(op, regT1, regT0);
410 addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
411 or32(Imm32(constant), regT0);
412 emitStoreInt32(dst, regT0, (op == dst));
413 return;
414 }
415
416 emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
417 addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
418 addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
419 or32(regT2, regT0);
420 emitStoreInt32(dst, regT0, (op1 == dst || op2 == dst));
421}
422
423void JIT::emitSlow_op_bitor(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
424{
425 unsigned dst = currentInstruction[1].u.operand;
426 unsigned op1 = currentInstruction[2].u.operand;
427 unsigned op2 = currentInstruction[3].u.operand;
428
429 if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2))
430 linkSlowCase(iter); // int32 check
431 linkSlowCase(iter); // int32 check
432
433 JITStubCall stubCall(this, cti_op_bitor);
434 stubCall.addArgument(op1);
435 stubCall.addArgument(op2);
436 stubCall.call(dst);
437}
438
439// BitXor (^)
440
441void JIT::emit_op_bitxor(Instruction* currentInstruction)
442{
443 unsigned dst = currentInstruction[1].u.operand;
444 unsigned op1 = currentInstruction[2].u.operand;
445 unsigned op2 = currentInstruction[3].u.operand;
446
447 unsigned op;
448 int32_t constant;
449 if (getOperandConstantImmediateInt(op1, op2, op, constant)) {
450 emitLoad(op, regT1, regT0);
451 addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
452 xor32(Imm32(constant), regT0);
453 emitStoreInt32(dst, regT0, (op == dst));
454 return;
455 }
456
457 emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
458 addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
459 addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
460 xor32(regT2, regT0);
461 emitStoreInt32(dst, regT0, (op1 == dst || op2 == dst));
462}
463
464void JIT::emitSlow_op_bitxor(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
465{
466 unsigned dst = currentInstruction[1].u.operand;
467 unsigned op1 = currentInstruction[2].u.operand;
468 unsigned op2 = currentInstruction[3].u.operand;
469
470 if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2))
471 linkSlowCase(iter); // int32 check
472 linkSlowCase(iter); // int32 check
473
474 JITStubCall stubCall(this, cti_op_bitxor);
475 stubCall.addArgument(op1);
476 stubCall.addArgument(op2);
477 stubCall.call(dst);
478}
479
480// BitNot (~)
481
482void JIT::emit_op_bitnot(Instruction* currentInstruction)
483{
484 unsigned dst = currentInstruction[1].u.operand;
485 unsigned src = currentInstruction[2].u.operand;
486
487 emitLoad(src, regT1, regT0);
488 addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
489
490 not32(regT0);
491 emitStoreInt32(dst, regT0, (dst == src));
492}
493
494void JIT::emitSlow_op_bitnot(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
495{
496 unsigned dst = currentInstruction[1].u.operand;
497
498 linkSlowCase(iter); // int32 check
499
500 JITStubCall stubCall(this, cti_op_bitnot);
501 stubCall.addArgument(regT1, regT0);
502 stubCall.call(dst);
503}
504
505// PostInc (i++)
506
507void JIT::emit_op_post_inc(Instruction* currentInstruction)
508{
509 unsigned dst = currentInstruction[1].u.operand;
510 unsigned srcDst = currentInstruction[2].u.operand;
511
512 emitLoad(srcDst, regT1, regT0);
513 addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
514
515 if (dst == srcDst) // x = x++ is a noop for ints.
516 return;
517
518 emitStoreInt32(dst, regT0);
519
520 addSlowCase(branchAdd32(Overflow, Imm32(1), regT0));
521 emitStoreInt32(srcDst, regT0, true);
522}
523
524void JIT::emitSlow_op_post_inc(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
525{
526 unsigned dst = currentInstruction[1].u.operand;
527 unsigned srcDst = currentInstruction[2].u.operand;
528
529 linkSlowCase(iter); // int32 check
530 if (dst != srcDst)
531 linkSlowCase(iter); // overflow check
532
533 JITStubCall stubCall(this, cti_op_post_inc);
534 stubCall.addArgument(srcDst);
535 stubCall.addArgument(Imm32(srcDst));
536 stubCall.call(dst);
537}
538
539// PostDec (i--)
540
541void JIT::emit_op_post_dec(Instruction* currentInstruction)
542{
543 unsigned dst = currentInstruction[1].u.operand;
544 unsigned srcDst = currentInstruction[2].u.operand;
545
546 emitLoad(srcDst, regT1, regT0);
547 addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
548
549 if (dst == srcDst) // x = x-- is a noop for ints.
550 return;
551
552 emitStoreInt32(dst, regT0);
553
554 addSlowCase(branchSub32(Overflow, Imm32(1), regT0));
555 emitStoreInt32(srcDst, regT0, true);
556}
557
558void JIT::emitSlow_op_post_dec(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
559{
560 unsigned dst = currentInstruction[1].u.operand;
561 unsigned srcDst = currentInstruction[2].u.operand;
562
563 linkSlowCase(iter); // int32 check
564 if (dst != srcDst)
565 linkSlowCase(iter); // overflow check
566
567 JITStubCall stubCall(this, cti_op_post_dec);
568 stubCall.addArgument(srcDst);
569 stubCall.addArgument(Imm32(srcDst));
570 stubCall.call(dst);
571}
572
573// PreInc (++i)
574
575void JIT::emit_op_pre_inc(Instruction* currentInstruction)
576{
577 unsigned srcDst = currentInstruction[1].u.operand;
578
579 emitLoad(srcDst, regT1, regT0);
580
581 addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
582 addSlowCase(branchAdd32(Overflow, Imm32(1), regT0));
583 emitStoreInt32(srcDst, regT0, true);
584}
585
586void JIT::emitSlow_op_pre_inc(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
587{
588 unsigned srcDst = currentInstruction[1].u.operand;
589
590 linkSlowCase(iter); // int32 check
591 linkSlowCase(iter); // overflow check
592
593 JITStubCall stubCall(this, cti_op_pre_inc);
594 stubCall.addArgument(srcDst);
595 stubCall.call(srcDst);
596}
597
598// PreDec (--i)
599
600void JIT::emit_op_pre_dec(Instruction* currentInstruction)
601{
602 unsigned srcDst = currentInstruction[1].u.operand;
603
604 emitLoad(srcDst, regT1, regT0);
605
606 addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
607 addSlowCase(branchSub32(Overflow, Imm32(1), regT0));
608 emitStoreInt32(srcDst, regT0, true);
609}
610
611void JIT::emitSlow_op_pre_dec(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
612{
613 unsigned srcDst = currentInstruction[1].u.operand;
614
615 linkSlowCase(iter); // int32 check
616 linkSlowCase(iter); // overflow check
617
618 JITStubCall stubCall(this, cti_op_pre_dec);
619 stubCall.addArgument(srcDst);
620 stubCall.call(srcDst);
621}
622
623// Addition (+)
624
625void JIT::emit_op_add(Instruction* currentInstruction)
626{
627 unsigned dst = currentInstruction[1].u.operand;
628 unsigned op1 = currentInstruction[2].u.operand;
629 unsigned op2 = currentInstruction[3].u.operand;
630 OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand);
631
632 if (!types.first().mightBeNumber() || !types.second().mightBeNumber()) {
633 JITStubCall stubCall(this, cti_op_add);
634 stubCall.addArgument(op1);
635 stubCall.addArgument(op2);
636 stubCall.call(dst);
637 return;
638 }
639
640 JumpList notInt32Op1;
641 JumpList notInt32Op2;
642
643 unsigned op;
644 int32_t constant;
645 if (getOperandConstantImmediateInt(op1, op2, op, constant)) {
646 emitAdd32Constant(dst, op, constant, op == op1 ? types.first() : types.second());
647 return;
648 }
649
650 emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
651 notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
652 notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
653
654 // Int32 case.
655 addSlowCase(branchAdd32(Overflow, regT2, regT0));
656 emitStoreInt32(dst, regT0, (op1 == dst || op2 == dst));
657
658 if (!supportsFloatingPoint()) {
659 addSlowCase(notInt32Op1);
660 addSlowCase(notInt32Op2);
661 return;
662 }
663 Jump end = jump();
664
665 // Double case.
666 emitBinaryDoubleOp(op_add, dst, op1, op2, types, notInt32Op1, notInt32Op2);
667 end.link(this);
668}
669
670void JIT::emitAdd32Constant(unsigned dst, unsigned op, int32_t constant, ResultType opType)
671{
672 // Int32 case.
673 emitLoad(op, regT1, regT0);
674 Jump notInt32 = branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag));
675 addSlowCase(branchAdd32(Overflow, Imm32(constant), regT0));
676 emitStoreInt32(dst, regT0, (op == dst));
677
678 // Double case.
679 if (!supportsFloatingPoint()) {
680 addSlowCase(notInt32);
681 return;
682 }
683 Jump end = jump();
684
685 notInt32.link(this);
686 if (!opType.definitelyIsNumber())
687 addSlowCase(branch32(Above, regT1, Imm32(JSValue::LowestTag)));
688 move(Imm32(constant), regT2);
689 convertInt32ToDouble(regT2, fpRegT0);
690 emitLoadDouble(op, fpRegT1);
691 addDouble(fpRegT1, fpRegT0);
692 emitStoreDouble(dst, fpRegT0);
693
694 end.link(this);
695}
696
697void JIT::emitSlow_op_add(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
698{
699 unsigned dst = currentInstruction[1].u.operand;
700 unsigned op1 = currentInstruction[2].u.operand;
701 unsigned op2 = currentInstruction[3].u.operand;
702 OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand);
703
704 if (!types.first().mightBeNumber() || !types.second().mightBeNumber())
705 return;
706
707 unsigned op;
708 int32_t constant;
709 if (getOperandConstantImmediateInt(op1, op2, op, constant)) {
710 linkSlowCase(iter); // overflow check
711
712 if (!supportsFloatingPoint())
713 linkSlowCase(iter); // non-sse case
714 else {
715 ResultType opType = op == op1 ? types.first() : types.second();
716 if (!opType.definitelyIsNumber())
717 linkSlowCase(iter); // double check
718 }
719 } else {
720 linkSlowCase(iter); // overflow check
721
722 if (!supportsFloatingPoint()) {
723 linkSlowCase(iter); // int32 check
724 linkSlowCase(iter); // int32 check
725 } else {
726 if (!types.first().definitelyIsNumber())
727 linkSlowCase(iter); // double check
728
729 if (!types.second().definitelyIsNumber()) {
730 linkSlowCase(iter); // int32 check
731 linkSlowCase(iter); // double check
732 }
733 }
734 }
735
736 JITStubCall stubCall(this, cti_op_add);
737 stubCall.addArgument(op1);
738 stubCall.addArgument(op2);
739 stubCall.call(dst);
740}
741
742// Subtraction (-)
743
744void JIT::emit_op_sub(Instruction* currentInstruction)
745{
746 unsigned dst = currentInstruction[1].u.operand;
747 unsigned op1 = currentInstruction[2].u.operand;
748 unsigned op2 = currentInstruction[3].u.operand;
749 OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand);
750
751 JumpList notInt32Op1;
752 JumpList notInt32Op2;
753
754 if (isOperandConstantImmediateInt(op2)) {
755 emitSub32Constant(dst, op1, getConstantOperand(op2).asInt32(), types.first());
756 return;
757 }
758
759 emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
760 notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
761 notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
762
763 // Int32 case.
764 addSlowCase(branchSub32(Overflow, regT2, regT0));
765 emitStoreInt32(dst, regT0, (op1 == dst || op2 == dst));
766
767 if (!supportsFloatingPoint()) {
768 addSlowCase(notInt32Op1);
769 addSlowCase(notInt32Op2);
770 return;
771 }
772 Jump end = jump();
773
774 // Double case.
775 emitBinaryDoubleOp(op_sub, dst, op1, op2, types, notInt32Op1, notInt32Op2);
776 end.link(this);
777}
778
779void JIT::emitSub32Constant(unsigned dst, unsigned op, int32_t constant, ResultType opType)
780{
781 // Int32 case.
782 emitLoad(op, regT1, regT0);
783 Jump notInt32 = branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag));
784 addSlowCase(branchSub32(Overflow, Imm32(constant), regT0));
785 emitStoreInt32(dst, regT0, (op == dst));
786
787 // Double case.
788 if (!supportsFloatingPoint()) {
789 addSlowCase(notInt32);
790 return;
791 }
792 Jump end = jump();
793
794 notInt32.link(this);
795 if (!opType.definitelyIsNumber())
796 addSlowCase(branch32(Above, regT1, Imm32(JSValue::LowestTag)));
797 move(Imm32(constant), regT2);
798 convertInt32ToDouble(regT2, fpRegT0);
799 emitLoadDouble(op, fpRegT1);
800 subDouble(fpRegT0, fpRegT1);
801 emitStoreDouble(dst, fpRegT1);
802
803 end.link(this);
804}
805
806void JIT::emitSlow_op_sub(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
807{
808 unsigned dst = currentInstruction[1].u.operand;
809 unsigned op1 = currentInstruction[2].u.operand;
810 unsigned op2 = currentInstruction[3].u.operand;
811 OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand);
812
813 if (isOperandConstantImmediateInt(op2)) {
814 linkSlowCase(iter); // overflow check
815
816 if (!supportsFloatingPoint() || !types.first().definitelyIsNumber())
817 linkSlowCase(iter); // int32 or double check
818 } else {
819 linkSlowCase(iter); // overflow check
820
821 if (!supportsFloatingPoint()) {
822 linkSlowCase(iter); // int32 check
823 linkSlowCase(iter); // int32 check
824 } else {
825 if (!types.first().definitelyIsNumber())
826 linkSlowCase(iter); // double check
827
828 if (!types.second().definitelyIsNumber()) {
829 linkSlowCase(iter); // int32 check
830 linkSlowCase(iter); // double check
831 }
832 }
833 }
834
835 JITStubCall stubCall(this, cti_op_sub);
836 stubCall.addArgument(op1);
837 stubCall.addArgument(op2);
838 stubCall.call(dst);
839}
840
841void JIT::emitBinaryDoubleOp(OpcodeID opcodeID, unsigned dst, unsigned op1, unsigned op2, OperandTypes types, JumpList& notInt32Op1, JumpList& notInt32Op2, bool op1IsInRegisters, bool op2IsInRegisters)
842{
843 JumpList end;
844
845 if (!notInt32Op1.empty()) {
846 // Double case 1: Op1 is not int32; Op2 is unknown.
847 notInt32Op1.link(this);
848
849 ASSERT(op1IsInRegisters);
850
851 // Verify Op1 is double.
852 if (!types.first().definitelyIsNumber())
853 addSlowCase(branch32(Above, regT1, Imm32(JSValue::LowestTag)));
854
855 if (!op2IsInRegisters)
856 emitLoad(op2, regT3, regT2);
857
858 Jump doubleOp2 = branch32(Below, regT3, Imm32(JSValue::LowestTag));
859
860 if (!types.second().definitelyIsNumber())
861 addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
862
863 convertInt32ToDouble(regT2, fpRegT0);
864 Jump doTheMath = jump();
865
866 // Load Op2 as double into double register.
867 doubleOp2.link(this);
868 emitLoadDouble(op2, fpRegT0);
869
870 // Do the math.
871 doTheMath.link(this);
872 switch (opcodeID) {
873 case op_mul:
874 emitLoadDouble(op1, fpRegT2);
875 mulDouble(fpRegT2, fpRegT0);
876 emitStoreDouble(dst, fpRegT0);
877 break;
878 case op_add:
879 emitLoadDouble(op1, fpRegT2);
880 addDouble(fpRegT2, fpRegT0);
881 emitStoreDouble(dst, fpRegT0);
882 break;
883 case op_sub:
884 emitLoadDouble(op1, fpRegT1);
885 subDouble(fpRegT0, fpRegT1);
886 emitStoreDouble(dst, fpRegT1);
887 break;
888 case op_div:
889 emitLoadDouble(op1, fpRegT1);
890 divDouble(fpRegT0, fpRegT1);
891 emitStoreDouble(dst, fpRegT1);
892 break;
893 case op_jnless:
894 emitLoadDouble(op1, fpRegT2);
895 addJump(branchDouble(DoubleLessThanOrEqualOrUnordered, fpRegT0, fpRegT2), dst);
896 break;
897 case op_jless:
898 emitLoadDouble(op1, fpRegT2);
899 addJump(branchDouble(DoubleLessThan, fpRegT2, fpRegT0), dst);
900 break;
901 case op_jnlesseq:
902 emitLoadDouble(op1, fpRegT2);
903 addJump(branchDouble(DoubleLessThanOrUnordered, fpRegT0, fpRegT2), dst);
904 break;
905 default:
906 ASSERT_NOT_REACHED();
907 }
908
909 if (!notInt32Op2.empty())
910 end.append(jump());
911 }
912
913 if (!notInt32Op2.empty()) {
914 // Double case 2: Op1 is int32; Op2 is not int32.
915 notInt32Op2.link(this);
916
917 ASSERT(op2IsInRegisters);
918
919 if (!op1IsInRegisters)
920 emitLoadPayload(op1, regT0);
921
922 convertInt32ToDouble(regT0, fpRegT0);
923
924 // Verify op2 is double.
925 if (!types.second().definitelyIsNumber())
926 addSlowCase(branch32(Above, regT3, Imm32(JSValue::LowestTag)));
927
928 // Do the math.
929 switch (opcodeID) {
930 case op_mul:
931 emitLoadDouble(op2, fpRegT2);
932 mulDouble(fpRegT2, fpRegT0);
933 emitStoreDouble(dst, fpRegT0);
934 break;
935 case op_add:
936 emitLoadDouble(op2, fpRegT2);
937 addDouble(fpRegT2, fpRegT0);
938 emitStoreDouble(dst, fpRegT0);
939 break;
940 case op_sub:
941 emitLoadDouble(op2, fpRegT2);
942 subDouble(fpRegT2, fpRegT0);
943 emitStoreDouble(dst, fpRegT0);
944 break;
945 case op_div:
946 emitLoadDouble(op2, fpRegT2);
947 divDouble(fpRegT2, fpRegT0);
948 emitStoreDouble(dst, fpRegT0);
949 break;
950 case op_jnless:
951 emitLoadDouble(op2, fpRegT1);
952 addJump(branchDouble(DoubleLessThanOrEqualOrUnordered, fpRegT1, fpRegT0), dst);
953 break;
954 case op_jless:
955 emitLoadDouble(op2, fpRegT1);
956 addJump(branchDouble(DoubleLessThan, fpRegT0, fpRegT1), dst);
957 break;
958 case op_jnlesseq:
959 emitLoadDouble(op2, fpRegT1);
960 addJump(branchDouble(DoubleLessThanOrUnordered, fpRegT1, fpRegT0), dst);
961 break;
962 default:
963 ASSERT_NOT_REACHED();
964 }
965 }
966
967 end.link(this);
968}
969
970// Multiplication (*)
971
972void JIT::emit_op_mul(Instruction* currentInstruction)
973{
974 unsigned dst = currentInstruction[1].u.operand;
975 unsigned op1 = currentInstruction[2].u.operand;
976 unsigned op2 = currentInstruction[3].u.operand;
977 OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand);
978
979 JumpList notInt32Op1;
980 JumpList notInt32Op2;
981
982 emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
983 notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
984 notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
985
986 // Int32 case.
987 move(regT0, regT3);
988 addSlowCase(branchMul32(Overflow, regT2, regT0));
989 addSlowCase(branchTest32(Zero, regT0));
990 emitStoreInt32(dst, regT0, (op1 == dst || op2 == dst));
991
992 if (!supportsFloatingPoint()) {
993 addSlowCase(notInt32Op1);
994 addSlowCase(notInt32Op2);
995 return;
996 }
997 Jump end = jump();
998
999 // Double case.
1000 emitBinaryDoubleOp(op_mul, dst, op1, op2, types, notInt32Op1, notInt32Op2);
1001 end.link(this);
1002}
1003
1004void JIT::emitSlow_op_mul(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1005{
1006 unsigned dst = currentInstruction[1].u.operand;
1007 unsigned op1 = currentInstruction[2].u.operand;
1008 unsigned op2 = currentInstruction[3].u.operand;
1009 OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand);
1010
1011 Jump overflow = getSlowCase(iter); // overflow check
1012 linkSlowCase(iter); // zero result check
1013
1014 Jump negZero = branchOr32(Signed, regT2, regT3);
1015 emitStoreInt32(dst, Imm32(0), (op1 == dst || op2 == dst));
1016
1017 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_mul));
1018
1019 negZero.link(this);
1020 overflow.link(this);
1021
1022 if (!supportsFloatingPoint()) {
1023 linkSlowCase(iter); // int32 check
1024 linkSlowCase(iter); // int32 check
1025 }
1026
1027 if (supportsFloatingPoint()) {
1028 if (!types.first().definitelyIsNumber())
1029 linkSlowCase(iter); // double check
1030
1031 if (!types.second().definitelyIsNumber()) {
1032 linkSlowCase(iter); // int32 check
1033 linkSlowCase(iter); // double check
1034 }
1035 }
1036
1037 Label jitStubCall(this);
1038 JITStubCall stubCall(this, cti_op_mul);
1039 stubCall.addArgument(op1);
1040 stubCall.addArgument(op2);
1041 stubCall.call(dst);
1042}
1043
1044// Division (/)
1045
1046void JIT::emit_op_div(Instruction* currentInstruction)
1047{
1048 unsigned dst = currentInstruction[1].u.operand;
1049 unsigned op1 = currentInstruction[2].u.operand;
1050 unsigned op2 = currentInstruction[3].u.operand;
1051 OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand);
1052
1053 if (!supportsFloatingPoint()) {
1054 addSlowCase(jump());
1055 return;
1056 }
1057
1058 // Int32 divide.
1059 JumpList notInt32Op1;
1060 JumpList notInt32Op2;
1061
1062 JumpList end;
1063
1064 emitLoad2(op1, regT1, regT0, op2, regT3, regT2);
1065
1066 notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)));
1067 notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag)));
1068
1069 convertInt32ToDouble(regT0, fpRegT0);
1070 convertInt32ToDouble(regT2, fpRegT1);
1071 divDouble(fpRegT1, fpRegT0);
1072
1073 JumpList doubleResult;
1074 branchConvertDoubleToInt32(fpRegT0, regT0, doubleResult, fpRegT1);
1075
1076 // Int32 result.
1077 emitStoreInt32(dst, regT0, (op1 == dst || op2 == dst));
1078 end.append(jump());
1079
1080 // Double result.
1081 doubleResult.link(this);
1082 emitStoreDouble(dst, fpRegT0);
1083 end.append(jump());
1084
1085 // Double divide.
1086 emitBinaryDoubleOp(op_div, dst, op1, op2, types, notInt32Op1, notInt32Op2);
1087 end.link(this);
1088}
1089
1090void JIT::emitSlow_op_div(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1091{
1092 unsigned dst = currentInstruction[1].u.operand;
1093 unsigned op1 = currentInstruction[2].u.operand;
1094 unsigned op2 = currentInstruction[3].u.operand;
1095 OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand);
1096
1097 if (!supportsFloatingPoint())
1098 linkSlowCase(iter);
1099 else {
1100 if (!types.first().definitelyIsNumber())
1101 linkSlowCase(iter); // double check
1102
1103 if (!types.second().definitelyIsNumber()) {
1104 linkSlowCase(iter); // int32 check
1105 linkSlowCase(iter); // double check
1106 }
1107 }
1108
1109 JITStubCall stubCall(this, cti_op_div);
1110 stubCall.addArgument(op1);
1111 stubCall.addArgument(op2);
1112 stubCall.call(dst);
1113}
1114
1115// Mod (%)
1116
1117/* ------------------------------ BEGIN: OP_MOD ------------------------------ */
1118
1119#if CPU(X86) || CPU(X86_64)
1120
1121void JIT::emit_op_mod(Instruction* currentInstruction)
1122{
1123 unsigned dst = currentInstruction[1].u.operand;
1124 unsigned op1 = currentInstruction[2].u.operand;
1125 unsigned op2 = currentInstruction[3].u.operand;
1126
1127 if (isOperandConstantImmediateInt(op2) && getConstantOperand(op2).asInt32() != 0) {
1128 emitLoad(op1, X86Registers::edx, X86Registers::eax);
1129 move(Imm32(getConstantOperand(op2).asInt32()), X86Registers::ecx);
1130 addSlowCase(branch32(NotEqual, X86Registers::edx, Imm32(JSValue::Int32Tag)));
1131 if (getConstantOperand(op2).asInt32() == -1)
1132 addSlowCase(branch32(Equal, X86Registers::eax, Imm32(0x80000000))); // -2147483648 / -1 => EXC_ARITHMETIC
1133 } else {
1134 emitLoad2(op1, X86Registers::edx, X86Registers::eax, op2, X86Registers::ebx, X86Registers::ecx);
1135 addSlowCase(branch32(NotEqual, X86Registers::edx, Imm32(JSValue::Int32Tag)));
1136 addSlowCase(branch32(NotEqual, X86Registers::ebx, Imm32(JSValue::Int32Tag)));
1137
1138 addSlowCase(branch32(Equal, X86Registers::eax, Imm32(0x80000000))); // -2147483648 / -1 => EXC_ARITHMETIC
1139 addSlowCase(branch32(Equal, X86Registers::ecx, Imm32(0))); // divide by 0
1140 }
1141
1142 move(X86Registers::eax, X86Registers::ebx); // Save dividend payload, in case of 0.
1143 m_assembler.cdq();
1144 m_assembler.idivl_r(X86Registers::ecx);
1145
1146 // If the remainder is zero and the dividend is negative, the result is -0.
1147 Jump storeResult1 = branchTest32(NonZero, X86Registers::edx);
1148 Jump storeResult2 = branchTest32(Zero, X86Registers::ebx, Imm32(0x80000000)); // not negative
1149 emitStore(dst, jsNumber(m_globalData, -0.0));
1150 Jump end = jump();
1151
1152 storeResult1.link(this);
1153 storeResult2.link(this);
1154 emitStoreInt32(dst, X86Registers::edx, (op1 == dst || op2 == dst));
1155 end.link(this);
1156}
1157
1158void JIT::emitSlow_op_mod(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1159{
1160 unsigned dst = currentInstruction[1].u.operand;
1161 unsigned op1 = currentInstruction[2].u.operand;
1162 unsigned op2 = currentInstruction[3].u.operand;
1163
1164 if (isOperandConstantImmediateInt(op2) && getConstantOperand(op2).asInt32() != 0) {
1165 linkSlowCase(iter); // int32 check
1166 if (getConstantOperand(op2).asInt32() == -1)
1167 linkSlowCase(iter); // 0x80000000 check
1168 } else {
1169 linkSlowCase(iter); // int32 check
1170 linkSlowCase(iter); // int32 check
1171 linkSlowCase(iter); // 0 check
1172 linkSlowCase(iter); // 0x80000000 check
1173 }
1174
1175 JITStubCall stubCall(this, cti_op_mod);
1176 stubCall.addArgument(op1);
1177 stubCall.addArgument(op2);
1178 stubCall.call(dst);
1179}
1180
1181#else // CPU(X86) || CPU(X86_64)
1182
1183void JIT::emit_op_mod(Instruction* currentInstruction)
1184{
1185 unsigned dst = currentInstruction[1].u.operand;
1186 unsigned op1 = currentInstruction[2].u.operand;
1187 unsigned op2 = currentInstruction[3].u.operand;
1188
1189 JITStubCall stubCall(this, cti_op_mod);
1190 stubCall.addArgument(op1);
1191 stubCall.addArgument(op2);
1192 stubCall.call(dst);
1193}
1194
1195void JIT::emitSlow_op_mod(Instruction*, Vector<SlowCaseEntry>::iterator&)
1196{
1197}
1198
1199#endif // CPU(X86) || CPU(X86_64)
1200
1201/* ------------------------------ END: OP_MOD ------------------------------ */
1202
1203#else // USE(JSVALUE32_64)
1204
1205void JIT::emit_op_lshift(Instruction* currentInstruction)
1206{
1207 unsigned result = currentInstruction[1].u.operand;
1208 unsigned op1 = currentInstruction[2].u.operand;
1209 unsigned op2 = currentInstruction[3].u.operand;
1210
1211 emitGetVirtualRegisters(src1: op1, dst1: regT0, src2: op2, dst2: regT2);
1212 // FIXME: would we be better using 'emitJumpSlowCaseIfNotImmediateIntegers'? - we *probably* ought to be consistent.
1213 emitJumpSlowCaseIfNotImmediateInteger(reg: regT0);
1214 emitJumpSlowCaseIfNotImmediateInteger(reg: regT2);
1215 emitFastArithImmToInt(reg: regT0);
1216 emitFastArithImmToInt(reg: regT2);
1217 lshift32(shift_amount: regT2, dest: regT0);
1218#if USE(JSVALUE32)
1219 addSlowCase(branchAdd32(Overflow, regT0, regT0));
1220 signExtend32ToPtr(regT0, regT0);
1221#endif
1222 emitFastArithReTagImmediate(src: regT0, dest: regT0);
1223 emitPutVirtualRegister(dst: result);
1224}
1225
1226void JIT::emitSlow_op_lshift(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1227{
1228 unsigned result = currentInstruction[1].u.operand;
1229 unsigned op1 = currentInstruction[2].u.operand;
1230 unsigned op2 = currentInstruction[3].u.operand;
1231
1232#if USE(JSVALUE64)
1233 UNUSED_PARAM(op1);
1234 UNUSED_PARAM(op2);
1235 linkSlowCase(iter);
1236 linkSlowCase(iter);
1237#else
1238 // If we are limited to 32-bit immediates there is a third slow case, which required the operands to have been reloaded.
1239 Jump notImm1 = getSlowCase(iter);
1240 Jump notImm2 = getSlowCase(iter);
1241 linkSlowCase(iter);
1242 emitGetVirtualRegisters(op1, regT0, op2, regT2);
1243 notImm1.link(this);
1244 notImm2.link(this);
1245#endif
1246 JITStubCall stubCall(this, cti_op_lshift);
1247 stubCall.addArgument(argument: regT0);
1248 stubCall.addArgument(argument: regT2);
1249 stubCall.call(dst: result);
1250}
1251
1252void JIT::emit_op_rshift(Instruction* currentInstruction)
1253{
1254 unsigned result = currentInstruction[1].u.operand;
1255 unsigned op1 = currentInstruction[2].u.operand;
1256 unsigned op2 = currentInstruction[3].u.operand;
1257
1258 if (isOperandConstantImmediateInt(src: op2)) {
1259 // isOperandConstantImmediateInt(op2) => 1 SlowCase
1260 emitGetVirtualRegister(src: op1, dst: regT0);
1261 emitJumpSlowCaseIfNotImmediateInteger(reg: regT0);
1262 // Mask with 0x1f as per ecma-262 11.7.2 step 7.
1263 rshift32(imm: Imm32(getConstantOperandImmediateInt(src: op2) & 0x1f), dest: regT0);
1264 } else {
1265 emitGetVirtualRegisters(src1: op1, dst1: regT0, src2: op2, dst2: regT2);
1266 if (supportsFloatingPointTruncate()) {
1267 Jump lhsIsInt = emitJumpIfImmediateInteger(reg: regT0);
1268#if USE(JSVALUE64)
1269 // supportsFloatingPoint() && USE(JSVALUE64) => 3 SlowCases
1270 addSlowCase(jump: emitJumpIfNotImmediateNumber(reg: regT0));
1271 addPtr(src: tagTypeNumberRegister, dest: regT0);
1272 movePtrToDouble(src: regT0, dest: fpRegT0);
1273 addSlowCase(jump: branchTruncateDoubleToInt32(src: fpRegT0, dest: regT0));
1274#else
1275 // supportsFloatingPoint() && !USE(JSVALUE64) => 5 SlowCases (of which 1 IfNotJSCell)
1276 emitJumpSlowCaseIfNotJSCell(regT0, op1);
1277 addSlowCase(checkStructure(regT0, m_globalData->numberStructure.get()));
1278 loadDouble(Address(regT0, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0);
1279 addSlowCase(branchTruncateDoubleToInt32(fpRegT0, regT0));
1280 addSlowCase(branchAdd32(Overflow, regT0, regT0));
1281#endif
1282 lhsIsInt.link(masm: this);
1283 emitJumpSlowCaseIfNotImmediateInteger(reg: regT2);
1284 } else {
1285 // !supportsFloatingPoint() => 2 SlowCases
1286 emitJumpSlowCaseIfNotImmediateInteger(reg: regT0);
1287 emitJumpSlowCaseIfNotImmediateInteger(reg: regT2);
1288 }
1289 emitFastArithImmToInt(reg: regT2);
1290 rshift32(shift_amount: regT2, dest: regT0);
1291#if USE(JSVALUE32)
1292 signExtend32ToPtr(regT0, regT0);
1293#endif
1294 }
1295#if USE(JSVALUE64)
1296 emitFastArithIntToImmNoCheck(src: regT0, dest: regT0);
1297#else
1298 orPtr(Imm32(JSImmediate::TagTypeNumber), regT0);
1299#endif
1300 emitPutVirtualRegister(dst: result);
1301}
1302
1303void JIT::emitSlow_op_rshift(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1304{
1305 unsigned result = currentInstruction[1].u.operand;
1306 unsigned op1 = currentInstruction[2].u.operand;
1307 unsigned op2 = currentInstruction[3].u.operand;
1308
1309 JITStubCall stubCall(this, cti_op_rshift);
1310
1311 if (isOperandConstantImmediateInt(src: op2)) {
1312 linkSlowCase(iter);
1313 stubCall.addArgument(argument: regT0);
1314 stubCall.addArgument(src: op2, scratchRegister: regT2);
1315 } else {
1316 if (supportsFloatingPointTruncate()) {
1317#if USE(JSVALUE64)
1318 linkSlowCase(iter);
1319 linkSlowCase(iter);
1320 linkSlowCase(iter);
1321#else
1322 linkSlowCaseIfNotJSCell(iter, op1);
1323 linkSlowCase(iter);
1324 linkSlowCase(iter);
1325 linkSlowCase(iter);
1326 linkSlowCase(iter);
1327#endif
1328 // We're reloading op1 to regT0 as we can no longer guarantee that
1329 // we have not munged the operand. It may have already been shifted
1330 // correctly, but it still will not have been tagged.
1331 stubCall.addArgument(src: op1, scratchRegister: regT0);
1332 stubCall.addArgument(argument: regT2);
1333 } else {
1334 linkSlowCase(iter);
1335 linkSlowCase(iter);
1336 stubCall.addArgument(argument: regT0);
1337 stubCall.addArgument(argument: regT2);
1338 }
1339 }
1340
1341 stubCall.call(dst: result);
1342}
1343
1344void JIT::emit_op_jnless(Instruction* currentInstruction)
1345{
1346 unsigned op1 = currentInstruction[1].u.operand;
1347 unsigned op2 = currentInstruction[2].u.operand;
1348 unsigned target = currentInstruction[3].u.operand;
1349
1350 // We generate inline code for the following cases in the fast path:
1351 // - int immediate to constant int immediate
1352 // - constant int immediate to int immediate
1353 // - int immediate to int immediate
1354
1355 if (isOperandConstantImmediateInt(src: op2)) {
1356 emitGetVirtualRegister(src: op1, dst: regT0);
1357 emitJumpSlowCaseIfNotImmediateInteger(reg: regT0);
1358#if USE(JSVALUE64)
1359 int32_t op2imm = getConstantOperandImmediateInt(src: op2);
1360#else
1361 int32_t op2imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op2)));
1362#endif
1363 addJump(jump: branch32(cond: GreaterThanOrEqual, left: regT0, right: Imm32(op2imm)), relativeOffset: target);
1364 } else if (isOperandConstantImmediateInt(src: op1)) {
1365 emitGetVirtualRegister(src: op2, dst: regT1);
1366 emitJumpSlowCaseIfNotImmediateInteger(reg: regT1);
1367#if USE(JSVALUE64)
1368 int32_t op1imm = getConstantOperandImmediateInt(src: op1);
1369#else
1370 int32_t op1imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op1)));
1371#endif
1372 addJump(jump: branch32(cond: LessThanOrEqual, left: regT1, right: Imm32(op1imm)), relativeOffset: target);
1373 } else {
1374 emitGetVirtualRegisters(src1: op1, dst1: regT0, src2: op2, dst2: regT1);
1375 emitJumpSlowCaseIfNotImmediateInteger(reg: regT0);
1376 emitJumpSlowCaseIfNotImmediateInteger(reg: regT1);
1377
1378 addJump(jump: branch32(cond: GreaterThanOrEqual, left: regT0, right: regT1), relativeOffset: target);
1379 }
1380}
1381
1382void JIT::emitSlow_op_jnless(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1383{
1384 unsigned op1 = currentInstruction[1].u.operand;
1385 unsigned op2 = currentInstruction[2].u.operand;
1386 unsigned target = currentInstruction[3].u.operand;
1387
1388 // We generate inline code for the following cases in the slow path:
1389 // - floating-point number to constant int immediate
1390 // - constant int immediate to floating-point number
1391 // - floating-point number to floating-point number.
1392
1393 if (isOperandConstantImmediateInt(src: op2)) {
1394 linkSlowCase(iter);
1395
1396 if (supportsFloatingPoint()) {
1397#if USE(JSVALUE64)
1398 Jump fail1 = emitJumpIfNotImmediateNumber(reg: regT0);
1399 addPtr(src: tagTypeNumberRegister, dest: regT0);
1400 movePtrToDouble(src: regT0, dest: fpRegT0);
1401#else
1402 Jump fail1;
1403 if (!m_codeBlock->isKnownNotImmediate(op1))
1404 fail1 = emitJumpIfNotJSCell(regT0);
1405
1406 Jump fail2 = checkStructure(regT0, m_globalData->numberStructure.get());
1407 loadDouble(Address(regT0, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0);
1408#endif
1409
1410 int32_t op2imm = getConstantOperand(src: op2).asInt32();;
1411
1412 move(imm: Imm32(op2imm), dest: regT1);
1413 convertInt32ToDouble(src: regT1, dest: fpRegT1);
1414
1415 emitJumpSlowToHot(jump: branchDouble(cond: DoubleLessThanOrEqualOrUnordered, left: fpRegT1, right: fpRegT0), relativeOffset: target);
1416
1417 emitJumpSlowToHot(jump: jump(), OPCODE_LENGTH(op_jnless));
1418
1419#if USE(JSVALUE64)
1420 fail1.link(masm: this);
1421#else
1422 if (!m_codeBlock->isKnownNotImmediate(op1))
1423 fail1.link(this);
1424 fail2.link(this);
1425#endif
1426 }
1427
1428 JITStubCall stubCall(this, cti_op_jless);
1429 stubCall.addArgument(argument: regT0);
1430 stubCall.addArgument(src: op2, scratchRegister: regT2);
1431 stubCall.call();
1432 emitJumpSlowToHot(jump: branchTest32(cond: Zero, reg: regT0), relativeOffset: target);
1433
1434 } else if (isOperandConstantImmediateInt(src: op1)) {
1435 linkSlowCase(iter);
1436
1437 if (supportsFloatingPoint()) {
1438#if USE(JSVALUE64)
1439 Jump fail1 = emitJumpIfNotImmediateNumber(reg: regT1);
1440 addPtr(src: tagTypeNumberRegister, dest: regT1);
1441 movePtrToDouble(src: regT1, dest: fpRegT1);
1442#else
1443 Jump fail1;
1444 if (!m_codeBlock->isKnownNotImmediate(op2))
1445 fail1 = emitJumpIfNotJSCell(regT1);
1446
1447 Jump fail2 = checkStructure(regT1, m_globalData->numberStructure.get());
1448 loadDouble(Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT1);
1449#endif
1450
1451 int32_t op1imm = getConstantOperand(src: op1).asInt32();;
1452
1453 move(imm: Imm32(op1imm), dest: regT0);
1454 convertInt32ToDouble(src: regT0, dest: fpRegT0);
1455
1456 emitJumpSlowToHot(jump: branchDouble(cond: DoubleLessThanOrEqualOrUnordered, left: fpRegT1, right: fpRegT0), relativeOffset: target);
1457
1458 emitJumpSlowToHot(jump: jump(), OPCODE_LENGTH(op_jnless));
1459
1460#if USE(JSVALUE64)
1461 fail1.link(masm: this);
1462#else
1463 if (!m_codeBlock->isKnownNotImmediate(op2))
1464 fail1.link(this);
1465 fail2.link(this);
1466#endif
1467 }
1468
1469 JITStubCall stubCall(this, cti_op_jless);
1470 stubCall.addArgument(src: op1, scratchRegister: regT2);
1471 stubCall.addArgument(argument: regT1);
1472 stubCall.call();
1473 emitJumpSlowToHot(jump: branchTest32(cond: Zero, reg: regT0), relativeOffset: target);
1474
1475 } else {
1476 linkSlowCase(iter);
1477
1478 if (supportsFloatingPoint()) {
1479#if USE(JSVALUE64)
1480 Jump fail1 = emitJumpIfNotImmediateNumber(reg: regT0);
1481 Jump fail2 = emitJumpIfNotImmediateNumber(reg: regT1);
1482 Jump fail3 = emitJumpIfImmediateInteger(reg: regT1);
1483 addPtr(src: tagTypeNumberRegister, dest: regT0);
1484 addPtr(src: tagTypeNumberRegister, dest: regT1);
1485 movePtrToDouble(src: regT0, dest: fpRegT0);
1486 movePtrToDouble(src: regT1, dest: fpRegT1);
1487#else
1488 Jump fail1;
1489 if (!m_codeBlock->isKnownNotImmediate(op1))
1490 fail1 = emitJumpIfNotJSCell(regT0);
1491
1492 Jump fail2;
1493 if (!m_codeBlock->isKnownNotImmediate(op2))
1494 fail2 = emitJumpIfNotJSCell(regT1);
1495
1496 Jump fail3 = checkStructure(regT0, m_globalData->numberStructure.get());
1497 Jump fail4 = checkStructure(regT1, m_globalData->numberStructure.get());
1498 loadDouble(Address(regT0, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0);
1499 loadDouble(Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT1);
1500#endif
1501
1502 emitJumpSlowToHot(jump: branchDouble(cond: DoubleLessThanOrEqualOrUnordered, left: fpRegT1, right: fpRegT0), relativeOffset: target);
1503
1504 emitJumpSlowToHot(jump: jump(), OPCODE_LENGTH(op_jnless));
1505
1506#if USE(JSVALUE64)
1507 fail1.link(masm: this);
1508 fail2.link(masm: this);
1509 fail3.link(masm: this);
1510#else
1511 if (!m_codeBlock->isKnownNotImmediate(op1))
1512 fail1.link(this);
1513 if (!m_codeBlock->isKnownNotImmediate(op2))
1514 fail2.link(this);
1515 fail3.link(this);
1516 fail4.link(this);
1517#endif
1518 }
1519
1520 linkSlowCase(iter);
1521 JITStubCall stubCall(this, cti_op_jless);
1522 stubCall.addArgument(argument: regT0);
1523 stubCall.addArgument(argument: regT1);
1524 stubCall.call();
1525 emitJumpSlowToHot(jump: branchTest32(cond: Zero, reg: regT0), relativeOffset: target);
1526 }
1527}
1528
1529void JIT::emit_op_jless(Instruction* currentInstruction)
1530{
1531 unsigned op1 = currentInstruction[1].u.operand;
1532 unsigned op2 = currentInstruction[2].u.operand;
1533 unsigned target = currentInstruction[3].u.operand;
1534
1535 // We generate inline code for the following cases in the fast path:
1536 // - int immediate to constant int immediate
1537 // - constant int immediate to int immediate
1538 // - int immediate to int immediate
1539
1540 if (isOperandConstantImmediateInt(src: op2)) {
1541 emitGetVirtualRegister(src: op1, dst: regT0);
1542 emitJumpSlowCaseIfNotImmediateInteger(reg: regT0);
1543#if USE(JSVALUE64)
1544 int32_t op2imm = getConstantOperandImmediateInt(src: op2);
1545#else
1546 int32_t op2imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op2)));
1547#endif
1548 addJump(jump: branch32(cond: LessThan, left: regT0, right: Imm32(op2imm)), relativeOffset: target);
1549 } else if (isOperandConstantImmediateInt(src: op1)) {
1550 emitGetVirtualRegister(src: op2, dst: regT1);
1551 emitJumpSlowCaseIfNotImmediateInteger(reg: regT1);
1552#if USE(JSVALUE64)
1553 int32_t op1imm = getConstantOperandImmediateInt(src: op1);
1554#else
1555 int32_t op1imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op1)));
1556#endif
1557 addJump(jump: branch32(cond: GreaterThan, left: regT1, right: Imm32(op1imm)), relativeOffset: target);
1558 } else {
1559 emitGetVirtualRegisters(src1: op1, dst1: regT0, src2: op2, dst2: regT1);
1560 emitJumpSlowCaseIfNotImmediateInteger(reg: regT0);
1561 emitJumpSlowCaseIfNotImmediateInteger(reg: regT1);
1562
1563 addJump(jump: branch32(cond: LessThan, left: regT0, right: regT1), relativeOffset: target);
1564 }
1565}
1566
1567void JIT::emitSlow_op_jless(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1568{
1569 unsigned op1 = currentInstruction[1].u.operand;
1570 unsigned op2 = currentInstruction[2].u.operand;
1571 unsigned target = currentInstruction[3].u.operand;
1572
1573 // We generate inline code for the following cases in the slow path:
1574 // - floating-point number to constant int immediate
1575 // - constant int immediate to floating-point number
1576 // - floating-point number to floating-point number.
1577
1578 if (isOperandConstantImmediateInt(src: op2)) {
1579 linkSlowCase(iter);
1580
1581 if (supportsFloatingPoint()) {
1582#if USE(JSVALUE64)
1583 Jump fail1 = emitJumpIfNotImmediateNumber(reg: regT0);
1584 addPtr(src: tagTypeNumberRegister, dest: regT0);
1585 movePtrToDouble(src: regT0, dest: fpRegT0);
1586#else
1587 Jump fail1;
1588 if (!m_codeBlock->isKnownNotImmediate(op1))
1589 fail1 = emitJumpIfNotJSCell(regT0);
1590
1591 Jump fail2 = checkStructure(regT0, m_globalData->numberStructure.get());
1592 loadDouble(Address(regT0, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0);
1593#endif
1594
1595 int32_t op2imm = getConstantOperand(src: op2).asInt32();
1596
1597 move(imm: Imm32(op2imm), dest: regT1);
1598 convertInt32ToDouble(src: regT1, dest: fpRegT1);
1599
1600 emitJumpSlowToHot(jump: branchDouble(cond: DoubleLessThan, left: fpRegT0, right: fpRegT1), relativeOffset: target);
1601
1602 emitJumpSlowToHot(jump: jump(), OPCODE_LENGTH(op_jnless));
1603
1604#if USE(JSVALUE64)
1605 fail1.link(masm: this);
1606#else
1607 if (!m_codeBlock->isKnownNotImmediate(op1))
1608 fail1.link(this);
1609 fail2.link(this);
1610#endif
1611 }
1612
1613 JITStubCall stubCall(this, cti_op_jless);
1614 stubCall.addArgument(argument: regT0);
1615 stubCall.addArgument(src: op2, scratchRegister: regT2);
1616 stubCall.call();
1617 emitJumpSlowToHot(jump: branchTest32(cond: NonZero, reg: regT0), relativeOffset: target);
1618
1619 } else if (isOperandConstantImmediateInt(src: op1)) {
1620 linkSlowCase(iter);
1621
1622 if (supportsFloatingPoint()) {
1623#if USE(JSVALUE64)
1624 Jump fail1 = emitJumpIfNotImmediateNumber(reg: regT1);
1625 addPtr(src: tagTypeNumberRegister, dest: regT1);
1626 movePtrToDouble(src: regT1, dest: fpRegT1);
1627#else
1628 Jump fail1;
1629 if (!m_codeBlock->isKnownNotImmediate(op2))
1630 fail1 = emitJumpIfNotJSCell(regT1);
1631
1632 Jump fail2 = checkStructure(regT1, m_globalData->numberStructure.get());
1633 loadDouble(Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT1);
1634#endif
1635
1636 int32_t op1imm = getConstantOperand(src: op1).asInt32();
1637
1638 move(imm: Imm32(op1imm), dest: regT0);
1639 convertInt32ToDouble(src: regT0, dest: fpRegT0);
1640
1641 emitJumpSlowToHot(jump: branchDouble(cond: DoubleLessThan, left: fpRegT0, right: fpRegT1), relativeOffset: target);
1642
1643 emitJumpSlowToHot(jump: jump(), OPCODE_LENGTH(op_jnless));
1644
1645#if USE(JSVALUE64)
1646 fail1.link(masm: this);
1647#else
1648 if (!m_codeBlock->isKnownNotImmediate(op2))
1649 fail1.link(this);
1650 fail2.link(this);
1651#endif
1652 }
1653
1654 JITStubCall stubCall(this, cti_op_jless);
1655 stubCall.addArgument(src: op1, scratchRegister: regT2);
1656 stubCall.addArgument(argument: regT1);
1657 stubCall.call();
1658 emitJumpSlowToHot(jump: branchTest32(cond: NonZero, reg: regT0), relativeOffset: target);
1659
1660 } else {
1661 linkSlowCase(iter);
1662
1663 if (supportsFloatingPoint()) {
1664#if USE(JSVALUE64)
1665 Jump fail1 = emitJumpIfNotImmediateNumber(reg: regT0);
1666 Jump fail2 = emitJumpIfNotImmediateNumber(reg: regT1);
1667 Jump fail3 = emitJumpIfImmediateInteger(reg: regT1);
1668 addPtr(src: tagTypeNumberRegister, dest: regT0);
1669 addPtr(src: tagTypeNumberRegister, dest: regT1);
1670 movePtrToDouble(src: regT0, dest: fpRegT0);
1671 movePtrToDouble(src: regT1, dest: fpRegT1);
1672#else
1673 Jump fail1;
1674 if (!m_codeBlock->isKnownNotImmediate(op1))
1675 fail1 = emitJumpIfNotJSCell(regT0);
1676
1677 Jump fail2;
1678 if (!m_codeBlock->isKnownNotImmediate(op2))
1679 fail2 = emitJumpIfNotJSCell(regT1);
1680
1681 Jump fail3 = checkStructure(regT0, m_globalData->numberStructure.get());
1682 Jump fail4 = checkStructure(regT1, m_globalData->numberStructure.get());
1683 loadDouble(Address(regT0, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0);
1684 loadDouble(Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT1);
1685#endif
1686
1687 emitJumpSlowToHot(jump: branchDouble(cond: DoubleLessThan, left: fpRegT0, right: fpRegT1), relativeOffset: target);
1688
1689 emitJumpSlowToHot(jump: jump(), OPCODE_LENGTH(op_jnless));
1690
1691#if USE(JSVALUE64)
1692 fail1.link(masm: this);
1693 fail2.link(masm: this);
1694 fail3.link(masm: this);
1695#else
1696 if (!m_codeBlock->isKnownNotImmediate(op1))
1697 fail1.link(this);
1698 if (!m_codeBlock->isKnownNotImmediate(op2))
1699 fail2.link(this);
1700 fail3.link(this);
1701 fail4.link(this);
1702#endif
1703 }
1704
1705 linkSlowCase(iter);
1706 JITStubCall stubCall(this, cti_op_jless);
1707 stubCall.addArgument(argument: regT0);
1708 stubCall.addArgument(argument: regT1);
1709 stubCall.call();
1710 emitJumpSlowToHot(jump: branchTest32(cond: NonZero, reg: regT0), relativeOffset: target);
1711 }
1712}
1713
1714void JIT::emit_op_jnlesseq(Instruction* currentInstruction)
1715{
1716 unsigned op1 = currentInstruction[1].u.operand;
1717 unsigned op2 = currentInstruction[2].u.operand;
1718 unsigned target = currentInstruction[3].u.operand;
1719
1720 // We generate inline code for the following cases in the fast path:
1721 // - int immediate to constant int immediate
1722 // - constant int immediate to int immediate
1723 // - int immediate to int immediate
1724
1725 if (isOperandConstantImmediateInt(src: op2)) {
1726 emitGetVirtualRegister(src: op1, dst: regT0);
1727 emitJumpSlowCaseIfNotImmediateInteger(reg: regT0);
1728#if USE(JSVALUE64)
1729 int32_t op2imm = getConstantOperandImmediateInt(src: op2);
1730#else
1731 int32_t op2imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op2)));
1732#endif
1733 addJump(jump: branch32(cond: GreaterThan, left: regT0, right: Imm32(op2imm)), relativeOffset: target);
1734 } else if (isOperandConstantImmediateInt(src: op1)) {
1735 emitGetVirtualRegister(src: op2, dst: regT1);
1736 emitJumpSlowCaseIfNotImmediateInteger(reg: regT1);
1737#if USE(JSVALUE64)
1738 int32_t op1imm = getConstantOperandImmediateInt(src: op1);
1739#else
1740 int32_t op1imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op1)));
1741#endif
1742 addJump(jump: branch32(cond: LessThan, left: regT1, right: Imm32(op1imm)), relativeOffset: target);
1743 } else {
1744 emitGetVirtualRegisters(src1: op1, dst1: regT0, src2: op2, dst2: regT1);
1745 emitJumpSlowCaseIfNotImmediateInteger(reg: regT0);
1746 emitJumpSlowCaseIfNotImmediateInteger(reg: regT1);
1747
1748 addJump(jump: branch32(cond: GreaterThan, left: regT0, right: regT1), relativeOffset: target);
1749 }
1750}
1751
1752void JIT::emitSlow_op_jnlesseq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1753{
1754 unsigned op1 = currentInstruction[1].u.operand;
1755 unsigned op2 = currentInstruction[2].u.operand;
1756 unsigned target = currentInstruction[3].u.operand;
1757
1758 // We generate inline code for the following cases in the slow path:
1759 // - floating-point number to constant int immediate
1760 // - constant int immediate to floating-point number
1761 // - floating-point number to floating-point number.
1762
1763 if (isOperandConstantImmediateInt(src: op2)) {
1764 linkSlowCase(iter);
1765
1766 if (supportsFloatingPoint()) {
1767#if USE(JSVALUE64)
1768 Jump fail1 = emitJumpIfNotImmediateNumber(reg: regT0);
1769 addPtr(src: tagTypeNumberRegister, dest: regT0);
1770 movePtrToDouble(src: regT0, dest: fpRegT0);
1771#else
1772 Jump fail1;
1773 if (!m_codeBlock->isKnownNotImmediate(op1))
1774 fail1 = emitJumpIfNotJSCell(regT0);
1775
1776 Jump fail2 = checkStructure(regT0, m_globalData->numberStructure.get());
1777 loadDouble(Address(regT0, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0);
1778#endif
1779
1780 int32_t op2imm = getConstantOperand(src: op2).asInt32();;
1781
1782 move(imm: Imm32(op2imm), dest: regT1);
1783 convertInt32ToDouble(src: regT1, dest: fpRegT1);
1784
1785 emitJumpSlowToHot(jump: branchDouble(cond: DoubleLessThanOrUnordered, left: fpRegT1, right: fpRegT0), relativeOffset: target);
1786
1787 emitJumpSlowToHot(jump: jump(), OPCODE_LENGTH(op_jnlesseq));
1788
1789#if USE(JSVALUE64)
1790 fail1.link(masm: this);
1791#else
1792 if (!m_codeBlock->isKnownNotImmediate(op1))
1793 fail1.link(this);
1794 fail2.link(this);
1795#endif
1796 }
1797
1798 JITStubCall stubCall(this, cti_op_jlesseq);
1799 stubCall.addArgument(argument: regT0);
1800 stubCall.addArgument(src: op2, scratchRegister: regT2);
1801 stubCall.call();
1802 emitJumpSlowToHot(jump: branchTest32(cond: Zero, reg: regT0), relativeOffset: target);
1803
1804 } else if (isOperandConstantImmediateInt(src: op1)) {
1805 linkSlowCase(iter);
1806
1807 if (supportsFloatingPoint()) {
1808#if USE(JSVALUE64)
1809 Jump fail1 = emitJumpIfNotImmediateNumber(reg: regT1);
1810 addPtr(src: tagTypeNumberRegister, dest: regT1);
1811 movePtrToDouble(src: regT1, dest: fpRegT1);
1812#else
1813 Jump fail1;
1814 if (!m_codeBlock->isKnownNotImmediate(op2))
1815 fail1 = emitJumpIfNotJSCell(regT1);
1816
1817 Jump fail2 = checkStructure(regT1, m_globalData->numberStructure.get());
1818 loadDouble(Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT1);
1819#endif
1820
1821 int32_t op1imm = getConstantOperand(src: op1).asInt32();;
1822
1823 move(imm: Imm32(op1imm), dest: regT0);
1824 convertInt32ToDouble(src: regT0, dest: fpRegT0);
1825
1826 emitJumpSlowToHot(jump: branchDouble(cond: DoubleLessThanOrUnordered, left: fpRegT1, right: fpRegT0), relativeOffset: target);
1827
1828 emitJumpSlowToHot(jump: jump(), OPCODE_LENGTH(op_jnlesseq));
1829
1830#if USE(JSVALUE64)
1831 fail1.link(masm: this);
1832#else
1833 if (!m_codeBlock->isKnownNotImmediate(op2))
1834 fail1.link(this);
1835 fail2.link(this);
1836#endif
1837 }
1838
1839 JITStubCall stubCall(this, cti_op_jlesseq);
1840 stubCall.addArgument(src: op1, scratchRegister: regT2);
1841 stubCall.addArgument(argument: regT1);
1842 stubCall.call();
1843 emitJumpSlowToHot(jump: branchTest32(cond: Zero, reg: regT0), relativeOffset: target);
1844
1845 } else {
1846 linkSlowCase(iter);
1847
1848 if (supportsFloatingPoint()) {
1849#if USE(JSVALUE64)
1850 Jump fail1 = emitJumpIfNotImmediateNumber(reg: regT0);
1851 Jump fail2 = emitJumpIfNotImmediateNumber(reg: regT1);
1852 Jump fail3 = emitJumpIfImmediateInteger(reg: regT1);
1853 addPtr(src: tagTypeNumberRegister, dest: regT0);
1854 addPtr(src: tagTypeNumberRegister, dest: regT1);
1855 movePtrToDouble(src: regT0, dest: fpRegT0);
1856 movePtrToDouble(src: regT1, dest: fpRegT1);
1857#else
1858 Jump fail1;
1859 if (!m_codeBlock->isKnownNotImmediate(op1))
1860 fail1 = emitJumpIfNotJSCell(regT0);
1861
1862 Jump fail2;
1863 if (!m_codeBlock->isKnownNotImmediate(op2))
1864 fail2 = emitJumpIfNotJSCell(regT1);
1865
1866 Jump fail3 = checkStructure(regT0, m_globalData->numberStructure.get());
1867 Jump fail4 = checkStructure(regT1, m_globalData->numberStructure.get());
1868 loadDouble(Address(regT0, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0);
1869 loadDouble(Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT1);
1870#endif
1871
1872 emitJumpSlowToHot(jump: branchDouble(cond: DoubleLessThanOrUnordered, left: fpRegT1, right: fpRegT0), relativeOffset: target);
1873
1874 emitJumpSlowToHot(jump: jump(), OPCODE_LENGTH(op_jnlesseq));
1875
1876#if USE(JSVALUE64)
1877 fail1.link(masm: this);
1878 fail2.link(masm: this);
1879 fail3.link(masm: this);
1880#else
1881 if (!m_codeBlock->isKnownNotImmediate(op1))
1882 fail1.link(this);
1883 if (!m_codeBlock->isKnownNotImmediate(op2))
1884 fail2.link(this);
1885 fail3.link(this);
1886 fail4.link(this);
1887#endif
1888 }
1889
1890 linkSlowCase(iter);
1891 JITStubCall stubCall(this, cti_op_jlesseq);
1892 stubCall.addArgument(argument: regT0);
1893 stubCall.addArgument(argument: regT1);
1894 stubCall.call();
1895 emitJumpSlowToHot(jump: branchTest32(cond: Zero, reg: regT0), relativeOffset: target);
1896 }
1897}
1898
1899void JIT::emit_op_bitand(Instruction* currentInstruction)
1900{
1901 unsigned result = currentInstruction[1].u.operand;
1902 unsigned op1 = currentInstruction[2].u.operand;
1903 unsigned op2 = currentInstruction[3].u.operand;
1904
1905 if (isOperandConstantImmediateInt(src: op1)) {
1906 emitGetVirtualRegister(src: op2, dst: regT0);
1907 emitJumpSlowCaseIfNotImmediateInteger(reg: regT0);
1908#if USE(JSVALUE64)
1909 int32_t imm = getConstantOperandImmediateInt(src: op1);
1910 andPtr(imm: Imm32(imm), srcDest: regT0);
1911 if (imm >= 0)
1912 emitFastArithIntToImmNoCheck(src: regT0, dest: regT0);
1913#else
1914 andPtr(Imm32(static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op1)))), regT0);
1915#endif
1916 } else if (isOperandConstantImmediateInt(src: op2)) {
1917 emitGetVirtualRegister(src: op1, dst: regT0);
1918 emitJumpSlowCaseIfNotImmediateInteger(reg: regT0);
1919#if USE(JSVALUE64)
1920 int32_t imm = getConstantOperandImmediateInt(src: op2);
1921 andPtr(imm: Imm32(imm), srcDest: regT0);
1922 if (imm >= 0)
1923 emitFastArithIntToImmNoCheck(src: regT0, dest: regT0);
1924#else
1925 andPtr(Imm32(static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op2)))), regT0);
1926#endif
1927 } else {
1928 emitGetVirtualRegisters(src1: op1, dst1: regT0, src2: op2, dst2: regT1);
1929 andPtr(src: regT1, dest: regT0);
1930 emitJumpSlowCaseIfNotImmediateInteger(reg: regT0);
1931 }
1932 emitPutVirtualRegister(dst: result);
1933}
1934
1935void JIT::emitSlow_op_bitand(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1936{
1937 unsigned result = currentInstruction[1].u.operand;
1938 unsigned op1 = currentInstruction[2].u.operand;
1939 unsigned op2 = currentInstruction[3].u.operand;
1940
1941 linkSlowCase(iter);
1942 if (isOperandConstantImmediateInt(src: op1)) {
1943 JITStubCall stubCall(this, cti_op_bitand);
1944 stubCall.addArgument(src: op1, scratchRegister: regT2);
1945 stubCall.addArgument(argument: regT0);
1946 stubCall.call(dst: result);
1947 } else if (isOperandConstantImmediateInt(src: op2)) {
1948 JITStubCall stubCall(this, cti_op_bitand);
1949 stubCall.addArgument(argument: regT0);
1950 stubCall.addArgument(src: op2, scratchRegister: regT2);
1951 stubCall.call(dst: result);
1952 } else {
1953 JITStubCall stubCall(this, cti_op_bitand);
1954 stubCall.addArgument(src: op1, scratchRegister: regT2);
1955 stubCall.addArgument(argument: regT1);
1956 stubCall.call(dst: result);
1957 }
1958}
1959
1960void JIT::emit_op_post_inc(Instruction* currentInstruction)
1961{
1962 unsigned result = currentInstruction[1].u.operand;
1963 unsigned srcDst = currentInstruction[2].u.operand;
1964
1965 emitGetVirtualRegister(src: srcDst, dst: regT0);
1966 move(src: regT0, dest: regT1);
1967 emitJumpSlowCaseIfNotImmediateInteger(reg: regT0);
1968#if USE(JSVALUE64)
1969 addSlowCase(jump: branchAdd32(cond: Overflow, imm: Imm32(1), dest: regT1));
1970 emitFastArithIntToImmNoCheck(src: regT1, dest: regT1);
1971#else
1972 addSlowCase(branchAdd32(Overflow, Imm32(1 << JSImmediate::IntegerPayloadShift), regT1));
1973 signExtend32ToPtr(regT1, regT1);
1974#endif
1975 emitPutVirtualRegister(dst: srcDst, from: regT1);
1976 emitPutVirtualRegister(dst: result);
1977}
1978
1979void JIT::emitSlow_op_post_inc(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
1980{
1981 unsigned result = currentInstruction[1].u.operand;
1982 unsigned srcDst = currentInstruction[2].u.operand;
1983
1984 linkSlowCase(iter);
1985 linkSlowCase(iter);
1986 JITStubCall stubCall(this, cti_op_post_inc);
1987 stubCall.addArgument(argument: regT0);
1988 stubCall.addArgument(argument: Imm32(srcDst));
1989 stubCall.call(dst: result);
1990}
1991
1992void JIT::emit_op_post_dec(Instruction* currentInstruction)
1993{
1994 unsigned result = currentInstruction[1].u.operand;
1995 unsigned srcDst = currentInstruction[2].u.operand;
1996
1997 emitGetVirtualRegister(src: srcDst, dst: regT0);
1998 move(src: regT0, dest: regT1);
1999 emitJumpSlowCaseIfNotImmediateInteger(reg: regT0);
2000#if USE(JSVALUE64)
2001 addSlowCase(jump: branchSub32(cond: Zero, imm: Imm32(1), dest: regT1));
2002 emitFastArithIntToImmNoCheck(src: regT1, dest: regT1);
2003#else
2004 addSlowCase(branchSub32(Zero, Imm32(1 << JSImmediate::IntegerPayloadShift), regT1));
2005 signExtend32ToPtr(regT1, regT1);
2006#endif
2007 emitPutVirtualRegister(dst: srcDst, from: regT1);
2008 emitPutVirtualRegister(dst: result);
2009}
2010
2011void JIT::emitSlow_op_post_dec(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
2012{
2013 unsigned result = currentInstruction[1].u.operand;
2014 unsigned srcDst = currentInstruction[2].u.operand;
2015
2016 linkSlowCase(iter);
2017 linkSlowCase(iter);
2018 JITStubCall stubCall(this, cti_op_post_dec);
2019 stubCall.addArgument(argument: regT0);
2020 stubCall.addArgument(argument: Imm32(srcDst));
2021 stubCall.call(dst: result);
2022}
2023
2024void JIT::emit_op_pre_inc(Instruction* currentInstruction)
2025{
2026 unsigned srcDst = currentInstruction[1].u.operand;
2027
2028 emitGetVirtualRegister(src: srcDst, dst: regT0);
2029 emitJumpSlowCaseIfNotImmediateInteger(reg: regT0);
2030#if USE(JSVALUE64)
2031 addSlowCase(jump: branchAdd32(cond: Overflow, imm: Imm32(1), dest: regT0));
2032 emitFastArithIntToImmNoCheck(src: regT0, dest: regT0);
2033#else
2034 addSlowCase(branchAdd32(Overflow, Imm32(1 << JSImmediate::IntegerPayloadShift), regT0));
2035 signExtend32ToPtr(regT0, regT0);
2036#endif
2037 emitPutVirtualRegister(dst: srcDst);
2038}
2039
2040void JIT::emitSlow_op_pre_inc(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
2041{
2042 unsigned srcDst = currentInstruction[1].u.operand;
2043
2044 Jump notImm = getSlowCase(iter);
2045 linkSlowCase(iter);
2046 emitGetVirtualRegister(src: srcDst, dst: regT0);
2047 notImm.link(masm: this);
2048 JITStubCall stubCall(this, cti_op_pre_inc);
2049 stubCall.addArgument(argument: regT0);
2050 stubCall.call(dst: srcDst);
2051}
2052
2053void JIT::emit_op_pre_dec(Instruction* currentInstruction)
2054{
2055 unsigned srcDst = currentInstruction[1].u.operand;
2056
2057 emitGetVirtualRegister(src: srcDst, dst: regT0);
2058 emitJumpSlowCaseIfNotImmediateInteger(reg: regT0);
2059#if USE(JSVALUE64)
2060 addSlowCase(jump: branchSub32(cond: Zero, imm: Imm32(1), dest: regT0));
2061 emitFastArithIntToImmNoCheck(src: regT0, dest: regT0);
2062#else
2063 addSlowCase(branchSub32(Zero, Imm32(1 << JSImmediate::IntegerPayloadShift), regT0));
2064 signExtend32ToPtr(regT0, regT0);
2065#endif
2066 emitPutVirtualRegister(dst: srcDst);
2067}
2068
2069void JIT::emitSlow_op_pre_dec(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
2070{
2071 unsigned srcDst = currentInstruction[1].u.operand;
2072
2073 Jump notImm = getSlowCase(iter);
2074 linkSlowCase(iter);
2075 emitGetVirtualRegister(src: srcDst, dst: regT0);
2076 notImm.link(masm: this);
2077 JITStubCall stubCall(this, cti_op_pre_dec);
2078 stubCall.addArgument(argument: regT0);
2079 stubCall.call(dst: srcDst);
2080}
2081
2082/* ------------------------------ BEGIN: OP_MOD ------------------------------ */
2083
2084#if CPU(X86) || CPU(X86_64)
2085
2086void JIT::emit_op_mod(Instruction* currentInstruction)
2087{
2088 unsigned result = currentInstruction[1].u.operand;
2089 unsigned op1 = currentInstruction[2].u.operand;
2090 unsigned op2 = currentInstruction[3].u.operand;
2091
2092 emitGetVirtualRegisters(src1: op1, dst1: X86Registers::eax, src2: op2, dst2: X86Registers::ecx);
2093 emitJumpSlowCaseIfNotImmediateInteger(reg: X86Registers::eax);
2094 emitJumpSlowCaseIfNotImmediateInteger(reg: X86Registers::ecx);
2095#if USE(JSVALUE64)
2096 addSlowCase(jump: branchPtr(cond: Equal, left: X86Registers::ecx, right: ImmPtr(JSValue::encode(value: jsNumber(globalData: m_globalData, i: 0)))));
2097 m_assembler.cdq();
2098 m_assembler.idivl_r(dst: X86Registers::ecx);
2099#else
2100 emitFastArithDeTagImmediate(X86Registers::eax);
2101 addSlowCase(emitFastArithDeTagImmediateJumpIfZero(X86Registers::ecx));
2102 m_assembler.cdq();
2103 m_assembler.idivl_r(X86Registers::ecx);
2104 signExtend32ToPtr(X86Registers::edx, X86Registers::edx);
2105#endif
2106 emitFastArithReTagImmediate(src: X86Registers::edx, dest: X86Registers::eax);
2107 emitPutVirtualRegister(dst: result);
2108}
2109
2110void JIT::emitSlow_op_mod(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
2111{
2112 unsigned result = currentInstruction[1].u.operand;
2113
2114#if USE(JSVALUE64)
2115 linkSlowCase(iter);
2116 linkSlowCase(iter);
2117 linkSlowCase(iter);
2118#else
2119 Jump notImm1 = getSlowCase(iter);
2120 Jump notImm2 = getSlowCase(iter);
2121 linkSlowCase(iter);
2122 emitFastArithReTagImmediate(X86Registers::eax, X86Registers::eax);
2123 emitFastArithReTagImmediate(X86Registers::ecx, X86Registers::ecx);
2124 notImm1.link(this);
2125 notImm2.link(this);
2126#endif
2127 JITStubCall stubCall(this, cti_op_mod);
2128 stubCall.addArgument(argument: X86Registers::eax);
2129 stubCall.addArgument(argument: X86Registers::ecx);
2130 stubCall.call(dst: result);
2131}
2132
2133#else // CPU(X86) || CPU(X86_64)
2134
2135void JIT::emit_op_mod(Instruction* currentInstruction)
2136{
2137 unsigned result = currentInstruction[1].u.operand;
2138 unsigned op1 = currentInstruction[2].u.operand;
2139 unsigned op2 = currentInstruction[3].u.operand;
2140
2141 JITStubCall stubCall(this, cti_op_mod);
2142 stubCall.addArgument(op1, regT2);
2143 stubCall.addArgument(op2, regT2);
2144 stubCall.call(result);
2145}
2146
2147void JIT::emitSlow_op_mod(Instruction*, Vector<SlowCaseEntry>::iterator&)
2148{
2149 ASSERT_NOT_REACHED();
2150}
2151
2152#endif // CPU(X86) || CPU(X86_64)
2153
2154/* ------------------------------ END: OP_MOD ------------------------------ */
2155
2156#if USE(JSVALUE64)
2157
2158/* ------------------------------ BEGIN: USE(JSVALUE64) (OP_ADD, OP_SUB, OP_MUL) ------------------------------ */
2159
2160void JIT::compileBinaryArithOp(OpcodeID opcodeID, unsigned, unsigned op1, unsigned op2, OperandTypes)
2161{
2162 emitGetVirtualRegisters(src1: op1, dst1: regT0, src2: op2, dst2: regT1);
2163 emitJumpSlowCaseIfNotImmediateInteger(reg: regT0);
2164 emitJumpSlowCaseIfNotImmediateInteger(reg: regT1);
2165 if (opcodeID == op_add)
2166 addSlowCase(jump: branchAdd32(cond: Overflow, src: regT1, dest: regT0));
2167 else if (opcodeID == op_sub)
2168 addSlowCase(jump: branchSub32(cond: Overflow, src: regT1, dest: regT0));
2169 else {
2170 ASSERT(opcodeID == op_mul);
2171 addSlowCase(jump: branchMul32(cond: Overflow, src: regT1, dest: regT0));
2172 addSlowCase(jump: branchTest32(cond: Zero, reg: regT0));
2173 }
2174 emitFastArithIntToImmNoCheck(src: regT0, dest: regT0);
2175}
2176
2177void JIT::compileBinaryArithOpSlowCase(OpcodeID opcodeID, Vector<SlowCaseEntry>::iterator& iter, unsigned result, unsigned op1, unsigned op2, OperandTypes types, bool op1HasImmediateIntFastCase, bool op2HasImmediateIntFastCase)
2178{
2179 // We assume that subtracting TagTypeNumber is equivalent to adding DoubleEncodeOffset.
2180 COMPILE_ASSERT(((JSImmediate::TagTypeNumber + JSImmediate::DoubleEncodeOffset) == 0), TagTypeNumber_PLUS_DoubleEncodeOffset_EQUALS_0);
2181
2182 Jump notImm1;
2183 Jump notImm2;
2184 if (op1HasImmediateIntFastCase) {
2185 notImm2 = getSlowCase(iter);
2186 } else if (op2HasImmediateIntFastCase) {
2187 notImm1 = getSlowCase(iter);
2188 } else {
2189 notImm1 = getSlowCase(iter);
2190 notImm2 = getSlowCase(iter);
2191 }
2192
2193 linkSlowCase(iter); // Integer overflow case - we could handle this in JIT code, but this is likely rare.
2194 if (opcodeID == op_mul && !op1HasImmediateIntFastCase && !op2HasImmediateIntFastCase) // op_mul has an extra slow case to handle 0 * negative number.
2195 linkSlowCase(iter);
2196 emitGetVirtualRegister(src: op1, dst: regT0);
2197
2198 Label stubFunctionCall(this);
2199 JITStubCall stubCall(this, opcodeID == op_add ? cti_op_add : opcodeID == op_sub ? cti_op_sub : cti_op_mul);
2200 if (op1HasImmediateIntFastCase || op2HasImmediateIntFastCase) {
2201 emitGetVirtualRegister(src: op1, dst: regT0);
2202 emitGetVirtualRegister(src: op2, dst: regT1);
2203 }
2204 stubCall.addArgument(argument: regT0);
2205 stubCall.addArgument(argument: regT1);
2206 stubCall.call(dst: result);
2207 Jump end = jump();
2208
2209 if (op1HasImmediateIntFastCase) {
2210 notImm2.link(masm: this);
2211 if (!types.second().definitelyIsNumber())
2212 emitJumpIfNotImmediateNumber(reg: regT0).linkTo(label: stubFunctionCall, masm: this);
2213 emitGetVirtualRegister(src: op1, dst: regT1);
2214 convertInt32ToDouble(src: regT1, dest: fpRegT1);
2215 addPtr(src: tagTypeNumberRegister, dest: regT0);
2216 movePtrToDouble(src: regT0, dest: fpRegT2);
2217 } else if (op2HasImmediateIntFastCase) {
2218 notImm1.link(masm: this);
2219 if (!types.first().definitelyIsNumber())
2220 emitJumpIfNotImmediateNumber(reg: regT0).linkTo(label: stubFunctionCall, masm: this);
2221 emitGetVirtualRegister(src: op2, dst: regT1);
2222 convertInt32ToDouble(src: regT1, dest: fpRegT1);
2223 addPtr(src: tagTypeNumberRegister, dest: regT0);
2224 movePtrToDouble(src: regT0, dest: fpRegT2);
2225 } else {
2226 // if we get here, eax is not an int32, edx not yet checked.
2227 notImm1.link(masm: this);
2228 if (!types.first().definitelyIsNumber())
2229 emitJumpIfNotImmediateNumber(reg: regT0).linkTo(label: stubFunctionCall, masm: this);
2230 if (!types.second().definitelyIsNumber())
2231 emitJumpIfNotImmediateNumber(reg: regT1).linkTo(label: stubFunctionCall, masm: this);
2232 addPtr(src: tagTypeNumberRegister, dest: regT0);
2233 movePtrToDouble(src: regT0, dest: fpRegT1);
2234 Jump op2isDouble = emitJumpIfNotImmediateInteger(reg: regT1);
2235 convertInt32ToDouble(src: regT1, dest: fpRegT2);
2236 Jump op2wasInteger = jump();
2237
2238 // if we get here, eax IS an int32, edx is not.
2239 notImm2.link(masm: this);
2240 if (!types.second().definitelyIsNumber())
2241 emitJumpIfNotImmediateNumber(reg: regT1).linkTo(label: stubFunctionCall, masm: this);
2242 convertInt32ToDouble(src: regT0, dest: fpRegT1);
2243 op2isDouble.link(masm: this);
2244 addPtr(src: tagTypeNumberRegister, dest: regT1);
2245 movePtrToDouble(src: regT1, dest: fpRegT2);
2246 op2wasInteger.link(masm: this);
2247 }
2248
2249 if (opcodeID == op_add)
2250 addDouble(src: fpRegT2, dest: fpRegT1);
2251 else if (opcodeID == op_sub)
2252 subDouble(src: fpRegT2, dest: fpRegT1);
2253 else if (opcodeID == op_mul)
2254 mulDouble(src: fpRegT2, dest: fpRegT1);
2255 else {
2256 ASSERT(opcodeID == op_div);
2257 divDouble(src: fpRegT2, dest: fpRegT1);
2258 }
2259 moveDoubleToPtr(src: fpRegT1, dest: regT0);
2260 subPtr(src: tagTypeNumberRegister, dest: regT0);
2261 emitPutVirtualRegister(dst: result, from: regT0);
2262
2263 end.link(masm: this);
2264}
2265
2266void JIT::emit_op_add(Instruction* currentInstruction)
2267{
2268 unsigned result = currentInstruction[1].u.operand;
2269 unsigned op1 = currentInstruction[2].u.operand;
2270 unsigned op2 = currentInstruction[3].u.operand;
2271 OperandTypes types = OperandTypes::fromInt(value: currentInstruction[4].u.operand);
2272
2273 if (!types.first().mightBeNumber() || !types.second().mightBeNumber()) {
2274 JITStubCall stubCall(this, cti_op_add);
2275 stubCall.addArgument(src: op1, scratchRegister: regT2);
2276 stubCall.addArgument(src: op2, scratchRegister: regT2);
2277 stubCall.call(dst: result);
2278 return;
2279 }
2280
2281 if (isOperandConstantImmediateInt(src: op1)) {
2282 emitGetVirtualRegister(src: op2, dst: regT0);
2283 emitJumpSlowCaseIfNotImmediateInteger(reg: regT0);
2284 addSlowCase(jump: branchAdd32(cond: Overflow, imm: Imm32(getConstantOperandImmediateInt(src: op1)), dest: regT0));
2285 emitFastArithIntToImmNoCheck(src: regT0, dest: regT0);
2286 } else if (isOperandConstantImmediateInt(src: op2)) {
2287 emitGetVirtualRegister(src: op1, dst: regT0);
2288 emitJumpSlowCaseIfNotImmediateInteger(reg: regT0);
2289 addSlowCase(jump: branchAdd32(cond: Overflow, imm: Imm32(getConstantOperandImmediateInt(src: op2)), dest: regT0));
2290 emitFastArithIntToImmNoCheck(src: regT0, dest: regT0);
2291 } else
2292 compileBinaryArithOp(opcodeID: op_add, result, op1, op2, types);
2293
2294 emitPutVirtualRegister(dst: result);
2295}
2296
2297void JIT::emitSlow_op_add(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
2298{
2299 unsigned result = currentInstruction[1].u.operand;
2300 unsigned op1 = currentInstruction[2].u.operand;
2301 unsigned op2 = currentInstruction[3].u.operand;
2302 OperandTypes types = OperandTypes::fromInt(value: currentInstruction[4].u.operand);
2303
2304 if (!types.first().mightBeNumber() || !types.second().mightBeNumber())
2305 return;
2306
2307 bool op1HasImmediateIntFastCase = isOperandConstantImmediateInt(src: op1);
2308 bool op2HasImmediateIntFastCase = !op1HasImmediateIntFastCase && isOperandConstantImmediateInt(src: op2);
2309 compileBinaryArithOpSlowCase(opcodeID: op_add, iter, result, op1, op2, types: OperandTypes::fromInt(value: currentInstruction[4].u.operand), op1HasImmediateIntFastCase, op2HasImmediateIntFastCase);
2310}
2311
2312void JIT::emit_op_mul(Instruction* currentInstruction)
2313{
2314 unsigned result = currentInstruction[1].u.operand;
2315 unsigned op1 = currentInstruction[2].u.operand;
2316 unsigned op2 = currentInstruction[3].u.operand;
2317 OperandTypes types = OperandTypes::fromInt(value: currentInstruction[4].u.operand);
2318
2319 // For now, only plant a fast int case if the constant operand is greater than zero.
2320 int32_t value;
2321 if (isOperandConstantImmediateInt(src: op1) && ((value = getConstantOperandImmediateInt(src: op1)) > 0)) {
2322 emitGetVirtualRegister(src: op2, dst: regT0);
2323 emitJumpSlowCaseIfNotImmediateInteger(reg: regT0);
2324 addSlowCase(jump: branchMul32(cond: Overflow, imm: Imm32(value), src: regT0, dest: regT0));
2325 emitFastArithReTagImmediate(src: regT0, dest: regT0);
2326 } else if (isOperandConstantImmediateInt(src: op2) && ((value = getConstantOperandImmediateInt(src: op2)) > 0)) {
2327 emitGetVirtualRegister(src: op1, dst: regT0);
2328 emitJumpSlowCaseIfNotImmediateInteger(reg: regT0);
2329 addSlowCase(jump: branchMul32(cond: Overflow, imm: Imm32(value), src: regT0, dest: regT0));
2330 emitFastArithReTagImmediate(src: regT0, dest: regT0);
2331 } else
2332 compileBinaryArithOp(opcodeID: op_mul, result, op1, op2, types);
2333
2334 emitPutVirtualRegister(dst: result);
2335}
2336
2337void JIT::emitSlow_op_mul(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
2338{
2339 unsigned result = currentInstruction[1].u.operand;
2340 unsigned op1 = currentInstruction[2].u.operand;
2341 unsigned op2 = currentInstruction[3].u.operand;
2342
2343 bool op1HasImmediateIntFastCase = isOperandConstantImmediateInt(src: op1) && getConstantOperandImmediateInt(src: op1) > 0;
2344 bool op2HasImmediateIntFastCase = !op1HasImmediateIntFastCase && isOperandConstantImmediateInt(src: op2) && getConstantOperandImmediateInt(src: op2) > 0;
2345 compileBinaryArithOpSlowCase(opcodeID: op_mul, iter, result, op1, op2, types: OperandTypes::fromInt(value: currentInstruction[4].u.operand), op1HasImmediateIntFastCase, op2HasImmediateIntFastCase);
2346}
2347
2348void JIT::emit_op_div(Instruction* currentInstruction)
2349{
2350 unsigned dst = currentInstruction[1].u.operand;
2351 unsigned op1 = currentInstruction[2].u.operand;
2352 unsigned op2 = currentInstruction[3].u.operand;
2353 OperandTypes types = OperandTypes::fromInt(value: currentInstruction[4].u.operand);
2354
2355 if (isOperandConstantImmediateDouble(src: op1)) {
2356 emitGetVirtualRegister(src: op1, dst: regT0);
2357 addPtr(src: tagTypeNumberRegister, dest: regT0);
2358 movePtrToDouble(src: regT0, dest: fpRegT0);
2359 } else if (isOperandConstantImmediateInt(src: op1)) {
2360 emitLoadInt32ToDouble(index: op1, value: fpRegT0);
2361 } else {
2362 emitGetVirtualRegister(src: op1, dst: regT0);
2363 if (!types.first().definitelyIsNumber())
2364 emitJumpSlowCaseIfNotImmediateNumber(reg: regT0);
2365 Jump notInt = emitJumpIfNotImmediateInteger(reg: regT0);
2366 convertInt32ToDouble(src: regT0, dest: fpRegT0);
2367 Jump skipDoubleLoad = jump();
2368 notInt.link(masm: this);
2369 addPtr(src: tagTypeNumberRegister, dest: regT0);
2370 movePtrToDouble(src: regT0, dest: fpRegT0);
2371 skipDoubleLoad.link(masm: this);
2372 }
2373
2374 if (isOperandConstantImmediateDouble(src: op2)) {
2375 emitGetVirtualRegister(src: op2, dst: regT1);
2376 addPtr(src: tagTypeNumberRegister, dest: regT1);
2377 movePtrToDouble(src: regT1, dest: fpRegT1);
2378 } else if (isOperandConstantImmediateInt(src: op2)) {
2379 emitLoadInt32ToDouble(index: op2, value: fpRegT1);
2380 } else {
2381 emitGetVirtualRegister(src: op2, dst: regT1);
2382 if (!types.second().definitelyIsNumber())
2383 emitJumpSlowCaseIfNotImmediateNumber(reg: regT1);
2384 Jump notInt = emitJumpIfNotImmediateInteger(reg: regT1);
2385 convertInt32ToDouble(src: regT1, dest: fpRegT1);
2386 Jump skipDoubleLoad = jump();
2387 notInt.link(masm: this);
2388 addPtr(src: tagTypeNumberRegister, dest: regT1);
2389 movePtrToDouble(src: regT1, dest: fpRegT1);
2390 skipDoubleLoad.link(masm: this);
2391 }
2392 divDouble(src: fpRegT1, dest: fpRegT0);
2393
2394 // Double result.
2395 moveDoubleToPtr(src: fpRegT0, dest: regT0);
2396 subPtr(src: tagTypeNumberRegister, dest: regT0);
2397
2398 emitPutVirtualRegister(dst, from: regT0);
2399}
2400
2401void JIT::emitSlow_op_div(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
2402{
2403 unsigned result = currentInstruction[1].u.operand;
2404 unsigned op1 = currentInstruction[2].u.operand;
2405 unsigned op2 = currentInstruction[3].u.operand;
2406 OperandTypes types = OperandTypes::fromInt(value: currentInstruction[4].u.operand);
2407 if (types.first().definitelyIsNumber() && types.second().definitelyIsNumber()) {
2408#ifndef NDEBUG
2409 breakpoint();
2410#endif
2411 return;
2412 }
2413 if (!isOperandConstantImmediateDouble(src: op1) && !isOperandConstantImmediateInt(src: op1)) {
2414 if (!types.first().definitelyIsNumber())
2415 linkSlowCase(iter);
2416 }
2417 if (!isOperandConstantImmediateDouble(src: op2) && !isOperandConstantImmediateInt(src: op2)) {
2418 if (!types.second().definitelyIsNumber())
2419 linkSlowCase(iter);
2420 }
2421 // There is an extra slow case for (op1 * -N) or (-N * op2), to check for 0 since this should produce a result of -0.
2422 JITStubCall stubCall(this, cti_op_div);
2423 stubCall.addArgument(src: op1, scratchRegister: regT2);
2424 stubCall.addArgument(src: op2, scratchRegister: regT2);
2425 stubCall.call(dst: result);
2426}
2427
2428void JIT::emit_op_sub(Instruction* currentInstruction)
2429{
2430 unsigned result = currentInstruction[1].u.operand;
2431 unsigned op1 = currentInstruction[2].u.operand;
2432 unsigned op2 = currentInstruction[3].u.operand;
2433 OperandTypes types = OperandTypes::fromInt(value: currentInstruction[4].u.operand);
2434
2435 compileBinaryArithOp(opcodeID: op_sub, result, op1, op2, types);
2436 emitPutVirtualRegister(dst: result);
2437}
2438
2439void JIT::emitSlow_op_sub(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
2440{
2441 unsigned result = currentInstruction[1].u.operand;
2442 unsigned op1 = currentInstruction[2].u.operand;
2443 unsigned op2 = currentInstruction[3].u.operand;
2444 OperandTypes types = OperandTypes::fromInt(value: currentInstruction[4].u.operand);
2445
2446 compileBinaryArithOpSlowCase(opcodeID: op_sub, iter, result, op1, op2, types, op1HasImmediateIntFastCase: false, op2HasImmediateIntFastCase: false);
2447}
2448
2449#else // USE(JSVALUE64)
2450
2451/* ------------------------------ BEGIN: !USE(JSVALUE64) (OP_ADD, OP_SUB, OP_MUL) ------------------------------ */
2452
2453void JIT::compileBinaryArithOp(OpcodeID opcodeID, unsigned dst, unsigned src1, unsigned src2, OperandTypes types)
2454{
2455 Structure* numberStructure = m_globalData->numberStructure.get();
2456 Jump wasJSNumberCell1;
2457 Jump wasJSNumberCell2;
2458
2459 emitGetVirtualRegisters(src1, regT0, src2, regT1);
2460
2461 if (types.second().isReusable() && supportsFloatingPoint()) {
2462 ASSERT(types.second().mightBeNumber());
2463
2464 // Check op2 is a number
2465 Jump op2imm = emitJumpIfImmediateInteger(regT1);
2466 if (!types.second().definitelyIsNumber()) {
2467 emitJumpSlowCaseIfNotJSCell(regT1, src2);
2468 addSlowCase(checkStructure(regT1, numberStructure));
2469 }
2470
2471 // (1) In this case src2 is a reusable number cell.
2472 // Slow case if src1 is not a number type.
2473 Jump op1imm = emitJumpIfImmediateInteger(regT0);
2474 if (!types.first().definitelyIsNumber()) {
2475 emitJumpSlowCaseIfNotJSCell(regT0, src1);
2476 addSlowCase(checkStructure(regT0, numberStructure));
2477 }
2478
2479 // (1a) if we get here, src1 is also a number cell
2480 loadDouble(Address(regT0, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0);
2481 Jump loadedDouble = jump();
2482 // (1b) if we get here, src1 is an immediate
2483 op1imm.link(this);
2484 emitFastArithImmToInt(regT0);
2485 convertInt32ToDouble(regT0, fpRegT0);
2486 // (1c)
2487 loadedDouble.link(this);
2488 if (opcodeID == op_add)
2489 addDouble(Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0);
2490 else if (opcodeID == op_sub)
2491 subDouble(Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0);
2492 else {
2493 ASSERT(opcodeID == op_mul);
2494 mulDouble(Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0);
2495 }
2496
2497 // Store the result to the JSNumberCell and jump.
2498 storeDouble(fpRegT0, Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)));
2499 move(regT1, regT0);
2500 emitPutVirtualRegister(dst);
2501 wasJSNumberCell2 = jump();
2502
2503 // (2) This handles cases where src2 is an immediate number.
2504 // Two slow cases - either src1 isn't an immediate, or the subtract overflows.
2505 op2imm.link(this);
2506 emitJumpSlowCaseIfNotImmediateInteger(regT0);
2507 } else if (types.first().isReusable() && supportsFloatingPoint()) {
2508 ASSERT(types.first().mightBeNumber());
2509
2510 // Check op1 is a number
2511 Jump op1imm = emitJumpIfImmediateInteger(regT0);
2512 if (!types.first().definitelyIsNumber()) {
2513 emitJumpSlowCaseIfNotJSCell(regT0, src1);
2514 addSlowCase(checkStructure(regT0, numberStructure));
2515 }
2516
2517 // (1) In this case src1 is a reusable number cell.
2518 // Slow case if src2 is not a number type.
2519 Jump op2imm = emitJumpIfImmediateInteger(regT1);
2520 if (!types.second().definitelyIsNumber()) {
2521 emitJumpSlowCaseIfNotJSCell(regT1, src2);
2522 addSlowCase(checkStructure(regT1, numberStructure));
2523 }
2524
2525 // (1a) if we get here, src2 is also a number cell
2526 loadDouble(Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT1);
2527 Jump loadedDouble = jump();
2528 // (1b) if we get here, src2 is an immediate
2529 op2imm.link(this);
2530 emitFastArithImmToInt(regT1);
2531 convertInt32ToDouble(regT1, fpRegT1);
2532 // (1c)
2533 loadedDouble.link(this);
2534 loadDouble(Address(regT0, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0);
2535 if (opcodeID == op_add)
2536 addDouble(fpRegT1, fpRegT0);
2537 else if (opcodeID == op_sub)
2538 subDouble(fpRegT1, fpRegT0);
2539 else {
2540 ASSERT(opcodeID == op_mul);
2541 mulDouble(fpRegT1, fpRegT0);
2542 }
2543 storeDouble(fpRegT0, Address(regT0, OBJECT_OFFSETOF(JSNumberCell, m_value)));
2544 emitPutVirtualRegister(dst);
2545
2546 // Store the result to the JSNumberCell and jump.
2547 storeDouble(fpRegT0, Address(regT0, OBJECT_OFFSETOF(JSNumberCell, m_value)));
2548 emitPutVirtualRegister(dst);
2549 wasJSNumberCell1 = jump();
2550
2551 // (2) This handles cases where src1 is an immediate number.
2552 // Two slow cases - either src2 isn't an immediate, or the subtract overflows.
2553 op1imm.link(this);
2554 emitJumpSlowCaseIfNotImmediateInteger(regT1);
2555 } else
2556 emitJumpSlowCaseIfNotImmediateIntegers(regT0, regT1, regT2);
2557
2558 if (opcodeID == op_add) {
2559 emitFastArithDeTagImmediate(regT0);
2560 addSlowCase(branchAdd32(Overflow, regT1, regT0));
2561 } else if (opcodeID == op_sub) {
2562 addSlowCase(branchSub32(Overflow, regT1, regT0));
2563 signExtend32ToPtr(regT0, regT0);
2564 emitFastArithReTagImmediate(regT0, regT0);
2565 } else {
2566 ASSERT(opcodeID == op_mul);
2567 // convert eax & edx from JSImmediates to ints, and check if either are zero
2568 emitFastArithImmToInt(regT1);
2569 Jump op1Zero = emitFastArithDeTagImmediateJumpIfZero(regT0);
2570 Jump op2NonZero = branchTest32(NonZero, regT1);
2571 op1Zero.link(this);
2572 // if either input is zero, add the two together, and check if the result is < 0.
2573 // If it is, we have a problem (N < 0), (N * 0) == -0, not representatble as a JSImmediate.
2574 move(regT0, regT2);
2575 addSlowCase(branchAdd32(Signed, regT1, regT2));
2576 // Skip the above check if neither input is zero
2577 op2NonZero.link(this);
2578 addSlowCase(branchMul32(Overflow, regT1, regT0));
2579 signExtend32ToPtr(regT0, regT0);
2580 emitFastArithReTagImmediate(regT0, regT0);
2581 }
2582 emitPutVirtualRegister(dst);
2583
2584 if (types.second().isReusable() && supportsFloatingPoint())
2585 wasJSNumberCell2.link(this);
2586 else if (types.first().isReusable() && supportsFloatingPoint())
2587 wasJSNumberCell1.link(this);
2588}
2589
2590void JIT::compileBinaryArithOpSlowCase(OpcodeID opcodeID, Vector<SlowCaseEntry>::iterator& iter, unsigned dst, unsigned src1, unsigned src2, OperandTypes types)
2591{
2592 linkSlowCase(iter);
2593 if (types.second().isReusable() && supportsFloatingPoint()) {
2594 if (!types.first().definitelyIsNumber()) {
2595 linkSlowCaseIfNotJSCell(iter, src1);
2596 linkSlowCase(iter);
2597 }
2598 if (!types.second().definitelyIsNumber()) {
2599 linkSlowCaseIfNotJSCell(iter, src2);
2600 linkSlowCase(iter);
2601 }
2602 } else if (types.first().isReusable() && supportsFloatingPoint()) {
2603 if (!types.first().definitelyIsNumber()) {
2604 linkSlowCaseIfNotJSCell(iter, src1);
2605 linkSlowCase(iter);
2606 }
2607 if (!types.second().definitelyIsNumber()) {
2608 linkSlowCaseIfNotJSCell(iter, src2);
2609 linkSlowCase(iter);
2610 }
2611 }
2612 linkSlowCase(iter);
2613
2614 // additional entry point to handle -0 cases.
2615 if (opcodeID == op_mul)
2616 linkSlowCase(iter);
2617
2618 JITStubCall stubCall(this, opcodeID == op_add ? cti_op_add : opcodeID == op_sub ? cti_op_sub : cti_op_mul);
2619 stubCall.addArgument(src1, regT2);
2620 stubCall.addArgument(src2, regT2);
2621 stubCall.call(dst);
2622}
2623
2624void JIT::emit_op_add(Instruction* currentInstruction)
2625{
2626 unsigned result = currentInstruction[1].u.operand;
2627 unsigned op1 = currentInstruction[2].u.operand;
2628 unsigned op2 = currentInstruction[3].u.operand;
2629 OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand);
2630
2631 if (!types.first().mightBeNumber() || !types.second().mightBeNumber()) {
2632 JITStubCall stubCall(this, cti_op_add);
2633 stubCall.addArgument(op1, regT2);
2634 stubCall.addArgument(op2, regT2);
2635 stubCall.call(result);
2636 return;
2637 }
2638
2639 if (isOperandConstantImmediateInt(op1)) {
2640 emitGetVirtualRegister(op2, regT0);
2641 emitJumpSlowCaseIfNotImmediateInteger(regT0);
2642 addSlowCase(branchAdd32(Overflow, Imm32(getConstantOperandImmediateInt(op1) << JSImmediate::IntegerPayloadShift), regT0));
2643 signExtend32ToPtr(regT0, regT0);
2644 emitPutVirtualRegister(result);
2645 } else if (isOperandConstantImmediateInt(op2)) {
2646 emitGetVirtualRegister(op1, regT0);
2647 emitJumpSlowCaseIfNotImmediateInteger(regT0);
2648 addSlowCase(branchAdd32(Overflow, Imm32(getConstantOperandImmediateInt(op2) << JSImmediate::IntegerPayloadShift), regT0));
2649 signExtend32ToPtr(regT0, regT0);
2650 emitPutVirtualRegister(result);
2651 } else {
2652 compileBinaryArithOp(op_add, result, op1, op2, OperandTypes::fromInt(currentInstruction[4].u.operand));
2653 }
2654}
2655
2656void JIT::emitSlow_op_add(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
2657{
2658 unsigned result = currentInstruction[1].u.operand;
2659 unsigned op1 = currentInstruction[2].u.operand;
2660 unsigned op2 = currentInstruction[3].u.operand;
2661
2662 OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand);
2663 if (!types.first().mightBeNumber() || !types.second().mightBeNumber())
2664 return;
2665
2666 if (isOperandConstantImmediateInt(op1)) {
2667 Jump notImm = getSlowCase(iter);
2668 linkSlowCase(iter);
2669 sub32(Imm32(getConstantOperandImmediateInt(op1) << JSImmediate::IntegerPayloadShift), regT0);
2670 notImm.link(this);
2671 JITStubCall stubCall(this, cti_op_add);
2672 stubCall.addArgument(op1, regT2);
2673 stubCall.addArgument(regT0);
2674 stubCall.call(result);
2675 } else if (isOperandConstantImmediateInt(op2)) {
2676 Jump notImm = getSlowCase(iter);
2677 linkSlowCase(iter);
2678 sub32(Imm32(getConstantOperandImmediateInt(op2) << JSImmediate::IntegerPayloadShift), regT0);
2679 notImm.link(this);
2680 JITStubCall stubCall(this, cti_op_add);
2681 stubCall.addArgument(regT0);
2682 stubCall.addArgument(op2, regT2);
2683 stubCall.call(result);
2684 } else {
2685 OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand);
2686 ASSERT(types.first().mightBeNumber() && types.second().mightBeNumber());
2687 compileBinaryArithOpSlowCase(op_add, iter, result, op1, op2, types);
2688 }
2689}
2690
2691void JIT::emit_op_mul(Instruction* currentInstruction)
2692{
2693 unsigned result = currentInstruction[1].u.operand;
2694 unsigned op1 = currentInstruction[2].u.operand;
2695 unsigned op2 = currentInstruction[3].u.operand;
2696
2697 // For now, only plant a fast int case if the constant operand is greater than zero.
2698 int32_t value;
2699 if (isOperandConstantImmediateInt(op1) && ((value = getConstantOperandImmediateInt(op1)) > 0)) {
2700 emitGetVirtualRegister(op2, regT0);
2701 emitJumpSlowCaseIfNotImmediateInteger(regT0);
2702 emitFastArithDeTagImmediate(regT0);
2703 addSlowCase(branchMul32(Overflow, Imm32(value), regT0, regT0));
2704 signExtend32ToPtr(regT0, regT0);
2705 emitFastArithReTagImmediate(regT0, regT0);
2706 emitPutVirtualRegister(result);
2707 } else if (isOperandConstantImmediateInt(op2) && ((value = getConstantOperandImmediateInt(op2)) > 0)) {
2708 emitGetVirtualRegister(op1, regT0);
2709 emitJumpSlowCaseIfNotImmediateInteger(regT0);
2710 emitFastArithDeTagImmediate(regT0);
2711 addSlowCase(branchMul32(Overflow, Imm32(value), regT0, regT0));
2712 signExtend32ToPtr(regT0, regT0);
2713 emitFastArithReTagImmediate(regT0, regT0);
2714 emitPutVirtualRegister(result);
2715 } else
2716 compileBinaryArithOp(op_mul, result, op1, op2, OperandTypes::fromInt(currentInstruction[4].u.operand));
2717}
2718
2719void JIT::emitSlow_op_mul(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
2720{
2721 unsigned result = currentInstruction[1].u.operand;
2722 unsigned op1 = currentInstruction[2].u.operand;
2723 unsigned op2 = currentInstruction[3].u.operand;
2724
2725 if ((isOperandConstantImmediateInt(op1) && (getConstantOperandImmediateInt(op1) > 0))
2726 || (isOperandConstantImmediateInt(op2) && (getConstantOperandImmediateInt(op2) > 0))) {
2727 linkSlowCase(iter);
2728 linkSlowCase(iter);
2729 // There is an extra slow case for (op1 * -N) or (-N * op2), to check for 0 since this should produce a result of -0.
2730 JITStubCall stubCall(this, cti_op_mul);
2731 stubCall.addArgument(op1, regT2);
2732 stubCall.addArgument(op2, regT2);
2733 stubCall.call(result);
2734 } else
2735 compileBinaryArithOpSlowCase(op_mul, iter, result, op1, op2, OperandTypes::fromInt(currentInstruction[4].u.operand));
2736}
2737
2738void JIT::emit_op_sub(Instruction* currentInstruction)
2739{
2740 compileBinaryArithOp(op_sub, currentInstruction[1].u.operand, currentInstruction[2].u.operand, currentInstruction[3].u.operand, OperandTypes::fromInt(currentInstruction[4].u.operand));
2741}
2742
2743void JIT::emitSlow_op_sub(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
2744{
2745 compileBinaryArithOpSlowCase(op_sub, iter, currentInstruction[1].u.operand, currentInstruction[2].u.operand, currentInstruction[3].u.operand, OperandTypes::fromInt(currentInstruction[4].u.operand));
2746}
2747
2748#endif // USE(JSVALUE64)
2749
2750/* ------------------------------ END: OP_ADD, OP_SUB, OP_MUL ------------------------------ */
2751
2752#endif // USE(JSVALUE32_64)
2753
2754} // namespace JSC
2755
2756#endif // ENABLE(JIT)
2757

source code of qtscript/src/3rdparty/javascriptcore/JavaScriptCore/jit/JITArithmetic.cpp