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

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

Buildfix for platforms using JSVALUE32.
https://bugs.webkit.org/show_bug.cgi?id=29915

Patch by Csaba Osztrogonac <[email protected]> on 2009-09-30
Reviewed by Geoffrey Garen.

After http://trac.webkit.org/changeset/48905 the build broke in JSVALUE32 case.
Also removed unreachable code.

  • jit/JITArithmetic.cpp:

(JSC::JIT::emit_op_add):

  • Declaration of "OperandTypes types" moved before first use.
  • Typos fixed: dst modified to result, regT2 added.
  • Unreachable code removed.

(JSC::JIT::emitSlow_op_add):

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