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 28 #if ENABLE(JIT) 29 #if USE(JSVALUE64) 30 #include "JIT.h" 31 32 #include "CodeBlock.h" 33 #include "JITInlineMethods.h" 34 #include "JITStubCall.h" 35 #include "JITStubs.h" 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 46 using namespace std; 47 48 namespace JSC { 49 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); 62 lshift32(regT2, regT0); 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 73 UNUSED_PARAM(op1); 74 UNUSED_PARAM(op2); 75 linkSlowCase(iter); 76 linkSlowCase(iter); 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. 94 rshift32(Imm32(getConstantOperandImmediateInt(op2) & 0x1f), regT0); 95 } else { 96 emitGetVirtualRegisters(op1, regT0, op2, regT2); 97 if (supportsFloatingPointTruncate()) { 98 Jump lhsIsInt = emitJumpIfImmediateInteger(regT0); 99 // supportsFloatingPoint() && USE(JSVALUE64) => 3 SlowCases 100 addSlowCase(emitJumpIfNotImmediateNumber(regT0)); 101 addPtr(tagTypeNumberRegister, regT0); 102 movePtrToDouble(regT0, fpRegT0); 103 addSlowCase(branchTruncateDoubleToInt32(fpRegT0, regT0)); 104 lhsIsInt.link(this); 105 emitJumpSlowCaseIfNotImmediateInteger(regT2); 106 } else { 107 // !supportsFloatingPoint() => 2 SlowCases 108 emitJumpSlowCaseIfNotImmediateInteger(regT0); 109 emitJumpSlowCaseIfNotImmediateInteger(regT2); 110 } 111 emitFastArithImmToInt(regT2); 112 rshift32(regT2, regT0); 113 } 114 emitFastArithIntToImmNoCheck(regT0, regT0); 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()) { 132 linkSlowCase(iter); 133 linkSlowCase(iter); 134 linkSlowCase(iter); 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 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)) 170 addSlowCase(branch32(LessThan, regT0, TrustedImm32(0))); 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); 182 addSlowCase(branch32(LessThan, regT0, TrustedImm32(0))); 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 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)) 205 failures.append(branch32(LessThan, regT0, TrustedImm32(0))); 206 emitFastArithReTagImmediate(regT0, regT0); 207 emitPutVirtualRegister(dst, regT0); 208 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_rshift)); 209 failures.link(this); 210 } 211 if (shift < 0 || !(shift & 31)) 212 linkSlowCase(iter); // failed to box in hot path 213 } else { 214 // op1 = regT0 215 // op2 = regT1 216 if (!isOperandConstantImmediateInt(op1)) { 217 linkSlowCase(iter); // int32 check -- op1 is not an int 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); 227 failures.append(branch32(LessThan, regT0, TrustedImm32(0))); 228 emitFastArithReTagImmediate(regT0, regT0); 229 emitPutVirtualRegister(dst, regT0); 230 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_rshift)); 231 failures.link(this); 232 } 233 } 234 235 linkSlowCase(iter); // int32 check - op2 is not an int 236 linkSlowCase(iter); // Can't represent unsigned result as an immediate 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 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 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 } 274 if (isOperandConstantImmediateInt(op2)) { 275 emitGetVirtualRegister(op1, regT0); 276 emitJumpSlowCaseIfNotImmediateInteger(regT0); 277 int32_t op2imm = getConstantOperandImmediateInt(op2); 278 addJump(branch32(GreaterThanOrEqual, regT0, Imm32(op2imm)), target); 279 } else if (isOperandConstantImmediateInt(op1)) { 280 emitGetVirtualRegister(op2, regT1); 281 emitJumpSlowCaseIfNotImmediateInteger(regT1); 282 int32_t op1imm = getConstantOperandImmediateInt(op1); 283 addJump(branch32(LessThanOrEqual, regT1, Imm32(op1imm)), target); 284 } else { 285 emitGetVirtualRegisters(op1, regT0, op2, regT1); 286 emitJumpSlowCaseIfNotImmediateInteger(regT0); 287 emitJumpSlowCaseIfNotImmediateInteger(regT1); 288 289 addJump(branch32(GreaterThanOrEqual, regT0, regT1), target); 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. 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 } 315 316 if (isOperandConstantImmediateInt(op2)) { 317 linkSlowCase(iter); 318 319 if (supportsFloatingPoint()) { 320 Jump fail1 = emitJumpIfNotImmediateNumber(regT0); 321 addPtr(tagTypeNumberRegister, regT0); 322 movePtrToDouble(regT0, fpRegT0); 323 324 int32_t op2imm = getConstantOperand(op2).asInt32();; 325 326 move(Imm32(op2imm), regT1); 327 convertInt32ToDouble(regT1, fpRegT1); 328 329 emitJumpSlowToHot(branchDouble(DoubleLessThanOrEqualOrUnordered, fpRegT1, fpRegT0), target); 330 331 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnless)); 332 333 fail1.link(this); 334 } 335 336 JITStubCall stubCall(this, cti_op_jless); 337 stubCall.addArgument(regT0); 338 stubCall.addArgument(op2, regT2); 339 stubCall.call(); 340 emitJumpSlowToHot(branchTest32(Zero, regT0), target); 341 342 } else if (isOperandConstantImmediateInt(op1)) { 343 linkSlowCase(iter); 344 345 if (supportsFloatingPoint()) { 346 Jump fail1 = emitJumpIfNotImmediateNumber(regT1); 347 addPtr(tagTypeNumberRegister, regT1); 348 movePtrToDouble(regT1, fpRegT1); 349 350 int32_t op1imm = getConstantOperand(op1).asInt32();; 351 352 move(Imm32(op1imm), regT0); 353 convertInt32ToDouble(regT0, fpRegT0); 354 355 emitJumpSlowToHot(branchDouble(DoubleLessThanOrEqualOrUnordered, fpRegT1, fpRegT0), target); 356 357 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnless)); 358 359 fail1.link(this); 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()) { 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); 379 380 emitJumpSlowToHot(branchDouble(DoubleLessThanOrEqualOrUnordered, fpRegT1, fpRegT0), target); 381 382 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnless)); 383 384 fail1.link(this); 385 fail2.link(this); 386 fail3.link(this); 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 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 } 427 if (isOperandConstantImmediateInt(op2)) { 428 emitGetVirtualRegister(op1, regT0); 429 emitJumpSlowCaseIfNotImmediateInteger(regT0); 430 int32_t op2imm = getConstantOperandImmediateInt(op2); 431 addJump(branch32(LessThan, regT0, Imm32(op2imm)), target); 432 } else if (isOperandConstantImmediateInt(op1)) { 433 emitGetVirtualRegister(op2, regT1); 434 emitJumpSlowCaseIfNotImmediateInteger(regT1); 435 int32_t op1imm = getConstantOperandImmediateInt(op1); 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. 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 } 468 469 if (isOperandConstantImmediateInt(op2)) { 470 linkSlowCase(iter); 471 472 if (supportsFloatingPoint()) { 473 Jump fail1 = emitJumpIfNotImmediateNumber(regT0); 474 addPtr(tagTypeNumberRegister, regT0); 475 movePtrToDouble(regT0, fpRegT0); 476 477 int32_t op2imm = getConstantOperand(op2).asInt32(); 478 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 486 fail1.link(this); 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()) { 499 Jump fail1 = emitJumpIfNotImmediateNumber(regT1); 500 addPtr(tagTypeNumberRegister, regT1); 501 movePtrToDouble(regT1, fpRegT1); 502 503 int32_t op1imm = getConstantOperand(op1).asInt32(); 504 505 move(Imm32(op1imm), regT0); 506 convertInt32ToDouble(regT0, fpRegT0); 507 508 emitJumpSlowToHot(branchDouble(DoubleLessThan, fpRegT0, fpRegT1), target); 509 510 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnless)); 511 512 fail1.link(this); 513 } 514 515 JITStubCall stubCall(this, cti_op_jless); 516 stubCall.addArgument(op1, regT2); 517 stubCall.addArgument(regT1); 518 stubCall.call(); 519 emitJumpSlowToHot(branchTest32(NonZero, regT0), target); 520 521 } else { 522 linkSlowCase(iter); 523 524 if (supportsFloatingPoint()) { 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); 532 533 emitJumpSlowToHot(branchDouble(DoubleLessThan, fpRegT0, fpRegT1), target); 534 535 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnless)); 536 537 fail1.link(this); 538 fail2.link(this); 539 fail3.link(this); 540 } 541 542 linkSlowCase(iter); 543 JITStubCall stubCall(this, cti_op_jless); 544 stubCall.addArgument(regT0); 545 stubCall.addArgument(regT1); 546 stubCall.call(); 547 emitJumpSlowToHot(branchTest32(NonZero, regT0), target); 548 } 549 } 550 551 void JIT::emit_op_jlesseq(Instruction* currentInstruction, bool invert) 552 { 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 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 } 580 if (isOperandConstantImmediateInt(op2)) { 581 emitGetVirtualRegister(op1, regT0); 582 emitJumpSlowCaseIfNotImmediateInteger(regT0); 583 int32_t op2imm = getConstantOperandImmediateInt(op2); 584 addJump(branch32(invert ? GreaterThan : LessThanOrEqual, regT0, Imm32(op2imm)), target); 585 } else if (isOperandConstantImmediateInt(op1)) { 586 emitGetVirtualRegister(op2, regT1); 587 emitJumpSlowCaseIfNotImmediateInteger(regT1); 588 int32_t op1imm = getConstantOperandImmediateInt(op1); 589 addJump(branch32(invert ? LessThan : GreaterThanOrEqual, regT1, Imm32(op1imm)), target); 590 } else { 591 emitGetVirtualRegisters(op1, regT0, op2, regT1); 592 emitJumpSlowCaseIfNotImmediateInteger(regT0); 593 emitJumpSlowCaseIfNotImmediateInteger(regT1); 594 595 addJump(branch32(invert ? GreaterThan : LessThanOrEqual, regT0, regT1), target); 596 } 597 } 598 599 void JIT::emitSlow_op_jlesseq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter, bool invert) 600 { 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 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 623 if (isOperandConstantImmediateInt(op2)) { 624 linkSlowCase(iter); 625 626 if (supportsFloatingPoint()) { 627 Jump fail1 = emitJumpIfNotImmediateNumber(regT0); 628 addPtr(tagTypeNumberRegister, regT0); 629 movePtrToDouble(regT0, fpRegT0); 630 631 int32_t op2imm = getConstantOperand(op2).asInt32();; 632 633 move(Imm32(op2imm), regT1); 634 convertInt32ToDouble(regT1, fpRegT1); 635 636 emitJumpSlowToHot(branchDouble(invert ? DoubleLessThanOrUnordered : DoubleGreaterThanOrEqual, fpRegT1, fpRegT0), target); 637 638 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnlesseq)); 639 640 fail1.link(this); 641 } 642 643 JITStubCall stubCall(this, cti_op_jlesseq); 644 stubCall.addArgument(regT0); 645 stubCall.addArgument(op2, regT2); 646 stubCall.call(); 647 emitJumpSlowToHot(branchTest32(invert ? Zero : NonZero, regT0), target); 648 649 } else if (isOperandConstantImmediateInt(op1)) { 650 linkSlowCase(iter); 651 652 if (supportsFloatingPoint()) { 653 Jump fail1 = emitJumpIfNotImmediateNumber(regT1); 654 addPtr(tagTypeNumberRegister, regT1); 655 movePtrToDouble(regT1, fpRegT1); 656 657 int32_t op1imm = getConstantOperand(op1).asInt32();; 658 659 move(Imm32(op1imm), regT0); 660 convertInt32ToDouble(regT0, fpRegT0); 661 662 emitJumpSlowToHot(branchDouble(invert ? DoubleLessThanOrUnordered : DoubleGreaterThanOrEqual, fpRegT1, fpRegT0), target); 663 664 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnlesseq)); 665 666 fail1.link(this); 667 } 668 669 JITStubCall stubCall(this, cti_op_jlesseq); 670 stubCall.addArgument(op1, regT2); 671 stubCall.addArgument(regT1); 672 stubCall.call(); 673 emitJumpSlowToHot(branchTest32(invert ? Zero : NonZero, regT0), target); 674 675 } else { 676 linkSlowCase(iter); 677 678 if (supportsFloatingPoint()) { 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); 686 687 emitJumpSlowToHot(branchDouble(invert ? DoubleLessThanOrUnordered : DoubleGreaterThanOrEqual, fpRegT1, fpRegT0), target); 688 689 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnlesseq)); 690 691 fail1.link(this); 692 fail2.link(this); 693 fail3.link(this); 694 } 695 696 linkSlowCase(iter); 697 JITStubCall stubCall(this, cti_op_jlesseq); 698 stubCall.addArgument(regT0); 699 stubCall.addArgument(regT1); 700 stubCall.call(); 701 emitJumpSlowToHot(branchTest32(invert ? Zero : NonZero, regT0), target); 702 } 703 } 704 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 715 void JIT::emit_op_bitand(Instruction* currentInstruction) 716 { 717 unsigned result = currentInstruction[1].u.operand; 718 unsigned op1 = currentInstruction[2].u.operand; 719 unsigned op2 = currentInstruction[3].u.operand; 720 721 if (isOperandConstantImmediateInt(op1)) { 722 emitGetVirtualRegister(op2, regT0); 723 emitJumpSlowCaseIfNotImmediateInteger(regT0); 724 int32_t imm = getConstantOperandImmediateInt(op1); 725 andPtr(Imm32(imm), regT0); 726 if (imm >= 0) 727 emitFastArithIntToImmNoCheck(regT0, regT0); 728 } else if (isOperandConstantImmediateInt(op2)) { 729 emitGetVirtualRegister(op1, regT0); 730 emitJumpSlowCaseIfNotImmediateInteger(regT0); 731 int32_t imm = getConstantOperandImmediateInt(op2); 732 andPtr(Imm32(imm), regT0); 733 if (imm >= 0) 734 emitFastArithIntToImmNoCheck(regT0, regT0); 735 } else { 736 emitGetVirtualRegisters(op1, regT0, op2, regT1); 737 andPtr(regT1, regT0); 738 emitJumpSlowCaseIfNotImmediateInteger(regT0); 739 } 740 emitPutVirtualRegister(result); 741 } 742 743 void JIT::emitSlow_op_bitand(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 744 { 745 unsigned result = currentInstruction[1].u.operand; 746 unsigned op1 = currentInstruction[2].u.operand; 747 unsigned op2 = currentInstruction[3].u.operand; 748 749 linkSlowCase(iter); 750 if (isOperandConstantImmediateInt(op1)) { 751 JITStubCall stubCall(this, cti_op_bitand); 752 stubCall.addArgument(op1, regT2); 753 stubCall.addArgument(regT0); 754 stubCall.call(result); 755 } else if (isOperandConstantImmediateInt(op2)) { 756 JITStubCall stubCall(this, cti_op_bitand); 757 stubCall.addArgument(regT0); 758 stubCall.addArgument(op2, regT2); 759 stubCall.call(result); 760 } else { 761 JITStubCall stubCall(this, cti_op_bitand); 762 stubCall.addArgument(op1, regT2); 763 stubCall.addArgument(regT1); 764 stubCall.call(result); 765 } 766 } 767 768 void JIT::emit_op_post_inc(Instruction* currentInstruction) 769 { 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); 776 addSlowCase(branchAdd32(Overflow, TrustedImm32(1), regT1)); 777 emitFastArithIntToImmNoCheck(regT1, regT1); 778 emitPutVirtualRegister(srcDst, regT1); 779 emitPutVirtualRegister(result); 780 } 781 782 void JIT::emitSlow_op_post_inc(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 783 { 784 unsigned result = currentInstruction[1].u.operand; 785 unsigned srcDst = currentInstruction[2].u.operand; 786 787 linkSlowCase(iter); 788 linkSlowCase(iter); 789 JITStubCall stubCall(this, cti_op_post_inc); 790 stubCall.addArgument(regT0); 791 stubCall.addArgument(Imm32(srcDst)); 792 stubCall.call(result); 793 } 794 795 void JIT::emit_op_post_dec(Instruction* currentInstruction) 796 { 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); 803 addSlowCase(branchSub32(Zero, TrustedImm32(1), regT1)); 804 emitFastArithIntToImmNoCheck(regT1, regT1); 805 emitPutVirtualRegister(srcDst, regT1); 806 emitPutVirtualRegister(result); 807 } 808 809 void JIT::emitSlow_op_post_dec(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 810 { 811 unsigned result = currentInstruction[1].u.operand; 812 unsigned srcDst = currentInstruction[2].u.operand; 813 814 linkSlowCase(iter); 815 linkSlowCase(iter); 816 JITStubCall stubCall(this, cti_op_post_dec); 817 stubCall.addArgument(regT0); 818 stubCall.addArgument(Imm32(srcDst)); 819 stubCall.call(result); 820 } 821 822 void JIT::emit_op_pre_inc(Instruction* currentInstruction) 823 { 824 unsigned srcDst = currentInstruction[1].u.operand; 825 826 emitGetVirtualRegister(srcDst, regT0); 827 emitJumpSlowCaseIfNotImmediateInteger(regT0); 828 addSlowCase(branchAdd32(Overflow, TrustedImm32(1), regT0)); 829 emitFastArithIntToImmNoCheck(regT0, regT0); 830 emitPutVirtualRegister(srcDst); 831 } 832 833 void JIT::emitSlow_op_pre_inc(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 834 { 835 unsigned srcDst = currentInstruction[1].u.operand; 836 837 Jump notImm = getSlowCase(iter); 838 linkSlowCase(iter); 839 emitGetVirtualRegister(srcDst, regT0); 840 notImm.link(this); 841 JITStubCall stubCall(this, cti_op_pre_inc); 842 stubCall.addArgument(regT0); 843 stubCall.call(srcDst); 844 } 845 846 void JIT::emit_op_pre_dec(Instruction* currentInstruction) 847 { 848 unsigned srcDst = currentInstruction[1].u.operand; 849 850 emitGetVirtualRegister(srcDst, regT0); 851 emitJumpSlowCaseIfNotImmediateInteger(regT0); 852 addSlowCase(branchSub32(Zero, TrustedImm32(1), regT0)); 853 emitFastArithIntToImmNoCheck(regT0, regT0); 854 emitPutVirtualRegister(srcDst); 855 } 856 857 void JIT::emitSlow_op_pre_dec(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 858 { 859 unsigned srcDst = currentInstruction[1].u.operand; 860 861 Jump notImm = getSlowCase(iter); 862 linkSlowCase(iter); 863 emitGetVirtualRegister(srcDst, regT0); 864 notImm.link(this); 865 JITStubCall stubCall(this, cti_op_pre_dec); 866 stubCall.addArgument(regT0); 867 stubCall.call(srcDst); 868 } 869 870 /* ------------------------------ BEGIN: OP_MOD ------------------------------ */ 871 872 #if CPU(X86) || CPU(X86_64) || CPU(MIPS) 873 874 void JIT::emit_op_mod(Instruction* currentInstruction) 875 { 876 unsigned result = currentInstruction[1].u.operand; 877 unsigned op1 = currentInstruction[2].u.operand; 878 unsigned op2 = currentInstruction[3].u.operand; 879 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); 885 #endif 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); 895 emitPutVirtualRegister(result); 896 } 897 898 void JIT::emitSlow_op_mod(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 899 { 900 unsigned result = currentInstruction[1].u.operand; 901 902 linkSlowCase(iter); 903 linkSlowCase(iter); 904 linkSlowCase(iter); 905 JITStubCall stubCall(this, cti_op_mod); 906 stubCall.addArgument(regT0); 907 stubCall.addArgument(regT2); 908 stubCall.call(result); 909 } 910 911 #else // CPU(X86) || CPU(X86_64) || CPU(MIPS) 912 913 void JIT::emit_op_mod(Instruction* currentInstruction) 914 { 915 unsigned result = currentInstruction[1].u.operand; 916 unsigned op1 = currentInstruction[2].u.operand; 917 unsigned op2 = currentInstruction[3].u.operand; 918 919 JITStubCall stubCall(this, cti_op_mod); 920 stubCall.addArgument(op1, regT2); 921 stubCall.addArgument(op2, regT2); 922 stubCall.call(result); 923 } 924 925 void JIT::emitSlow_op_mod(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 926 { 927 #if ENABLE(JIT_USE_SOFT_MODULO) 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 939 ASSERT_NOT_REACHED(); 940 #endif 941 } 942 943 #endif // CPU(X86) || CPU(X86_64) 944 945 /* ------------------------------ END: OP_MOD ------------------------------ */ 946 947 /* ------------------------------ BEGIN: USE(JSVALUE64) (OP_ADD, OP_SUB, OP_MUL) ------------------------------ */ 948 949 void JIT::compileBinaryArithOp(OpcodeID opcodeID, unsigned, unsigned op1, unsigned op2, OperandTypes) 950 { 951 emitGetVirtualRegisters(op1, regT0, op2, regT1); 952 emitJumpSlowCaseIfNotImmediateInteger(regT0); 953 emitJumpSlowCaseIfNotImmediateInteger(regT1); 954 if (opcodeID == op_add) 955 addSlowCase(branchAdd32(Overflow, regT1, regT0)); 956 else if (opcodeID == op_sub) 957 addSlowCase(branchSub32(Overflow, regT1, regT0)); 958 else { 959 ASSERT(opcodeID == op_mul); 960 addSlowCase(branchMul32(Overflow, regT1, regT0)); 961 addSlowCase(branchTest32(Zero, regT0)); 962 } 963 emitFastArithIntToImmNoCheck(regT0, regT0); 964 } 965 966 void JIT::compileBinaryArithOpSlowCase(OpcodeID opcodeID, Vector<SlowCaseEntry>::iterator& iter, unsigned result, unsigned op1, unsigned op2, OperandTypes types, bool op1HasImmediateIntFastCase, bool op2HasImmediateIntFastCase) 967 { 968 // We assume that subtracting TagTypeNumber is equivalent to adding DoubleEncodeOffset. 969 COMPILE_ASSERT(((TagTypeNumber + DoubleEncodeOffset) == 0), TagTypeNumber_PLUS_DoubleEncodeOffset_EQUALS_0); 970 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 } 981 982 linkSlowCase(iter); // Integer overflow case - we could handle this in JIT code, but this is likely rare. 983 if (opcodeID == op_mul && !op1HasImmediateIntFastCase && !op2HasImmediateIntFastCase) // op_mul has an extra slow case to handle 0 * negative number. 984 linkSlowCase(iter); 985 emitGetVirtualRegister(op1, regT0); 986 987 Label stubFunctionCall(this); 988 JITStubCall stubCall(this, opcodeID == op_add ? cti_op_add : opcodeID == op_sub ? cti_op_sub : cti_op_mul); 989 if (op1HasImmediateIntFastCase || op2HasImmediateIntFastCase) { 990 emitGetVirtualRegister(op1, regT0); 991 emitGetVirtualRegister(op2, regT1); 992 } 993 stubCall.addArgument(regT0); 994 stubCall.addArgument(regT1); 995 stubCall.call(result); 996 Jump end = jump(); 997 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 } 1037 1038 if (opcodeID == op_add) 1039 addDouble(fpRegT2, fpRegT1); 1040 else if (opcodeID == op_sub) 1041 subDouble(fpRegT2, fpRegT1); 1042 else if (opcodeID == op_mul) 1043 mulDouble(fpRegT2, fpRegT1); 1044 else { 1045 ASSERT(opcodeID == op_div); 1046 divDouble(fpRegT2, fpRegT1); 1047 } 1048 moveDoubleToPtr(fpRegT1, regT0); 1049 subPtr(tagTypeNumberRegister, regT0); 1050 emitPutVirtualRegister(result, regT0); 1051 1052 end.link(this); 1053 } 1054 1055 void JIT::emit_op_add(Instruction* currentInstruction) 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()) { 1063 JITStubCall stubCall(this, cti_op_add); 1064 stubCall.addArgument(op1, regT2); 1065 stubCall.addArgument(op2, regT2); 1066 stubCall.call(result); 1067 return; 1068 } 1069 1070 if (isOperandConstantImmediateInt(op1)) { 1071 emitGetVirtualRegister(op2, regT0); 1072 emitJumpSlowCaseIfNotImmediateInteger(regT0); 1073 addSlowCase(branchAdd32(Overflow, Imm32(getConstantOperandImmediateInt(op1)), regT0)); 1074 emitFastArithIntToImmNoCheck(regT0, regT0); 1075 } else if (isOperandConstantImmediateInt(op2)) { 1076 emitGetVirtualRegister(op1, regT0); 1077 emitJumpSlowCaseIfNotImmediateInteger(regT0); 1078 addSlowCase(branchAdd32(Overflow, Imm32(getConstantOperandImmediateInt(op2)), regT0)); 1079 emitFastArithIntToImmNoCheck(regT0, regT0); 1080 } else 1081 compileBinaryArithOp(op_add, result, op1, op2, types); 1082 1083 emitPutVirtualRegister(result); 1084 } 1085 1086 void JIT::emitSlow_op_add(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 1087 { 1088 unsigned result = currentInstruction[1].u.operand; 1089 unsigned op1 = currentInstruction[2].u.operand; 1090 unsigned op2 = currentInstruction[3].u.operand; 1091 OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); 1092 1093 if (!types.first().mightBeNumber() || !types.second().mightBeNumber()) 1094 return; 1095 1096 bool op1HasImmediateIntFastCase = isOperandConstantImmediateInt(op1); 1097 bool op2HasImmediateIntFastCase = !op1HasImmediateIntFastCase && isOperandConstantImmediateInt(op2); 1098 compileBinaryArithOpSlowCase(op_add, iter, result, op1, op2, OperandTypes::fromInt(currentInstruction[4].u.operand), op1HasImmediateIntFastCase, op2HasImmediateIntFastCase); 1099 } 1100 1101 void JIT::emit_op_mul(Instruction* currentInstruction) 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)) { 1111 emitGetVirtualRegister(op2, regT0); 1112 emitJumpSlowCaseIfNotImmediateInteger(regT0); 1113 addSlowCase(branchMul32(Overflow, Imm32(value), regT0, regT0)); 1114 emitFastArithReTagImmediate(regT0, regT0); 1115 } else if (isOperandConstantImmediateInt(op2) && ((value = getConstantOperandImmediateInt(op2)) > 0)) { 1116 emitGetVirtualRegister(op1, regT0); 1117 emitJumpSlowCaseIfNotImmediateInteger(regT0); 1118 addSlowCase(branchMul32(Overflow, Imm32(value), regT0, regT0)); 1119 emitFastArithReTagImmediate(regT0, regT0); 1120 } else 1121 compileBinaryArithOp(op_mul, result, op1, op2, types); 1122 1123 emitPutVirtualRegister(result); 1124 } 1125 1126 void JIT::emitSlow_op_mul(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 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 1133 bool op1HasImmediateIntFastCase = isOperandConstantImmediateInt(op1) && getConstantOperandImmediateInt(op1) > 0; 1134 bool op2HasImmediateIntFastCase = !op1HasImmediateIntFastCase && isOperandConstantImmediateInt(op2) && getConstantOperandImmediateInt(op2) > 0; 1135 compileBinaryArithOpSlowCase(op_mul, iter, result, op1, op2, OperandTypes::fromInt(currentInstruction[4].u.operand), op1HasImmediateIntFastCase, op2HasImmediateIntFastCase); 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 } 1163 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); 1216 } 1217 1218 void JIT::emit_op_sub(Instruction* currentInstruction) 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); 1226 emitPutVirtualRegister(result); 1227 } 1228 1229 void JIT::emitSlow_op_sub(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) 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 1236 compileBinaryArithOpSlowCase(op_sub, iter, result, op1, op2, types, false, false); 1237 } 1238 1239 /* ------------------------------ END: OP_ADD, OP_SUB, OP_MUL ------------------------------ */ 1240 1241 } // namespace JSC 1242 1243 #endif // USE(JSVALUE64) 1244 #endif // ENABLE(JIT) 1245