Changeset 96379 in webkit
- Timestamp:
- Sep 29, 2011 5:09:46 PM (13 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 5 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r96377 r96379 1 2011-09-29 Gavin Barraclough <barraclough@apple.com> 2 3 Start refactoring DFGSpeculativeJIT 4 https://bugs.webkit.org/show_bug.cgi?id=69112 5 6 Reviewed by Oliver Hunt. 7 8 Again, move JSVALUE64 code into a DFJSpeculativeJIT64.cpp 9 10 * JavaScriptCore.xcodeproj/project.pbxproj: 11 * dfg/DFGSpeculativeJIT.cpp: 12 (JSC::DFG::ValueSource::dump): 13 (JSC::DFG::ValueRecovery::dump): 14 (JSC::DFG::OSRExit::OSRExit): 15 (JSC::DFG::OSRExit::dump): 16 (JSC::DFG::SpeculativeJIT::compilePeepHoleDoubleBranch): 17 (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectEquality): 18 (JSC::DFG::SpeculativeJIT::compilePeepHoleIntegerBranch): 19 (JSC::DFG::SpeculativeJIT::compile): 20 (JSC::DFG::SpeculativeJIT::checkArgumentTypes): 21 (JSC::DFG::SpeculativeJIT::computeValueRecoveryFor): 22 * dfg/DFGSpeculativeJIT.h: 23 (JSC::DFG::SpeculativeJIT::emitAllocateJSFinalObject): 24 * dfg/DFGSpeculativeJIT32_64.cpp: 25 (JSC::DFG::SpeculativeJIT::compare): 26 * dfg/DFGSpeculativeJIT64.cpp: Copied from Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp. 27 (JSC::DFG::SpeculativeJIT::fillSpeculateIntInternal): 28 (JSC::DFG::SpeculativeJIT::fillSpeculateCell): 29 (JSC::DFG::SpeculativeJIT::compile): 30 1 31 2011-09-29 Gavin Barraclough <barraclough@apple.com> 2 32 -
trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
r96377 r96379 305 305 86880F1F14328BB900B08D42 /* DFGSpeculativeJIT32_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86880F1B14328BB900B08D42 /* DFGSpeculativeJIT32_64.cpp */; }; 306 306 86880F44143531A800B08D42 /* DFGJITCodeGenerator64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86880F43143531A700B08D42 /* DFGJITCodeGenerator64.cpp */; }; 307 86880F4D14353B2100B08D42 /* DFGSpeculativeJIT64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86880F4C14353B2100B08D42 /* DFGSpeculativeJIT64.cpp */; }; 307 308 868BFA08117CEFD100B908B1 /* AtomicString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 868BFA00117CEFD100B908B1 /* AtomicString.cpp */; }; 308 309 868BFA09117CEFD100B908B1 /* AtomicString.h in Headers */ = {isa = PBXBuildFile; fileRef = 868BFA01117CEFD100B908B1 /* AtomicString.h */; settings = {ATTRIBUTES = (Private, ); }; }; … … 1072 1073 86880F311434FFAF00B08D42 /* ChangeLog */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ChangeLog; sourceTree = "<group>"; }; 1073 1074 86880F43143531A700B08D42 /* DFGJITCodeGenerator64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGJITCodeGenerator64.cpp; path = dfg/DFGJITCodeGenerator64.cpp; sourceTree = "<group>"; }; 1075 86880F4C14353B2100B08D42 /* DFGSpeculativeJIT64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGSpeculativeJIT64.cpp; path = dfg/DFGSpeculativeJIT64.cpp; sourceTree = "<group>"; }; 1074 1076 868BFA00117CEFD100B908B1 /* AtomicString.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AtomicString.cpp; path = text/AtomicString.cpp; sourceTree = "<group>"; }; 1075 1077 868BFA01117CEFD100B908B1 /* AtomicString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AtomicString.h; path = text/AtomicString.h; sourceTree = "<group>"; }; … … 2302 2304 86EC9DC31328DF82002B2AD7 /* DFGSpeculativeJIT.h */, 2303 2305 86880F1B14328BB900B08D42 /* DFGSpeculativeJIT32_64.cpp */, 2306 86880F4C14353B2100B08D42 /* DFGSpeculativeJIT64.cpp */, 2304 2307 ); 2305 2308 name = dfg; … … 3385 3388 86880F1F14328BB900B08D42 /* DFGSpeculativeJIT32_64.cpp in Sources */, 3386 3389 86880F44143531A800B08D42 /* DFGJITCodeGenerator64.cpp in Sources */, 3390 86880F4D14353B2100B08D42 /* DFGSpeculativeJIT64.cpp in Sources */, 3387 3391 ); 3388 3392 runOnlyForDeploymentPostprocessing = 0; -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
r96375 r96379 29 29 30 30 #if ENABLE(DFG_JIT) 31 #if USE(JSVALUE64)32 31 33 32 namespace JSC { namespace DFG { 34 35 template<bool strict>36 GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& returnFormat)37 {38 #if ENABLE(DFG_DEBUG_VERBOSE)39 fprintf(stderr, "SpecInt@%d ", nodeIndex);40 #endif41 Node& node = m_jit.graph()[nodeIndex];42 VirtualRegister virtualRegister = node.virtualRegister();43 GenerationInfo& info = m_generationInfo[virtualRegister];44 45 switch (info.registerFormat()) {46 case DataFormatNone: {47 if (node.hasConstant() && !isInt32Constant(nodeIndex)) {48 terminateSpeculativeExecution();49 returnFormat = DataFormatInteger;50 return allocate();51 }52 53 GPRReg gpr = allocate();54 55 if (node.hasConstant()) {56 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);57 ASSERT(isInt32Constant(nodeIndex));58 m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr);59 info.fillInteger(gpr);60 returnFormat = DataFormatInteger;61 return gpr;62 }63 64 DataFormat spillFormat = info.spillFormat();65 ASSERT(spillFormat & DataFormatJS);66 67 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);68 69 if (spillFormat == DataFormatJSInteger) {70 // If we know this was spilled as an integer we can fill without checking.71 if (strict) {72 m_jit.load32(JITCompiler::addressFor(virtualRegister), gpr);73 info.fillInteger(gpr);74 returnFormat = DataFormatInteger;75 return gpr;76 }77 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr);78 info.fillJSValue(gpr, DataFormatJSInteger);79 returnFormat = DataFormatJSInteger;80 return gpr;81 }82 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr);83 84 // Fill as JSValue, and fall through.85 info.fillJSValue(gpr, DataFormatJSInteger);86 m_gprs.unlock(gpr);87 }88 89 case DataFormatJS: {90 // Check the value is an integer.91 GPRReg gpr = info.gpr();92 m_gprs.lock(gpr);93 speculationCheck(m_jit.branchPtr(MacroAssembler::Below, gpr, GPRInfo::tagTypeNumberRegister));94 info.fillJSValue(gpr, DataFormatJSInteger);95 // If !strict we're done, return.96 if (!strict) {97 returnFormat = DataFormatJSInteger;98 return gpr;99 }100 // else fall through & handle as DataFormatJSInteger.101 m_gprs.unlock(gpr);102 }103 104 case DataFormatJSInteger: {105 // In a strict fill we need to strip off the value tag.106 if (strict) {107 GPRReg gpr = info.gpr();108 GPRReg result;109 // If the register has already been locked we need to take a copy.110 // If not, we'll zero extend in place, so mark on the info that this is now type DataFormatInteger, not DataFormatJSInteger.111 if (m_gprs.isLocked(gpr))112 result = allocate();113 else {114 m_gprs.lock(gpr);115 info.fillInteger(gpr);116 result = gpr;117 }118 m_jit.zeroExtend32ToPtr(gpr, result);119 returnFormat = DataFormatInteger;120 return result;121 }122 123 GPRReg gpr = info.gpr();124 m_gprs.lock(gpr);125 returnFormat = DataFormatJSInteger;126 return gpr;127 }128 129 case DataFormatInteger: {130 GPRReg gpr = info.gpr();131 m_gprs.lock(gpr);132 returnFormat = DataFormatInteger;133 return gpr;134 }135 136 case DataFormatDouble:137 case DataFormatCell:138 case DataFormatBoolean:139 case DataFormatJSDouble:140 case DataFormatJSCell:141 case DataFormatJSBoolean: {142 terminateSpeculativeExecution();143 returnFormat = DataFormatInteger;144 return allocate();145 }146 147 case DataFormatStorage:148 ASSERT_NOT_REACHED();149 }150 151 ASSERT_NOT_REACHED();152 return InvalidGPRReg;153 }154 33 155 34 #ifndef NDEBUG … … 190 69 fprintf(out, "%%%s", FPRInfo::debugName(fpr())); 191 70 break; 71 #if USE(JSVALUE32_64) 72 case InPair: 73 fprintf(out, "pair(%%%s, %%%s)", GPRInfo::debugName(tagGPR()), GPRInfo::debugName(payloadGPR())); 74 break; 75 #endif 192 76 case DisplacedInRegisterFile: 193 77 fprintf(out, "*%d", virtualRegister()); … … 233 117 #endif 234 118 235 GPRReg SpeculativeJIT::fillSpeculateInt(NodeIndex nodeIndex, DataFormat& returnFormat) 236 { 237 return fillSpeculateIntInternal<false>(nodeIndex, returnFormat); 238 } 239 240 GPRReg SpeculativeJIT::fillSpeculateIntStrict(NodeIndex nodeIndex) 241 { 242 DataFormat mustBeDataFormatInteger; 243 GPRReg result = fillSpeculateIntInternal<true>(nodeIndex, mustBeDataFormatInteger); 244 ASSERT(mustBeDataFormatInteger == DataFormatInteger); 245 return result; 246 } 247 248 FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex) 249 { 250 #if ENABLE(DFG_DEBUG_VERBOSE) 251 fprintf(stderr, "SpecDouble@%d ", nodeIndex); 252 #endif 253 Node& node = m_jit.graph()[nodeIndex]; 254 VirtualRegister virtualRegister = node.virtualRegister(); 255 GenerationInfo& info = m_generationInfo[virtualRegister]; 256 257 if (info.registerFormat() == DataFormatNone) { 258 GPRReg gpr = allocate(); 259 260 if (node.hasConstant()) { 261 if (isInt32Constant(nodeIndex)) { 262 FPRReg fpr = fprAllocate(); 263 m_jit.move(MacroAssembler::ImmPtr(reinterpret_cast<void*>(reinterpretDoubleToIntptr(static_cast<double>(valueOfInt32Constant(nodeIndex))))), gpr); 264 m_jit.movePtrToDouble(gpr, fpr); 265 unlock(gpr); 266 267 m_fprs.retain(fpr, virtualRegister, SpillOrderDouble); 268 info.fillDouble(fpr); 269 return fpr; 270 } 271 if (isNumberConstant(nodeIndex)) { 272 FPRReg fpr = fprAllocate(); 273 m_jit.move(MacroAssembler::ImmPtr(reinterpret_cast<void*>(reinterpretDoubleToIntptr(valueOfNumberConstant(nodeIndex)))), gpr); 274 m_jit.movePtrToDouble(gpr, fpr); 275 unlock(gpr); 276 277 m_fprs.retain(fpr, virtualRegister, SpillOrderDouble); 278 info.fillDouble(fpr); 279 return fpr; 280 } 281 terminateSpeculativeExecution(); 282 return fprAllocate(); 283 } 284 285 DataFormat spillFormat = info.spillFormat(); 286 ASSERT(spillFormat & DataFormatJS); 287 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled); 288 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr); 289 info.fillJSValue(gpr, spillFormat); 290 unlock(gpr); 291 } 292 293 switch (info.registerFormat()) { 294 case DataFormatNone: // Should have filled, above. 295 case DataFormatBoolean: // This type never occurs. 296 case DataFormatStorage: 297 ASSERT_NOT_REACHED(); 298 299 case DataFormatCell: 300 case DataFormatJSCell: 301 case DataFormatJS: 302 case DataFormatJSBoolean: { 303 GPRReg jsValueGpr = info.gpr(); 304 m_gprs.lock(jsValueGpr); 305 FPRReg fpr = fprAllocate(); 306 GPRReg tempGpr = allocate(); 307 308 JITCompiler::Jump isInteger = m_jit.branchPtr(MacroAssembler::AboveOrEqual, jsValueGpr, GPRInfo::tagTypeNumberRegister); 309 310 speculationCheck(m_jit.branchTestPtr(MacroAssembler::Zero, jsValueGpr, GPRInfo::tagTypeNumberRegister)); 311 312 // First, if we get here we have a double encoded as a JSValue 313 m_jit.move(jsValueGpr, tempGpr); 314 unboxDouble(tempGpr, fpr); 315 JITCompiler::Jump hasUnboxedDouble = m_jit.jump(); 316 317 // Finally, handle integers. 318 isInteger.link(&m_jit); 319 m_jit.convertInt32ToDouble(jsValueGpr, fpr); 320 hasUnboxedDouble.link(&m_jit); 321 322 m_gprs.release(jsValueGpr); 323 m_gprs.unlock(jsValueGpr); 324 m_gprs.unlock(tempGpr); 325 m_fprs.retain(fpr, virtualRegister, SpillOrderDouble); 326 info.fillDouble(fpr); 327 info.killSpilled(); 328 return fpr; 329 } 330 331 case DataFormatJSInteger: 332 case DataFormatInteger: { 333 FPRReg fpr = fprAllocate(); 334 GPRReg gpr = info.gpr(); 335 m_gprs.lock(gpr); 336 m_jit.convertInt32ToDouble(gpr, fpr); 337 m_gprs.unlock(gpr); 338 return fpr; 339 } 340 341 // Unbox the double 342 case DataFormatJSDouble: { 343 GPRReg gpr = info.gpr(); 344 FPRReg fpr = fprAllocate(); 345 if (m_gprs.isLocked(gpr)) { 346 // Make sure we don't trample gpr if it is in use. 347 GPRReg temp = allocate(); 348 m_jit.move(gpr, temp); 349 unboxDouble(temp, fpr); 350 unlock(temp); 351 } else 352 unboxDouble(gpr, fpr); 353 354 m_gprs.release(gpr); 355 m_fprs.retain(fpr, virtualRegister, SpillOrderDouble); 356 357 info.fillDouble(fpr); 358 return fpr; 359 } 360 361 case DataFormatDouble: { 362 FPRReg fpr = info.fpr(); 363 m_fprs.lock(fpr); 364 return fpr; 365 } 366 } 367 368 ASSERT_NOT_REACHED(); 369 return InvalidFPRReg; 370 } 371 372 GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex) 373 { 374 #if ENABLE(DFG_DEBUG_VERBOSE) 375 fprintf(stderr, "SpecCell@%d ", nodeIndex); 376 #endif 377 Node& node = m_jit.graph()[nodeIndex]; 378 VirtualRegister virtualRegister = node.virtualRegister(); 379 GenerationInfo& info = m_generationInfo[virtualRegister]; 380 381 switch (info.registerFormat()) { 382 case DataFormatNone: { 383 GPRReg gpr = allocate(); 384 385 if (node.hasConstant()) { 386 JSValue jsValue = valueOfJSConstant(nodeIndex); 387 if (jsValue.isCell()) { 388 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); 389 m_jit.move(MacroAssembler::TrustedImmPtr(jsValue.asCell()), gpr); 390 info.fillJSValue(gpr, DataFormatJSCell); 391 return gpr; 392 } 393 terminateSpeculativeExecution(); 394 return gpr; 395 } 396 ASSERT(info.spillFormat() & DataFormatJS); 397 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled); 398 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr); 399 400 info.fillJSValue(gpr, DataFormatJS); 401 if (info.spillFormat() != DataFormatJSCell) 402 speculationCheck(m_jit.branchTestPtr(MacroAssembler::NonZero, gpr, GPRInfo::tagMaskRegister)); 403 info.fillJSValue(gpr, DataFormatJSCell); 404 return gpr; 405 } 406 407 case DataFormatCell: 408 case DataFormatJSCell: { 409 GPRReg gpr = info.gpr(); 410 m_gprs.lock(gpr); 411 return gpr; 412 } 413 414 case DataFormatJS: { 415 GPRReg gpr = info.gpr(); 416 m_gprs.lock(gpr); 417 speculationCheck(m_jit.branchTestPtr(MacroAssembler::NonZero, gpr, GPRInfo::tagMaskRegister)); 418 info.fillJSValue(gpr, DataFormatJSCell); 419 return gpr; 420 } 421 422 case DataFormatJSInteger: 423 case DataFormatInteger: 424 case DataFormatJSDouble: 425 case DataFormatDouble: 426 case DataFormatJSBoolean: 427 case DataFormatBoolean: { 428 terminateSpeculativeExecution(); 429 return allocate(); 430 } 431 432 case DataFormatStorage: 433 ASSERT_NOT_REACHED(); 434 } 435 436 ASSERT_NOT_REACHED(); 437 return InvalidGPRReg; 438 } 439 440 GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex) 441 { 442 #if ENABLE(DFG_DEBUG_VERBOSE) 443 fprintf(stderr, "SpecBool@%d ", nodeIndex); 444 #endif 445 Node& node = m_jit.graph()[nodeIndex]; 446 VirtualRegister virtualRegister = node.virtualRegister(); 447 GenerationInfo& info = m_generationInfo[virtualRegister]; 448 449 switch (info.registerFormat()) { 450 case DataFormatNone: { 451 GPRReg gpr = allocate(); 452 453 if (node.hasConstant()) { 454 JSValue jsValue = valueOfJSConstant(nodeIndex); 455 if (jsValue.isBoolean()) { 456 m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); 457 m_jit.move(MacroAssembler::TrustedImmPtr(JSValue::encode(jsValue)), gpr); 458 info.fillJSValue(gpr, DataFormatJSBoolean); 459 return gpr; 460 } 461 terminateSpeculativeExecution(); 462 return gpr; 463 } 464 ASSERT(info.spillFormat() & DataFormatJS); 465 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled); 466 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr); 467 468 info.fillJSValue(gpr, DataFormatJS); 469 if (info.spillFormat() != DataFormatJSBoolean) { 470 m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr); 471 speculationCheck(m_jit.branchTestPtr(MacroAssembler::NonZero, gpr, TrustedImm32(static_cast<int32_t>(~1))), SpeculationRecovery(BooleanSpeculationCheck, gpr, InvalidGPRReg)); 472 m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr); 473 } 474 info.fillJSValue(gpr, DataFormatJSBoolean); 475 return gpr; 476 } 477 478 case DataFormatBoolean: 479 case DataFormatJSBoolean: { 480 GPRReg gpr = info.gpr(); 481 m_gprs.lock(gpr); 482 return gpr; 483 } 484 485 case DataFormatJS: { 486 GPRReg gpr = info.gpr(); 487 m_gprs.lock(gpr); 488 m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr); 489 speculationCheck(m_jit.branchTestPtr(MacroAssembler::NonZero, gpr, TrustedImm32(static_cast<int32_t>(~1))), SpeculationRecovery(BooleanSpeculationCheck, gpr, InvalidGPRReg)); 490 m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr); 491 info.fillJSValue(gpr, DataFormatJSBoolean); 492 return gpr; 493 } 494 495 case DataFormatJSInteger: 496 case DataFormatInteger: 497 case DataFormatJSDouble: 498 case DataFormatDouble: 499 case DataFormatJSCell: 500 case DataFormatCell: { 501 terminateSpeculativeExecution(); 502 return allocate(); 503 } 504 505 case DataFormatStorage: 506 ASSERT_NOT_REACHED(); 507 } 508 509 ASSERT_NOT_REACHED(); 510 return InvalidGPRReg; 119 void SpeculativeJIT::compilePeepHoleDoubleBranch(Node& node, NodeIndex branchNodeIndex, JITCompiler::DoubleCondition condition) 120 { 121 Node& branchNode = m_jit.graph()[branchNodeIndex]; 122 BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(branchNode.takenBytecodeOffset()); 123 BlockIndex notTaken = m_jit.graph().blockIndexForBytecodeOffset(branchNode.notTakenBytecodeOffset()); 124 125 SpeculateDoubleOperand op1(this, node.child1()); 126 SpeculateDoubleOperand op2(this, node.child2()); 127 128 addBranch(m_jit.branchDouble(condition, op1.fpr(), op2.fpr()), taken); 129 130 if (notTaken != (m_block + 1)) 131 addBranch(m_jit.jump(), notTaken); 132 } 133 134 void SpeculativeJIT::compilePeepHoleObjectEquality(Node& node, NodeIndex branchNodeIndex, void* vptr) 135 { 136 Node& branchNode = m_jit.graph()[branchNodeIndex]; 137 BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(branchNode.takenBytecodeOffset()); 138 BlockIndex notTaken = m_jit.graph().blockIndexForBytecodeOffset(branchNode.notTakenBytecodeOffset()); 139 140 MacroAssembler::RelationalCondition condition = MacroAssembler::Equal; 141 142 if (taken == (m_block + 1)) { 143 condition = MacroAssembler::NotEqual; 144 BlockIndex tmp = taken; 145 taken = notTaken; 146 notTaken = tmp; 147 } 148 149 SpeculateCellOperand op1(this, node.child1()); 150 SpeculateCellOperand op2(this, node.child2()); 151 152 GPRReg op1GPR = op1.gpr(); 153 GPRReg op2GPR = op2.gpr(); 154 155 speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1GPR), MacroAssembler::TrustedImmPtr(vptr))); 156 speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op2GPR), MacroAssembler::TrustedImmPtr(vptr))); 157 158 addBranch(m_jit.branchPtr(condition, op1GPR, op2GPR), taken); 159 if (notTaken != (m_block + 1)) 160 addBranch(m_jit.jump(), notTaken); 511 161 } 512 162 … … 545 195 } 546 196 547 JITCompiler::Jump SpeculativeJIT::convertToDouble(GPRReg value, FPRReg result, GPRReg tmp)548 {549 JITCompiler::Jump isInteger = m_jit.branchPtr(MacroAssembler::AboveOrEqual, value, GPRInfo::tagTypeNumberRegister);550 551 JITCompiler::Jump notNumber = m_jit.branchTestPtr(MacroAssembler::Zero, value, GPRInfo::tagTypeNumberRegister);552 553 m_jit.move(value, tmp);554 unboxDouble(tmp, result);555 556 JITCompiler::Jump done = m_jit.jump();557 558 isInteger.link(&m_jit);559 560 m_jit.convertInt32ToDouble(value, result);561 562 done.link(&m_jit);563 564 return notNumber;565 }566 567 void SpeculativeJIT::compilePeepHoleDoubleBranch(Node& node, NodeIndex branchNodeIndex, JITCompiler::DoubleCondition condition)568 {569 Node& branchNode = m_jit.graph()[branchNodeIndex];570 BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(branchNode.takenBytecodeOffset());571 BlockIndex notTaken = m_jit.graph().blockIndexForBytecodeOffset(branchNode.notTakenBytecodeOffset());572 573 SpeculateDoubleOperand op1(this, node.child1());574 SpeculateDoubleOperand op2(this, node.child2());575 576 addBranch(m_jit.branchDouble(condition, op1.fpr(), op2.fpr()), taken);577 578 if (notTaken != (m_block + 1))579 addBranch(m_jit.jump(), notTaken);580 }581 582 void SpeculativeJIT::compilePeepHoleObjectEquality(Node& node, NodeIndex branchNodeIndex, void* vptr)583 {584 Node& branchNode = m_jit.graph()[branchNodeIndex];585 BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(branchNode.takenBytecodeOffset());586 BlockIndex notTaken = m_jit.graph().blockIndexForBytecodeOffset(branchNode.notTakenBytecodeOffset());587 588 MacroAssembler::RelationalCondition condition = MacroAssembler::Equal;589 590 if (taken == (m_block + 1)) {591 condition = MacroAssembler::NotEqual;592 BlockIndex tmp = taken;593 taken = notTaken;594 notTaken = tmp;595 }596 597 SpeculateCellOperand op1(this, node.child1());598 SpeculateCellOperand op2(this, node.child2());599 600 GPRReg op1GPR = op1.gpr();601 GPRReg op2GPR = op2.gpr();602 603 speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1GPR), MacroAssembler::TrustedImmPtr(vptr)));604 speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op2GPR), MacroAssembler::TrustedImmPtr(vptr)));605 606 addBranch(m_jit.branchPtr(condition, op1GPR, op2GPR), taken);607 if (notTaken != (m_block + 1))608 addBranch(m_jit.jump(), notTaken);609 }610 611 void SpeculativeJIT::compileObjectEquality(Node& node, void* vptr)612 {613 SpeculateCellOperand op1(this, node.child1());614 SpeculateCellOperand op2(this, node.child2());615 GPRTemporary result(this, op1);616 617 GPRReg op1GPR = op1.gpr();618 GPRReg op2GPR = op2.gpr();619 GPRReg resultGPR = result.gpr();620 621 speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1GPR), MacroAssembler::TrustedImmPtr(vptr)));622 speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op2GPR), MacroAssembler::TrustedImmPtr(vptr)));623 624 MacroAssembler::Jump falseCase = m_jit.branchPtr(MacroAssembler::NotEqual, op1GPR, op2GPR);625 m_jit.move(Imm32(ValueTrue), resultGPR);626 MacroAssembler::Jump done = m_jit.jump();627 falseCase.link(&m_jit);628 m_jit.move(Imm32(ValueFalse), resultGPR);629 done.link(&m_jit);630 631 jsValueResult(resultGPR, m_compileIndex, DataFormatJSBoolean);632 }633 634 // Returns true if the compare is fused with a subsequent branch.635 bool SpeculativeJIT::compare(Node& node, MacroAssembler::RelationalCondition condition, MacroAssembler::DoubleCondition doubleCondition, Z_DFGOperation_EJJ operation)636 {637 // Fused compare & branch.638 NodeIndex branchNodeIndex = detectPeepHoleBranch();639 if (branchNodeIndex != NoNode) {640 // detectPeepHoleBranch currently only permits the branch to be the very next node,641 // so can be no intervening nodes to also reference the compare.642 ASSERT(node.adjustedRefCount() == 1);643 644 if (shouldSpeculateInteger(node.child1(), node.child2())) {645 compilePeepHoleIntegerBranch(node, branchNodeIndex, condition);646 use(node.child1());647 use(node.child2());648 } else if (shouldSpeculateNumber(node.child1(), node.child2())) {649 compilePeepHoleDoubleBranch(node, branchNodeIndex, doubleCondition);650 use(node.child1());651 use(node.child2());652 } else if (node.op == CompareEq && shouldSpeculateFinalObject(node.child1(), node.child2())) {653 compilePeepHoleObjectEquality(node, branchNodeIndex, m_jit.globalData()->jsFinalObjectVPtr);654 use(node.child1());655 use(node.child2());656 } else if (node.op == CompareEq && shouldSpeculateArray(node.child1(), node.child2())) {657 compilePeepHoleObjectEquality(node, branchNodeIndex, m_jit.globalData()->jsArrayVPtr);658 use(node.child1());659 use(node.child2());660 } else661 nonSpeculativePeepholeBranch(node, branchNodeIndex, condition, operation);662 663 m_compileIndex = branchNodeIndex;664 return true;665 }666 667 if (shouldSpeculateInteger(node.child1(), node.child2())) {668 SpeculateIntegerOperand op1(this, node.child1());669 SpeculateIntegerOperand op2(this, node.child2());670 GPRTemporary result(this, op1, op2);671 672 m_jit.compare32(condition, op1.gpr(), op2.gpr(), result.gpr());673 674 // If we add a DataFormatBool, we should use it here.675 m_jit.or32(TrustedImm32(ValueFalse), result.gpr());676 jsValueResult(result.gpr(), m_compileIndex, DataFormatJSBoolean);677 } else if (shouldSpeculateNumber(node.child1(), node.child2())) {678 SpeculateDoubleOperand op1(this, node.child1());679 SpeculateDoubleOperand op2(this, node.child2());680 GPRTemporary result(this);681 682 m_jit.move(TrustedImm32(ValueTrue), result.gpr());683 MacroAssembler::Jump trueCase = m_jit.branchDouble(doubleCondition, op1.fpr(), op2.fpr());684 m_jit.xorPtr(Imm32(true), result.gpr());685 trueCase.link(&m_jit);686 687 jsValueResult(result.gpr(), m_compileIndex, DataFormatJSBoolean);688 } else if (node.op == CompareEq && shouldSpeculateFinalObject(node.child1(), node.child2()))689 compileObjectEquality(node, m_jit.globalData()->jsFinalObjectVPtr);690 else if (node.op == CompareEq && shouldSpeculateArray(node.child1(), node.child2()))691 compileObjectEquality(node, m_jit.globalData()->jsArrayVPtr);692 else693 nonSpeculativeNonPeepholeCompare(node, condition, operation);694 695 return false;696 }697 698 template<typename T>699 void SpeculativeJIT::emitAllocateJSFinalObject(T structure, GPRReg resultGPR, GPRReg scratchGPR, MacroAssembler::JumpList& slowPath)700 {701 MarkedSpace::SizeClass* sizeClass = &m_jit.globalData()->heap.sizeClassForObject(sizeof(JSFinalObject));702 703 m_jit.loadPtr(&sizeClass->firstFreeCell, resultGPR);704 slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, resultGPR));705 706 // The object is half-allocated: we have what we know is a fresh object, but707 // it's still on the GC's free list.708 709 // Ditch the structure by placing it into the structure slot, so that we can reuse710 // scratchGPR.711 m_jit.storePtr(structure, MacroAssembler::Address(resultGPR, JSObject::structureOffset()));712 713 // Now that we have scratchGPR back, remove the object from the free list714 m_jit.loadPtr(MacroAssembler::Address(resultGPR), scratchGPR);715 m_jit.storePtr(scratchGPR, &sizeClass->firstFreeCell);716 717 // Initialize the object's vtable718 m_jit.storePtr(MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsFinalObjectVPtr), MacroAssembler::Address(resultGPR));719 720 // Initialize the object's inheritorID.721 m_jit.storePtr(MacroAssembler::TrustedImmPtr(0), MacroAssembler::Address(resultGPR, JSObject::offsetOfInheritorID()));722 723 // Initialize the object's property storage pointer.724 m_jit.addPtr(MacroAssembler::TrustedImm32(sizeof(JSObject)), resultGPR, scratchGPR);725 m_jit.storePtr(scratchGPR, MacroAssembler::Address(resultGPR, JSFinalObject::offsetOfPropertyStorage()));726 }727 728 void SpeculativeJIT::compile(Node& node)729 {730 NodeType op = node.op;731 732 switch (op) {733 case JSConstant:734 initConstantInfo(m_compileIndex);735 break;736 737 case GetLocal: {738 PredictedType prediction = node.variableAccessData()->prediction();739 740 // If we have no prediction for this local, then don't attempt to compile.741 if (prediction == PredictNone) {742 terminateSpeculativeExecution();743 break;744 }745 746 GPRTemporary result(this);747 if (isInt32Prediction(prediction)) {748 m_jit.load32(JITCompiler::payloadFor(node.local()), result.gpr());749 750 // Like integerResult, but don't useChildren - our children are phi nodes,751 // and don't represent values within this dataflow with virtual registers.752 VirtualRegister virtualRegister = node.virtualRegister();753 m_gprs.retain(result.gpr(), virtualRegister, SpillOrderInteger);754 m_generationInfo[virtualRegister].initInteger(m_compileIndex, node.refCount(), result.gpr());755 } else {756 m_jit.loadPtr(JITCompiler::addressFor(node.local()), result.gpr());757 758 // Like jsValueResult, but don't useChildren - our children are phi nodes,759 // and don't represent values within this dataflow with virtual registers.760 VirtualRegister virtualRegister = node.virtualRegister();761 m_gprs.retain(result.gpr(), virtualRegister, SpillOrderJS);762 763 DataFormat format;764 if (isArrayPrediction(prediction))765 format = DataFormatJSCell;766 else if (isBooleanPrediction(prediction))767 format = DataFormatJSBoolean;768 else769 format = DataFormatJS;770 771 m_generationInfo[virtualRegister].initJSValue(m_compileIndex, node.refCount(), result.gpr(), format);772 }773 break;774 }775 776 case SetLocal: {777 // SetLocal doubles as a hint as to where a node will be stored and778 // as a speculation point. So before we speculate make sure that we779 // know where the child of this node needs to go in the virtual780 // register file.781 compileMovHint(node);782 783 // As far as OSR is concerned, we're on the bytecode index corresponding784 // to the *next* instruction, since we've already "executed" the785 // SetLocal and whatever other DFG Nodes are associated with the same786 // bytecode index as the SetLocal.787 ASSERT(m_bytecodeIndexForOSR == node.codeOrigin.bytecodeIndex());788 Node& nextNode = m_jit.graph()[m_compileIndex+1];789 790 // This assertion will fail if we ever emit multiple SetLocal's for791 // a single bytecode instruction. That's unlikely to happen. But if792 // it does, the solution is to to have this perform a search until793 // it finds a Node with a different bytecode index from the one we've794 // got, and to abstractly execute the SetLocal's along the way. Or,795 // better yet, handle all of the SetLocal's at once: abstract interpret796 // all of them, then emit code for all of them, with OSR exiting to797 // the next non-SetLocal instruction. Note the special case for when798 // both this SetLocal and the next op have a bytecode index of 0; this799 // occurs for SetLocal's generated at the top of the code block to800 // initialize locals to undefined. Ideally, we'd have a way of marking801 // in the CodeOrigin that a SetLocal is synthetic. This will make the802 // assertion more sensible-looking. We should then also assert that803 // synthetic SetLocal's don't have speculation checks, since they804 // should only be dropping values that we statically know we are805 // allowed to drop into the variables. DFGPropagator will guarantee806 // this, since it should have at least an approximation (if not807 // exact knowledge) of the type of the SetLocal's child node, and808 // should merge that information into the local that is being set.809 ASSERT(m_bytecodeIndexForOSR != nextNode.codeOrigin.bytecodeIndex()810 || (!m_bytecodeIndexForOSR && !nextNode.codeOrigin.bytecodeIndex()));811 m_bytecodeIndexForOSR = nextNode.codeOrigin.bytecodeIndex();812 813 PredictedType predictedType = node.variableAccessData()->prediction();814 if (isInt32Prediction(predictedType)) {815 SpeculateIntegerOperand value(this, node.child1());816 m_jit.store32(value.gpr(), JITCompiler::payloadFor(node.local()));817 noResult(m_compileIndex);818 } else if (isArrayPrediction(predictedType)) {819 SpeculateCellOperand cell(this, node.child1());820 GPRReg cellGPR = cell.gpr();821 speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(cellGPR), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));822 m_jit.storePtr(cellGPR, JITCompiler::addressFor(node.local()));823 noResult(m_compileIndex);824 } else if (isBooleanPrediction(predictedType)) {825 SpeculateBooleanOperand boolean(this, node.child1());826 m_jit.storePtr(boolean.gpr(), JITCompiler::addressFor(node.local()));827 noResult(m_compileIndex);828 } else {829 JSValueOperand value(this, node.child1());830 m_jit.storePtr(value.gpr(), JITCompiler::addressFor(node.local()));831 noResult(m_compileIndex);832 }833 834 // Indicate that it's no longer necessary to retrieve the value of835 // this bytecode variable from registers or other locations in the register file.836 valueSourceReferenceForOperand(node.local()) = ValueSource::forPrediction(predictedType);837 break;838 }839 840 case SetArgument:841 // This is a no-op; it just marks the fact that the argument is being used.842 // But it may be profitable to use this as a hook to run speculation checks843 // on arguments, thereby allowing us to trivially eliminate such checks if844 // the argument is not used.845 break;846 847 case BitAnd:848 case BitOr:849 case BitXor:850 if (isInt32Constant(node.child1())) {851 SpeculateIntegerOperand op2(this, node.child2());852 GPRTemporary result(this, op2);853 854 bitOp(op, valueOfInt32Constant(node.child1()), op2.gpr(), result.gpr());855 856 integerResult(result.gpr(), m_compileIndex);857 } else if (isInt32Constant(node.child2())) {858 SpeculateIntegerOperand op1(this, node.child1());859 GPRTemporary result(this, op1);860 861 bitOp(op, valueOfInt32Constant(node.child2()), op1.gpr(), result.gpr());862 863 integerResult(result.gpr(), m_compileIndex);864 } else {865 SpeculateIntegerOperand op1(this, node.child1());866 SpeculateIntegerOperand op2(this, node.child2());867 GPRTemporary result(this, op1, op2);868 869 GPRReg reg1 = op1.gpr();870 GPRReg reg2 = op2.gpr();871 bitOp(op, reg1, reg2, result.gpr());872 873 integerResult(result.gpr(), m_compileIndex);874 }875 break;876 877 case BitRShift:878 case BitLShift:879 case BitURShift:880 if (isInt32Constant(node.child2())) {881 SpeculateIntegerOperand op1(this, node.child1());882 GPRTemporary result(this, op1);883 884 shiftOp(op, op1.gpr(), valueOfInt32Constant(node.child2()) & 0x1f, result.gpr());885 886 integerResult(result.gpr(), m_compileIndex);887 } else {888 // Do not allow shift amount to be used as the result, MacroAssembler does not permit this.889 SpeculateIntegerOperand op1(this, node.child1());890 SpeculateIntegerOperand op2(this, node.child2());891 GPRTemporary result(this, op1);892 893 GPRReg reg1 = op1.gpr();894 GPRReg reg2 = op2.gpr();895 shiftOp(op, reg1, reg2, result.gpr());896 897 integerResult(result.gpr(), m_compileIndex);898 }899 break;900 901 case UInt32ToNumber: {902 if (!nodeCanSpeculateInteger(node.arithNodeFlags())) {903 // We know that this sometimes produces doubles. So produce a double every904 // time. This at least allows subsequent code to not have weird conditionals.905 906 IntegerOperand op1(this, node.child1());907 FPRTemporary result(this);908 909 GPRReg inputGPR = op1.gpr();910 FPRReg outputFPR = result.fpr();911 912 m_jit.convertInt32ToDouble(inputGPR, outputFPR);913 914 JITCompiler::Jump positive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, inputGPR, TrustedImm32(0));915 m_jit.addDouble(JITCompiler::AbsoluteAddress(&twoToThe32), outputFPR);916 positive.link(&m_jit);917 918 doubleResult(outputFPR, m_compileIndex);919 }920 921 IntegerOperand op1(this, node.child1());922 GPRTemporary result(this, op1);923 924 // Test the operand is positive.925 speculationCheck(m_jit.branch32(MacroAssembler::LessThan, op1.gpr(), TrustedImm32(0)));926 927 m_jit.move(op1.gpr(), result.gpr());928 integerResult(result.gpr(), m_compileIndex, op1.format());929 break;930 }931 932 case ValueToInt32: {933 if (shouldNotSpeculateInteger(node.child1())) {934 // Do it the safe way.935 nonSpeculativeValueToInt32(node);936 break;937 }938 939 if (shouldNotSpeculateInteger(node.child1())) {940 // Do it the safe way.941 nonSpeculativeValueToInt32(node);942 break;943 }944 945 SpeculateIntegerOperand op1(this, node.child1());946 GPRTemporary result(this, op1);947 m_jit.move(op1.gpr(), result.gpr());948 integerResult(result.gpr(), m_compileIndex, op1.format());949 break;950 }951 952 case ValueToNumber: {953 if (shouldNotSpeculateInteger(node.child1())) {954 SpeculateDoubleOperand op1(this, node.child1());955 FPRTemporary result(this, op1);956 m_jit.moveDouble(op1.fpr(), result.fpr());957 doubleResult(result.fpr(), m_compileIndex);958 break;959 }960 961 SpeculateIntegerOperand op1(this, node.child1());962 GPRTemporary result(this, op1);963 m_jit.move(op1.gpr(), result.gpr());964 integerResult(result.gpr(), m_compileIndex, op1.format());965 break;966 }967 968 case ValueToDouble: {969 SpeculateDoubleOperand op1(this, node.child1());970 FPRTemporary result(this, op1);971 m_jit.moveDouble(op1.fpr(), result.fpr());972 doubleResult(result.fpr(), m_compileIndex);973 break;974 }975 976 case ValueAdd:977 case ArithAdd: {978 if (shouldSpeculateInteger(node.child1(), node.child2()) && nodeCanSpeculateInteger(node.arithNodeFlags())) {979 if (isInt32Constant(node.child1())) {980 int32_t imm1 = valueOfInt32Constant(node.child1());981 SpeculateIntegerOperand op2(this, node.child2());982 GPRTemporary result(this);983 984 if (nodeCanTruncateInteger(node.arithNodeFlags())) {985 m_jit.move(op2.gpr(), result.gpr());986 m_jit.add32(Imm32(imm1), result.gpr());987 } else988 speculationCheck(m_jit.branchAdd32(MacroAssembler::Overflow, op2.gpr(), Imm32(imm1), result.gpr()));989 990 integerResult(result.gpr(), m_compileIndex);991 break;992 }993 994 if (isInt32Constant(node.child2())) {995 SpeculateIntegerOperand op1(this, node.child1());996 int32_t imm2 = valueOfInt32Constant(node.child2());997 GPRTemporary result(this);998 999 if (nodeCanTruncateInteger(node.arithNodeFlags())) {1000 m_jit.move(op1.gpr(), result.gpr());1001 m_jit.add32(Imm32(imm2), result.gpr());1002 } else1003 speculationCheck(m_jit.branchAdd32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr()));1004 1005 integerResult(result.gpr(), m_compileIndex);1006 break;1007 }1008 1009 SpeculateIntegerOperand op1(this, node.child1());1010 SpeculateIntegerOperand op2(this, node.child2());1011 GPRTemporary result(this, op1, op2);1012 1013 GPRReg gpr1 = op1.gpr();1014 GPRReg gpr2 = op2.gpr();1015 GPRReg gprResult = result.gpr();1016 1017 if (nodeCanTruncateInteger(node.arithNodeFlags())) {1018 if (gpr1 == gprResult)1019 m_jit.add32(gpr2, gprResult);1020 else {1021 m_jit.move(gpr2, gprResult);1022 m_jit.add32(gpr1, gprResult);1023 }1024 } else {1025 MacroAssembler::Jump check = m_jit.branchAdd32(MacroAssembler::Overflow, gpr1, gpr2, gprResult);1026 1027 if (gpr1 == gprResult)1028 speculationCheck(check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr2));1029 else if (gpr2 == gprResult)1030 speculationCheck(check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr1));1031 else1032 speculationCheck(check);1033 }1034 1035 integerResult(gprResult, m_compileIndex);1036 break;1037 }1038 1039 if (shouldSpeculateNumber(node.child1(), node.child2())) {1040 SpeculateDoubleOperand op1(this, node.child1());1041 SpeculateDoubleOperand op2(this, node.child2());1042 FPRTemporary result(this, op1, op2);1043 1044 FPRReg reg1 = op1.fpr();1045 FPRReg reg2 = op2.fpr();1046 m_jit.addDouble(reg1, reg2, result.fpr());1047 1048 doubleResult(result.fpr(), m_compileIndex);1049 break;1050 }1051 1052 ASSERT(op == ValueAdd);1053 1054 JSValueOperand op1(this, node.child1());1055 JSValueOperand op2(this, node.child2());1056 1057 GPRReg op1GPR = op1.gpr();1058 GPRReg op2GPR = op2.gpr();1059 1060 flushRegisters();1061 1062 GPRResult result(this);1063 if (isKnownNotNumber(node.child1()) || isKnownNotNumber(node.child2()))1064 callOperation(operationValueAddNotNumber, result.gpr(), op1GPR, op2GPR);1065 else1066 callOperation(operationValueAdd, result.gpr(), op1GPR, op2GPR);1067 1068 jsValueResult(result.gpr(), m_compileIndex);1069 break;1070 }1071 1072 case ArithSub: {1073 if (shouldSpeculateInteger(node.child1(), node.child2()) && nodeCanSpeculateInteger(node.arithNodeFlags())) {1074 if (isInt32Constant(node.child2())) {1075 SpeculateIntegerOperand op1(this, node.child1());1076 int32_t imm2 = valueOfInt32Constant(node.child2());1077 GPRTemporary result(this);1078 1079 if (nodeCanTruncateInteger(node.arithNodeFlags())) {1080 m_jit.move(op1.gpr(), result.gpr());1081 m_jit.sub32(Imm32(imm2), result.gpr());1082 } else1083 speculationCheck(m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr()));1084 1085 integerResult(result.gpr(), m_compileIndex);1086 break;1087 }1088 1089 SpeculateIntegerOperand op1(this, node.child1());1090 SpeculateIntegerOperand op2(this, node.child2());1091 GPRTemporary result(this);1092 1093 if (nodeCanTruncateInteger(node.arithNodeFlags())) {1094 m_jit.move(op1.gpr(), result.gpr());1095 m_jit.sub32(op2.gpr(), result.gpr());1096 } else1097 speculationCheck(m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), op2.gpr(), result.gpr()));1098 1099 integerResult(result.gpr(), m_compileIndex);1100 break;1101 }1102 1103 SpeculateDoubleOperand op1(this, node.child1());1104 SpeculateDoubleOperand op2(this, node.child2());1105 FPRTemporary result(this, op1);1106 1107 FPRReg reg1 = op1.fpr();1108 FPRReg reg2 = op2.fpr();1109 m_jit.subDouble(reg1, reg2, result.fpr());1110 1111 doubleResult(result.fpr(), m_compileIndex);1112 break;1113 }1114 1115 case ArithMul: {1116 if (shouldSpeculateInteger(node.child1(), node.child2()) && nodeCanSpeculateInteger(node.arithNodeFlags())) {1117 SpeculateIntegerOperand op1(this, node.child1());1118 SpeculateIntegerOperand op2(this, node.child2());1119 GPRTemporary result(this);1120 1121 GPRReg reg1 = op1.gpr();1122 GPRReg reg2 = op2.gpr();1123 1124 // What is unfortunate is that we cannot take advantage of nodeCanTruncateInteger()1125 // here. A multiply on integers performed in the double domain and then truncated to1126 // an integer will give a different result than a multiply performed in the integer1127 // domain and then truncated, if the integer domain result would have resulted in1128 // something bigger than what a 32-bit integer can hold. JavaScript mandates that1129 // the semantics are always as if the multiply had been performed in the double1130 // domain.1131 1132 speculationCheck(m_jit.branchMul32(MacroAssembler::Overflow, reg1, reg2, result.gpr()));1133 1134 // Check for negative zero, if the users of this node care about such things.1135 if (!nodeCanIgnoreNegativeZero(node.arithNodeFlags())) {1136 MacroAssembler::Jump resultNonZero = m_jit.branchTest32(MacroAssembler::NonZero, result.gpr());1137 speculationCheck(m_jit.branch32(MacroAssembler::LessThan, reg1, TrustedImm32(0)));1138 speculationCheck(m_jit.branch32(MacroAssembler::LessThan, reg2, TrustedImm32(0)));1139 resultNonZero.link(&m_jit);1140 }1141 1142 integerResult(result.gpr(), m_compileIndex);1143 break;1144 }1145 1146 SpeculateDoubleOperand op1(this, node.child1());1147 SpeculateDoubleOperand op2(this, node.child2());1148 FPRTemporary result(this, op1, op2);1149 1150 FPRReg reg1 = op1.fpr();1151 FPRReg reg2 = op2.fpr();1152 1153 m_jit.mulDouble(reg1, reg2, result.fpr());1154 1155 doubleResult(result.fpr(), m_compileIndex);1156 break;1157 }1158 1159 case ArithDiv: {1160 if (shouldSpeculateInteger(node.child1(), node.child2()) && nodeCanSpeculateInteger(node.arithNodeFlags())) {1161 SpeculateIntegerOperand op1(this, node.child1());1162 SpeculateIntegerOperand op2(this, node.child2());1163 GPRTemporary eax(this, X86Registers::eax);1164 GPRTemporary edx(this, X86Registers::edx);1165 GPRReg op1GPR = op1.gpr();1166 GPRReg op2GPR = op2.gpr();1167 1168 speculationCheck(m_jit.branchTest32(JITCompiler::Zero, op2GPR));1169 1170 // If the user cares about negative zero, then speculate that we're not about1171 // to produce negative zero.1172 if (!nodeCanIgnoreNegativeZero(node.arithNodeFlags())) {1173 MacroAssembler::Jump numeratorNonZero = m_jit.branchTest32(MacroAssembler::NonZero, op1GPR);1174 speculationCheck(m_jit.branch32(MacroAssembler::LessThan, op2GPR, TrustedImm32(0)));1175 numeratorNonZero.link(&m_jit);1176 }1177 1178 GPRReg temp2 = InvalidGPRReg;1179 if (op2GPR == X86Registers::eax || op2GPR == X86Registers::edx) {1180 temp2 = allocate();1181 m_jit.move(op2GPR, temp2);1182 op2GPR = temp2;1183 }1184 1185 m_jit.move(op1GPR, eax.gpr());1186 m_jit.assembler().cdq();1187 m_jit.assembler().idivl_r(op2GPR);1188 1189 // Check that there was no remainder. If there had been, then we'd be obligated to1190 // produce a double result instead.1191 speculationCheck(m_jit.branchTest32(JITCompiler::NonZero, edx.gpr()));1192 1193 integerResult(eax.gpr(), m_compileIndex);1194 break;1195 }1196 1197 SpeculateDoubleOperand op1(this, node.child1());1198 SpeculateDoubleOperand op2(this, node.child2());1199 FPRTemporary result(this, op1);1200 1201 FPRReg reg1 = op1.fpr();1202 FPRReg reg2 = op2.fpr();1203 m_jit.divDouble(reg1, reg2, result.fpr());1204 1205 doubleResult(result.fpr(), m_compileIndex);1206 break;1207 }1208 1209 case ArithMod: {1210 if (shouldNotSpeculateInteger(node.child1()) || shouldNotSpeculateInteger(node.child2())1211 || !nodeCanSpeculateInteger(node.arithNodeFlags())) {1212 SpeculateDoubleOperand op1(this, node.child1());1213 SpeculateDoubleOperand op2(this, node.child2());1214 1215 FPRReg op1FPR = op1.fpr();1216 FPRReg op2FPR = op2.fpr();1217 1218 flushRegisters();1219 1220 FPRResult result(this);1221 1222 callOperation(fmod, result.fpr(), op1FPR, op2FPR);1223 1224 doubleResult(result.fpr(), m_compileIndex);1225 break;1226 }1227 1228 SpeculateIntegerOperand op1(this, node.child1());1229 SpeculateIntegerOperand op2(this, node.child2());1230 GPRTemporary eax(this, X86Registers::eax);1231 GPRTemporary edx(this, X86Registers::edx);1232 GPRReg op1Gpr = op1.gpr();1233 GPRReg op2Gpr = op2.gpr();1234 1235 speculationCheck(m_jit.branchTest32(JITCompiler::Zero, op2Gpr));1236 1237 GPRReg temp2 = InvalidGPRReg;1238 if (op2Gpr == X86Registers::eax || op2Gpr == X86Registers::edx) {1239 temp2 = allocate();1240 m_jit.move(op2Gpr, temp2);1241 op2Gpr = temp2;1242 }1243 1244 m_jit.move(op1Gpr, eax.gpr());1245 m_jit.assembler().cdq();1246 m_jit.assembler().idivl_r(op2Gpr);1247 1248 if (temp2 != InvalidGPRReg)1249 unlock(temp2);1250 1251 integerResult(edx.gpr(), m_compileIndex);1252 break;1253 }1254 1255 case ArithAbs: {1256 if (shouldSpeculateInteger(node.child1()) && nodeCanSpeculateInteger(node.arithNodeFlags())) {1257 SpeculateIntegerOperand op1(this, node.child1());1258 GPRTemporary result(this, op1);1259 GPRTemporary scratch(this);1260 1261 m_jit.zeroExtend32ToPtr(op1.gpr(), result.gpr());1262 m_jit.rshift32(result.gpr(), MacroAssembler::TrustedImm32(31), scratch.gpr());1263 m_jit.add32(scratch.gpr(), result.gpr());1264 m_jit.xor32(scratch.gpr(), result.gpr());1265 speculationCheck(m_jit.branch32(MacroAssembler::Equal, result.gpr(), MacroAssembler::TrustedImm32(1 << 31)));1266 integerResult(result.gpr(), m_compileIndex);1267 break;1268 }1269 1270 SpeculateDoubleOperand op1(this, node.child1());1271 FPRTemporary result(this);1272 1273 static const double negativeZeroConstant = -0.0;1274 1275 m_jit.loadDouble(&negativeZeroConstant, result.fpr());1276 m_jit.andnotDouble(op1.fpr(), result.fpr());1277 doubleResult(result.fpr(), m_compileIndex);1278 break;1279 }1280 1281 case ArithMin:1282 case ArithMax: {1283 if (shouldSpeculateInteger(node.child1(), node.child2()) && nodeCanSpeculateInteger(node.arithNodeFlags())) {1284 SpeculateStrictInt32Operand op1(this, node.child1());1285 SpeculateStrictInt32Operand op2(this, node.child2());1286 GPRTemporary result(this, op1);1287 1288 MacroAssembler::Jump op1Less = m_jit.branch32(op == ArithMin ? MacroAssembler::LessThan : MacroAssembler::GreaterThan, op1.gpr(), op2.gpr());1289 m_jit.move(op2.gpr(), result.gpr());1290 if (op1.gpr() != result.gpr()) {1291 MacroAssembler::Jump done = m_jit.jump();1292 op1Less.link(&m_jit);1293 m_jit.move(op1.gpr(), result.gpr());1294 done.link(&m_jit);1295 } else1296 op1Less.link(&m_jit);1297 1298 integerResult(result.gpr(), m_compileIndex);1299 break;1300 }1301 1302 SpeculateDoubleOperand op1(this, node.child1());1303 SpeculateDoubleOperand op2(this, node.child2());1304 FPRTemporary result(this, op1);1305 1306 MacroAssembler::JumpList done;1307 1308 MacroAssembler::Jump op1Less = m_jit.branchDouble(op == ArithMin ? MacroAssembler::DoubleLessThan : MacroAssembler::DoubleGreaterThan, op1.fpr(), op2.fpr());1309 1310 // op2 is eather the lesser one or one of then is NaN1311 MacroAssembler::Jump op2Less = m_jit.branchDouble(op == ArithMin ? MacroAssembler::DoubleGreaterThan : MacroAssembler::DoubleLessThan, op1.fpr(), op2.fpr());1312 1313 // Unordered case. We don't know which of op1, op2 is NaN. Manufacture NaN by adding1314 // op1 + op2 and putting it into result.1315 m_jit.addDouble(op1.fpr(), op2.fpr(), result.fpr());1316 done.append(m_jit.jump());1317 1318 op2Less.link(&m_jit);1319 m_jit.moveDouble(op2.fpr(), result.fpr());1320 1321 if (op1.fpr() != result.fpr()) {1322 done.append(m_jit.jump());1323 1324 op1Less.link(&m_jit);1325 m_jit.moveDouble(op1.fpr(), result.fpr());1326 } else1327 op1Less.link(&m_jit);1328 1329 done.link(&m_jit);1330 1331 doubleResult(result.fpr(), m_compileIndex);1332 break;1333 }1334 1335 case ArithSqrt: {1336 SpeculateDoubleOperand op1(this, node.child1());1337 FPRTemporary result(this, op1);1338 1339 m_jit.sqrtDouble(op1.fpr(), result.fpr());1340 1341 doubleResult(result.fpr(), m_compileIndex);1342 break;1343 }1344 1345 case LogicalNot: {1346 if (isKnownBoolean(node.child1())) {1347 SpeculateBooleanOperand value(this, node.child1());1348 GPRTemporary result(this, value);1349 1350 m_jit.move(value.gpr(), result.gpr());1351 m_jit.xorPtr(TrustedImm32(true), result.gpr());1352 1353 jsValueResult(result.gpr(), m_compileIndex, DataFormatJSBoolean);1354 break;1355 }1356 1357 PredictedType prediction = m_jit.getPrediction(node.child1());1358 if (isBooleanPrediction(prediction) || !prediction) {1359 JSValueOperand value(this, node.child1());1360 GPRTemporary result(this); // FIXME: We could reuse, but on speculation fail would need recovery to restore tag (akin to add).1361 1362 m_jit.move(value.gpr(), result.gpr());1363 m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), result.gpr());1364 speculationCheck(m_jit.branchTestPtr(JITCompiler::NonZero, result.gpr(), TrustedImm32(static_cast<int32_t>(~1))));1365 m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueTrue)), result.gpr());1366 1367 // If we add a DataFormatBool, we should use it here.1368 jsValueResult(result.gpr(), m_compileIndex, DataFormatJSBoolean);1369 break;1370 }1371 1372 nonSpeculativeLogicalNot(node);1373 1374 break;1375 }1376 1377 case CompareLess:1378 if (compare(node, JITCompiler::LessThan, JITCompiler::DoubleLessThan, operationCompareLess))1379 return;1380 break;1381 1382 case CompareLessEq:1383 if (compare(node, JITCompiler::LessThanOrEqual, JITCompiler::DoubleLessThanOrEqual, operationCompareLessEq))1384 return;1385 break;1386 1387 case CompareGreater:1388 if (compare(node, JITCompiler::GreaterThan, JITCompiler::DoubleGreaterThan, operationCompareGreater))1389 return;1390 break;1391 1392 case CompareGreaterEq:1393 if (compare(node, JITCompiler::GreaterThanOrEqual, JITCompiler::DoubleGreaterThanOrEqual, operationCompareGreaterEq))1394 return;1395 break;1396 1397 case CompareEq:1398 if (isNullConstant(node.child1())) {1399 if (nonSpeculativeCompareNull(node, node.child2()))1400 return;1401 break;1402 }1403 if (isNullConstant(node.child2())) {1404 if (nonSpeculativeCompareNull(node, node.child1()))1405 return;1406 break;1407 }1408 if (compare(node, JITCompiler::Equal, JITCompiler::DoubleEqual, operationCompareEq))1409 return;1410 break;1411 1412 case CompareStrictEq:1413 if (nonSpeculativeStrictEq(node))1414 return;1415 break;1416 1417 case GetByVal: {1418 ASSERT(node.child3() == NoNode);1419 SpeculateCellOperand base(this, node.child1());1420 SpeculateStrictInt32Operand property(this, node.child2());1421 GPRTemporary storage(this);1422 1423 GPRReg baseReg = base.gpr();1424 GPRReg propertyReg = property.gpr();1425 GPRReg storageReg = storage.gpr();1426 1427 if (!m_compileOkay)1428 return;1429 1430 // Get the array storage. We haven't yet checked this is a JSArray, so this is only safe if1431 // an access with offset JSArray::storageOffset() is valid for all JSCells!1432 m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);1433 1434 // Check that base is an array, and that property is contained within m_vector (< m_vectorLength).1435 // If we have predicted the base to be type array, we can skip the check.1436 if (!isKnownArray(node.child1()))1437 speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));1438 speculationCheck(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset())));1439 1440 // FIXME: In cases where there are subsequent by_val accesses to the same base it might help to cache1441 // the storage pointer - especially if there happens to be another register free right now. If we do so,1442 // then we'll need to allocate a new temporary for result.1443 GPRTemporary& result = storage;1444 m_jit.loadPtr(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), result.gpr());1445 speculationCheck(m_jit.branchTestPtr(MacroAssembler::Zero, result.gpr()));1446 1447 jsValueResult(result.gpr(), m_compileIndex);1448 break;1449 }1450 1451 case PutByVal: {1452 SpeculateCellOperand base(this, node.child1());1453 SpeculateStrictInt32Operand property(this, node.child2());1454 JSValueOperand value(this, node.child3());1455 GPRTemporary scratch(this);1456 1457 // Map base, property & value into registers, allocate a scratch register.1458 GPRReg baseReg = base.gpr();1459 GPRReg propertyReg = property.gpr();1460 GPRReg valueReg = value.gpr();1461 GPRReg scratchReg = scratch.gpr();1462 1463 if (!m_compileOkay)1464 return;1465 1466 writeBarrier(baseReg, value.gpr(), node.child3(), WriteBarrierForPropertyAccess, scratchReg);1467 1468 // Check that base is an array, and that property is contained within m_vector (< m_vectorLength).1469 // If we have predicted the base to be type array, we can skip the check.1470 if (!isKnownArray(node.child1()))1471 speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));1472 1473 base.use();1474 property.use();1475 value.use();1476 1477 MacroAssembler::Jump withinArrayBounds = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()));1478 1479 // Code to handle put beyond array bounds.1480 silentSpillAllRegisters(scratchReg);1481 setupStubArguments(baseReg, propertyReg, valueReg);1482 m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);1483 JITCompiler::Call functionCall = appendCallWithExceptionCheck(operationPutByValBeyondArrayBounds);1484 silentFillAllRegisters(scratchReg);1485 JITCompiler::Jump wasBeyondArrayBounds = m_jit.jump();1486 1487 withinArrayBounds.link(&m_jit);1488 1489 // Get the array storage.1490 GPRReg storageReg = scratchReg;1491 m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);1492 1493 // Check if we're writing to a hole; if so increment m_numValuesInVector.1494 MacroAssembler::Jump notHoleValue = m_jit.branchTestPtr(MacroAssembler::NonZero, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));1495 m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));1496 1497 // If we're writing to a hole we might be growing the array;1498 MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length)));1499 m_jit.add32(TrustedImm32(1), propertyReg);1500 m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length)));1501 m_jit.sub32(TrustedImm32(1), propertyReg);1502 1503 lengthDoesNotNeedUpdate.link(&m_jit);1504 notHoleValue.link(&m_jit);1505 1506 // Store the value to the array.1507 m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));1508 1509 wasBeyondArrayBounds.link(&m_jit);1510 1511 noResult(m_compileIndex, UseChildrenCalledExplicitly);1512 break;1513 }1514 1515 case PutByValAlias: {1516 SpeculateCellOperand base(this, node.child1());1517 SpeculateStrictInt32Operand property(this, node.child2());1518 JSValueOperand value(this, node.child3());1519 GPRTemporary scratch(this);1520 1521 GPRReg baseReg = base.gpr();1522 GPRReg scratchReg = scratch.gpr();1523 1524 writeBarrier(base.gpr(), value.gpr(), node.child3(), WriteBarrierForPropertyAccess, scratchReg);1525 1526 // Get the array storage.1527 GPRReg storageReg = scratchReg;1528 m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);1529 1530 // Store the value to the array.1531 GPRReg propertyReg = property.gpr();1532 GPRReg valueReg = value.gpr();1533 m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));1534 1535 noResult(m_compileIndex);1536 break;1537 }1538 1539 case DFG::Jump: {1540 BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(node.takenBytecodeOffset());1541 if (taken != (m_block + 1))1542 addBranch(m_jit.jump(), taken);1543 noResult(m_compileIndex);1544 break;1545 }1546 1547 case Branch:1548 if (isStrictInt32(node.child1())) {1549 SpeculateStrictInt32Operand op(this, node.child1());1550 1551 BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(node.takenBytecodeOffset());1552 BlockIndex notTaken = m_jit.graph().blockIndexForBytecodeOffset(node.notTakenBytecodeOffset());1553 1554 MacroAssembler::ResultCondition condition = MacroAssembler::NonZero;1555 1556 if (taken == (m_block + 1)) {1557 condition = MacroAssembler::Zero;1558 BlockIndex tmp = taken;1559 taken = notTaken;1560 notTaken = tmp;1561 }1562 1563 addBranch(m_jit.branchTest32(condition, op.gpr()), taken);1564 if (notTaken != (m_block + 1))1565 addBranch(m_jit.jump(), notTaken);1566 1567 noResult(m_compileIndex);1568 break;1569 }1570 if (shouldSpeculateInteger(node.child1())) {1571 SpeculateIntegerOperand op(this, node.child1());1572 1573 BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(node.takenBytecodeOffset());1574 BlockIndex notTaken = m_jit.graph().blockIndexForBytecodeOffset(node.notTakenBytecodeOffset());1575 1576 MacroAssembler::RelationalCondition condition = MacroAssembler::NotEqual;1577 1578 if (taken == (m_block + 1)) {1579 condition = MacroAssembler::Equal;1580 BlockIndex tmp = taken;1581 taken = notTaken;1582 notTaken = tmp;1583 }1584 1585 addBranch(m_jit.branchPtr(condition, op.gpr(), GPRInfo::tagTypeNumberRegister), taken);1586 1587 if (notTaken != (m_block + 1))1588 addBranch(m_jit.jump(), notTaken);1589 1590 noResult(m_compileIndex);1591 break;1592 }1593 emitBranch(node);1594 break;1595 1596 case Return: {1597 ASSERT(GPRInfo::callFrameRegister != GPRInfo::regT1);1598 ASSERT(GPRInfo::regT1 != GPRInfo::returnValueGPR);1599 ASSERT(GPRInfo::returnValueGPR != GPRInfo::callFrameRegister);1600 1601 #if ENABLE(DFG_SUCCESS_STATS)1602 static SamplingCounter counter("SpeculativeJIT");1603 m_jit.emitCount(counter);1604 #endif1605 1606 // Return the result in returnValueGPR.1607 JSValueOperand op1(this, node.child1());1608 m_jit.move(op1.gpr(), GPRInfo::returnValueGPR);1609 1610 // Grab the return address.1611 m_jit.emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, GPRInfo::regT1);1612 // Restore our caller's "r".1613 m_jit.emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, GPRInfo::callFrameRegister);1614 // Return.1615 m_jit.restoreReturnAddressBeforeReturn(GPRInfo::regT1);1616 m_jit.ret();1617 1618 noResult(m_compileIndex);1619 break;1620 }1621 1622 case Throw:1623 case ThrowReferenceError: {1624 // We expect that throw statements are rare and are intended to exit the code block1625 // anyway, so we just OSR back to the old JIT for now.1626 terminateSpeculativeExecution();1627 break;1628 }1629 1630 case ToPrimitive: {1631 if (shouldSpeculateInteger(node.child1())) {1632 // It's really profitable to speculate integer, since it's really cheap,1633 // it means we don't have to do any real work, and we emit a lot less code.1634 1635 SpeculateIntegerOperand op1(this, node.child1());1636 GPRTemporary result(this, op1);1637 1638 m_jit.move(op1.gpr(), result.gpr());1639 if (op1.format() == DataFormatInteger)1640 m_jit.orPtr(GPRInfo::tagTypeNumberRegister, result.gpr());1641 1642 jsValueResult(result.gpr(), m_compileIndex);1643 break;1644 }1645 1646 // FIXME: Add string speculation here.1647 1648 bool wasPrimitive = isKnownNumeric(node.child1()) || isKnownBoolean(node.child1());1649 1650 JSValueOperand op1(this, node.child1());1651 GPRTemporary result(this, op1);1652 1653 GPRReg op1GPR = op1.gpr();1654 GPRReg resultGPR = result.gpr();1655 1656 op1.use();1657 1658 if (wasPrimitive)1659 m_jit.move(op1GPR, resultGPR);1660 else {1661 MacroAssembler::JumpList alreadyPrimitive;1662 1663 alreadyPrimitive.append(m_jit.branchTestPtr(MacroAssembler::NonZero, op1GPR, GPRInfo::tagMaskRegister));1664 alreadyPrimitive.append(m_jit.branchPtr(MacroAssembler::Equal, MacroAssembler::Address(op1GPR), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsStringVPtr)));1665 1666 silentSpillAllRegisters(resultGPR);1667 m_jit.move(op1GPR, GPRInfo::argumentGPR1);1668 m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);1669 appendCallWithExceptionCheck(operationToPrimitive);1670 m_jit.move(GPRInfo::returnValueGPR, resultGPR);1671 silentFillAllRegisters(resultGPR);1672 1673 MacroAssembler::Jump done = m_jit.jump();1674 1675 alreadyPrimitive.link(&m_jit);1676 m_jit.move(op1GPR, resultGPR);1677 1678 done.link(&m_jit);1679 }1680 1681 jsValueResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly);1682 break;1683 }1684 1685 case StrCat:1686 case NewArray: {1687 // We really don't want to grow the register file just to do a StrCat or NewArray.1688 // Say we have 50 functions on the stack that all have a StrCat in them that has1689 // upwards of 10 operands. In the DFG this would mean that each one gets1690 // some random virtual register, and then to do the StrCat we'd need a second1691 // span of 10 operands just to have somewhere to copy the 10 operands to, where1692 // they'd be contiguous and we could easily tell the C code how to find them.1693 // Ugly! So instead we use the scratchBuffer infrastructure in JSGlobalData. That1694 // way, those 50 functions will share the same scratchBuffer for offloading their1695 // StrCat operands. It's about as good as we can do, unless we start doing1696 // virtual register coalescing to ensure that operands to StrCat get spilled1697 // in exactly the place where StrCat wants them, or else have the StrCat1698 // refer to those operands' SetLocal instructions to force them to spill in1699 // the right place. Basically, any way you cut it, the current approach1700 // probably has the best balance of performance and sensibility in the sense1701 // that it does not increase the complexity of the DFG JIT just to make StrCat1702 // fast and pretty.1703 1704 EncodedJSValue* buffer = static_cast<EncodedJSValue*>(m_jit.globalData()->scratchBufferForSize(sizeof(EncodedJSValue) * node.numChildren()));1705 1706 for (unsigned operandIdx = 0; operandIdx < node.numChildren(); ++operandIdx) {1707 JSValueOperand operand(this, m_jit.graph().m_varArgChildren[node.firstChild() + operandIdx]);1708 GPRReg opGPR = operand.gpr();1709 operand.use();1710 1711 m_jit.storePtr(opGPR, buffer + operandIdx);1712 }1713 1714 flushRegisters();1715 1716 GPRResult result(this);1717 1718 callOperation(op == StrCat ? operationStrCat : operationNewArray, result.gpr(), buffer, node.numChildren());1719 1720 cellResult(result.gpr(), m_compileIndex, UseChildrenCalledExplicitly);1721 break;1722 }1723 1724 case NewArrayBuffer: {1725 flushRegisters();1726 GPRResult result(this);1727 1728 callOperation(operationNewArrayBuffer, result.gpr(), node.startConstant(), node.numConstants());1729 1730 cellResult(result.gpr(), m_compileIndex);1731 break;1732 }1733 1734 case NewRegexp: {1735 flushRegisters();1736 GPRResult result(this);1737 1738 callOperation(operationNewRegexp, result.gpr(), m_jit.codeBlock()->regexp(node.regexpIndex()));1739 1740 cellResult(result.gpr(), m_compileIndex);1741 break;1742 }1743 1744 case ConvertThis: {1745 SpeculateCellOperand thisValue(this, node.child1());1746 1747 speculationCheck(m_jit.branchPtr(JITCompiler::Equal, JITCompiler::Address(thisValue.gpr()), JITCompiler::TrustedImmPtr(m_jit.globalData()->jsStringVPtr)));1748 1749 cellResult(thisValue.gpr(), m_compileIndex);1750 break;1751 }1752 1753 case CreateThis: {1754 // Note that there is not so much profit to speculate here. The only things we1755 // speculate on are (1) that it's a cell, since that eliminates cell checks1756 // later if the proto is reused, and (2) if we have a FinalObject prediction1757 // then we speculate because we want to get recompiled if it isn't (since1758 // otherwise we'd start taking slow path a lot).1759 1760 SpeculateCellOperand proto(this, node.child1());1761 GPRTemporary result(this);1762 GPRTemporary scratch(this);1763 1764 GPRReg protoGPR = proto.gpr();1765 GPRReg resultGPR = result.gpr();1766 GPRReg scratchGPR = scratch.gpr();1767 1768 proto.use();1769 1770 MacroAssembler::JumpList slowPath;1771 1772 // Need to verify that the prototype is an object. If we have reason to believe1773 // that it's a FinalObject then we speculate on that directly. Otherwise we1774 // do the slow (structure-based) check.1775 if (shouldSpeculateFinalObject(node.child1()))1776 speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(protoGPR), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsFinalObjectVPtr)));1777 else {1778 m_jit.loadPtr(MacroAssembler::Address(protoGPR, JSCell::structureOffset()), scratchGPR);1779 slowPath.append(m_jit.branch8(MacroAssembler::Below, MacroAssembler::Address(scratchGPR, Structure::typeInfoTypeOffset()), MacroAssembler::TrustedImm32(ObjectType)));1780 }1781 1782 // Load the inheritorID (the Structure that objects who have protoGPR as the prototype1783 // use to refer to that prototype). If the inheritorID is not set, go to slow path.1784 m_jit.loadPtr(MacroAssembler::Address(protoGPR, JSObject::offsetOfInheritorID()), scratchGPR);1785 slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, scratchGPR));1786 1787 emitAllocateJSFinalObject(scratchGPR, resultGPR, scratchGPR, slowPath);1788 1789 MacroAssembler::Jump done = m_jit.jump();1790 1791 slowPath.link(&m_jit);1792 1793 silentSpillAllRegisters(resultGPR);1794 m_jit.move(protoGPR, GPRInfo::argumentGPR1);1795 m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);1796 appendCallWithExceptionCheck(operationCreateThis);1797 m_jit.move(GPRInfo::returnValueGPR, resultGPR);1798 silentFillAllRegisters(resultGPR);1799 1800 done.link(&m_jit);1801 1802 cellResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly);1803 break;1804 }1805 1806 case NewObject: {1807 GPRTemporary result(this);1808 GPRTemporary scratch(this);1809 1810 GPRReg resultGPR = result.gpr();1811 GPRReg scratchGPR = scratch.gpr();1812 1813 MacroAssembler::JumpList slowPath;1814 1815 emitAllocateJSFinalObject(MacroAssembler::TrustedImmPtr(m_jit.codeBlock()->globalObject()->emptyObjectStructure()), resultGPR, scratchGPR, slowPath);1816 1817 MacroAssembler::Jump done = m_jit.jump();1818 1819 slowPath.link(&m_jit);1820 1821 silentSpillAllRegisters(resultGPR);1822 m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);1823 appendCallWithExceptionCheck(operationNewObject);1824 m_jit.move(GPRInfo::returnValueGPR, resultGPR);1825 silentFillAllRegisters(resultGPR);1826 1827 done.link(&m_jit);1828 1829 cellResult(resultGPR, m_compileIndex);1830 break;1831 }1832 1833 case GetCallee: {1834 GPRTemporary result(this);1835 m_jit.loadPtr(JITCompiler::addressFor(static_cast<VirtualRegister>(RegisterFile::Callee)), result.gpr());1836 cellResult(result.gpr(), m_compileIndex);1837 break;1838 }1839 1840 case GetScopeChain: {1841 GPRTemporary result(this);1842 GPRReg resultGPR = result.gpr();1843 1844 m_jit.loadPtr(JITCompiler::addressFor(static_cast<VirtualRegister>(RegisterFile::ScopeChain)), resultGPR);1845 bool checkTopLevel = m_jit.codeBlock()->codeType() == FunctionCode && m_jit.codeBlock()->needsFullScopeChain();1846 int skip = node.scopeChainDepth();1847 ASSERT(skip || !checkTopLevel);1848 if (checkTopLevel && skip--) {1849 JITCompiler::Jump activationNotCreated;1850 if (checkTopLevel)1851 activationNotCreated = m_jit.branchTestPtr(JITCompiler::Zero, JITCompiler::addressFor(static_cast<VirtualRegister>(m_jit.codeBlock()->activationRegister())));1852 m_jit.loadPtr(JITCompiler::Address(resultGPR, OBJECT_OFFSETOF(ScopeChainNode, next)), resultGPR);1853 activationNotCreated.link(&m_jit);1854 }1855 while (skip--)1856 m_jit.loadPtr(JITCompiler::Address(resultGPR, OBJECT_OFFSETOF(ScopeChainNode, next)), resultGPR);1857 1858 m_jit.loadPtr(JITCompiler::Address(resultGPR, OBJECT_OFFSETOF(ScopeChainNode, object)), resultGPR);1859 1860 cellResult(resultGPR, m_compileIndex);1861 break;1862 }1863 case GetScopedVar: {1864 SpeculateCellOperand scopeChain(this, node.child1());1865 GPRTemporary result(this);1866 GPRReg resultGPR = result.gpr();1867 m_jit.loadPtr(JITCompiler::Address(scopeChain.gpr(), JSVariableObject::offsetOfRegisters()), resultGPR);1868 m_jit.loadPtr(JITCompiler::Address(resultGPR, node.varNumber() * sizeof(Register)), resultGPR);1869 jsValueResult(resultGPR, m_compileIndex);1870 break;1871 }1872 case PutScopedVar: {1873 SpeculateCellOperand scopeChain(this, node.child1());1874 GPRTemporary scratchRegister(this);1875 GPRReg scratchGPR = scratchRegister.gpr();1876 m_jit.loadPtr(JITCompiler::Address(scopeChain.gpr(), JSVariableObject::offsetOfRegisters()), scratchGPR);1877 JSValueOperand value(this, node.child2());1878 m_jit.storePtr(value.gpr(), JITCompiler::Address(scratchGPR, node.varNumber() * sizeof(Register)));1879 writeBarrier(scopeChain.gpr(), value.gpr(), node.child2(), WriteBarrierForVariableAccess, scratchGPR);1880 noResult(m_compileIndex);1881 break;1882 }1883 case GetById: {1884 SpeculateCellOperand base(this, node.child1());1885 GPRTemporary result(this, base);1886 1887 GPRReg baseGPR = base.gpr();1888 GPRReg resultGPR = result.gpr();1889 GPRReg scratchGPR;1890 1891 if (resultGPR == baseGPR)1892 scratchGPR = tryAllocate();1893 else1894 scratchGPR = resultGPR;1895 1896 base.use();1897 1898 cachedGetById(baseGPR, resultGPR, scratchGPR, node.identifierNumber());1899 1900 jsValueResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly);1901 break;1902 }1903 1904 case GetArrayLength: {1905 SpeculateCellOperand base(this, node.child1());1906 GPRTemporary result(this);1907 1908 GPRReg baseGPR = base.gpr();1909 GPRReg resultGPR = result.gpr();1910 1911 if (!isKnownArray(node.child1()))1912 speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));1913 1914 m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), resultGPR);1915 m_jit.load32(MacroAssembler::Address(resultGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), resultGPR);1916 1917 speculationCheck(m_jit.branch32(MacroAssembler::LessThan, resultGPR, MacroAssembler::TrustedImm32(0)));1918 1919 integerResult(resultGPR, m_compileIndex);1920 break;1921 }1922 1923 case CheckStructure: {1924 SpeculateCellOperand base(this, node.child1());1925 GPRTemporary result(this, base);1926 1927 GPRReg baseGPR = base.gpr();1928 GPRReg resultGPR = result.gpr();1929 1930 speculationCheck(m_jit.branchPtr(JITCompiler::NotEqual, JITCompiler::Address(baseGPR, JSCell::structureOffset()), JITCompiler::TrustedImmPtr(node.structure())));1931 1932 m_jit.loadPtr(JITCompiler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), resultGPR);1933 1934 storageResult(resultGPR, m_compileIndex);1935 break;1936 }1937 1938 case GetByOffset: {1939 StorageOperand storage(this, node.child1());1940 GPRTemporary result(this, storage);1941 1942 GPRReg storageGPR = storage.gpr();1943 GPRReg resultGPR = result.gpr();1944 1945 StorageAccessData& storageAccessData = m_jit.graph().m_storageAccessData[node.storageAccessDataIndex()];1946 1947 m_jit.loadPtr(JITCompiler::Address(storageGPR, storageAccessData.offset * sizeof(EncodedJSValue)), resultGPR);1948 1949 jsValueResult(resultGPR, m_compileIndex);1950 break;1951 }1952 1953 case GetMethod: {1954 SpeculateCellOperand base(this, node.child1());1955 GPRTemporary result(this, base);1956 1957 GPRReg baseGPR = base.gpr();1958 GPRReg resultGPR = result.gpr();1959 GPRReg scratchGPR;1960 1961 if (resultGPR == baseGPR)1962 scratchGPR = tryAllocate();1963 else1964 scratchGPR = resultGPR;1965 1966 base.use();1967 1968 cachedGetMethod(baseGPR, resultGPR, scratchGPR, node.identifierNumber());1969 1970 jsValueResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly);1971 break;1972 }1973 1974 case CheckMethod: {1975 MethodCheckData& methodCheckData = m_jit.graph().m_methodCheckData[node.methodCheckDataIndex()];1976 1977 SpeculateCellOperand base(this, node.child1());1978 GPRTemporary scratch(this); // this needs to be a separate register, unfortunately.1979 GPRReg baseGPR = base.gpr();1980 GPRReg scratchGPR = scratch.gpr();1981 1982 speculationCheck(m_jit.branchPtr(JITCompiler::NotEqual, JITCompiler::Address(baseGPR, JSCell::structureOffset()), JITCompiler::TrustedImmPtr(methodCheckData.structure)));1983 if (methodCheckData.prototype != m_jit.codeBlock()->globalObject()->methodCallDummy()) {1984 m_jit.move(JITCompiler::TrustedImmPtr(methodCheckData.prototype->structureAddress()), scratchGPR);1985 speculationCheck(m_jit.branchPtr(JITCompiler::NotEqual, JITCompiler::Address(scratchGPR), JITCompiler::TrustedImmPtr(methodCheckData.prototypeStructure)));1986 }1987 1988 useChildren(node);1989 initConstantInfo(m_compileIndex);1990 break;1991 }1992 1993 case PutById: {1994 SpeculateCellOperand base(this, node.child1());1995 JSValueOperand value(this, node.child2());1996 GPRTemporary scratch(this);1997 1998 GPRReg baseGPR = base.gpr();1999 GPRReg valueGPR = value.gpr();2000 GPRReg scratchGPR = scratch.gpr();2001 2002 base.use();2003 value.use();2004 2005 cachedPutById(baseGPR, valueGPR, node.child2(), scratchGPR, node.identifierNumber(), NotDirect);2006 2007 noResult(m_compileIndex, UseChildrenCalledExplicitly);2008 break;2009 }2010 2011 case PutByIdDirect: {2012 SpeculateCellOperand base(this, node.child1());2013 JSValueOperand value(this, node.child2());2014 GPRTemporary scratch(this);2015 2016 GPRReg baseGPR = base.gpr();2017 GPRReg valueGPR = value.gpr();2018 GPRReg scratchGPR = scratch.gpr();2019 2020 base.use();2021 value.use();2022 2023 cachedPutById(baseGPR, valueGPR, node.child2(), scratchGPR, node.identifierNumber(), Direct);2024 2025 noResult(m_compileIndex, UseChildrenCalledExplicitly);2026 break;2027 }2028 2029 case GetGlobalVar: {2030 GPRTemporary result(this);2031 2032 JSVariableObject* globalObject = m_jit.codeBlock()->globalObject();2033 m_jit.loadPtr(globalObject->addressOfRegisters(), result.gpr());2034 m_jit.loadPtr(JITCompiler::addressForGlobalVar(result.gpr(), node.varNumber()), result.gpr());2035 2036 jsValueResult(result.gpr(), m_compileIndex);2037 break;2038 }2039 2040 case PutGlobalVar: {2041 JSValueOperand value(this, node.child1());2042 GPRTemporary globalObject(this);2043 GPRTemporary scratch(this);2044 2045 GPRReg globalObjectReg = globalObject.gpr();2046 GPRReg scratchReg = scratch.gpr();2047 2048 m_jit.move(MacroAssembler::TrustedImmPtr(m_jit.codeBlock()->globalObject()), globalObjectReg);2049 2050 writeBarrier(m_jit.codeBlock()->globalObject(), value.gpr(), node.child1(), WriteBarrierForVariableAccess, scratchReg);2051 2052 m_jit.loadPtr(MacroAssembler::Address(globalObjectReg, JSVariableObject::offsetOfRegisters()), scratchReg);2053 m_jit.storePtr(value.gpr(), JITCompiler::addressForGlobalVar(scratchReg, node.varNumber()));2054 2055 noResult(m_compileIndex);2056 break;2057 }2058 2059 case CheckHasInstance: {2060 SpeculateCellOperand base(this, node.child1());2061 GPRTemporary structure(this);2062 2063 // Speculate that base 'ImplementsDefaultHasInstance'.2064 m_jit.loadPtr(MacroAssembler::Address(base.gpr(), JSCell::structureOffset()), structure.gpr());2065 speculationCheck(m_jit.branchTest8(MacroAssembler::Zero, MacroAssembler::Address(structure.gpr(), Structure::typeInfoFlagsOffset()), MacroAssembler::TrustedImm32(ImplementsDefaultHasInstance)));2066 2067 noResult(m_compileIndex);2068 break;2069 }2070 2071 case InstanceOf: {2072 SpeculateCellOperand value(this, node.child1());2073 // Base unused since we speculate default InstanceOf behaviour in CheckHasInstance.2074 SpeculateCellOperand prototype(this, node.child3());2075 2076 GPRTemporary scratch(this);2077 2078 GPRReg valueReg = value.gpr();2079 GPRReg prototypeReg = prototype.gpr();2080 GPRReg scratchReg = scratch.gpr();2081 2082 // Check that prototype is an object.2083 m_jit.loadPtr(MacroAssembler::Address(prototypeReg, JSCell::structureOffset()), scratchReg);2084 speculationCheck(m_jit.branchIfNotObject(scratchReg));2085 2086 // Initialize scratchReg with the value being checked.2087 m_jit.move(valueReg, scratchReg);2088 2089 // Walk up the prototype chain of the value (in scratchReg), comparing to prototypeReg.2090 MacroAssembler::Label loop(&m_jit);2091 m_jit.loadPtr(MacroAssembler::Address(scratchReg, JSCell::structureOffset()), scratchReg);2092 m_jit.loadPtr(MacroAssembler::Address(scratchReg, Structure::prototypeOffset()), scratchReg);2093 MacroAssembler::Jump isInstance = m_jit.branchPtr(MacroAssembler::Equal, scratchReg, prototypeReg);2094 m_jit.branchTestPtr(MacroAssembler::Zero, scratchReg, GPRInfo::tagMaskRegister).linkTo(loop, &m_jit);2095 2096 // No match - result is false.2097 m_jit.move(MacroAssembler::TrustedImmPtr(JSValue::encode(jsBoolean(false))), scratchReg);2098 MacroAssembler::Jump putResult = m_jit.jump();2099 2100 isInstance.link(&m_jit);2101 m_jit.move(MacroAssembler::TrustedImmPtr(JSValue::encode(jsBoolean(true))), scratchReg);2102 2103 putResult.link(&m_jit);2104 jsValueResult(scratchReg, m_compileIndex, DataFormatJSBoolean);2105 break;2106 }2107 2108 case Phi:2109 ASSERT_NOT_REACHED();2110 2111 case Breakpoint:2112 #if ENABLE(DEBUG_WITH_BREAKPOINT)2113 m_jit.breakpoint();2114 #else2115 ASSERT_NOT_REACHED();2116 #endif2117 break;2118 2119 case Call:2120 case Construct:2121 emitCall(node);2122 break;2123 2124 case Resolve: {2125 flushRegisters();2126 GPRResult result(this);2127 callOperation(operationResolve, result.gpr(), identifier(node.identifierNumber()));2128 jsValueResult(result.gpr(), m_compileIndex);2129 break;2130 }2131 2132 case ResolveBase: {2133 flushRegisters();2134 GPRResult result(this);2135 callOperation(operationResolveBase, result.gpr(), identifier(node.identifierNumber()));2136 jsValueResult(result.gpr(), m_compileIndex);2137 break;2138 }2139 2140 case ResolveBaseStrictPut: {2141 flushRegisters();2142 GPRResult result(this);2143 callOperation(operationResolveBaseStrictPut, result.gpr(), identifier(node.identifierNumber()));2144 jsValueResult(result.gpr(), m_compileIndex);2145 break;2146 }2147 2148 case ResolveGlobal: {2149 GPRTemporary globalObject(this);2150 GPRTemporary resolveInfo(this);2151 GPRTemporary result(this);2152 2153 GPRReg globalObjectGPR = globalObject.gpr();2154 GPRReg resolveInfoGPR = resolveInfo.gpr();2155 GPRReg resultGPR = result.gpr();2156 2157 ResolveGlobalData& data = m_jit.graph().m_resolveGlobalData[node.resolveGlobalDataIndex()];2158 GlobalResolveInfo* resolveInfoAddress = &(m_jit.codeBlock()->globalResolveInfo(data.resolveInfoIndex));2159 2160 // Check Structure of global object2161 m_jit.move(JITCompiler::TrustedImmPtr(m_jit.codeBlock()->globalObject()), globalObjectGPR);2162 m_jit.move(JITCompiler::TrustedImmPtr(resolveInfoAddress), resolveInfoGPR);2163 m_jit.loadPtr(JITCompiler::Address(resolveInfoGPR, OBJECT_OFFSETOF(GlobalResolveInfo, structure)), resultGPR);2164 JITCompiler::Jump structuresMatch = m_jit.branchPtr(JITCompiler::Equal, resultGPR, JITCompiler::Address(globalObjectGPR, JSCell::structureOffset()));2165 2166 silentSpillAllRegisters(resultGPR);2167 m_jit.move(resolveInfoGPR, GPRInfo::argumentGPR1);2168 m_jit.move(JITCompiler::TrustedImmPtr(&m_jit.codeBlock()->identifier(data.identifierNumber)), GPRInfo::argumentGPR2);2169 m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);2170 JITCompiler::Call functionCall = appendCallWithExceptionCheck(operationResolveGlobal);2171 m_jit.move(GPRInfo::returnValueGPR, resultGPR);2172 silentFillAllRegisters(resultGPR);2173 2174 JITCompiler::Jump wasSlow = m_jit.jump();2175 2176 // Fast case2177 structuresMatch.link(&m_jit);2178 m_jit.loadPtr(JITCompiler::Address(globalObjectGPR, JSObject::offsetOfPropertyStorage()), resultGPR);2179 m_jit.load32(JITCompiler::Address(resolveInfoGPR, OBJECT_OFFSETOF(GlobalResolveInfo, offset)), resolveInfoGPR);2180 m_jit.loadPtr(JITCompiler::BaseIndex(resultGPR, resolveInfoGPR, JITCompiler::ScalePtr), resultGPR);2181 2182 wasSlow.link(&m_jit);2183 2184 jsValueResult(resultGPR, m_compileIndex);2185 break;2186 }2187 2188 case ForceOSRExit: {2189 terminateSpeculativeExecution();2190 break;2191 }2192 2193 case Phantom:2194 // This is a no-op.2195 noResult(m_compileIndex);2196 break;2197 }2198 2199 if (node.hasResult() && node.mustGenerate())2200 use(m_compileIndex);2201 }2202 2203 197 void SpeculativeJIT::compileMovHint(Node& node) 2204 198 { … … 2213 207 ASSERT(m_compileOkay); 2214 208 ASSERT(m_compileIndex == block.begin); 2215 209 2216 210 if (block.isOSRTarget) 2217 211 m_jit.noticeOSREntry(block); 2218 212 2219 213 m_blockHeads[m_block] = m_jit.label(); 2220 214 #if ENABLE(DFG_JIT_BREAK_ON_EVERY_BLOCK) 2221 215 m_jit.breakpoint(); 2222 216 #endif 2223 217 2224 218 ASSERT(m_arguments.size() == block.m_argumentsAtHead.size()); 2225 219 for (size_t i = 0; i < m_arguments.size(); ++i) { … … 2276 270 if (info.registerFormat() == DataFormatDouble) 2277 271 fprintf(stderr, ", %s", FPRInfo::debugName(info.fpr())); 272 #if USE(JSVALUE32_64) 273 else if (info.registerFormat() & DataFormatJS) 274 fprintf(stderr, ", %s %s", GPRInfo::debugName(info.tagGPR()), GPRInfo::debugName(info.payloadGPR())); 275 #endif 2278 276 else 2279 277 fprintf(stderr, ", %s", GPRInfo::debugName(info.gpr())); … … 2294 292 computeValueRecoveryFor(operand).dump(stderr); 2295 293 #endif 2296 294 2297 295 #if ENABLE(DFG_DEBUG_VERBOSE) 2298 296 fprintf(stderr, "\n"); … … 2319 317 VirtualRegister virtualRegister = (VirtualRegister)(m_jit.codeBlock()->thisRegister() + i); 2320 318 PredictedType predictedType = m_jit.graph()[m_jit.graph().m_arguments[i]].variableAccessData()->prediction(); 319 #if USE(JSVALUE64) 2321 320 if (isInt32Prediction(predictedType)) 2322 321 speculationCheck(m_jit.branchPtr(MacroAssembler::Below, JITCompiler::addressFor(virtualRegister), GPRInfo::tagTypeNumberRegister)); … … 2332 331 speculationCheck(m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), TrustedImm32(static_cast<int32_t>(~1)))); 2333 332 } 333 #else 334 if (isInt32Prediction(predictedType)) 335 speculationCheck(m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag))); 336 else if (isArrayPrediction(predictedType)) { 337 GPRTemporary temp(this); 338 m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr()); 339 speculationCheck(m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag))); 340 m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr()); 341 speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr))); 342 } // FIXME: need boolean predictions, but we currently don't have that support. 343 #endif 2334 344 } 2335 345 } … … 2354 364 case Int32InRegisterFile: 2355 365 return ValueRecovery::alreadyInRegisterFileAsUnboxedInt32(); 2356 366 2357 367 case HaveNode: { 2358 368 if (m_jit.isConstant(valueSource.nodeIndex())) … … 2456 466 if (infoPtr->registerFormat() == DataFormatDouble) 2457 467 return ValueRecovery::inFPR(infoPtr->fpr()); 468 #if USE(JSVALUE32_64) 469 if (infoPtr->registerFormat() & DataFormatJS) 470 return ValueRecovery::inPair(infoPtr->tagGPR(), infoPtr->payloadGPR()); 471 #endif 2458 472 return ValueRecovery::inGPR(infoPtr->gpr(), infoPtr->registerFormat()); 2459 473 } … … 2474 488 2475 489 #endif 2476 #endif -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
r96375 r96379 579 579 // with the structure GPR being clobbered. 580 580 template<typename T> 581 void emitAllocateJSFinalObject(T structure, GPRReg resultGPR, GPRReg scratchGPR, MacroAssembler::JumpList& slowPath); 582 581 void emitAllocateJSFinalObject(T structure, GPRReg resultGPR, GPRReg scratchGPR, MacroAssembler::JumpList& slowPath) 582 { 583 MarkedSpace::SizeClass* sizeClass = &m_jit.globalData()->heap.sizeClassForObject(sizeof(JSFinalObject)); 584 585 m_jit.loadPtr(&sizeClass->firstFreeCell, resultGPR); 586 slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, resultGPR)); 587 588 // The object is half-allocated: we have what we know is a fresh object, but 589 // it's still on the GC's free list. 590 591 // Ditch the structure by placing it into the structure slot, so that we can reuse 592 // scratchGPR. 593 m_jit.storePtr(structure, MacroAssembler::Address(resultGPR, JSObject::structureOffset())); 594 595 // Now that we have scratchGPR back, remove the object from the free list 596 m_jit.loadPtr(MacroAssembler::Address(resultGPR), scratchGPR); 597 m_jit.storePtr(scratchGPR, &sizeClass->firstFreeCell); 598 599 // Initialize the object's vtable 600 m_jit.storePtr(MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsFinalObjectVPtr), MacroAssembler::Address(resultGPR)); 601 602 // Initialize the object's inheritorID. 603 m_jit.storePtr(MacroAssembler::TrustedImmPtr(0), MacroAssembler::Address(resultGPR, JSObject::offsetOfInheritorID())); 604 605 // Initialize the object's property storage pointer. 606 m_jit.addPtr(MacroAssembler::TrustedImm32(sizeof(JSObject)), resultGPR, scratchGPR); 607 m_jit.storePtr(scratchGPR, MacroAssembler::Address(resultGPR, JSFinalObject::offsetOfPropertyStorage())); 608 } 609 583 610 #if USE(JSVALUE64) 584 611 JITCompiler::Jump convertToDouble(GPRReg value, FPRReg result, GPRReg tmp); -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
r96375 r96379 28 28 29 29 #if ENABLE(DFG_JIT) 30 31 #include "DFGJITCompilerInlineMethods.h" 32 33 namespace JSC { namespace DFG { 34 30 35 #if USE(JSVALUE32_64) 31 #include "DFGJITCompilerInlineMethods.h"32 33 namespace JSC { namespace DFG {34 36 35 37 template<bool strict> … … 114 116 return InvalidGPRReg; 115 117 } 116 117 #ifndef NDEBUG118 void ValueSource::dump(FILE* out) const119 {120 switch (kind()) {121 case SourceNotSet:122 fprintf(out, "NotSet");123 break;124 case ValueInRegisterFile:125 fprintf(out, "InRegFile");126 break;127 case Int32InRegisterFile:128 fprintf(out, "Int32");129 break;130 case HaveNode:131 fprintf(out, "Node(%d)", m_nodeIndex);132 break;133 }134 }135 136 void ValueRecovery::dump(FILE* out) const137 {138 switch (technique()) {139 case AlreadyInRegisterFile:140 fprintf(out, "-");141 break;142 case AlreadyInRegisterFileAsUnboxedInt32:143 fprintf(out, "(int32)");144 break;145 case InGPR:146 fprintf(out, "%%%s", GPRInfo::debugName(gpr()));147 break;148 case UnboxedInt32InGPR:149 fprintf(out, "int32(%%%s)", GPRInfo::debugName(gpr()));150 break;151 case InFPR:152 fprintf(out, "%%%s", FPRInfo::debugName(fpr()));153 break;154 #if USE(JSVALUE32_64)155 case InPair:156 fprintf(out, "pair(%%%s, %%%s)", GPRInfo::debugName(tagGPR()), GPRInfo::debugName(payloadGPR()));157 break;158 #endif159 case DisplacedInRegisterFile:160 fprintf(out, "*%d", virtualRegister());161 break;162 case Constant:163 fprintf(out, "[%s]", constant().description());164 break;165 case DontKnow:166 fprintf(out, "!");167 break;168 default:169 fprintf(out, "?%d", technique());170 break;171 }172 }173 #endif174 175 OSRExit::OSRExit(MacroAssembler::Jump check, SpeculativeJIT* jit, unsigned recoveryIndex)176 : m_check(check)177 , m_nodeIndex(jit->m_compileIndex)178 , m_bytecodeIndex(jit->m_bytecodeIndexForOSR)179 , m_recoveryIndex(recoveryIndex)180 , m_arguments(jit->m_arguments.size())181 , m_variables(jit->m_variables.size())182 , m_lastSetOperand(jit->m_lastSetOperand)183 {184 ASSERT(m_bytecodeIndex != std::numeric_limits<uint32_t>::max());185 for (unsigned argument = 0; argument < m_arguments.size(); ++argument)186 m_arguments[argument] = jit->computeValueRecoveryFor(jit->m_arguments[argument]);187 for (unsigned variable = 0; variable < m_variables.size(); ++variable)188 m_variables[variable] = jit->computeValueRecoveryFor(jit->m_variables[variable]);189 }190 191 #ifndef NDEBUG192 void OSRExit::dump(FILE* out) const193 {194 for (unsigned argument = 0; argument < m_arguments.size(); ++argument)195 m_arguments[argument].dump(out);196 fprintf(out, " : ");197 for (unsigned variable = 0; variable < m_variables.size(); ++variable)198 m_variables[variable].dump(out);199 }200 #endif201 118 202 119 GPRReg SpeculativeJIT::fillSpeculateInt(NodeIndex nodeIndex, DataFormat& returnFormat) … … 412 329 } 413 330 414 void SpeculativeJIT::compilePeepHoleIntegerBranch(Node& node, NodeIndex branchNodeIndex, JITCompiler::RelationalCondition condition)415 {416 Node& branchNode = m_jit.graph()[branchNodeIndex];417 BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(branchNode.takenBytecodeOffset());418 BlockIndex notTaken = m_jit.graph().blockIndexForBytecodeOffset(branchNode.notTakenBytecodeOffset());419 420 // The branch instruction will branch to the taken block.421 // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.422 if (taken == (m_block + 1)) {423 condition = JITCompiler::invert(condition);424 BlockIndex tmp = taken;425 taken = notTaken;426 notTaken = tmp;427 }428 429 if (isInt32Constant(node.child1())) {430 int32_t imm = valueOfInt32Constant(node.child1());431 SpeculateIntegerOperand op2(this, node.child2());432 addBranch(m_jit.branch32(condition, JITCompiler::Imm32(imm), op2.gpr()), taken);433 } else if (isInt32Constant(node.child2())) {434 SpeculateIntegerOperand op1(this, node.child1());435 int32_t imm = valueOfInt32Constant(node.child2());436 addBranch(m_jit.branch32(condition, op1.gpr(), JITCompiler::Imm32(imm)), taken);437 } else {438 SpeculateIntegerOperand op1(this, node.child1());439 SpeculateIntegerOperand op2(this, node.child2());440 addBranch(m_jit.branch32(condition, op1.gpr(), op2.gpr()), taken);441 }442 443 // Check for fall through, otherwise we need to jump.444 if (notTaken != (m_block + 1))445 addBranch(m_jit.jump(), notTaken);446 }447 448 331 JITCompiler::Jump SpeculativeJIT::convertToDouble(JSValueOperand& op, FPRReg result) 449 332 { … … 460 343 461 344 return notNumber; 462 }463 464 void SpeculativeJIT::compilePeepHoleDoubleBranch(Node& node, NodeIndex branchNodeIndex, JITCompiler::DoubleCondition condition)465 {466 Node& branchNode = m_jit.graph()[branchNodeIndex];467 BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(branchNode.takenBytecodeOffset());468 BlockIndex notTaken = m_jit.graph().blockIndexForBytecodeOffset(branchNode.notTakenBytecodeOffset());469 470 SpeculateDoubleOperand op1(this, node.child1());471 SpeculateDoubleOperand op2(this, node.child2());472 473 addBranch(m_jit.branchDouble(condition, op1.fpr(), op2.fpr()), taken);474 475 if (notTaken != (m_block + 1))476 addBranch(m_jit.jump(), notTaken);477 }478 479 void SpeculativeJIT::compilePeepHoleObjectEquality(Node& node, NodeIndex branchNodeIndex, void* vptr)480 {481 Node& branchNode = m_jit.graph()[branchNodeIndex];482 BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(branchNode.takenBytecodeOffset());483 BlockIndex notTaken = m_jit.graph().blockIndexForBytecodeOffset(branchNode.notTakenBytecodeOffset());484 485 MacroAssembler::RelationalCondition condition = MacroAssembler::Equal;486 487 if (taken == (m_block + 1)) {488 condition = MacroAssembler::NotEqual;489 BlockIndex tmp = taken;490 taken = notTaken;491 notTaken = tmp;492 }493 494 SpeculateCellOperand op1(this, node.child1());495 SpeculateCellOperand op2(this, node.child2());496 497 GPRReg op1GPR = op1.gpr();498 GPRReg op2GPR = op2.gpr();499 500 speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1GPR), MacroAssembler::TrustedImmPtr(vptr)));501 speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op2GPR), MacroAssembler::TrustedImmPtr(vptr)));502 503 addBranch(m_jit.branchPtr(condition, op1GPR, op2GPR), taken);504 if (notTaken != (m_block + 1))505 addBranch(m_jit.jump(), notTaken);506 345 } 507 346 … … 556 395 } else if (node.op == CompareEq && shouldSpeculateArray(node.child1(), node.child2())) { 557 396 compilePeepHoleObjectEquality(node, branchNodeIndex, m_jit.globalData()->jsArrayVPtr); 558 // } else if (isKnownNumeric(node.child1()) || isKnownNumeric(node.child2())) {559 // compilePeepHoleDoubleBranch(node, branchNodeIndex, doubleCondition, operation);560 397 use(node.child1()); 561 398 use(node.child2()); … … 567 404 } 568 405 569 // if (isKnownNotInteger(node.child1()) || isKnownNotInteger(node.child2()))570 406 if (shouldSpeculateFinalObject(node.child1(), node.child2())) 571 407 compileObjectEquality(node, m_jit.globalData()->jsFinalObjectVPtr); … … 603 439 604 440 return false; 605 }606 607 template<typename T>608 void SpeculativeJIT::emitAllocateJSFinalObject(T structure, GPRReg resultGPR, GPRReg scratchGPR, MacroAssembler::JumpList& slowPath)609 {610 MarkedSpace::SizeClass* sizeClass = &m_jit.globalData()->heap.sizeClassForObject(sizeof(JSFinalObject));611 612 m_jit.loadPtr(&sizeClass->firstFreeCell, resultGPR);613 slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, resultGPR));614 615 // The object is half-allocated: we have what we know is a fresh object, but616 // it's still on the GC's free list.617 618 // Ditch the structure by placing it into the structure slot, so that we can reuse619 // scratchGPR.620 m_jit.storePtr(structure, MacroAssembler::Address(resultGPR, JSObject::structureOffset()));621 622 // Now that we have scratchGPR back, remove the object from the free list623 m_jit.loadPtr(MacroAssembler::Address(resultGPR), scratchGPR);624 m_jit.storePtr(scratchGPR, &sizeClass->firstFreeCell);625 626 // Initialize the object's vtable627 m_jit.storePtr(MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsFinalObjectVPtr), MacroAssembler::Address(resultGPR));628 629 // Initialize the object's inheritorID.630 m_jit.storePtr(MacroAssembler::TrustedImmPtr(0), MacroAssembler::Address(resultGPR, JSObject::offsetOfInheritorID()));631 632 // Initialize the object's property storage pointer.633 m_jit.addPtr(MacroAssembler::TrustedImm32(sizeof(JSObject)), resultGPR, scratchGPR);634 m_jit.storePtr(scratchGPR, MacroAssembler::Address(resultGPR, JSFinalObject::offsetOfPropertyStorage()));635 441 } 636 442 … … 2134 1940 } 2135 1941 2136 void SpeculativeJIT::compileMovHint(Node& node)2137 {2138 ASSERT(node.op == SetLocal);2139 2140 setNodeIndexForOperand(node.child1(), node.local());2141 m_lastSetOperand = node.local();2142 }2143 2144 void SpeculativeJIT::compile(BasicBlock& block)2145 {2146 ASSERT(m_compileOkay);2147 ASSERT(m_compileIndex == block.begin);2148 2149 if (block.isOSRTarget)2150 m_jit.noticeOSREntry(block);2151 2152 m_blockHeads[m_block] = m_jit.label();2153 #if ENABLE(DFG_JIT_BREAK_ON_EVERY_BLOCK)2154 m_jit.breakpoint();2155 1942 #endif 2156 1943 2157 ASSERT(m_arguments.size() == block.m_argumentsAtHead.size()); 2158 for (size_t i = 0; i < m_arguments.size(); ++i) { 2159 NodeIndex nodeIndex = block.m_argumentsAtHead[i].value; 2160 if (nodeIndex == NoNode) 2161 m_arguments[i] = ValueSource(ValueInRegisterFile); 2162 else 2163 m_arguments[i] = ValueSource::forPrediction(m_jit.graph()[nodeIndex].variableAccessData()->prediction()); 2164 } 2165 2166 ASSERT(m_variables.size() == block.m_localsAtHead.size()); 2167 for (size_t i = 0; i < m_variables.size(); ++i) { 2168 NodeIndex nodeIndex = block.m_localsAtHead[i].value; 2169 if (nodeIndex == NoNode) 2170 m_variables[i] = ValueSource(ValueInRegisterFile); 2171 else 2172 m_variables[i] = ValueSource::forPrediction(m_jit.graph()[nodeIndex].variableAccessData()->prediction()); 2173 } 2174 2175 m_lastSetOperand = std::numeric_limits<int>::max(); 2176 m_bytecodeIndexForOSR = std::numeric_limits<uint32_t>::max(); 2177 2178 for (; m_compileIndex < block.end; ++m_compileIndex) { 2179 Node& node = m_jit.graph()[m_compileIndex]; 2180 m_bytecodeIndexForOSR = node.codeOrigin.bytecodeIndex(); 2181 if (!node.shouldGenerate()) { 2182 #if ENABLE(DFG_DEBUG_VERBOSE) 2183 fprintf(stderr, "SpeculativeJIT skipping Node @%d (bc#%u) at JIT offset 0x%x ", (int)m_compileIndex, node.codeOrigin.bytecodeIndex(), m_jit.debugOffset()); 1944 } } // namespace JSC::DFG 1945 2184 1946 #endif 2185 if (node.op == SetLocal)2186 compileMovHint(node);2187 } else {2188 2189 #if ENABLE(DFG_DEBUG_VERBOSE)2190 fprintf(stderr, "SpeculativeJIT generating Node @%d (bc#%u) at JIT offset 0x%x ", (int)m_compileIndex, node.codeOrigin.bytecodeIndex(), m_jit.debugOffset());2191 #endif2192 #if ENABLE(DFG_JIT_BREAK_ON_EVERY_NODE)2193 m_jit.breakpoint();2194 #endif2195 checkConsistency();2196 compile(node);2197 if (!m_compileOkay) {2198 m_compileOkay = true;2199 m_compileIndex = block.end;2200 clearGenerationInfo();2201 return;2202 }2203 2204 #if ENABLE(DFG_DEBUG_VERBOSE)2205 if (node.hasResult()) {2206 GenerationInfo& info = m_generationInfo[node.virtualRegister()];2207 fprintf(stderr, "-> %s, vr#%d", dataFormatToString(info.registerFormat()), (int)node.virtualRegister());2208 if (info.registerFormat() != DataFormatNone) {2209 if (info.registerFormat() == DataFormatDouble)2210 fprintf(stderr, ", %s", FPRInfo::debugName(info.fpr()));2211 else if (!(info.registerFormat() & DataFormatJS))2212 fprintf(stderr, ", %s", GPRInfo::debugName(info.gpr()));2213 else2214 fprintf(stderr, ", %s %s", GPRInfo::debugName(info.tagGPR()), GPRInfo::debugName(info.payloadGPR()));2215 }2216 fprintf(stderr, " ");2217 } else2218 fprintf(stderr, " ");2219 #endif2220 }2221 2222 #if ENABLE(DFG_VERBOSE_VALUE_RECOVERIES)2223 for (int operand = -m_arguments.size() - RegisterFile::CallFrameHeaderSize; operand < -RegisterFile::CallFrameHeaderSize; ++operand)2224 computeValueRecoveryFor(operand).dump(stderr);2225 2226 fprintf(stderr, " : ");2227 2228 for (int operand = 0; operand < (int)m_variables.size(); ++operand)2229 computeValueRecoveryFor(operand).dump(stderr);2230 #endif2231 2232 #if ENABLE(DFG_DEBUG_VERBOSE)2233 fprintf(stderr, "\n");2234 #endif2235 2236 if (node.shouldGenerate())2237 checkConsistency();2238 }2239 }2240 2241 // If we are making type predictions about our arguments then2242 // we need to check that they are correct on function entry.2243 void SpeculativeJIT::checkArgumentTypes()2244 {2245 ASSERT(!m_compileIndex);2246 m_bytecodeIndexForOSR = 0;2247 2248 for (size_t i = 0; i < m_arguments.size(); ++i)2249 m_arguments[i] = ValueSource(ValueInRegisterFile);2250 for (size_t i = 0; i < m_variables.size(); ++i)2251 m_variables[i] = ValueSource(ValueInRegisterFile);2252 2253 for (int i = 0; i < m_jit.codeBlock()->m_numParameters; ++i) {2254 VirtualRegister virtualRegister = (VirtualRegister)(m_jit.codeBlock()->thisRegister() + i);2255 PredictedType predictedType = m_jit.graph()[m_jit.graph().m_arguments[i]].variableAccessData()->prediction();2256 if (isInt32Prediction(predictedType))2257 speculationCheck(m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag)));2258 else if (isArrayPrediction(predictedType)) {2259 GPRTemporary temp(this);2260 m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr());2261 speculationCheck(m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag)));2262 m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr());2263 speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));2264 } // FIXME: need boolean predictions, but we currently don't have that support.2265 }2266 }2267 2268 bool SpeculativeJIT::compile()2269 {2270 checkArgumentTypes();2271 2272 ASSERT(!m_compileIndex);2273 for (m_block = 0; m_block < m_jit.graph().m_blocks.size(); ++m_block)2274 compile(*m_jit.graph().m_blocks[m_block]);2275 linkBranches();2276 return true;2277 }2278 2279 ValueRecovery SpeculativeJIT::computeValueRecoveryFor(const ValueSource& valueSource)2280 {2281 switch (valueSource.kind()) {2282 case ValueInRegisterFile:2283 return ValueRecovery::alreadyInRegisterFile();2284 2285 case Int32InRegisterFile:2286 return ValueRecovery::alreadyInRegisterFileAsUnboxedInt32();2287 2288 case HaveNode: {2289 if (m_jit.isConstant(valueSource.nodeIndex()))2290 return ValueRecovery::constant(m_jit.valueOfJSConstant(valueSource.nodeIndex()));2291 2292 Node* nodePtr = &m_jit.graph()[valueSource.nodeIndex()];2293 if (!nodePtr->shouldGenerate()) {2294 // It's legitimately dead. As in, nobody will ever use this node, or operand,2295 // ever. Set it to Undefined to make the GC happy after the OSR.2296 return ValueRecovery::constant(jsUndefined());2297 }2298 2299 GenerationInfo* infoPtr = &m_generationInfo[nodePtr->virtualRegister()];2300 if (!infoPtr->alive() || infoPtr->nodeIndex() != valueSource.nodeIndex()) {2301 // Try to see if there is an alternate node that would contain the value we want.2302 // There are four possibilities:2303 //2304 // ValueToNumber: If the only live version of the value is a ValueToNumber node2305 // then it means that all remaining uses of the value would have performed a2306 // ValueToNumber conversion anyway. Thus, we can substitute ValueToNumber.2307 //2308 // ValueToInt32: Likewise, if the only remaining live version of the value is2309 // ValueToInt32, then we can use it. But if there is both a ValueToInt322310 // and a ValueToNumber, then we better go with ValueToNumber because it2311 // means that some remaining uses would have converted to number while2312 // others would have converted to Int32.2313 //2314 // UInt32ToNumber: If the only live version of the value is a UInt32ToNumber2315 // then the only remaining uses are ones that want a properly formed number2316 // rather than a UInt32 intermediate.2317 //2318 // The reverse of the above: This node could be a UInt32ToNumber, but its2319 // alternative is still alive. This means that the only remaining uses of2320 // the number would be fine with a UInt32 intermediate.2321 2322 bool found = false;2323 2324 if (nodePtr->op == UInt32ToNumber) {2325 NodeIndex nodeIndex = nodePtr->child1();2326 nodePtr = &m_jit.graph()[nodeIndex];2327 infoPtr = &m_generationInfo[nodePtr->virtualRegister()];2328 if (infoPtr->alive() && infoPtr->nodeIndex() == nodeIndex)2329 found = true;2330 }2331 2332 if (!found) {2333 NodeIndex valueToNumberIndex = NoNode;2334 NodeIndex valueToInt32Index = NoNode;2335 NodeIndex uint32ToNumberIndex = NoNode;2336 2337 for (unsigned virtualRegister = 0; virtualRegister < m_generationInfo.size(); ++virtualRegister) {2338 GenerationInfo& info = m_generationInfo[virtualRegister];2339 if (!info.alive())2340 continue;2341 if (info.nodeIndex() == NoNode)2342 continue;2343 Node& node = m_jit.graph()[info.nodeIndex()];2344 if (node.child1Unchecked() != valueSource.nodeIndex())2345 continue;2346 switch (node.op) {2347 case ValueToNumber:2348 case ValueToDouble:2349 valueToNumberIndex = info.nodeIndex();2350 break;2351 case ValueToInt32:2352 valueToInt32Index = info.nodeIndex();2353 break;2354 case UInt32ToNumber:2355 uint32ToNumberIndex = info.nodeIndex();2356 break;2357 default:2358 break;2359 }2360 }2361 2362 NodeIndex nodeIndexToUse;2363 if (valueToNumberIndex != NoNode)2364 nodeIndexToUse = valueToNumberIndex;2365 else if (valueToInt32Index != NoNode)2366 nodeIndexToUse = valueToInt32Index;2367 else if (uint32ToNumberIndex != NoNode)2368 nodeIndexToUse = uint32ToNumberIndex;2369 else2370 nodeIndexToUse = NoNode;2371 2372 if (nodeIndexToUse != NoNode) {2373 nodePtr = &m_jit.graph()[nodeIndexToUse];2374 infoPtr = &m_generationInfo[nodePtr->virtualRegister()];2375 ASSERT(infoPtr->alive() && infoPtr->nodeIndex() == nodeIndexToUse);2376 found = true;2377 }2378 }2379 2380 if (!found)2381 return ValueRecovery::constant(jsUndefined());2382 }2383 2384 ASSERT(infoPtr->alive());2385 2386 if (infoPtr->registerFormat() != DataFormatNone) {2387 if (infoPtr->registerFormat() == DataFormatDouble)2388 return ValueRecovery::inFPR(infoPtr->fpr());2389 if (infoPtr->registerFormat() & DataFormatJS)2390 return ValueRecovery::inPair(infoPtr->tagGPR(), infoPtr->payloadGPR());2391 return ValueRecovery::inGPR(infoPtr->gpr(), infoPtr->registerFormat());2392 }2393 if (infoPtr->spillFormat() != DataFormatNone)2394 return ValueRecovery::displacedInRegisterFile(static_cast<VirtualRegister>(nodePtr->virtualRegister()));2395 2396 ASSERT_NOT_REACHED();2397 return ValueRecovery();2398 }2399 2400 default:2401 ASSERT_NOT_REACHED();2402 return ValueRecovery();2403 }2404 }2405 2406 } } // namespace JSC::DFG2407 2408 #endif2409 #endif -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
r96376 r96379 25 25 26 26 #include "config.h" 27 28 27 #include "DFGSpeculativeJIT.h" 29 28 30 29 #if ENABLE(DFG_JIT) 30 31 namespace JSC { namespace DFG { 32 31 33 #if USE(JSVALUE64) 32 33 namespace JSC { namespace DFG {34 34 35 35 template<bool strict> … … 144 144 return allocate(); 145 145 } 146 146 147 147 case DataFormatStorage: 148 148 ASSERT_NOT_REACHED(); … … 152 152 return InvalidGPRReg; 153 153 } 154 155 #ifndef NDEBUG156 void ValueSource::dump(FILE* out) const157 {158 switch (kind()) {159 case SourceNotSet:160 fprintf(out, "NotSet");161 break;162 case ValueInRegisterFile:163 fprintf(out, "InRegFile");164 break;165 case Int32InRegisterFile:166 fprintf(out, "Int32");167 break;168 case HaveNode:169 fprintf(out, "Node(%d)", m_nodeIndex);170 break;171 }172 }173 174 void ValueRecovery::dump(FILE* out) const175 {176 switch (technique()) {177 case AlreadyInRegisterFile:178 fprintf(out, "-");179 break;180 case AlreadyInRegisterFileAsUnboxedInt32:181 fprintf(out, "(int32)");182 break;183 case InGPR:184 fprintf(out, "%%%s", GPRInfo::debugName(gpr()));185 break;186 case UnboxedInt32InGPR:187 fprintf(out, "int32(%%%s)", GPRInfo::debugName(gpr()));188 break;189 case InFPR:190 fprintf(out, "%%%s", FPRInfo::debugName(fpr()));191 break;192 case DisplacedInRegisterFile:193 fprintf(out, "*%d", virtualRegister());194 break;195 case Constant:196 fprintf(out, "[%s]", constant().description());197 break;198 case DontKnow:199 fprintf(out, "!");200 break;201 default:202 fprintf(out, "?%d", technique());203 break;204 }205 }206 #endif207 208 OSRExit::OSRExit(MacroAssembler::Jump check, SpeculativeJIT* jit, unsigned recoveryIndex)209 : m_check(check)210 , m_nodeIndex(jit->m_compileIndex)211 , m_bytecodeIndex(jit->m_bytecodeIndexForOSR)212 , m_recoveryIndex(recoveryIndex)213 , m_arguments(jit->m_arguments.size())214 , m_variables(jit->m_variables.size())215 , m_lastSetOperand(jit->m_lastSetOperand)216 {217 ASSERT(m_bytecodeIndex != std::numeric_limits<uint32_t>::max());218 for (unsigned argument = 0; argument < m_arguments.size(); ++argument)219 m_arguments[argument] = jit->computeValueRecoveryFor(jit->m_arguments[argument]);220 for (unsigned variable = 0; variable < m_variables.size(); ++variable)221 m_variables[variable] = jit->computeValueRecoveryFor(jit->m_variables[variable]);222 }223 224 #ifndef NDEBUG225 void OSRExit::dump(FILE* out) const226 {227 for (unsigned argument = 0; argument < m_arguments.size(); ++argument)228 m_arguments[argument].dump(out);229 fprintf(out, " : ");230 for (unsigned variable = 0; variable < m_variables.size(); ++variable)231 m_variables[variable].dump(out);232 }233 #endif234 154 235 155 GPRReg SpeculativeJIT::fillSpeculateInt(NodeIndex nodeIndex, DataFormat& returnFormat) … … 429 349 return allocate(); 430 350 } 431 351 432 352 case DataFormatStorage: 433 353 ASSERT_NOT_REACHED(); … … 509 429 ASSERT_NOT_REACHED(); 510 430 return InvalidGPRReg; 511 }512 513 void SpeculativeJIT::compilePeepHoleIntegerBranch(Node& node, NodeIndex branchNodeIndex, JITCompiler::RelationalCondition condition)514 {515 Node& branchNode = m_jit.graph()[branchNodeIndex];516 BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(branchNode.takenBytecodeOffset());517 BlockIndex notTaken = m_jit.graph().blockIndexForBytecodeOffset(branchNode.notTakenBytecodeOffset());518 519 // The branch instruction will branch to the taken block.520 // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.521 if (taken == (m_block + 1)) {522 condition = JITCompiler::invert(condition);523 BlockIndex tmp = taken;524 taken = notTaken;525 notTaken = tmp;526 }527 528 if (isInt32Constant(node.child1())) {529 int32_t imm = valueOfInt32Constant(node.child1());530 SpeculateIntegerOperand op2(this, node.child2());531 addBranch(m_jit.branch32(condition, JITCompiler::Imm32(imm), op2.gpr()), taken);532 } else if (isInt32Constant(node.child2())) {533 SpeculateIntegerOperand op1(this, node.child1());534 int32_t imm = valueOfInt32Constant(node.child2());535 addBranch(m_jit.branch32(condition, op1.gpr(), JITCompiler::Imm32(imm)), taken);536 } else {537 SpeculateIntegerOperand op1(this, node.child1());538 SpeculateIntegerOperand op2(this, node.child2());539 addBranch(m_jit.branch32(condition, op1.gpr(), op2.gpr()), taken);540 }541 542 // Check for fall through, otherwise we need to jump.543 if (notTaken != (m_block + 1))544 addBranch(m_jit.jump(), notTaken);545 431 } 546 432 … … 563 449 564 450 return notNumber; 565 }566 567 void SpeculativeJIT::compilePeepHoleDoubleBranch(Node& node, NodeIndex branchNodeIndex, JITCompiler::DoubleCondition condition)568 {569 Node& branchNode = m_jit.graph()[branchNodeIndex];570 BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(branchNode.takenBytecodeOffset());571 BlockIndex notTaken = m_jit.graph().blockIndexForBytecodeOffset(branchNode.notTakenBytecodeOffset());572 573 SpeculateDoubleOperand op1(this, node.child1());574 SpeculateDoubleOperand op2(this, node.child2());575 576 addBranch(m_jit.branchDouble(condition, op1.fpr(), op2.fpr()), taken);577 578 if (notTaken != (m_block + 1))579 addBranch(m_jit.jump(), notTaken);580 }581 582 void SpeculativeJIT::compilePeepHoleObjectEquality(Node& node, NodeIndex branchNodeIndex, void* vptr)583 {584 Node& branchNode = m_jit.graph()[branchNodeIndex];585 BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(branchNode.takenBytecodeOffset());586 BlockIndex notTaken = m_jit.graph().blockIndexForBytecodeOffset(branchNode.notTakenBytecodeOffset());587 588 MacroAssembler::RelationalCondition condition = MacroAssembler::Equal;589 590 if (taken == (m_block + 1)) {591 condition = MacroAssembler::NotEqual;592 BlockIndex tmp = taken;593 taken = notTaken;594 notTaken = tmp;595 }596 597 SpeculateCellOperand op1(this, node.child1());598 SpeculateCellOperand op2(this, node.child2());599 600 GPRReg op1GPR = op1.gpr();601 GPRReg op2GPR = op2.gpr();602 603 speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1GPR), MacroAssembler::TrustedImmPtr(vptr)));604 speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op2GPR), MacroAssembler::TrustedImmPtr(vptr)));605 606 addBranch(m_jit.branchPtr(condition, op1GPR, op2GPR), taken);607 if (notTaken != (m_block + 1))608 addBranch(m_jit.jump(), notTaken);609 451 } 610 452 … … 696 538 } 697 539 698 template<typename T>699 void SpeculativeJIT::emitAllocateJSFinalObject(T structure, GPRReg resultGPR, GPRReg scratchGPR, MacroAssembler::JumpList& slowPath)700 {701 MarkedSpace::SizeClass* sizeClass = &m_jit.globalData()->heap.sizeClassForObject(sizeof(JSFinalObject));702 703 m_jit.loadPtr(&sizeClass->firstFreeCell, resultGPR);704 slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, resultGPR));705 706 // The object is half-allocated: we have what we know is a fresh object, but707 // it's still on the GC's free list.708 709 // Ditch the structure by placing it into the structure slot, so that we can reuse710 // scratchGPR.711 m_jit.storePtr(structure, MacroAssembler::Address(resultGPR, JSObject::structureOffset()));712 713 // Now that we have scratchGPR back, remove the object from the free list714 m_jit.loadPtr(MacroAssembler::Address(resultGPR), scratchGPR);715 m_jit.storePtr(scratchGPR, &sizeClass->firstFreeCell);716 717 // Initialize the object's vtable718 m_jit.storePtr(MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsFinalObjectVPtr), MacroAssembler::Address(resultGPR));719 720 // Initialize the object's inheritorID.721 m_jit.storePtr(MacroAssembler::TrustedImmPtr(0), MacroAssembler::Address(resultGPR, JSObject::offsetOfInheritorID()));722 723 // Initialize the object's property storage pointer.724 m_jit.addPtr(MacroAssembler::TrustedImm32(sizeof(JSObject)), resultGPR, scratchGPR);725 m_jit.storePtr(scratchGPR, MacroAssembler::Address(resultGPR, JSFinalObject::offsetOfPropertyStorage()));726 }727 728 540 void SpeculativeJIT::compile(Node& node) 729 541 { … … 768 580 else 769 581 format = DataFormatJS; 770 582 771 583 m_generationInfo[virtualRegister].initJSValue(m_compileIndex, node.refCount(), result.gpr(), format); 772 584 } … … 831 643 noResult(m_compileIndex); 832 644 } 833 645 834 646 // Indicate that it's no longer necessary to retrieve the value of 835 647 // this bytecode variable from registers or other locations in the register file. … … 837 649 break; 838 650 } 839 651 840 652 case SetArgument: 841 653 // This is a no-op; it just marks the fact that the argument is being used. … … 918 730 doubleResult(outputFPR, m_compileIndex); 919 731 } 920 732 921 733 IntegerOperand op1(this, node.child1()); 922 734 GPRTemporary result(this, op1); … … 929 741 break; 930 742 } 931 743 932 744 case ValueToInt32: { 933 745 if (shouldNotSpeculateInteger(node.child1())) { … … 981 793 SpeculateIntegerOperand op2(this, node.child2()); 982 794 GPRTemporary result(this); 983 795 984 796 if (nodeCanTruncateInteger(node.arithNodeFlags())) { 985 797 m_jit.move(op2.gpr(), result.gpr()); … … 1014 826 GPRReg gpr2 = op2.gpr(); 1015 827 GPRReg gprResult = result.gpr(); 1016 828 1017 829 if (nodeCanTruncateInteger(node.arithNodeFlags())) { 1018 830 if (gpr1 == gprResult) … … 1041 853 SpeculateDoubleOperand op2(this, node.child2()); 1042 854 FPRTemporary result(this, op1, op2); 1043 855 1044 856 FPRReg reg1 = op1.fpr(); 1045 857 FPRReg reg2 = op2.fpr(); 1046 858 m_jit.addDouble(reg1, reg2, result.fpr()); 1047 859 1048 860 doubleResult(result.fpr(), m_compileIndex); 1049 861 break; 1050 862 } 1051 863 1052 864 ASSERT(op == ValueAdd); 1053 865 1054 866 JSValueOperand op1(this, node.child1()); 1055 867 JSValueOperand op2(this, node.child2()); … … 1121 933 GPRReg reg1 = op1.gpr(); 1122 934 GPRReg reg2 = op2.gpr(); 1123 935 1124 936 // What is unfortunate is that we cannot take advantage of nodeCanTruncateInteger() 1125 937 // here. A multiply on integers performed in the double domain and then truncated to … … 1143 955 break; 1144 956 } 1145 957 1146 958 SpeculateDoubleOperand op1(this, node.child1()); 1147 959 SpeculateDoubleOperand op2(this, node.child2()); … … 1252 1064 break; 1253 1065 } 1254 1066 1255 1067 case ArithAbs: { 1256 1068 if (shouldSpeculateInteger(node.child1()) && nodeCanSpeculateInteger(node.arithNodeFlags())) { … … 1971 1783 break; 1972 1784 } 1973 1785 1974 1786 case CheckMethod: { 1975 1787 MethodCheckData& methodCheckData = m_jit.graph().m_methodCheckData[node.methodCheckDataIndex()]; … … 2196 2008 break; 2197 2009 } 2198 2010 2199 2011 if (node.hasResult() && node.mustGenerate()) 2200 2012 use(m_compileIndex); 2201 2013 } 2202 2014 2203 void SpeculativeJIT::compileMovHint(Node& node)2204 {2205 ASSERT(node.op == SetLocal);2206 2207 setNodeIndexForOperand(node.child1(), node.local());2208 m_lastSetOperand = node.local();2209 }2210 2211 void SpeculativeJIT::compile(BasicBlock& block)2212 {2213 ASSERT(m_compileOkay);2214 ASSERT(m_compileIndex == block.begin);2215 2216 if (block.isOSRTarget)2217 m_jit.noticeOSREntry(block);2218 2219 m_blockHeads[m_block] = m_jit.label();2220 #if ENABLE(DFG_JIT_BREAK_ON_EVERY_BLOCK)2221 m_jit.breakpoint();2222 2015 #endif 2223 2224 ASSERT(m_arguments.size() == block.m_argumentsAtHead.size()); 2225 for (size_t i = 0; i < m_arguments.size(); ++i) { 2226 NodeIndex nodeIndex = block.m_argumentsAtHead[i].value; 2227 if (nodeIndex == NoNode) 2228 m_arguments[i] = ValueSource(ValueInRegisterFile); 2229 else 2230 m_arguments[i] = ValueSource::forPrediction(m_jit.graph()[nodeIndex].variableAccessData()->prediction()); 2231 } 2232 2233 ASSERT(m_variables.size() == block.m_localsAtHead.size()); 2234 for (size_t i = 0; i < m_variables.size(); ++i) { 2235 NodeIndex nodeIndex = block.m_localsAtHead[i].value; 2236 if (nodeIndex == NoNode) 2237 m_variables[i] = ValueSource(ValueInRegisterFile); 2238 else 2239 m_variables[i] = ValueSource::forPrediction(m_jit.graph()[nodeIndex].variableAccessData()->prediction()); 2240 } 2241 2242 m_lastSetOperand = std::numeric_limits<int>::max(); 2243 m_bytecodeIndexForOSR = std::numeric_limits<uint32_t>::max(); 2244 2245 for (; m_compileIndex < block.end; ++m_compileIndex) { 2246 Node& node = m_jit.graph()[m_compileIndex]; 2247 m_bytecodeIndexForOSR = node.codeOrigin.bytecodeIndex(); 2248 if (!node.shouldGenerate()) { 2249 #if ENABLE(DFG_DEBUG_VERBOSE) 2250 fprintf(stderr, "SpeculativeJIT skipping Node @%d (bc#%u) at JIT offset 0x%x ", (int)m_compileIndex, node.codeOrigin.bytecodeIndex(), m_jit.debugOffset()); 2016 2017 } } // namespace JSC::DFG 2018 2251 2019 #endif 2252 if (node.op == SetLocal)2253 compileMovHint(node);2254 } else {2255 2256 #if ENABLE(DFG_DEBUG_VERBOSE)2257 fprintf(stderr, "SpeculativeJIT generating Node @%d (bc#%u) at JIT offset 0x%x ", (int)m_compileIndex, node.codeOrigin.bytecodeIndex(), m_jit.debugOffset());2258 #endif2259 #if ENABLE(DFG_JIT_BREAK_ON_EVERY_NODE)2260 m_jit.breakpoint();2261 #endif2262 checkConsistency();2263 compile(node);2264 if (!m_compileOkay) {2265 m_compileOkay = true;2266 m_compileIndex = block.end;2267 clearGenerationInfo();2268 return;2269 }2270 2271 #if ENABLE(DFG_DEBUG_VERBOSE)2272 if (node.hasResult()) {2273 GenerationInfo& info = m_generationInfo[node.virtualRegister()];2274 fprintf(stderr, "-> %s, vr#%d", dataFormatToString(info.registerFormat()), (int)node.virtualRegister());2275 if (info.registerFormat() != DataFormatNone) {2276 if (info.registerFormat() == DataFormatDouble)2277 fprintf(stderr, ", %s", FPRInfo::debugName(info.fpr()));2278 else2279 fprintf(stderr, ", %s", GPRInfo::debugName(info.gpr()));2280 }2281 fprintf(stderr, " ");2282 } else2283 fprintf(stderr, " ");2284 #endif2285 }2286 2287 #if ENABLE(DFG_VERBOSE_VALUE_RECOVERIES)2288 for (int operand = -m_arguments.size() - RegisterFile::CallFrameHeaderSize; operand < -RegisterFile::CallFrameHeaderSize; ++operand)2289 computeValueRecoveryFor(operand).dump(stderr);2290 2291 fprintf(stderr, " : ");2292 2293 for (int operand = 0; operand < (int)m_variables.size(); ++operand)2294 computeValueRecoveryFor(operand).dump(stderr);2295 #endif2296 2297 #if ENABLE(DFG_DEBUG_VERBOSE)2298 fprintf(stderr, "\n");2299 #endif2300 2301 if (node.shouldGenerate())2302 checkConsistency();2303 }2304 }2305 2306 // If we are making type predictions about our arguments then2307 // we need to check that they are correct on function entry.2308 void SpeculativeJIT::checkArgumentTypes()2309 {2310 ASSERT(!m_compileIndex);2311 m_bytecodeIndexForOSR = 0;2312 2313 for (size_t i = 0; i < m_arguments.size(); ++i)2314 m_arguments[i] = ValueSource(ValueInRegisterFile);2315 for (size_t i = 0; i < m_variables.size(); ++i)2316 m_variables[i] = ValueSource(ValueInRegisterFile);2317 2318 for (int i = 0; i < m_jit.codeBlock()->m_numParameters; ++i) {2319 VirtualRegister virtualRegister = (VirtualRegister)(m_jit.codeBlock()->thisRegister() + i);2320 PredictedType predictedType = m_jit.graph()[m_jit.graph().m_arguments[i]].variableAccessData()->prediction();2321 if (isInt32Prediction(predictedType))2322 speculationCheck(m_jit.branchPtr(MacroAssembler::Below, JITCompiler::addressFor(virtualRegister), GPRInfo::tagTypeNumberRegister));2323 else if (isArrayPrediction(predictedType)) {2324 GPRTemporary temp(this);2325 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());2326 speculationCheck(m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister));2327 speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));2328 } else if (isBooleanPrediction(predictedType)) {2329 GPRTemporary temp(this);2330 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());2331 m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), temp.gpr());2332 speculationCheck(m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), TrustedImm32(static_cast<int32_t>(~1))));2333 }2334 }2335 }2336 2337 bool SpeculativeJIT::compile()2338 {2339 checkArgumentTypes();2340 2341 ASSERT(!m_compileIndex);2342 for (m_block = 0; m_block < m_jit.graph().m_blocks.size(); ++m_block)2343 compile(*m_jit.graph().m_blocks[m_block]);2344 linkBranches();2345 return true;2346 }2347 2348 ValueRecovery SpeculativeJIT::computeValueRecoveryFor(const ValueSource& valueSource)2349 {2350 switch (valueSource.kind()) {2351 case ValueInRegisterFile:2352 return ValueRecovery::alreadyInRegisterFile();2353 2354 case Int32InRegisterFile:2355 return ValueRecovery::alreadyInRegisterFileAsUnboxedInt32();2356 2357 case HaveNode: {2358 if (m_jit.isConstant(valueSource.nodeIndex()))2359 return ValueRecovery::constant(m_jit.valueOfJSConstant(valueSource.nodeIndex()));2360 2361 Node* nodePtr = &m_jit.graph()[valueSource.nodeIndex()];2362 if (!nodePtr->shouldGenerate()) {2363 // It's legitimately dead. As in, nobody will ever use this node, or operand,2364 // ever. Set it to Undefined to make the GC happy after the OSR.2365 return ValueRecovery::constant(jsUndefined());2366 }2367 2368 GenerationInfo* infoPtr = &m_generationInfo[nodePtr->virtualRegister()];2369 if (!infoPtr->alive() || infoPtr->nodeIndex() != valueSource.nodeIndex()) {2370 // Try to see if there is an alternate node that would contain the value we want.2371 // There are four possibilities:2372 //2373 // ValueToNumber: If the only live version of the value is a ValueToNumber node2374 // then it means that all remaining uses of the value would have performed a2375 // ValueToNumber conversion anyway. Thus, we can substitute ValueToNumber.2376 //2377 // ValueToInt32: Likewise, if the only remaining live version of the value is2378 // ValueToInt32, then we can use it. But if there is both a ValueToInt322379 // and a ValueToNumber, then we better go with ValueToNumber because it2380 // means that some remaining uses would have converted to number while2381 // others would have converted to Int32.2382 //2383 // UInt32ToNumber: If the only live version of the value is a UInt32ToNumber2384 // then the only remaining uses are ones that want a properly formed number2385 // rather than a UInt32 intermediate.2386 //2387 // The reverse of the above: This node could be a UInt32ToNumber, but its2388 // alternative is still alive. This means that the only remaining uses of2389 // the number would be fine with a UInt32 intermediate.2390 2391 bool found = false;2392 2393 if (nodePtr->op == UInt32ToNumber) {2394 NodeIndex nodeIndex = nodePtr->child1();2395 nodePtr = &m_jit.graph()[nodeIndex];2396 infoPtr = &m_generationInfo[nodePtr->virtualRegister()];2397 if (infoPtr->alive() && infoPtr->nodeIndex() == nodeIndex)2398 found = true;2399 }2400 2401 if (!found) {2402 NodeIndex valueToNumberIndex = NoNode;2403 NodeIndex valueToInt32Index = NoNode;2404 NodeIndex uint32ToNumberIndex = NoNode;2405 2406 for (unsigned virtualRegister = 0; virtualRegister < m_generationInfo.size(); ++virtualRegister) {2407 GenerationInfo& info = m_generationInfo[virtualRegister];2408 if (!info.alive())2409 continue;2410 if (info.nodeIndex() == NoNode)2411 continue;2412 Node& node = m_jit.graph()[info.nodeIndex()];2413 if (node.child1Unchecked() != valueSource.nodeIndex())2414 continue;2415 switch (node.op) {2416 case ValueToNumber:2417 case ValueToDouble:2418 valueToNumberIndex = info.nodeIndex();2419 break;2420 case ValueToInt32:2421 valueToInt32Index = info.nodeIndex();2422 break;2423 case UInt32ToNumber:2424 uint32ToNumberIndex = info.nodeIndex();2425 break;2426 default:2427 break;2428 }2429 }2430 2431 NodeIndex nodeIndexToUse;2432 if (valueToNumberIndex != NoNode)2433 nodeIndexToUse = valueToNumberIndex;2434 else if (valueToInt32Index != NoNode)2435 nodeIndexToUse = valueToInt32Index;2436 else if (uint32ToNumberIndex != NoNode)2437 nodeIndexToUse = uint32ToNumberIndex;2438 else2439 nodeIndexToUse = NoNode;2440 2441 if (nodeIndexToUse != NoNode) {2442 nodePtr = &m_jit.graph()[nodeIndexToUse];2443 infoPtr = &m_generationInfo[nodePtr->virtualRegister()];2444 ASSERT(infoPtr->alive() && infoPtr->nodeIndex() == nodeIndexToUse);2445 found = true;2446 }2447 }2448 2449 if (!found)2450 return ValueRecovery::constant(jsUndefined());2451 }2452 2453 ASSERT(infoPtr->alive());2454 2455 if (infoPtr->registerFormat() != DataFormatNone) {2456 if (infoPtr->registerFormat() == DataFormatDouble)2457 return ValueRecovery::inFPR(infoPtr->fpr());2458 return ValueRecovery::inGPR(infoPtr->gpr(), infoPtr->registerFormat());2459 }2460 if (infoPtr->spillFormat() != DataFormatNone)2461 return ValueRecovery::displacedInRegisterFile(static_cast<VirtualRegister>(nodePtr->virtualRegister()));2462 2463 ASSERT_NOT_REACHED();2464 return ValueRecovery();2465 }2466 2467 default:2468 ASSERT_NOT_REACHED();2469 return ValueRecovery();2470 }2471 }2472 2473 } } // namespace JSC::DFG2474 2475 #endif2476 #endif
Note: See TracChangeset
for help on using the changeset viewer.