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