1 /* 2 * Copyright (C) 2011 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "DFGSpeculativeJIT.h" 28 29 #if ENABLE(DFG_JIT) 30 31 namespace JSC { namespace DFG { 32 33 template<bool strict> 34 GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& returnFormat) 35 { 36 Node& node = m_jit.graph()[nodeIndex]; 37 VirtualRegister virtualRegister = node.virtualRegister; 38 GenerationInfo& info = m_generationInfo[virtualRegister]; 39 40 switch (info.registerFormat()) { 41 case DataFormatNone: { 42 GPRReg gpr = allocate(); 43 JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(gpr); 44 45 if (node.isConstant()) { 46 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); 47 if (isInt32Constant(nodeIndex)) { 48 m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), reg); 49 info.fillInteger(gpr); 50 returnFormat = DataFormatInteger; 51 return gpr; 52 } 53 m_jit.move(constantAsJSValueAsImmPtr(nodeIndex), reg); 54 } else { 55 DataFormat spillFormat = info.spillFormat(); 56 ASSERT(spillFormat & DataFormatJS); 57 58 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled); 59 60 if (spillFormat == DataFormatJSInteger) { 61 // If we know this was spilled as an integer we can fill without checking. 62 if (strict) { 63 m_jit.load32(JITCompiler::addressFor(virtualRegister), reg); 64 info.fillInteger(gpr); 65 returnFormat = DataFormatInteger; 66 return gpr; 67 } 68 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), reg); 69 info.fillJSValue(gpr, DataFormatJSInteger); 70 returnFormat = DataFormatJSInteger; 71 return gpr; 72 } 73 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), reg); 74 } 75 76 // Fill as JSValue, and fall through. 77 info.fillJSValue(gpr, DataFormatJSInteger); 78 m_gprs.unlock(gpr); 79 } 80 81 case DataFormatJS: { 82 // Check the value is an integer. 83 GPRReg gpr = info.gpr(); 84 m_gprs.lock(gpr); 85 JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(gpr); 86 speculationCheck(m_jit.branchPtr(MacroAssembler::Below, reg, JITCompiler::tagTypeNumberRegister)); 87 info.fillJSValue(gpr, DataFormatJSInteger); 88 // If !strict we're done, return. 89 if (!strict) { 90 returnFormat = DataFormatJSInteger; 91 return gpr; 92 } 93 // else fall through & handle as DataFormatJSInteger. 94 m_gprs.unlock(gpr); 95 } 96 97 case DataFormatJSInteger: { 98 // In a strict fill we need to strip off the value tag. 99 if (strict) { 100 GPRReg gpr = info.gpr(); 101 GPRReg result; 102 // If the register has already been locked we need to take a copy. 103 // If not, we'll zero extend in place, so mark on the info that this is now type DataFormatInteger, not DataFormatJSInteger. 104 if (m_gprs.isLocked(gpr)) 105 result = allocate(); 106 else { 107 m_gprs.lock(gpr); 108 info.fillInteger(gpr); 109 result = gpr; 110 } 111 m_jit.zeroExtend32ToPtr(JITCompiler::gprToRegisterID(gpr), JITCompiler::gprToRegisterID(result)); 112 returnFormat = DataFormatInteger; 113 return result; 114 } 115 116 GPRReg gpr = info.gpr(); 117 m_gprs.lock(gpr); 118 returnFormat = DataFormatJSInteger; 119 return gpr; 120 } 121 122 case DataFormatInteger: { 123 GPRReg gpr = info.gpr(); 124 m_gprs.lock(gpr); 125 returnFormat = DataFormatInteger; 126 return gpr; 127 } 128 129 case DataFormatDouble: 130 case DataFormatCell: 131 case DataFormatJSDouble: 132 case DataFormatJSCell: { 133 terminateSpeculativeExecution(); 134 returnFormat = DataFormatInteger; 135 return allocate(); 136 } 137 } 138 139 ASSERT_NOT_REACHED(); 140 return InvalidGPRReg; 141 } 142 143 SpeculationCheck::SpeculationCheck(MacroAssembler::Jump check, SpeculativeJIT* jit, unsigned recoveryIndex) 144 : m_check(check) 145 , m_nodeIndex(jit->m_compileIndex) 146 , m_recoveryIndex(recoveryIndex) 147 { 148 for (GPRReg gpr = gpr0; gpr < numberOfGPRs; next(gpr)) { 149 VirtualRegister virtualRegister = jit->m_gprs.name(gpr); 150 if (virtualRegister != InvalidVirtualRegister) { 151 GenerationInfo& info = jit->m_generationInfo[virtualRegister]; 152 m_gprInfo[gpr].nodeIndex = info.nodeIndex(); 153 m_gprInfo[gpr].format = info.registerFormat(); 154 } else 155 m_gprInfo[gpr].nodeIndex = NoNode; 156 } 157 for (FPRReg fpr = fpr0; fpr < numberOfFPRs; next(fpr)) { 158 VirtualRegister virtualRegister = jit->m_fprs.name(fpr); 159 if (virtualRegister != InvalidVirtualRegister) { 160 GenerationInfo& info = jit->m_generationInfo[virtualRegister]; 161 ASSERT(info.registerFormat() == DataFormatDouble); 162 m_fprInfo[fpr] = info.nodeIndex(); 163 } else 164 m_fprInfo[fpr] = NoNode; 165 } 166 } 167 168 GPRReg SpeculativeJIT::fillSpeculateInt(NodeIndex nodeIndex, DataFormat& returnFormat) 169 { 170 return fillSpeculateIntInternal<false>(nodeIndex, returnFormat); 171 } 172 173 GPRReg SpeculativeJIT::fillSpeculateIntStrict(NodeIndex nodeIndex) 174 { 175 DataFormat mustBeDataFormatInteger; 176 GPRReg result = fillSpeculateIntInternal<true>(nodeIndex, mustBeDataFormatInteger); 177 ASSERT(mustBeDataFormatInteger == DataFormatInteger); 178 return result; 179 } 180 181 GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex) 182 { 183 Node& node = m_jit.graph()[nodeIndex]; 184 VirtualRegister virtualRegister = node.virtualRegister; 185 GenerationInfo& info = m_generationInfo[virtualRegister]; 186 187 switch (info.registerFormat()) { 188 case DataFormatNone: { 189 GPRReg gpr = allocate(); 190 JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(gpr); 191 192 if (node.isConstant()) { 193 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); 194 JSValue jsValue = constantAsJSValue(nodeIndex); 195 if (jsValue.isCell()) { 196 m_jit.move(MacroAssembler::TrustedImmPtr(jsValue.asCell()), reg); 197 info.fillJSValue(gpr, DataFormatJSCell); 198 return gpr; 199 } 200 terminateSpeculativeExecution(); 201 return gpr; 202 } 203 ASSERT(info.spillFormat() & DataFormatJS); 204 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled); 205 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), reg); 206 207 if (info.spillFormat() != DataFormatJSCell) 208 speculationCheck(m_jit.branchTestPtr(MacroAssembler::NonZero, reg, JITCompiler::tagMaskRegister)); 209 info.fillJSValue(gpr, DataFormatJSCell); 210 return gpr; 211 } 212 213 case DataFormatCell: 214 case DataFormatJSCell: { 215 GPRReg gpr = info.gpr(); 216 m_gprs.lock(gpr); 217 return gpr; 218 } 219 220 case DataFormatJS: { 221 GPRReg gpr = info.gpr(); 222 m_gprs.lock(gpr); 223 JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(gpr); 224 speculationCheck(m_jit.branchTestPtr(MacroAssembler::NonZero, reg, JITCompiler::tagMaskRegister)); 225 info.fillJSValue(gpr, DataFormatJSCell); 226 return gpr; 227 } 228 229 case DataFormatJSInteger: 230 case DataFormatInteger: 231 case DataFormatJSDouble: 232 case DataFormatDouble: { 233 terminateSpeculativeExecution(); 234 return allocate(); 235 } 236 } 237 238 ASSERT_NOT_REACHED(); 239 return InvalidGPRReg; 240 } 241 242 bool SpeculativeJIT::compile(Node& node) 243 { 244 checkConsistency(); 245 NodeType op = node.op; 246 247 switch (op) { 248 case Int32Constant: 249 case DoubleConstant: 250 case JSConstant: 251 initConstantInfo(m_compileIndex); 252 break; 253 254 case GetLocal: { 255 GPRTemporary result(this); 256 m_jit.loadPtr(JITCompiler::addressFor(node.local()), result.registerID()); 257 jsValueResult(result.gpr(), m_compileIndex); 258 break; 259 } 260 261 case SetLocal: { 262 JSValueOperand value(this, node.child1); 263 m_jit.storePtr(value.registerID(), JITCompiler::addressFor(node.local())); 264 noResult(m_compileIndex); 265 break; 266 } 267 268 case BitAnd: 269 case BitOr: 270 case BitXor: 271 if (isInt32Constant(node.child1)) { 272 SpeculateIntegerOperand op2(this, node.child2); 273 GPRTemporary result(this, op2); 274 275 bitOp(op, valueOfInt32Constant(node.child1), op2.registerID(), result.registerID()); 276 277 integerResult(result.gpr(), m_compileIndex); 278 } else if (isInt32Constant(node.child2)) { 279 SpeculateIntegerOperand op1(this, node.child1); 280 GPRTemporary result(this, op1); 281 282 bitOp(op, valueOfInt32Constant(node.child2), op1.registerID(), result.registerID()); 283 284 integerResult(result.gpr(), m_compileIndex); 285 } else { 286 SpeculateIntegerOperand op1(this, node.child1); 287 SpeculateIntegerOperand op2(this, node.child2); 288 GPRTemporary result(this, op1, op2); 289 290 MacroAssembler::RegisterID reg1 = op1.registerID(); 291 MacroAssembler::RegisterID reg2 = op2.registerID(); 292 bitOp(op, reg1, reg2, result.registerID()); 293 294 integerResult(result.gpr(), m_compileIndex); 295 } 296 break; 297 298 case BitRShift: 299 case BitLShift: 300 case BitURShift: 301 if (isInt32Constant(node.child2)) { 302 SpeculateIntegerOperand op1(this, node.child1); 303 GPRTemporary result(this, op1); 304 305 shiftOp(op, op1.registerID(), valueOfInt32Constant(node.child2) & 0x1f, result.registerID()); 306 307 integerResult(result.gpr(), m_compileIndex); 308 } else { 309 // Do not allow shift amount to be used as the result, MacroAssembler does not permit this. 310 SpeculateIntegerOperand op1(this, node.child1); 311 SpeculateIntegerOperand op2(this, node.child2); 312 GPRTemporary result(this, op1); 313 314 MacroAssembler::RegisterID reg1 = op1.registerID(); 315 MacroAssembler::RegisterID reg2 = op2.registerID(); 316 shiftOp(op, reg1, reg2, result.registerID()); 317 318 integerResult(result.gpr(), m_compileIndex); 319 } 320 break; 321 322 case UInt32ToNumber: { 323 IntegerOperand op1(this, node.child1); 324 GPRTemporary result(this, op1); 325 326 // Test the operand is positive. 327 speculationCheck(m_jit.branch32(MacroAssembler::LessThan, op1.registerID(), TrustedImm32(0))); 328 329 m_jit.move(op1.registerID(), result.registerID()); 330 integerResult(result.gpr(), m_compileIndex, op1.format()); 331 break; 332 } 333 334 case NumberToInt32: { 335 SpeculateIntegerOperand op1(this, node.child1); 336 GPRTemporary result(this, op1); 337 m_jit.move(op1.registerID(), result.registerID()); 338 integerResult(result.gpr(), m_compileIndex, op1.format()); 339 break; 340 } 341 342 case Int32ToNumber: { 343 SpeculateIntegerOperand op1(this, node.child1); 344 GPRTemporary result(this, op1); 345 m_jit.move(op1.registerID(), result.registerID()); 346 integerResult(result.gpr(), m_compileIndex, op1.format()); 347 break; 348 } 349 350 case ValueToInt32: { 351 SpeculateIntegerOperand op1(this, node.child1); 352 GPRTemporary result(this, op1); 353 m_jit.move(op1.registerID(), result.registerID()); 354 integerResult(result.gpr(), m_compileIndex, op1.format()); 355 break; 356 } 357 358 case ValueToNumber: { 359 SpeculateIntegerOperand op1(this, node.child1); 360 GPRTemporary result(this, op1); 361 m_jit.move(op1.registerID(), result.registerID()); 362 integerResult(result.gpr(), m_compileIndex, op1.format()); 363 break; 364 } 365 366 case ValueAdd: 367 case ArithAdd: { 368 int32_t imm1; 369 if (isDoubleConstantWithInt32Value(node.child1, imm1)) { 370 SpeculateIntegerOperand op2(this, node.child2); 371 GPRTemporary result(this); 372 373 MacroAssembler::RegisterID reg = op2.registerID(); 374 speculationCheck(m_jit.branchAdd32(MacroAssembler::Overflow, reg, Imm32(imm1), result.registerID())); 375 376 integerResult(result.gpr(), m_compileIndex); 377 break; 378 } 379 380 int32_t imm2; 381 if (isDoubleConstantWithInt32Value(node.child2, imm2)) { 382 SpeculateIntegerOperand op1(this, node.child1); 383 GPRTemporary result(this); 384 385 MacroAssembler::RegisterID reg = op1.registerID(); 386 speculationCheck(m_jit.branchAdd32(MacroAssembler::Overflow, reg, Imm32(imm2), result.registerID())); 387 388 integerResult(result.gpr(), m_compileIndex); 389 break; 390 } 391 392 SpeculateIntegerOperand op1(this, node.child1); 393 SpeculateIntegerOperand op2(this, node.child2); 394 GPRTemporary result(this, op1, op2); 395 396 GPRReg gpr1 = op1.gpr(); 397 GPRReg gpr2 = op2.gpr(); 398 GPRReg gprResult = result.gpr(); 399 MacroAssembler::Jump check = m_jit.branchAdd32(MacroAssembler::Overflow, JITCompiler::gprToRegisterID(gpr1), JITCompiler::gprToRegisterID(gpr2), JITCompiler::gprToRegisterID(gprResult)); 400 401 if (gpr1 == gprResult) 402 speculationCheck(check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr2)); 403 else if (gpr2 == gprResult) 404 speculationCheck(check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr1)); 405 else 406 speculationCheck(check); 407 408 integerResult(gprResult, m_compileIndex); 409 break; 410 } 411 412 case ArithSub: { 413 int32_t imm2; 414 if (isDoubleConstantWithInt32Value(node.child2, imm2)) { 415 SpeculateIntegerOperand op1(this, node.child1); 416 GPRTemporary result(this); 417 418 MacroAssembler::RegisterID reg = op1.registerID(); 419 speculationCheck(m_jit.branchSub32(MacroAssembler::Overflow, reg, Imm32(imm2), result.registerID())); 420 421 integerResult(result.gpr(), m_compileIndex); 422 break; 423 } 424 425 SpeculateIntegerOperand op1(this, node.child1); 426 SpeculateIntegerOperand op2(this, node.child2); 427 GPRTemporary result(this); 428 429 MacroAssembler::RegisterID reg1 = op1.registerID(); 430 MacroAssembler::RegisterID reg2 = op2.registerID(); 431 speculationCheck(m_jit.branchSub32(MacroAssembler::Overflow, reg1, reg2, result.registerID())); 432 433 integerResult(result.gpr(), m_compileIndex); 434 break; 435 } 436 437 case ArithMul: { 438 SpeculateIntegerOperand op1(this, node.child1); 439 SpeculateIntegerOperand op2(this, node.child2); 440 GPRTemporary result(this); 441 442 MacroAssembler::RegisterID reg1 = op1.registerID(); 443 MacroAssembler::RegisterID reg2 = op2.registerID(); 444 speculationCheck(m_jit.branchMul32(MacroAssembler::Overflow, reg1, reg2, result.registerID())); 445 446 MacroAssembler::Jump resultNonZero = m_jit.branchTest32(MacroAssembler::NonZero, result.registerID()); 447 speculationCheck(m_jit.branch32(MacroAssembler::LessThan, reg1, TrustedImm32(0))); 448 speculationCheck(m_jit.branch32(MacroAssembler::LessThan, reg2, TrustedImm32(0))); 449 resultNonZero.link(&m_jit); 450 451 integerResult(result.gpr(), m_compileIndex); 452 break; 453 } 454 455 case ArithDiv: { 456 SpeculateIntegerOperand op1(this, node.child1); 457 SpeculateIntegerOperand op2(this, node.child2); 458 GPRTemporary result(this, op1, op2); 459 460 terminateSpeculativeExecution(); 461 462 integerResult(result.gpr(), m_compileIndex); 463 break; 464 } 465 466 case ArithMod: { 467 SpeculateIntegerOperand op1(this, node.child1); 468 SpeculateIntegerOperand op2(this, node.child2); 469 GPRTemporary result(this, op1, op2); 470 471 terminateSpeculativeExecution(); 472 473 integerResult(result.gpr(), m_compileIndex); 474 break; 475 } 476 477 case LogicalNot: { 478 JSValueOperand value(this, node.child1); 479 GPRTemporary result(this); // FIXME: We could reuse, but on speculation fail would need recovery to restore tag (akin to add). 480 481 m_jit.move(value.registerID(), result.registerID()); 482 m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), result.registerID()); 483 speculationCheck(m_jit.branchTestPtr(JITCompiler::NonZero, result.registerID(), TrustedImm32(static_cast<int32_t>(~1)))); 484 m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueTrue)), result.registerID()); 485 486 // If we add a DataFormatBool, we should use it here. 487 jsValueResult(result.gpr(), m_compileIndex); 488 break; 489 } 490 491 case CompareLess: { 492 SpeculateIntegerOperand op1(this, node.child1); 493 SpeculateIntegerOperand op2(this, node.child2); 494 GPRTemporary result(this, op1, op2); 495 496 m_jit.set32Compare32(JITCompiler::LessThan, op1.registerID(), op2.registerID(), result.registerID()); 497 498 // If we add a DataFormatBool, we should use it here. 499 m_jit.or32(TrustedImm32(ValueFalse), result.registerID()); 500 jsValueResult(result.gpr(), m_compileIndex); 501 break; 502 } 503 504 case CompareLessEq: { 505 SpeculateIntegerOperand op1(this, node.child1); 506 SpeculateIntegerOperand op2(this, node.child2); 507 GPRTemporary result(this, op1, op2); 508 509 m_jit.set32Compare32(JITCompiler::LessThanOrEqual, op1.registerID(), op2.registerID(), result.registerID()); 510 511 // If we add a DataFormatBool, we should use it here. 512 m_jit.or32(TrustedImm32(ValueFalse), result.registerID()); 513 jsValueResult(result.gpr(), m_compileIndex); 514 break; 515 } 516 517 case CompareEq: { 518 SpeculateIntegerOperand op1(this, node.child1); 519 SpeculateIntegerOperand op2(this, node.child2); 520 GPRTemporary result(this, op1, op2); 521 522 m_jit.set32Compare32(JITCompiler::Equal, op1.registerID(), op2.registerID(), result.registerID()); 523 524 // If we add a DataFormatBool, we should use it here. 525 m_jit.or32(TrustedImm32(ValueFalse), result.registerID()); 526 jsValueResult(result.gpr(), m_compileIndex); 527 break; 528 } 529 530 case CompareStrictEq: { 531 SpeculateIntegerOperand op1(this, node.child1); 532 SpeculateIntegerOperand op2(this, node.child2); 533 GPRTemporary result(this, op1, op2); 534 535 m_jit.set32Compare32(JITCompiler::Equal, op1.registerID(), op2.registerID(), result.registerID()); 536 537 // If we add a DataFormatBool, we should use it here. 538 m_jit.or32(TrustedImm32(ValueFalse), result.registerID()); 539 jsValueResult(result.gpr(), m_compileIndex); 540 break; 541 } 542 543 case GetByVal: { 544 NodeIndex alias = node.child3; 545 if (alias != NoNode) { 546 // FIXME: result should be able to reuse child1, child2. Should have an 'UnusedOperand' type. 547 JSValueOperand aliasedValue(this, node.child3); 548 GPRTemporary result(this, aliasedValue); 549 m_jit.move(aliasedValue.registerID(), result.registerID()); 550 jsValueResult(result.gpr(), m_compileIndex); 551 break; 552 } 553 554 SpeculateCellOperand base(this, node.child1); 555 SpeculateStrictInt32Operand property(this, node.child2); 556 GPRTemporary storage(this); 557 558 MacroAssembler::RegisterID baseReg = base.registerID(); 559 MacroAssembler::RegisterID propertyReg = property.registerID(); 560 MacroAssembler::RegisterID storageReg = storage.registerID(); 561 562 // Get the array storage. We haven't yet checked this is a JSArray, so this is only safe if 563 // an access with offset JSArray::storageOffset() is valid for all JSCells! 564 m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg); 565 566 // Check that base is an array, and that property is contained within m_vector (< m_vectorLength). 567 speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr))); 568 speculationCheck(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()))); 569 570 // FIXME: In cases where there are subsequent by_val accesses to the same base it might help to cache 571 // the storage pointer - especially if there happens to be another register free right now. If we do so, 572 // then we'll need to allocate a new temporary for result. 573 GPRTemporary& result = storage; 574 m_jit.loadPtr(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), result.registerID()); 575 speculationCheck(m_jit.branchTestPtr(MacroAssembler::Zero, result.registerID())); 576 577 jsValueResult(result.gpr(), m_compileIndex); 578 break; 579 } 580 581 case PutByVal: { 582 SpeculateCellOperand base(this, node.child1); 583 SpeculateStrictInt32Operand property(this, node.child2); 584 JSValueOperand value(this, node.child3); 585 GPRTemporary storage(this); 586 587 // Map base, property & value into registers, allocate a register for storage. 588 MacroAssembler::RegisterID baseReg = base.registerID(); 589 MacroAssembler::RegisterID propertyReg = property.registerID(); 590 MacroAssembler::RegisterID valueReg = value.registerID(); 591 MacroAssembler::RegisterID storageReg = storage.registerID(); 592 593 // Check that base is an array, and that property is contained within m_vector (< m_vectorLength). 594 speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr))); 595 speculationCheck(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()))); 596 597 // Get the array storage. 598 m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg); 599 600 // Check if we're writing to a hole; if so increment m_numValuesInVector. 601 MacroAssembler::Jump notHoleValue = m_jit.branchTestPtr(MacroAssembler::NonZero, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); 602 m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector))); 603 604 // If we're writing to a hole we might be growing the array; 605 MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length))); 606 m_jit.add32(TrustedImm32(1), propertyReg); 607 m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length))); 608 m_jit.sub32(TrustedImm32(1), propertyReg); 609 610 lengthDoesNotNeedUpdate.link(&m_jit); 611 notHoleValue.link(&m_jit); 612 613 // Store the value to the array. 614 m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); 615 616 noResult(m_compileIndex); 617 break; 618 } 619 620 case PutByValAlias: { 621 SpeculateCellOperand base(this, node.child1); 622 SpeculateStrictInt32Operand property(this, node.child2); 623 JSValueOperand value(this, node.child3); 624 GPRTemporary storage(this, base); // storage may overwrite base. 625 626 // Get the array storage. 627 MacroAssembler::RegisterID storageReg = storage.registerID(); 628 m_jit.loadPtr(MacroAssembler::Address(base.registerID(), JSArray::storageOffset()), storageReg); 629 630 // Map property & value into registers. 631 MacroAssembler::RegisterID propertyReg = property.registerID(); 632 MacroAssembler::RegisterID valueReg = value.registerID(); 633 634 // Store the value to the array. 635 m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); 636 637 noResult(m_compileIndex); 638 break; 639 } 640 641 case DFG::Jump: { 642 BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(node.takenBytecodeOffset()); 643 if (taken != (m_block + 1)) 644 addBranch(m_jit.jump(), taken); 645 noResult(m_compileIndex); 646 break; 647 } 648 649 case Branch: { 650 JSValueOperand value(this, node.child1); 651 MacroAssembler::RegisterID valueReg = value.registerID(); 652 653 BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(node.takenBytecodeOffset()); 654 BlockIndex notTaken = m_jit.graph().blockIndexForBytecodeOffset(node.notTakenBytecodeOffset()); 655 656 // Integers 657 addBranch(m_jit.branchPtr(MacroAssembler::Equal, valueReg, MacroAssembler::ImmPtr(JSValue::encode(jsNumber(0)))), notTaken); 658 MacroAssembler::Jump isNonZeroInteger = m_jit.branchPtr(MacroAssembler::AboveOrEqual, valueReg, JITCompiler::tagTypeNumberRegister); 659 660 // Booleans 661 addBranch(m_jit.branchPtr(MacroAssembler::Equal, valueReg, MacroAssembler::ImmPtr(JSValue::encode(jsBoolean(false)))), notTaken); 662 speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, valueReg, MacroAssembler::ImmPtr(JSValue::encode(jsBoolean(true))))); 663 664 if (taken == (m_block + 1)) 665 isNonZeroInteger.link(&m_jit); 666 else { 667 addBranch(isNonZeroInteger, taken); 668 addBranch(m_jit.jump(), taken); 669 } 670 671 noResult(m_compileIndex); 672 break; 673 } 674 675 case Return: { 676 ASSERT(JITCompiler::callFrameRegister != JITCompiler::regT1); 677 ASSERT(JITCompiler::regT1 != JITCompiler::returnValueRegister); 678 ASSERT(JITCompiler::returnValueRegister != JITCompiler::callFrameRegister); 679 680 #if DFG_SUCCESS_STATS 681 static SamplingCounter counter("SpeculativeJIT"); 682 m_jit.emitCount(counter); 683 #endif 684 685 // Return the result in returnValueRegister. 686 JSValueOperand op1(this, node.child1); 687 m_jit.move(op1.registerID(), JITCompiler::returnValueRegister); 688 689 // Grab the return address. 690 m_jit.emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, JITCompiler::regT1); 691 // Restore our caller's "r". 692 m_jit.emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, JITCompiler::callFrameRegister); 693 // Return. 694 m_jit.restoreReturnAddressBeforeReturn(JITCompiler::regT1); 695 m_jit.ret(); 696 697 noResult(m_compileIndex); 698 break; 699 } 700 701 case ConvertThis: { 702 SpeculateCellOperand thisValue(this, node.child1); 703 GPRTemporary temp(this); 704 705 m_jit.loadPtr(JITCompiler::Address(thisValue.registerID(), JSCell::structureOffset()), temp.registerID()); 706 speculationCheck(m_jit.branchTest8(JITCompiler::NonZero, JITCompiler::Address(temp.registerID(), Structure::typeInfoFlagsOffset()), JITCompiler::TrustedImm32(NeedsThisConversion))); 707 708 cellResult(thisValue.gpr(), m_compileIndex); 709 break; 710 } 711 712 case GetById: { 713 JSValueOperand base(this, node.child1); 714 GPRReg baseGPR = base.gpr(); 715 flushRegisters(); 716 717 GPRResult result(this); 718 callOperation(operationGetById, result.gpr(), baseGPR, identifier(node.identifierNumber())); 719 jsValueResult(result.gpr(), m_compileIndex); 720 break; 721 } 722 723 case PutById: { 724 JSValueOperand base(this, node.child1); 725 JSValueOperand value(this, node.child2); 726 GPRReg valueGPR = value.gpr(); 727 GPRReg baseGPR = base.gpr(); 728 flushRegisters(); 729 730 callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByIdStrict : operationPutByIdNonStrict, valueGPR, baseGPR, identifier(node.identifierNumber())); 731 noResult(m_compileIndex); 732 break; 733 } 734 735 case PutByIdDirect: { 736 JSValueOperand base(this, node.child1); 737 JSValueOperand value(this, node.child2); 738 GPRReg valueGPR = value.gpr(); 739 GPRReg baseGPR = base.gpr(); 740 flushRegisters(); 741 742 callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByIdDirectStrict : operationPutByIdDirectNonStrict, valueGPR, baseGPR, identifier(node.identifierNumber())); 743 noResult(m_compileIndex); 744 break; 745 } 746 747 case GetGlobalVar: { 748 GPRTemporary result(this); 749 750 JSVariableObject* globalObject = m_jit.codeBlock()->globalObject(); 751 m_jit.loadPtr(globalObject->addressOfRegisters(), result.registerID()); 752 m_jit.loadPtr(JITCompiler::addressForGlobalVar(result.registerID(), node.varNumber()), result.registerID()); 753 754 jsValueResult(result.gpr(), m_compileIndex); 755 break; 756 } 757 758 case PutGlobalVar: { 759 JSValueOperand value(this, node.child1); 760 GPRTemporary temp(this); 761 762 JSVariableObject* globalObject = m_jit.codeBlock()->globalObject(); 763 m_jit.loadPtr(globalObject->addressOfRegisters(), temp.registerID()); 764 m_jit.storePtr(value.registerID(), JITCompiler::addressForGlobalVar(temp.registerID(), node.varNumber())); 765 766 noResult(m_compileIndex); 767 break; 768 } 769 } 770 771 // Check if generation for the speculative path has failed catastrophically. :-) 772 // In the future, we may want to throw away the code we've generated in this case. 773 // For now, there is no point generating any further code, return immediately. 774 if (m_didTerminate) 775 return false; 776 777 if (node.mustGenerate()) 778 use(m_compileIndex); 779 780 checkConsistency(); 781 782 return true; 783 } 784 785 bool SpeculativeJIT::compile(BasicBlock& block) 786 { 787 ASSERT(m_compileIndex == block.begin); 788 m_blockHeads[m_block] = m_jit.label(); 789 #if DFG_JIT_BREAK_ON_EVERY_BLOCK 790 m_jit.breakpoint(); 791 #endif 792 793 for (; m_compileIndex < block.end; ++m_compileIndex) { 794 Node& node = m_jit.graph()[m_compileIndex]; 795 if (!node.refCount) 796 continue; 797 798 #if DFG_DEBUG_VERBOSE 799 fprintf(stderr, "SpeculativeJIT generating Node @%d at JIT offset 0x%x\n", (int)m_compileIndex, m_jit.debugOffset()); 800 #endif 801 #if DFG_JIT_BREAK_ON_EVERY_NODE 802 m_jit.breakpoint(); 803 #endif 804 if (!compile(node)) 805 return false; 806 } 807 return true; 808 } 809 810 bool SpeculativeJIT::compile() 811 { 812 ASSERT(!m_compileIndex); 813 Vector<BasicBlock> blocks = m_jit.graph().m_blocks; 814 for (m_block = 0; m_block < blocks.size(); ++m_block) { 815 if (!compile(blocks[m_block])) 816 return false; 817 } 818 linkBranches(); 819 return true; 820 } 821 822 } } // namespace JSC::DFG 823 824 #endif 825