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